C# 有没有一种方法可以使用四元数。FromToRotation支持使用一个轴?

C# 有没有一种方法可以使用四元数。FromToRotation支持使用一个轴?,c#,unity3d,quaternions,C#,Unity3d,Quaternions,我已经为这个问题挣扎了太多个小时,现在是我向你寻求帮助的时候了 形势 我有一个移动的角色,我四处走动,并与它行走的表面对齐。我通过光线投射到下一个它将要打开的曲面,并获得与曲面对齐所需的旋转来实现这一点 Quaternion newRotation = Quaternion.FromToRotation(transform.up, foundSurface.normal) * transform.rotation; 角色是一个称为Modelholder的变换,它可以平滑地旋转到新的旋转,并使用

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

形势

我有一个移动的角色,我四处走动,并与它行走的表面对齐。我通过光线投射到下一个它将要打开的曲面,并获得与曲面对齐所需的旋转来实现这一点

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

摄影机只是一个跟随modelholder的变换,并且有一个称为Rotator的子变换,该变换也基于鼠标移动进行旋转(这次是下巴和俯仰)。摄影机是此旋转器变换的子对象

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

问题

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

模特儿运动:

模型运动:

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

我尝试过的事情:

  • 我试着不把模特和模特分开。这并不能解决问题,只会给我带来更多的问题,因为我有一个平滑但反应灵敏的摄像头

  • 我尝试在重新对齐之前保存lookdirection,并在重新对齐时将其旋转到旧的lookdirection。 这只是做了一个超级奇怪的翻转,这是更迷惑

  • 我试着检测新旧旋转之间的比较差异,看看我是否能“检测”出它什么时候想要翻转,什么时候想要滚桶,这样我就可以对抗它了。我只感到困惑和沮丧


您需要计算一个
新旋转
,该旋转在使局部向上成为曲面法线的同时,尽可能保持前进方向

FromToRotation
仅保证使用时的一个对齐轴。相反,您可以使用叉积和
四元数.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);
虽然我不赞成将Slerp/Lerp方法与
t
一起使用,但它不能保证达到或超过1。我建议改为使用
四元数。旋转方向

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);

我爱你,爱你,爱你拍摄了一段你的问题的视频,让你的模型看起来像统一轴。我真的希望更多的人在问起旋转的时候会这么做。这个脚本是附加在什么对象上的?为什么要使用
transform.up
而不是
modelHolder.up
?@RobinHerben感谢您的回复。今天晚些时候,我将对此进行另一次尝试。@RobinHerben我要求对这个问题进行澄清,但与此同时,如果您执行
Vector3 newPlayerRight=Vector3.Cross(foundSurface.normal,modelHolder.forward),会发生什么情况相反?那也不行。但是我没有一个单独的模型和模型持有者,而是通过使用交叉积和lookrotation方法来实现的!将您的答案标记为已接受,谢谢@RobinHerben我想问一个新问题,包括关于你现在正在使用的东西的信息(对于初学者来说,我不知道你的相机是如何设置的),但类似的东西可能会有所帮助:
Vector3先前的CameraForward
四元数cameraPivotGoal=四元数.LookRotation(以前的CameraForward,foundSurface.normal)
cameraHolder.rotation=Quaternion.rotatetowwards(camerrapivot.rotation,camerrapivotgoal,Time.deltaTime*cameraRotationSpeed)
/*更新相机控制器内部值*/
(假设您的相机有一个像这里这样的枢轴父级)@RobinHerbern我明白了,这就把事情弄清楚了。好吧,只有当你沿着地面移动时,这才有意义,而这不是问题的初衷。在像这样的“行走”的情况下,旋转轴是固定的,你需要保持向前相对于旋转轴的方向不变。在飞行/坠落的情况下,你关心的是绝对向前,旋转轴是保持尽可能接近它所需要的。我在我的答案中添加了一部分,希望能解决这个问题。如果没有帮助,请考虑问一个单独的问题。