倾斜模型与加速度坐标系

3

我已经花了一些时间在一个CharacterController上工作(这是目前的代码):

using UnityEngine;

[RequireComponent(typeof(CharacterController))]
class MomentumMovement : MonoBehaviour
{
    public GameObject playerCamera;
    public GameObject playerModel;

    CharacterController controller;
    float speed = 400f;
    Vector3 lastVelocity;

    void Start()
    {
        controller = GetComponent<CharacterController>();
        lastVelocity = controller.velocity;
    }

    Vector3 ScaleDirectionVector(Vector3 direction)
    {
        float multiplier = 1 / (Mathf.Abs(direction.x) + Mathf.Abs(direction.z));
        return new Vector3(
            direction.x * multiplier,
            0,
            direction.z * multiplier
        );
    }

    void Move()
    {
        Vector3 moveVector = ScaleDirectionVector(playerCamera.transform.forward) * Input.GetAxis("Vertical");
        moveVector += ScaleDirectionVector(playerCamera.transform.right) * Input.GetAxis("Horizontal");
        moveVector *= speed * Time.deltaTime;
        controller.SimpleMove(moveVector);
        playerModel.transform.position = transform.position;
    }

    void RotateToVelocity()
    {
        Vector3 lookAt = transform.position + controller.velocity.normalized;
        Vector3 targetPostition = new Vector3(lookAt.x, transform.position.y, lookAt.z);
        if (targetPostition - transform.position != Vector3.zero)
        {
            Quaternion q = Quaternion.LookRotation(targetPostition - transform.position);
            transform.rotation = Quaternion.RotateTowards(transform.rotation, q, 500 * Time.deltaTime);
        }

    }

    Vector3 CalculateTilt(Vector3 acceleration)
    {
        return new Vector3(
            acceleration.z,
            0,
            acceleration.x
        );
    }

    void TiltToAcceleration()
    {
        Vector3 centerOfMass = controller.center + controller.transform.position;
        Vector3 acceleration = controller.velocity / Time.deltaTime - lastVelocity;
        Vector3 tilt = CalculateTilt(acceleration);
        Quaternion targetRotation = Quaternion.Euler(transform.eulerAngles + tilt);
        playerModel.transform.rotation = Quaternion.Lerp(playerModel.transform.rotation, targetRotation, 10 * Time.deltaTime);
    }

    void FixedUpdate()
    {
        Move();
        RotateToVelocity();
        TiltToAcceleration();
        lastVelocity = controller.velocity / Time.deltaTime;
    }
}

我遇到了几天的问题,要在玩家模型上添加“加速倾斜”效果。

需要注意的是脚本附加在一个带有CharacterController的GameObject上,而playerModel是场景中的一个独立对象,我试图通过这种方式防止一些局部-全局旋转问题(我可能在这里错了)

由于某种原因(这是最好的代码变体),只有当朝着正向z加速时,加速倾斜才看起来正确。
现在,我知道这与三角函数有关,但我已经尝试了许多Sin(transform.eulerAngles.y)或Cos(transform.eulerAngles.y)* something的计算变化,但仍然无法使其正常工作。

请问有人能指出我的错误吗?谢谢大家。

注意: 模型移动中也存在奇怪的抖动,如果有人能帮我解决这个问题,那就太好了。

2个回答

1
我正在寻找像这样的方法,并试图按照您的代码进行操作,但我认为您的加速度公式是错误的。 Vector3 acceleration = controller.velocity / Time.deltaTime - lastVelocity; 这是您的加速度公式,但它不正确,因为您正在除以 deltaTime - lastVelocity,而且您的 lastVelocity 变量被设置为 velocity / Time.deltaTime,这是一个问题,这也是您的代码不准确并且不会倾斜转向或朝向实际速度的原因。您的加速度公式应该是这样的: Vector3 acceleration = (controller.velocity - lastVelocity) / timeTaken; 您不能仅仅通过除以 deltaTime 来计算,因为这不是公式所需的,虽然大多数公式使用 Δt 作为时间变量,但它并不代表 unity 中的 deltaTime。它表示从 lastVelocity 到当前速度所需的时间。这意味着您需要创建一个名为 timeTaken 的浮点变量,在 update 中不断添加 Time.deltaTime 给它。您还需要确保 lastVelocity 只是设置为 controller.velocity 而不是除以 deltaTime。因此在您的代码中,在设置 lastVelocity 后,开始更新 timeTaken,并在调用 TiltToAcceleration 后将 timeTaken 重置为零并更新 lastVelocity。您还可以使用步进轮跟踪距离并以这种方式更新变量,因为这是我为我的游戏所做的,我不会解释它,因为它会更加复杂,但也会导致更准确的倾斜。我知道我来晚了,但这是修复抖动并使其倾斜转向的方法。还要避免将 fixedUpdate 用于所有内容。虽然对于 Rigidbody 物理更新使用它很好(只要您已将身体设置为插值),但它在非常不同的时间步进中更新。因此,请确保使用 update 进行旋转,并且您将看到它的平滑程度。

0
弄清楚了,这是一个非常容易修复的错误,虽然抖动仍然是一个问题,但模型现在可以正确地倾斜了。
以下是代码:
using UnityEngine;

[RequireComponent(typeof(CharacterController))]
class MomentumMovement : MonoBehaviour
{
    public GameObject playerCamera;
    public GameObject playerModel;

    CharacterController controller;
    float speed = 400f;
    Vector3 lastVelocity;

