【问题标题】:Unity3D smooth camera movement and lookAtUnity3D 平滑相机移动和查看
【发布时间】:2017-01-25 08:39:38
【问题描述】:

在我的 Unity3D C# 项目中遇到相机移动问题。

我有什么:

  • 场景中的一些物体
  • 一个相机,可以从任何物体的位置或它自己的当前位置飞行

我需要什么:

  • 平滑旋转相机到对象的原点之一
  • 飞到物体附近的位置(有一个空的,所以我飞到空的坐标)

算法:旋转到物体的原点,旋转完成后开始飞到空的位置。飞行时,查看物体的原点。

问题是它不平滑,相机在运动结束时“跳跃”。

我的 C# 代码(附在相机上):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class testMove : MonoBehaviour {
    public GameObject startObj;
    public GameObject endObj;    
    public float speed = 1.0F;
    private float startTime;
    private float journeyLength;
    private string endObjName;
    private GameObject endObjLookAt;
    void Start () {
        startTime = Time.time;        
        if (startObj) {            
        } else {
            startObj = this.gameObject;
        }       
        journeyLength = Vector3.Distance(startObj.transform.position, endObj.transform.position);        
        endObjName = endObj.name;
        endObjLookAt = GameObject.Find(endObjName + "LookAt");
    }   

    void Update () {
        if (endObj) {            
            float distCovered = (Time.time - startTime) * speed;
            float fracJourney = distCovered / journeyLength;
            tweenLook(endObjLookAt, fracJourney);
            float angle = Quaternion.Angle(transform.rotation, Quaternion.LookRotation(endObjLookAt.transform.position - transform.position));            
            if (angle <= 0.0001) { 
                Debug.Log("rotation finished");
                tweenPos(startObj, endObj, fracJourney);
                transform.LookAt(endObjLookAt.transform.position);                
            }
        }
    }

    private void tweenPos(GameObject startObj, GameObject endObj, float fracJourney) {
        Vector3 newposition = Vector3.Lerp(startObj.transform.position, endObj.transform.position, fracJourney);        
        transform.position = newposition;        
    }

    private void tweenLook(GameObject endObjLookAt, float fracJourney) {
        Quaternion newrotation = Quaternion.LookRotation(endObjLookAt.transform.position - transform.position);
        transform.rotation = Quaternion.Slerp(transform.rotation, newrotation, fracJourney);
    }
}

【问题讨论】:

  • 为什么不Lerp()ing?
  • @YotamSalmon 您能否有礼貌地告诉我 Lerp 应该使用什么参数以及在哪里?抱歉,我对 Unity 很陌生。只是想在 Unity 中移植我的 ThreeJs 相机运动。
  • 对不起,如果我看起来很粗鲁,那绝不是我的意图:) 你传递了一个 T 初始值(可以是 int、float、vector、Quaterion 等)、T 最终值和 lerping 因子(0-1 ),它实际上会影响运动。通常您使用 Time.deltaTime * N (N 变化) 作为 lerping 因素
  • @YotamSalmon 没关系,我不认为你粗鲁!谢谢! :)
  • @halfer 非常感谢 yoo,明白了!

标签: c# unity3d camera


【解决方案1】:

由于您要实现的目标意味着一个接一个地执行操作,因此我建议使用 协程

public class testMove : MonoBehaviour
{
    public Transform startObj;
    public Transform endObj;
    private Transform endObjLookAt;

    public float rotationDuration;
    public AnimationCurve rotationCurve;

    public float movementDuration;
    public AnimationCurve movementCurve;

    private IEnumerator moveAndRotateCameraIEnumerator;

