最大化缩放距离以适合 2 objects

Maximize zoom distance to fit 2 objects

Objective: 在 Z 轴上移动相机位置 ONLY,使平截头体适合 2 objects。

条件:

top-view 在正交模式下看到的结果 应该如下所示:

到目前为止我做了什么:

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

知道了,objective就是找相邻的边,也就是相机到黑点的距离,还是会和黄点相配.

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

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;
}

由于相机 object 位于 0,我只需将 return 值添加到 gameObject.transform.position.z

有人会说 “但这是在寻找垂直视场,你需要水平视场”,好吧,我也试过水平视场,找到了:

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;

而且它不工作,在某些情况下,相机位置离预期位置太远,有时它很合适,而另一些情况下它就会关闭。

如有任何帮助,我们将不胜感激。

我会避免使用角度并在向量和平面的世界中工作。

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

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);

求交点到y​​ellowPoint位置的差值,与相机的前进方向做点积,求出相机向前移动的方法:

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);

这种方法的好处在于,无论相机的方向如何,或者点与相机的相对位置如何,它都会起作用。