Unity - 绕Y轴旋转object,同时不断设置朝向地面的不同旋转

Unity - rotating object around Y axis, while constantly setting up different rotation towards the ground

所以我不知道我是否在标题中正确解释了它,但我想做的是通过单击 Q 或 E 围绕 Y 轴旋转 object,但同时我正在向地面投射光线以检查点旋转以使其朝向正确的方向。

为了阐明这一点,这里有一个例子: 我正在尝试放置壁炉,我在山上。为了防止壁炉进入地形,我需要旋转它,以便我 "stick" 到它底部的地形,但我想将它围绕 Y 旋转几度.. 这是我得到的代码:

using UnityEngine;

public class Foobar : MonoBehaviour
{
    Transform cam;
    Transform prefabAsTransform;
    Vector3 currentPos;
    float addToY = 0.5f;
    int mask;

    void Start()
    {
        cam = Camera.main.transform;
        prefabAsTransform = transform;
        mask = LayerMask.GetMask("Default");
    }

    void Update()
    {
        RaycastHit hit;
        if (Physics.Raycast(cam.position, cam.forward, out hit, Mathf.Infinity, mask))
        {
            currentPos = new Vector3(hit.point.x, hit.point.y + addToY, hit.point.z);
            prefabAsTransform.position = currentPos;
            prefabAsTransform.transform.up = hit.normal;
        }

        if (prefabAsTransform != null)
        {
            if (Input.GetKeyDown(KeyCode.Q))
            {
                if (Input.GetKey(KeyCode.LeftControl))
                {
                    prefabAsTransform.Rotate(new Vector3(0, 1, 0));
                }
                else
                {
                    prefabAsTransform.Rotate(new Vector3(0, 10, 0));
                }
            }
            if (Input.GetKeyDown(KeyCode.E))
            {
                if (Input.GetKey(KeyCode.LeftControl))
                {
                    prefabAsTransform.Rotate(new Vector3(0, -1, 0));
                }
                else
                {
                    prefabAsTransform.Rotate(new Vector3(0, -10, 0));
                }
            }
        }
    }
}

这里的问题是它面对地形没有任何问题,但我无法自己绕 Y 旋转它。我认为这是因为我不断更新轮换,但我不知道如何改变它。

是的,这是因为你用 prefabAsTransform.transform.up = hit.normal; 设置了每帧的旋转,而没有考虑当前的前进方向。

相反,您应该使用prefabAsTransform.rotation = LookRotation(newForward, newUp); 但是,您如何使用当前转发来确定newForward?您可以为此使用叉积。这对我有用:

void Update()
{
    RaycastHit hit;
    if (Physics.Raycast(cam.position, cam.forward, out hit, Mathf.Infinity, mask))
    {
        currentPos = new Vector3(hit.point.x, hit.point.y + addToY, hit.point.z);
        prefabAsTransform.position = currentPos;

        Vector3 newUp = hit.normal;
        Vector3 oldForward = prefabAsTransform.forward;

        Vector3 newRight = Vector3.Cross(newUp, oldForward);
        Vector3 newForward = Vector3.Cross(newRight, newUp);

        prefabAsTransform.rotation = Quaternion.LookRotation(newForward, newUp);
    }

    if (prefabAsTransform != null)
    {
        if (Input.GetKeyDown(KeyCode.Q))
        {
            if (Input.GetKey(KeyCode.LeftControl))
            {
                prefabAsTransform.Rotate(new Vector3(0, 1, 0));
            }
            else
            {
                prefabAsTransform.Rotate(new Vector3(0, 10, 0));
            }
        }
        if (Input.GetKeyDown(KeyCode.E))
        {
            if (Input.GetKey(KeyCode.LeftControl))
            {
                prefabAsTransform.Rotate(new Vector3(0, -1, 0));
            }
            else
            {
                prefabAsTransform.Rotate(new Vector3(0, -10, 0));
            }
        }
    }
}