四元数在X和Z轴上不带Y轴

时间:2019-07-03 21:52:07

标签: c# unity3d

Quaternion Rotation我正在尝试将播放器绕X,Y和Z轴旋转。 Y轴不应从最后一个角度移动。例如,如果我向左旋转45度,则播放器不应旋转回0。播放器的X和Z轴最多旋转30度,然后在不再使用Input时,请稳定为0。

通过反复试验,我终于使我的Y角不Slerp回到0。但是,X和Z仍然认为Y是0度。播放器旋转了(假定向左旋转45度),但是沿X和Z的移动就好像Y是0度。

我一直在阅读文章和主题,并观看多个领域的视频,包括但不限于StackOverflow,Unity论坛,Unity API和YouTube视频。

Video of Current Game-注意引擎排气-X和Z永远不会更改为“相机”视图/播放器Y方向的新法线。

        void Update()
    {
        if(!controller.isGrounded)
        {

            //Three degree's
            moveDirection = new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Thrust"), Input.GetAxis("Vertical"));
            moveDirection *= speed;

            //rotate around Y-Axis
            transform.Rotate(0, Input.GetAxis("Yaw") * rotationSpeed, 0);
            float currentY = transform.eulerAngles.y; //save Y for later

            //rotation around X and Z
            float tiltAroundX = Input.GetAxis("Vertical") * tiltAngle;
            float tiltAroundZ = -1 * (Input.GetAxis("Horizontal") * tiltAngle);

            Quaternion targetRotation = Quaternion.Euler(tiltAroundX, currentY, tiltAroundZ);

            Vector3 finalRotation = Quaternion.Slerp(transform.rotation, targetRotation, smooth).eulerAngles;
            finalRotation.y = currentY; //reintroduce Y
            transform.rotation = Quaternion.Euler(finalRotation);

        controller.Move(moveDirection * Time.deltaTime);
    }

2 个答案:

答案 0 :(得分:3)

经过进一步的研究使我走上了不同的道路,我发现有两个问题。这两个问题都围绕着这样一个事实,即旋转后Z轴从未归一化为新的Y轴度。 @Ruzihm,解决了旋转问题。我解决了当时可见的运动问题。旋转正常后,即可轻松看到它。

本质上,必须在Y轴旋转(transform.forward)发生任何变化后重新计算Z轴(Vector3.up)。一旦有了新的法线(transform.forward),就需要将运动矢量展平到飞机上,以防止玩家潜入世界表面。谢谢@Ruzihm的所有帮助。

这是新代码:

//Three degree's
moveDirection = new Vector3(Input.GetAxis("Horizontal"),
                            Input.GetAxis("Thrust"),
                            Input.GetAxis("Vertical"));

//Normalize the movement direction and flatten the Plane
moveDirection = transform.TransformDirection(moveDirection);
moveDirection = Vector3.ProjectOnPlane(moveDirection, Vector3.up);

moveDirection *= speed;

// collect inputs
float yaw = Input.GetAxis("Yaw") * rotationSpeed;
float pitch = Input.GetAxis("Vertical") * tiltAngle;
float roll = -1 * (Input.GetAxis("Horizontal") * tiltAngle);

// Get current forward direction projected to plane normal to up (horizontal plane)
Vector3 forwardCurrent = transform.forward
                        - Vector3.Dot(transform.forward, Vector3.up) * Vector3.up;
// Debug to view forwardCurrent
Debug.DrawRay(transform.position, forwardCurrent * 2, Color.white);

// create rotation based on forward
Quaternion targetRotation = Quaternion.LookRotation(forwardCurrent);

// rotate based on yaw, then pitch, then roll. 
// This order prevents changes to the projected forward direction

targetRotation = targetRotation * Quaternion.AngleAxis(yaw, Vector3.up);


// Debug to see forward after applying yaw
Debug.DrawRay(transform.position, targetRotation * Vector3.forward, Color.red);

targetRotation = targetRotation * Quaternion.AngleAxis(pitch, Vector3.right);
targetRotation = targetRotation * Quaternion.AngleAxis(roll, Vector3.forward);

transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, smooth);


controller.Move(moveDirection * Time.deltaTime);

答案 1 :(得分:2)

在使用欧拉角时,关于旋转顺序的假设似乎有些不正确。施加滚动,然后俯仰,最后偏转。这意味着保持相同的偏航然后将横摇和俯仰设置为零(甚至只是改变横摇)都可以完全改变您所面临的展平方向。

通过偏航旋转可能会有所帮助,使向前的方向变平(也就是将其投影到一个完全水平的平面上),然后基于该旋转(使用Quaternion.LookRotation),然后可以手动旋转每个轴。

if(!controller.isGrounded)
{

    //Three degree's
    moveDirection = new Vector3(Input.GetAxis("Horizontal"), 
                                Input.GetAxis("Thrust"), 
                                Input.GetAxis("Vertical"));
    moveDirection *= speed;

    // collect inputs
    float yaw = Input.GetAxis("Yaw") * rotationSpeed;
    float pitch = Input.GetAxis("Vertical") * tiltAngle;
    float roll = -1 * (Input.GetAxis("Horizontal") * tiltAngle);

    // Get current forward direction projected to plane normal to up (horizontal plane)
    Vector3 forwardCurrent = transform.forward 
                            - Vector3.Dot(transform.forward,Vector3.up) * Vector3.up;

    // Debug to view forwardCurrent
    Debug.DrawRay(transform.location, forwardCurrent, Color.white, 0f, false);

    // create rotation based on forward
    Quaternion targetRotation = Quaternion.LookRotation(forwardCurrent);

    // rotate based on yaw, then pitch, then roll. 
    // This order prevents changes to the projected forward direction

    targetRotation = targetRotation * Quaternion.AngleAxis(yaw, Vector3.up);


    // Debug to see forward after applying yaw
    Debug.DrawRay(transform.location, targetRotation * Vector3.forward, Color.red, 0f, false);

    targetRotation = targetRotation * Quaternion.AngleAxis(pitch, Vector3.right);
    targetRotation = targetRotation  * Quaternion.AngleAxis(roll, Vector3.forward);

    transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, smooth);

    //debug new forward/up
    Debug.DrawRay(transform.location, Transform.forward, Color.blue, 0f, false);
    Debug.DrawRay(transform.location, Transform.up, Color.green, 0f, false);

    controller.Move(moveDirection * Time.deltaTime);
}

这可以被认为是部分答案,因为能够确定“展平”的方向并重新排列应用组件旋转的过程对于回答您的问题很有用,但可能不足以获得所需的全部效果,具体取决于详细信息。

作为旁注,如果要确保它实际上会达到目标旋转而不是无限接近它,则可能要考虑使用Quaternion.RotateTowards而不是Quaternion.Slerp