c# - 有没有办法使用 Quaternion.FromToRotation 来支持使用一个轴?

标签 c# unity3d quaternions

我已经为这个问题苦苦挣扎了太多小时,现在是时候寻求您的帮助了。

情况

我有一个移动的角色,我四处走动并与它行走的表面对齐。我通过将光线转换到下一个表面并获得与表面对齐所需的旋转来做到这一点

Quaternion newRotation = Quaternion.FromToRotation(transform.up, foundSurface.normal) * transform.rotation;

角色是一个名为 Modelholder 的变换,它平滑地旋转到新的旋转
modelHolder.rotation = Quaternion.Slerp(modelHolder.rotation, newRotation, Time.deltaTime * modelRotationSmoothing);

modelHolder 里面是模型。我根据鼠标下巴的移动更改了 model.localRotation.y。

相机只是一个跟随模型支架的变换,并且有一个称为 Rotator 的子变换,它也根据鼠标移动(这次是下巴和俯仰)旋转。相机是这个旋转器变换的子对象。

有了这个,我可以走上人行道和天花板,同时正确地对齐所有东西,非常整洁。

问题

我制作了一个抓钩,可以将角色移动到抓钩的表面。飞行结束时的重新对齐与步行对齐的方式相同。这一切都很好,除非你从地面抓到天花板(反之亦然)。当我向东或向西看时,该模型似乎会进行“桶形滚动”以重新对齐新表面,但在向北或向南看时会进行后空翻或前空翻。

ModelHolder 运动:
https://streamable.com/qf94k

模型运动:
https://streamable.com/4xkl4

滚桶很好,但我想以某种方式找到一种旋转方式,这样玩家在着陆后就不会朝相反的方向看(或者从天花板上往北或向南跳,因为然后重新对齐重力会导致翻转)因为翻转是可怕的迷失方向。

我尝试过的事情:
  • 我尝试在 modelHolder 和模型中没有分离。这并不能解决问题,只会给我带来更多问题,即拥有流畅但响应迅速的相机。
  • 在重新对齐时,我尝试在重新对齐和旋转到旧的lookdirection之前保存lookdirection。
    这只是做了一个非常奇怪的翻转和转动的事情,这更加令人迷惑。
  • 我试图检测新旧旋转之间比较的差异,看看我是否能以某种方式“检测”它什么时候想要翻转,什么时候想要滚桶,这样我就可以解决这个问题。我发现只有困惑和沮丧。
  • 最佳答案

    你需要计算一个 newRotation尽可能保持向前的方向,同时使局部向上是表面的法线。
    FromToRotation仅保证您使用的方式对齐一个轴。相反,您可以使用交叉产品和 Quaternion.LookRotation做你需要的计算。

    Vector3 newPlayerRight = Vector3.Cross(foundSurface.normal, modelHolder.forward);
    Vector3 newPlayerForward = Vector3.Cross(newPlayerRight, foundSurface.normal);
    
    Quaternion newRotation = Quaternion.LookRotation(newPlayerForward, foundSurface.normal);
    

    然后,您可以像以前一样继续:
    modelHolder.rotation = Quaternion.Slerp(modelHolder.rotation, newRotation, 
            Time.deltaTime * modelRotationSmoothing);
    

    尽管我不赞成使用带有 t 的 Slerp/Lerp 方法不能保证达到或超过 1。我建议使用 Quaternion.RotateTowards :
    float modelRotationSpeed = 180f;
    modelHolder.rotation = Quaternion.RotateTowards(modelHolder.rotation, newRotation, 
            Time.deltaTime * modelRotationSpeed);
    

    为了保持相对于刚穿过的边缘的前向角度,您可以尝试不同的方法:
    Quaternion newRotation;
    
    // ..
    
    Vector3 previousSurfaceNormal = modelHolder.up;
    Vector3 previousForward = modelHolder.forward;
    bool flyingOrFallingToNewSurface;
    
    if (flyingOrFallingToNewSurface)
    {
        Vector3 newPlayerRight = Vector3.Cross(foundSurface.normal, modelHolder.forward);
        Vector3 newPlayerForward = Vector3.Cross(newPlayerRight, foundSurface.normal);
    
        newRotation = Quaternion.LookRotation(newPlayerForward, foundSurface.normal);
    } else
    {
        // This direction lies in both surfaces. 
        Vector3 edgeTraversed = Vector3.Cross(previousSurfaceNormal, foundSurface.normal);
    
        // Find the angle from edgeTraversed to previousForward
        float ang = Vector3.SignedAngle(edgeTraversed, previousForward, previousSurfaceNormal);
    
        // Find newForward in new plane that's the same angle
        Vector3 newPlayerForward = Quaternion.AngleAxis(ang,foundSurface.normal) * edgeTraversed;
    
        newRotation = Quaternion.LookRotation(newPlayerForward, foundSurface.normal);
    }
    
    // ...
    
    float modelRotationSpeed = 180f;
    modelHolder.rotation = Quaternion.RotateTowards(modelHolder.rotation, newRotation, 
            Time.deltaTime * modelRotationSpeed);
    

    关于c# - 有没有办法使用 Quaternion.FromToRotation 来支持使用一个轴?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60111798/

    相关文章:

    c# - 紧急错误cs0542成员名称不能与它们的封闭类型相同

    c++ - 在两个四元数之间插值很长

    c - 反四元数

    c# - 无法从 Google OAuth2 token 端点获取访问 token

    c# - Unity中的LoadScene()函数什么时候改变场景?

    c# - 组合框.选定的值无法传递给查询

    c# - 保存游戏状态的最佳方法是什么?

    opengl - 关于glm四元数旋转

    C# 变量作用域让我停滞不前

    c# - 当前上下文中不存在变量 C#