    void Start()
    {
        controller = GetComponent<CharacterController>();
        lastVelocity = controller.velocity;
    }

    Vector3 ScaleDirectionVector(Vector3 direction)
    {
        float multiplier = 1 / (Mathf.Abs(direction.x) + Mathf.Abs(direction.z));
        return new Vector3(
            direction.x * multiplier,
            0,
            direction.z * multiplier
        );
    }

    void Move()
    {
        Vector3 moveVector = ScaleDirectionVector(playerCamera.transform.forward) * Input.GetAxis("Vertical");
        moveVector += ScaleDirectionVector(playerCamera.transform.right) * Input.GetAxis("Horizontal");
        moveVector *= speed * Time.deltaTime;
        controller.SimpleMove(moveVector);
        playerModel.transform.position = transform.position;
    }

    void RotateToVelocity()
    {
        Vector3 lookAt = transform.position + controller.velocity.normalized;
        Vector3 targetPosition = new Vector3(lookAt.x, transform.position.y, lookAt.z);
        if (targetPosition - transform.position != Vector3.zero)
        {
            Quaternion q = Quaternion.LookRotation(targetPosition - transform.position);
            transform.rotation = Quaternion.RotateTowards(transform.rotation, q, 500 * Time.deltaTime);
        }

    }

    Vector3 CalculateTilt(Vector3 acceleration)
    {
        Vector3 tiltAxis = Vector3.Cross(acceleration, Vector3.up);
        tiltAxis.y = 0;
        Quaternion targetRotation = Quaternion.AngleAxis(30, tiltAxis) * transform.rotation;
        return targetRotation.eulerAngles;
    }

    void TiltToAcceleration()
    {
        Vector3 centerOfMass = controller.center + controller.transform.position;
        Vector3 acceleration = controller.velocity / Time.deltaTime - lastVelocity;
        Vector3 tilt = CalculateTilt(acceleration);
        Quaternion targetRotation = Quaternion.Euler(tilt);
        playerModel.transform.rotation = Quaternion.Lerp(playerModel.transform.rotation, targetRotation, 10 * Time.deltaTime);
    }

    void FixedUpdate()
    {
        Move();
        RotateToVelocity();
        TiltToAcceleration();
        lastVelocity = controller.velocity / Time.deltaTime;
    }
}

我最终计算出要旋转的轴(即世界“上”方向与加速度向量的叉积),并手动将模型沿其旋转30度。

现在,这是我以前尝试过的事情,但问题的关键在于这一行代码:
Quaternion targetRotation = Quaternion.Euler(transform.eulerAngles + tilt);

后来这被改为:

Quaternion targetRotation = Quaternion.Euler(tilt);

希望我的代码能帮助到大家! 编辑:这是新版本的代码,减少了大部分抖动:
using UnityEngine;

[RequireComponent(typeof(CharacterController))]
class MomentumMovement : MonoBehaviour
{
    public GameObject playerCamera;
    public GameObject playerModel;

    CharacterController controller;
    float speed = 400f;
    Vector3 lastVelocity;

    void Start()
    {
        controller = GetComponent<CharacterController>();
        lastVelocity = controller.velocity;
    }

    Vector3 ScaleDirectionVector(Vector3 direction)
    {
        float multiplier = 1 / (Mathf.Abs(direction.x) + Mathf.Abs(direction.z));
        return new Vector3(
            direction.x * multiplier,
            0,
            direction.z * multiplier
        );
    }

    void Move()
    {
        Vector3 moveVector = ScaleDirectionVector(playerCamera.transform.forward) * Input.GetAxis("Vertical");
        moveVector += ScaleDirectionVector(playerCamera.transform.right) * Input.GetAxis("Horizontal");
        moveVector *= speed * Time.deltaTime;
        controller.SimpleMove(moveVector);
        playerModel.transform.position = transform.position;
    }

    void RotateToVelocity()
    {
        Vector3 lookAt = transform.position + controller.velocity.normalized;
        Vector3 targetPosition = new Vector3(lookAt.x, transform.position.y, lookAt.z);
        if (targetPosition - transform.position != Vector3.zero)
        {
            Quaternion q = Quaternion.LookRotation(targetPosition - transform.position);
            transform.rotation = Quaternion.RotateTowards(transform.rotation, q, 500 * Time.deltaTime);
        }

    }

    Vector3 CalculateTilt(Vector3 acceleration)
    {
        acceleration.y = 0;
        Vector3 tiltAxis = Vector3.Cross(acceleration, Vector3.up);
        float angle = Mathf.Clamp(-acceleration.magnitude, -30, 30);
        Quaternion targetRotation = Quaternion.AngleAxis(angle, tiltAxis) * transform.rotation;
        return targetRotation.eulerAngles;
    }

    void TiltToAcceleration()
    {
        Vector3 centerOfMass = controller.center + controller.transform.position;
        Vector3 acceleration = controller.velocity / Time.deltaTime - lastVelocity;
        Vector3 tilt = CalculateTilt(acceleration);
        Quaternion targetRotation = Quaternion.Euler(tilt);
        playerModel.transform.rotation = Quaternion.Lerp(playerModel.transform.rotation, targetRotation, 10 * Time.deltaTime);
    }

    void FixedUpdate()
    {
        Move();
        RotateToVelocity();
        TiltToAcceleration();
        lastVelocity = controller.velocity / Time.deltaTime;
    }
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接