2

目标:在 Z 轴上 移动相机位置,使视锥体适合 2 个对象。

条件:

  • 其中一个对象将始终与相机 X 位置对齐
  • 相机设置为透视模式,而不是正交。
  • 2个球体没有父级

从顶视图以正交模式看到的结果应如下所示: 在此处输入图像描述

到目前为止我所做的:

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

在此处输入图像描述

知道了这一点,目标是找到相邻的一面,这将是相机和仍然适合黄色的黑点之间的距离。

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

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

有人可能会说“但这是在寻找垂直的 FOV,你需要水平的”,好吧,我也尝试过水平的,发现:

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;

而且它不起作用,在某些情况下,相机位置离预期位置很远,有时它很合适,而另一些则只是关闭。

任何帮助将不胜感激,谢谢。

4

1 回答 1

1

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

确定黄点在摄像机的哪一侧:

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

这种方法的好处是,无论相机的方向如何,或者相机点的相对位置如何,它都可以工作。

于 2020-01-31T16:01:40.500 回答