【问题标题】:Unity - Looking through the scope of a gunUnity - 通过枪的范围看
【发布时间】:2015-10-09 16:10:13
【问题描述】:

现在我有 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);
        }
    }
}

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

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

层次结构:

【问题讨论】:

    标签: unity3d camera zooming lerp


    【解决方案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() 期望第三个参数是什么?根据to the documentation,第三个参数应该在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);
            }
        }
    }
    

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

    【讨论】:

    • 我已经实现了这个并且 lerp 确实停止了正确但它仍然 lerp 太远了,几乎把我的手和枪放在地图的另一边。它与层次结构和父子关系有关吗?还是本地定位 vs 全球定位?
    • @KyleJensen 哦,对不起!你是绝对正确的,这是由于本地与全球定位。我仍在修改CameraTransform.position,实际上我应该修改CameraTransform.localPosition。让我知道更新的答案是否有帮助。
    • 我已经将所有内容都更改为 localPosition 并且它现在根本不动......:S
    • 嗯...在我们继续之前,我只想验证一下 - ZoomedTransform.position 到底是什么?
    • 如果您查看我在问题中包含的层次结构,我有两个摄像头,我最初只是在两个摄像头之间切换,但这并不理想。相反,我想将一个摄像头位置调整到另一个摄像头位置的位置。我移除了相机,所以它只是一个变换。我认为问题在于它是主摄像头的孩子,但我不知道我还能做些什么并让它始终相对于枪
    【解决方案2】:

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

    CameraTransform.position + ZoomedTransform.position
    

    这意味着当您的相机移动到更接近该位置时,相机的新位置会导致目的地发生变化。所以你的相机会一直在移动。

    您的目的地应该是ZoomedTransform.position。因为position is in world coordinates,所以不需要添加。 (而当你确实需要在空格之间进行转换时,请查看TransformPoint 和类似的方法。)

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 这不是问题的原因,它应该停在该位置
      • 抱歉,我想我误解了正在发生的事情。 CameraTransform.position = Vector3.Lerp (CameraTransform.position, CameraTransform.position + ZoomedTransform.position, 5f * Time.deltaTime); 当您轮班时,您会不断地将 ZoomedTransform.position 添加到 CamerTransform.position。我认为你需要一个 If 语句来检查它是否在正确的位置,如果不是,那么 Lerp
      • 没关系,只需阅读 Unity api 即可。我认为您需要做的就是将CameraTransform.position + ZoomedTransform.position 换成ZoomedTransform.position Unity Lerp api 我认为这只是在其他相机所在的位置拍摄完毕。
      • 当我这样做时,相机会从玩家身上移开
      • 我编辑了问题以显示播放器和相机的层次结构
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-03
      • 2023-03-10
      • 2020-02-15
      • 1970-01-01
      • 2012-11-13
      • 1970-01-01
      相关资源
      最近更新 更多