最大化缩放距离以适合2个对象 [英] Maximize zoom distance to fit 2 objects

查看:99
本文介绍了最大化缩放距离以适合2个对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目标: 在Z轴上仅移动相机位置 ,以使平截头体适合2个对象.

Objective: Move the camera position ONLY on the Z axis so the frustrum fit 2 objects.

条件:

  • 其中一个对象始终与相机X位置对齐
  • 相机设置为透视模式,而不是按地形设置.
  • 2个球体没有父级
  • One of the objects will be allways aligned with the camera X position
  • Camera is set on perspective mode, not ortographic.
  • the 2 spheres have no parent

结果在顶视图中以拼写方式显示应如下所示:

The result seen in ortographic mode from top-view should look like this:

我到目前为止所做的事情:

使用三角函数可以将其视为:

Using trigonometry this can be seen it as:

知道这一点,目的是找到相邻面,即相机与黑点之间的距离,而黑点仍然适合黄色.

Knowing that, the objective is to find the Adjacent side, which will be the distance between the camera and the black point that will still fit the yellow one.

技术上,这段代码应该找到相邻的值:

TECHNICALLY this piece of code should find the adjacent value:

private float CalculateMaxZoomDistanceToBall()
{
    //Calculate angle from camera, should be divided of 2 cause it's placed on the middle of the line
    Camera currentCamera = cameraComp;
    angleDegrees = currentCamera.fieldOfView / 2; //(degrees)

    //pass the angle to radians 
    angleRadians = angleDegrees * Mathf.Deg2Rad;

    //Calculate the SinAngle
    sinAngle = Mathf.Sin(angleRadians);

    //Calculate Opposite       
    opposite = Mathf.Abs(blackPoint.transform.localPosition.x - yellowPoint.transform.position.x);

    //Calculate hypotenuse
    hypotenuse = opposite / sinAngle;

    //Calculate CosX
    cosAngle = Mathf.Cos(angleRadians);

    //Calculate adjacent distance
    adjacent = cosAngle * hypotenuse;
    
    return adjacent;
}

由于相机对象位于0,我只需将返回值添加到gameObject.transform.position.z

as the camera object is positioned at 0, I simply add the return value to the gameObject.transform.position.z

有人可能会说",但这是在寻找垂直的FOV,您需要水平的FOV.,好吧,我也尝试过使用水平的FOV,找到了:

And someone could say "but this is looking for the vertical FOV, you need the horizontal one", okey, I've also tried with the horizontal one, finded with:

float vFOVrad = currentCamera.fieldOfView * Mathf.Deg2Rad; 
float cameraHeightAt1 = Mathf.Tan(vFOVrad * 0.5f);
float hFOVrad = Mathf.Atan(cameraHeightAt1 * currentCamera.aspect) * 2;
hFOV = hFOVrad * Mathf.Rad2Deg;

并且它不起作用,在某些情况下,摄像机的位置距离预期的位置很远,有时它很合适,而另一些恰好关闭.

And it's not working, in some cases the camera position is to far of the espected position, sometimes it fits well and others it just goes to close.

感谢您的帮助.

推荐答案

我会避免使用角度,而不会在矢量和平面的世界中工作.

I would avoid working with angles and work in the world of vectors and planes.

确定黄点在相机的哪一侧:

Determine which side of the camera the yellow point is on:

Camera cam = cameraComp;
Transform camTransform = cam.transform;
Vector3 yellowPos = yellowPoint.transform.position;

// <0 if on left, >0 if on right
float camDirection = Vector3.Dot(camTransform.right, yellowPos - camTransform.position);

// if it's directly straight ahead, do nothing.
if (Mathf.Approximately(camDirection, 0f)) return;

在黄点的同一侧找到相机视口边缘的光线.视口中的高度无关紧要.

Find a ray for the camera viewport edge on the same side of the yellow point. Height in the viewport won't matter.

Ray edgeRay = cam.ViewportPointToRay(camDirection < 0f ? Vector3.zero : Vector3.right);

定义垂直于相机右侧并经过黄点位置的代数平面(而非物理平面):

Define an algebraic plane (not physics plane) normal to the camera's right and going through the position of the yellow point:

Plane yellowPlane = new Plane(camTransform.right, yellowPos);

使用代数射线投射(而非物理射线投射)查找射线与平面的交点:

Find the intersection of the ray and plane using algebraic raycast (not physics raycast):

float raycastDistance;
if (! yellowPlane.Raycast(edgeRay, out raycastDistance)) return; // should not return

Vector3 raycastPoint = edgeRay.GetPoint(raycastDistance);

找到相交点到yellowPoint位置的差,并以相机的正向进行点积运算,以查找如何沿相机的正向移动相机:

Find the difference from the intersection point to the yellowPoint position, and do a dot product with the camera's forward direction to find how to move the camera along its forward direction:

float forwardDelta = Vector3.Dot(camTransform.forward, yellowPos - raycastPoint);

camTransform.Translate(0f, 0f, forwardDelta);

所以,总共:

Camera cam = cameraComp;
Transform camTransform = cam.transform;
Vector3 yellowPos = yellowPoint.transform.position;

// <0 if on left, >0 if on right
float camDirection = Vector3.Dot(camTransform.right, yellowPos - camTransform.position);

// if it's directly straight ahead, do nothing.
if (Mathf.Approximately(camDirection, 0f)) return;

Ray edgeRay = cam.ViewportPointToRay(camDirection < 0f ? Vector3.zero : Vector3.right);

Plane yellowPlane = new Plane(camTransform.right, yellowPos);

float raycastDistance;
if (! yellowPlane.Raycast(edgeRay, out raycastDistance)) return; // should not return

Vector3 raycastPoint = edgeRay.GetPoint(raycastDistance);

float forwardDelta = Vector3.Dot(camTransform.forward, yellowPos - raycastPoint);

camTransform.Translate(0f, 0f, forwardDelta);

这种方法的优点是,不管相机的方向或相机上点的相对位置如何,它都可以工作.

The good thing about this approach is that it will work regardless of the orientation of the camera, or the relative position of the point from the camera.

这篇关于最大化缩放距离以适合2个对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