    void Start()
    {
        // If you want to do it on start just call MoveAndRotateCamera() here, else call if from anywhere you want (a script, a game button, ...)
    }

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            MoveAndRotateCamera();
        }
    }

    public void MoveAndRotateCamera(Transform startTransform = null, Transform endTransform = null)
    {
        if(startTransform)
        {
            startObj = startTransform;
        }
        else
        {
            startObj = this.transform;
        }

        if(endTransform)
        {
            endObj = endTransform;
        }
        endObjLookAt = GameObject.Find(endObj.name + "LookAt").transform;

        if(moveAndRotateCameraIEnumerator != null)
        {
            StopCoroutine(moveAndRotateCameraIEnumerator);
        }
        moveAndRotateCameraIEnumerator = MoveAndRotateCameraCoroutine();
        StartCoroutine(moveAndRotateCameraIEnumerator);
    }

    private IEnumerator MoveAndRotateCameraCoroutine()
    {
        //ROTATION
        Vector3 startEulerAngles = transform.eulerAngles;
        transform.LookAt(endObjLookAt);
        Vector3 deltaEulerAngles = new Vector3(Mathf.DeltaAngle(startEulerAngles.x, transform.eulerAngles.x), Mathf.DeltaAngle(startEulerAngles.y, transform.eulerAngles.y), Mathf.DeltaAngle(startEulerAngles.z, transform.eulerAngles.z));

        Debug.Log("Starting rotation...");
        float timer = 0.0f;
        while(timer < rotationDuration)
        {
            timer += Time.deltaTime;
            transform.eulerAngles = startEulerAngles + deltaEulerAngles * rotationCurve.Evaluate(timer / rotationDuration);
            yield return new WaitForEndOfFrame();
        }
        transform.eulerAngles = startEulerAngles + deltaEulerAngles;
        Debug.Log("Rotation done!");
        //----

        //MOVEMENT
        Vector3 startPosition = transform.position;

        Debug.Log("Starting movement...");
        timer = 0.0f;
        while(timer < movementDuration)
        {
            timer += Time.deltaTime;
            transform.position = Vector3.Lerp(startPosition, endObj.position, movementCurve.Evaluate(timer / movementDuration));
            transform.LookAt(endObjLookAt);
            yield return new WaitForEndOfFrame();
        }
        transform.position = endObj.position;
        transform.LookAt(endObjLookAt);
        Debug.Log("Movement done!");
        //----
    }
}

请注意以下几点:

  • 将您的 GameObject 变量更改为 Transform 变量,因为您总是使用它们来访问 Transform 组件,因此您可以直接使用它
  • 为旋转和移动添加了时间概念,而不是速度概念(您也可以使用速度代替:只需将 Time.deltaTime 乘以您的速度系数)
  • 使用 AnimationCurve 允许您调整旋转/移动的方式:只需在 Inspector 中设置曲线(曲线必须从 (0, 0) 开始并在 (1, 1) 结束)

希望对你有帮助,

【讨论】:

  • 非常感谢您!想给你拿点啤酒(:但还是有一个问题:相机在最后一帧跳了起来。试着解释一下,我的意思是:想想,我们有 30 帧这个动作。在 29 日,我们有相机看着我们的物体,但它不平行于对象方向(感觉就像你在看一个角度的东西),但在第 30 帧,它看起来很正常。希望你能理解我的糟糕描述
  • 您确定检查器上的 AnimationCurve 曲线在 (1.0, 1.0) 处结束(我只是尝试多次运行它并且没有任何问题)?提示:您可以使用 Ctrl 键将曲线点捕捉到舍入值。
  • 是的,我确定,我已经从标准预设中选择了我的曲线。我会试着找出问题所在。非常感谢你!
  • 我想我想出了问题所在(Transform eulerAngles 的值不是 0,所以 LookAt() 改变了方向):稍后我会编辑我的答案 :)
  • 刚刚发现出了什么问题。我的空(一个物体,相机飞到)是直接向上的另一个空(看)。我搬了第一个空的,一切都好!我的错,你的代码太棒了!祝你有美好的一天!
猜你喜欢
  • 2014-01-20
  • 2012-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-21
  • 1970-01-01
  • 2020-06-23
  • 1970-01-01
相关资源
最近更新 更多