我已经为这个问题苦苦挣扎了太多小时,现在是时候寻求您的帮助了。
情况
我有一个移动的角色,我四处走动并与它行走的表面对齐。我通过将光线转换到下一个表面并获得与表面对齐所需的旋转来做到这一点
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
滚桶很好,但我想以某种方式找到一种旋转方式,这样玩家在着陆后就不会朝相反的方向看(或者从天花板上往北或向南跳,因为然后重新对齐重力会导致翻转)因为翻转是可怕的迷失方向。
我尝试过的事情:
这只是做了一个非常奇怪的翻转和转动的事情,这更加令人迷惑。
最佳答案
你需要计算一个 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/