1

现在我有 2 个摄像头:主摄像头显示枪的正常状态,第二个摄像头连接到枪上(枪是主摄像头的子摄像头),切换时它会透过枪的范围并增加视野。

为了更好地理解,这里有一个视觉效果:

在此处输入图像描述

在此处输入图像描述

现在,如果我只是打开第二个摄像头并关闭主摄像头,这将非常有效,但它不是很理想。每个场景应该只有 1 个摄像头。

所以我想调整相机的位置以查看范围并手动减小视野。所以我写了以下脚本:

[RequireComponent(typeof(Camera))]
public class Zoom : MonoBehaviour {

    private Transform CameraTransform = null;
    public Transform ZoomedTransform;

    private bool zoomed = false;

    void Start () {
        CameraTransform = Camera.main.transform;
    }

    // Update is called once per frame
    void Update () {
        if (Input.GetKey (KeyCode.LeftShift)) 
        {
            CameraTransform.position = Vector3.Lerp (
                CameraTransform.position, 
                CameraTransform.position + ZoomedTransform.position, 
                5f * Time.deltaTime
            );
            CameraTransform.Rotate(ZoomedTransform.rotation.eulerAngles);
        }
    }
}

问题在于它不起作用:当我按下变焦按钮时,相机以光速穿过场景,很难准确判断发生了什么。

谁能给我一些关于我做错了什么的见解?我认为这与父子关系有关,但即使我尝试使用静态值,我似乎也无法复制正确的解决方案。

等级制度:

在此处输入图像描述

4

3 回答 3

1

ZoomedTransform(这个答案是在一个相对变换的假设下运行的,而不是 31eee384 的答案所怀疑的相机的绝对位置。)

我认为您的代码存在一些问题。我将单独处理它们,以便它们更容易理解,但它们都与以下行有关:

CameraTransform.position = Vector3.Lerp (CameraTransform.position, CameraTransform.position + ZoomedTransform.position, 5f * Time.deltaTime);

首先,让我们看看您是如何使用Vector3.Lerp(). 对于 的第三个参数Vector3.Lerp(),您提供5f * Time.deltaTime. 这个值到底有什么作用?好吧,标准帧速率约为 60 FPS,所以Time.deltaTime= ~1/60。因此,5f * Time.deltaTime= 5/60 = ~0.0833。

Vector3.Lerp()但是,第三个论点的期望是什么?根据文档,第三个参数应该在 0 和 1 之间,并确定返回的参数Vector3应该更接近第一个还是第二个给定的Vector3。所以是的,5f * Time.deltaTime落在这个范围内,但不会发生插值 - 因为它总是在 ~0.0833 左右,而不是从 0 到 1(或 1 到 0)。每一帧,你基本上总是回来cameraPos + zoomTransform * 0.0833

另一个值得注意的问题是您如何更新CameraTransform.position每一帧的值,然后使用新的(增加的)值作为Vector3.Lerp()下一帧的参数。(这有点像int i = i + 1;循环。)这就是为什么你的相机飞过地图这么快的原因。这是每一帧发生的事情,使用Vector3.Lerp()我之前计算的假设结果(伪代码):

// Frame 1
cameraPosFrame_1 = cameraPosFrame_0 + zoomTransform * 0.0833;
// Frame 2
cameraPosFrame_2 = cameraPosFrame_1 + zoomTransform * 0.0833;
// Frame 3
cameraPosFrame_3 = cameraPosFrame_2 + zoomTransform * 0.0833;
// etc...

每一帧,zoomTransform * 0.0833都被添加到相机的位置。这最终会是一个非常非常快速且不间断的增值 - 所以你的相机会飞过地图。

解决这些问题的一种方法是使用变量来存储相机的初始本地位置、缩放进度和缩放速度。这样,我们就不会丢失相机的原始位置,并且我们可以跟踪变焦的进展情况以及何时停止变焦。

[RequireComponent(typeof(Camera))]
public class Zoom : MonoBehaviour {

    private Transform CameraTransform = null;
    public Transform ZoomedTransform;
    private Vector3 startLocalPos;
    private float zoomProgress = 0;
    private float zoomLength = 2; // Number of seconds zoom will take

    private bool zoomed = false;

    void Start () {
        CameraTransform = Camera.main.transform;
        startLocalPos = CameraTransform.localPosition;
    }

    // Update is called once per frame
    void Update () {
        if (Input.GetKey (KeyCode.LeftShift)) 
        {
            zoomProgress += Time.deltaTime;

            CameraTransform.localPosition = Vector3.Lerp (startLocalPos, startLocalPos + ZoomedTransform.position, zoomProgress / zoomLength);
            CameraTransform.Rotate(ZoomedTransform.rotation.eulerAngles);
        }
    }
}

希望这可以帮助!如果您有任何问题,请告诉我。这个答案确实有点杂乱无章,所以我希望你能从中得到重点。

于 2015-10-09T20:10:35.830 回答
1

您的 lerp 目标相对于相机的当前位置,因此它不断移动。这是您的目标:

CameraTransform.position + ZoomedTransform.position

这意味着当您的相机移动到更接近该位置时,相机的新位置会导致目的地发生变化。因此,您的相机将永远移动。

你的目的地应该是ZoomedTransform.position。不需要添加,因为position在世界坐标中。(而当你确实需要在空格之间进行转换时,可以使用 check outTransformPoint和类似的方法。)

于 2015-10-09T19:43:16.133 回答
0

自从我在 Unity 中做任何事情以来已经有一段时间了,但我认为它是在帧时间而不是在实际时间处理 Lerp 函数。您将需要在帧时未处理的另一个函数中调用它。

于 2015-10-09T16:17:15.200 回答