绑带旋转镜


9

我使用以下代码旋转游戏角色以观看目标:

        transform.rotation = Quaternion.Slerp(startQuaternion, lookQuaternion, turningNormalizer*turningSpeed/10f)

startQuaternion是给定新目标时角色的当前旋转。

lookQuaternion是角色应查看的方向,其设置如下:

    destinationVector = currentWaypoint.transform.position - transform.position;
    lookQuaternion = Quaternion.LookRotation(destinationVector, Vector3.up);

TurningNormalizer只是Time.deltaTime增加,并且turningSpeed是编辑器中给定的静态值。

问题在于,尽管角色在大多数情况下都应该旋转,但在必须接近180度时仍存在问题。然后它有时会抖动并镜像旋转:

在此处输入图片说明

在此绘制效果不佳的图像中,角色(右侧)开始转向左侧的圆圈。不仅仅是左右旋转,它还可以启动“镜舞”:

  1. 它开始向新面貌旋转
  2. 然后突然突然以相同的角度但在另一侧并继续旋转

它执行此“镜像”的时间很长,直到它看着目标为止。这是带有四元数的东西吗?

编辑1: 显然问题不是由旋转本身引起的。更有可能的问题是,角色在旋转时会朝着面部移动。作为限制角度,当允许角色移动时,面对和目标之间的角度会减少,并且有时会消除抖动/镜像旋转。

这当然引发了更多的问题,为什么角色不能同时没有问题地同时移动和旋转呢?机芯使用的代码:

transform.Translate(Vector3.forward * runningSpeed/10f * Time.deltaTime);

每隔一帧会更新一次“ lookQuaternion”吗?如果是这样,那么我的推测是,一些小错误会导致某种抖动,玩家会``超调''外观旋转,因此新的观看方向就在``紧随其后'' 的另一侧... 。
史蒂芬Stadnicki

Answers:


5

3D空间中的每个方向都可以由2个不同的单元四元数表示,q并且-q(按分量取反q)。例如,由3x3单位矩阵表示的方向I可以由2个四元数表示:

 q:  { 0,  0,  0},  1
-q:  {-0, -0, -0}, -1

两者在3D空间中都表示相同的方向,其点积正好-1位于每个半球的另一半球中,正好位于超球体的相对两侧。

当锯齿花更长的弧度旋转时,观察到的结果是在两个不在同一半球中的四元数之间进行锯齿时。如果发生这种情况,只需在绑扎它们之前对它们之一进行否定,则绑带将缩短弧度。

点积是一种很容易发现是否发生这种情况的工具。如果两个四元数的点积均小于0,则它们不在同一半球中。因此,如果两个点的乘积均小于0,则在保留它们之前,仅按分量取反另一个四元数即可。


我想知道我在尝试此操作时是否正确理解了您, if(Quaternion.Dot (lookQuaternion, startQuaternion) < 0) { startQuaternion = Quaternion.Inverse(startQuaternion); }但是它不能解决问题。抱歉,格式不佳,我似乎无法驯服此评论部分。
Esa 2013年

几乎但不是Inverse,那是与的不同操作Negateif(Quaternion.Dot (lookQuaternion, q) < 0) { q.x = -q.x; q.y = -q.y; q.z = -q.z; q.w = -q.w; }我不使用C#,但是从文档的外观来看,您似乎也可以直接使用Negate-Function
Maik Semder

if(Quaternion.Dot (lookQuaternion, startQuaternion) < 0) { startQuaternion = Quaternion.Negate(startQuaternion); }
Maik Semder

恐怕这些都无法解决问题。我已经更新了问题。
2013年

是的,多数民众赞成在不同的错误混合。简化您的测试设置,一次测试一件事,而不是同时进行平移和旋转。首先确保一个可行,然后另一个可行,然后两者都可行。首先只关注旋转,使用一些众所周知的方向值,例如从170度开始,向下移动到零,查看错误的地方并将其发布在此处
Maik Semder

1

好吧,你的问题是因为形成四元数的那两个向量成180度,所以在插值哪个弧时应该问的问题是?上弧还是下弧

这基本上是造成镜像的原因,每次插值时,它都会沿相反方向移动,同时仍保持角度。

根据此链接

当θ为180度时,由于没有最短的旋转方向,因此结果不确定,我认为这种情况尚未得到正确处理,如果选择一些垂直于qa或qb的任意轴会更好,我会感谢您提供最佳想法的任何想法。

您需要做的是将您的起始四元数与中间四元数进行插值(以确定采用哪个弧线),并在达到该时间时使用中间四元数继续到实际的目标四元数。


1

我怀疑您看到的问题与您的代码无关,而只是沿着球体表面进行插值的一个基本问题(在本例中为viewDirection)。在一个球体上(几乎)任何两个点之间,都有一个大圆-例如,任意将我们的“起点”固定在北极,那么大圆就是终点所在的子午线。从一个点到另一个点的插值沿着这个大圆圈移动。

现在,对于球体上的大多数点,附近的点对应于附近的大圆;例如,洛杉矶和凤凰城所在的子午线彼此之间非常接近。但是,当目标点是原始点的对立面时-南极到起点的北极-不再有一个大圆环通过它们,而是所有一个大圆环都通过了另一个圆环。更糟糕的是,这意味着南极附近的点不是“最多的点”。彼此靠近的两个点以及南极附近的两个点都可能具有极为不同的子午线。

我怀疑您所看到的是子午线中这种不稳定性的体现-换句话说,就是插值弧。当外观目标位于角色的正后方时,诸如角色位置的“ Euler积分”中的一阶不正确以及在框与框之间改变外观方向的方式将导致这些问题。从一帧到下一帧的插值弧不同,这很可能会导致您看到的“错位”。

至于如何处理,最好想到的是不要在每一帧都重新计算“目标”视线方向。取而代之的是,将相同的对象用于几帧的跨度,然后计算一个新的对象并将其用于几帧,依此类推。如果需要,您甚至可以在几帧的跨度内从一个目标插值到下一个目标,以便运动方向不会突然改变。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.