我已经为这个问题苦苦挣扎了好几个小时,现在该是我寻求帮助的时候了。
情况
我走动时有一个移动的角色,并与它行走的表面对齐。我通过射线投射到将要在其下的下一个曲面并使用
获取与该曲面对齐所需的旋转来完成此操作Quaternion newRotation = Quaternion.FromToRotation(transform.up, foundSurface.normal) * transform.rotation;
角色是一个名为Modelholder的变换,可通过以下方式平滑旋转到新的旋转角度
modelHolder.rotation = Quaternion.Slerp(modelHolder.rotation, newRotation, Time.deltaTime * modelRotationSmoothing);
模型内部是模型。我根据鼠标下巴的运动来更改model.localRotation.y。
相机只是跟随模型持有者的变换,还有一个称为Rotator的子变换,该子变换也会根据鼠标的移动(这次是颚和俯仰)进行旋转。相机是此Rotator变换的子代。
有了这个,我就可以在步行和天花板上行走,同时可以使所有东西正确对齐,整齐美观。
问题
我做了一个抓钩,将角色移到抓钩的表面。飞行结束时的重新对齐与步行对齐相同。除了从地面到天花板抓地(反之亦然)时,这一切都很好。当我向东或向西看时,该模型似乎进行了“滚转”以重新对准新曲面,但在向北或向南看时,将进行后翻转或前翻转。
ModelHolder运动: https://streamable.com/qf94k
模型运动: https://streamable.com/4xkl4
桶状滚子很好,但我想以某种方式找到一种旋转方式,以使玩家着陆后不会朝相反的方向看(或者在向北或向南看时从天花板上跳下来,因为然后重新对准重力也会引起翻转),因为翻转会使人迷失方向。
我尝试过的事情:
我试图在modelHolder和model中没有分离。这并不能解决问题,只会给我带来更多问题,那就是拥有平滑但反应灵敏的相机。
我尝试在重新对齐之前保存外观方向,并在重新对齐时将其旋转到旧的外观方向。 这只是做一个超级怪异的翻转和翻转事情,这更加令人迷惑。
我尝试尝试检测新旧旋转之间的差异,以查看我是否可以某种方式“检测”它何时要进行翻转以及何时要进行滚桶运动,以便对此进行应对。我只发现困惑和沮丧。
答案 0 :(得分:2)
您需要计算一个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);
尽管我不赞成将Slerp / Lerp方法与无法保证达到或超过1的t
一起使用,但我建议使用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);