【问题标题】:Smooth move camera position according to array of cameras根据相机阵列平滑移动相机位置
【发布时间】:2018-04-13 14:16:20
【问题描述】:

我目前正在尝试使用预定义的摄像头位置数组平滑地更改摄像头的位置。 它应该是这样的:

  • 我按空格,相机应该会平滑地切换到相机阵列中相机0的位置
  • 我再次按空格,相机应该会顺利切换到相机阵列中相机1的位置
  • 等等

    public class CameraWaypoints : MonoBehaviour {
    
    public Camera[] CamPOVs;
    private Camera _main;
    private int _indexCurrentCamera;
    private int _indexTargetCamera;
    private float _speed = 0.1f;
    
    void Start () {
        _indexTargetCamera = 0;
        _main = Camera.main;
    
        //disable all camera's
        for (int i = 0; i < CamPOVs.Length; i++)
        {
            CamPOVs[i].enabled = false;
        }
    
        _indexCurrentCamera = 0;
    }
    
    // Update is called once per frame
    void Update () {
    
        if (Input.GetKeyDown(KeyCode.Space))
        {
            if (_indexTargetCamera < CamPOVs.Length)
            {
                _indexCurrentCamera = _indexTargetCamera;
                _indexTargetCamera++;
            }
        }
    
        //prevent array out of bounds
        if (_indexTargetCamera >= CamPOVs.Length)
        {
            _indexTargetCamera = 0;
        }
    
        _main.transform.position = Vector3.Lerp(CamPOVs[_indexCurrentCamera].transform.position, CamPOVs[_indexTargetCamera].transform.position, Time.time * _speed);
    
        _main.transform.rotation = CamPOVs[_indexTargetCamera].transform.rotation;
    
    
    }
    }
    

使用我当前的解决方案,相机实际上可以平滑地移动到目标。 但是,一旦达到该目标,然后按空格键,相机只会更改为目标,而不进行平滑处理。

就好像一旦 lerp 成功完成了一次,它就不会再 lerp 了,除非我当然重新开始。

编辑:澄清一下:按下空格键时,相机目标实际上会发生变化,并且相机会跟随这个目标。问题是,一旦相机位置到达目标位置一次,它就不再平滑地移动到目标,而是立即改变它的位置到目标。

【问题讨论】:

  • 听起来像是“缺少重新初始化”的问题,Start() 只执行一次?
  • 也许你更改目标太快(因为每次调用 Update() 都会检查 GetKeyDown(...)
  • 不是问题,因为所有相机移动都在更新函数中处理。
  • 问题发生的时候不改目标。它实际上是在相机到达目标之前没有改变目标时发生的。

标签: c# unity3d camera lerp


【解决方案1】:

之后按空格键,相机就变成了目标, 没有平滑。

当您按下space 时,源和目标都会更改,因此您会立即设置变换的位置。

一旦 lerp 成功完成一次,它将永远不会 lerp 再次,除非我当然重新开始。

来自文档:

1.时间.时间

这是自游戏开始以来的秒数

2。 Vector3.Lerp

参数t(时间)被限制在[0, 1]范围内

因此,Time.time 将继续上升,但 Lerp 将限制为最大值 1。当您计算 Time.time * 0.1 (your speed) 时,需要 10 秒才能达到您的目标。任何超过 10 秒的内容都将被限制为 1,这将导致立即跳转到您的目的地。请改用Time.deltaTime

此外,您不需要多个摄像头来充当定位目标。一系列转换就可以了。

说了这么多,它应该是这样的:

public class CameraWaypoints : MonoBehaviour
{
    public Transform[] CamPOVs;
    public float _speed = 0.1f;

    private Camera _main;
    private int _indexTargetCamera;        

    void Awake ()
    {
        _main = Camera.main;
        _indexTargetCamera = 0;         
    }

    void Update ()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            _indexTargetCamera = ++_indexTargetCamera % CamPOVs.Length;
        }

         var time = Time.deltaTime * _speed;

         // Alternatives to Lerp are MoveTowards and Slerp (for rotation)  
         var position = Vector3.Lerp(_main.transform.position, CamPOVs[_indexTargetCamera].position, time);
         var rotation = Quaternion.Lerp(_main.transform.rotation, CamPOVs[_indexTargetCamera].rotation, time);

        _main.transform.position = position;
        _main.transform.rotation = rotation;
    }
}

【讨论】:

  • 非常感谢,这就像一个魅力!你对某些事情的阐述帮助我理解了其中的大部分内容,这正是我在这里的原因。我还有几个小问题:1)你有理由把时间放在变量中吗? 2) _indexTargetCamera = ++_indexTargetCamera % CamPOVs.Length; =>这对我来说是未来所有数组的一个很好的解决方案,像这样循环它们而不冒索引超出范围的风险吗?它看起来很干净,只是想知道这样做是否有任何缺点。
  • 不能再编辑我的评论了,但是你有什么理由把你的第一个方法命名为“Awake()”而不是我的标准“Start()”吗?
  • @Thrindil 不客气,问好问题! #1 是的,我们将time 用于位置和旋转Lerps,因此它节省了两次计算该值(这是一种优化)。
  • #2 是的,它可以防止边界问题并且可以用于任何数组。当该行执行时,它首先将值加一(++ 预增量),然后从array.length 计算任何余数(% 模数基本上包装数字连续) .我能想到的唯一缺点是,在引擎盖下,模运算需要一个除法,如果运行数百万(和数百万)次可能会稍微比@987654332慢@分支(这里不是问题)。
  • 非常感谢,你太棒了!你完美地回答了我所有的问题!
猜你喜欢
  • 2012-09-17
  • 1970-01-01
  • 1970-01-01
  • 2012-07-21
  • 2020-06-23
  • 1970-01-01
  • 1970-01-01
  • 2014-01-20
  • 1970-01-01
相关资源
最近更新 更多