关于球体的任意旋转

我正在编写一个允许用户在球体表面移动的机制。 球体上的位置当前被存储为thetaphi ,其中theta是z轴和当前位置的xz投影之间的角度(即围绕y轴的旋转), phi是从y轴到位置。 我解释得不好,但它本质上是theta = yawphi = pitch

 Vector3 position = new Vector3(0,0,1); position.X = (float)Math.Sin(phi) * (float)Math.Sin(theta); position.Y = (float)Math.Sin(phi) * (float)Math.Cos(theta); position.Z = (float)Math.Cos(phi); position *= r; 

我相信这是准确的,但是我可能是错的。 我需要能够以半径为r的世界空间的原点在球体表面围绕球体的任意伪二维方向移动。 例如,握住W应该相对于玩家的方向向上移动球体。

我相信我应该用四元数来表示球体上的位置/方向,但是我想不出正确的方法。 球形几何不是我的强项。

本质上,我需要填写下面的块:

 public void Move(Direction dir) { switch (dir) { case Direction.Left: // update quaternion to rotate left break; case Direction.Right: // update quaternion to rotate right break; case Direction.Up: // update quaternion to rotate upward break; case Direction.Down: // update quaternion to rotate downward break; } } 

事实上,事实certificate,你不能“双向”:如果你的目的是在球体上没有任何“绝对定位”的意义(也就是说,如果球员不是总是面向极点),那么你需要有一个玩家定位的概念。 这是因为,与直觉所暗示的相反,球体上的运动完全像飞机上的运动,甚至不是局部的(相当)。 球体的固有曲率意味着玩家可以采取自动旋转的动作!

对于我所说的最极端的例子,假设玩家从赤道上的一个点开始(为了方便起见,我们将想象一个从上面映射到赤道上的钟面,并将玩家放在6点钟),面向“向上” – 即朝北极。 假设玩家一直走到北极, 那么他们会直接面对12点的方向。 现在,让玩家直接向右移动,从北极回到赤道; 他们会在3点的时候结束 – 但是因为他们的面子在右移时不会改变他们的想法是他们的面部不会改变,不管他们如何移动),他们仍然会面对12点 – 他们现在面临赤道! 现在,让他们“倒退”回到起点(6点)。 那么他们仍然会面对赤道,所以他们会面向3点 – 只是沿着球体移动,而不改变他们的“个人”方向,导致他们从面向北极旋转到面朝赤道! 从某种意义上说,这是一个老式的“猎人向南走一英里,向西走一英里再向北走一英里的玩笑”的细节,但是这里我们利用球体的曲率来改变方向。 请注意,即使在更小的尺度上也会发生同样的效果。 这是它的最极端的版本,但即使是短“北一脚,一脚东,一脚南,一脚西”长方形也不会让玩家正好面对以前的样子 – 这是一个expression球体具有非平凡曲率的事实。

幸运的是,四元数(正如你自己所指出的那样)处理这种情况。 因为四元数表示一个任意的旋转,所以它实际上代表了一个任意的“点加方向”:设想从原点处的“三轴”开始,给它任意的旋转,然后向一个方向移动一个单位, Z轴点; 有一点想法会让你相信,这会使你带有一些“方向”(即,三轴的X轴和Y轴的一些排列)的单位球面上的一个点,并且你可以得到每个点+方向的单位球体这种方式(只要指定您的Z轴指向从原点到球体上的点的线,然后运输您的三轴线回到原点沿线)。 更重要的是,由于四元数的乘法相当于旋转的组合,所以你描述的每一个操作都可以用你当前的方向乘以适当select的四元数来表示:具体地说,由于(单位)四元数(qx,qy,qz ,qw)表示通过arccos(qw)'围绕(qx,qy,qz)轴旋转,然后(根据您对坐标系的具体select,让c_a为cosα,s_a为sinα)两个四元组M_x =(s_a,0,0,c_a),M_y =(0,s_a,0,c_a)和M_z =(0,0,s_a,c_a)将代表'rotate(ie move)in我正在面对的方向是阿尔法“,”沿与我目前正在面对的方向正交的方向旋转“。 (这些四元数中的第三个将表示“旋转我的角色关于他自己的坐标轴”)这意味着每一个嘀嗒声你都会知道哪个键已经被按下,然后,例如,如果玩家已经按下,则说Cur_q = M_x * Cur_q ,或者Cur_q = M_y * Cur_q如果玩家向右按压)(或者如果玩家向左按压,则可能是Cur_q = M_yinv * Cur_q ,其中M_yinv是M_y四元数的“反向”,以另一种方式表示旋转)。 请注意,你必须小心你应用旋转的“方”,无论是预乘还是后乘; 坦率地说,通过反复试验来解决这个问题可能是最容易的,可以尝试两个乘法运算并看看哪些工作是正确的。

从更新的四元数到球体上的一个点(以及角色的方向)也是相对简单的:通过最后一段的对应关系,你所要做的就是使用你的四元数的基向量(1, 0,0),(0,1,0)和(0,0,1)通过“旋转vector四元数”操作v→ (其中这里的乘法是四元数乘法,并且用“简并四元数”(x,y,z,0))来确定向量v =(x,y,z)。 例如,单位球面上的位置是通过变换z向量得到的:pos =(qx,qy,qz,qw)*(0,0,1,0)*(-qx,-qy,-qz, (qq,qy,qz,qw)*(qy,-qx,qw,qz)=(qq * qw + qz * qx) (2(qy*qw+qz*qx), 2(qz*qy-qw*qx), (qz^2+qw^2)-(qx^2+qy^2)) 2 qw ^ 2) – (qx ^ 2 + qy ^ 2) (2(qy*qw+qz*qx), 2(qz*qy-qw*qx), (qz^2+qw^2)-(qx^2+qy^2))将是单位球体上的“已转换”用户的坐标(并且获得任意球体上的坐标,当然,您只需乘以球体的半径); 类似的计算适用于其他轴,以定义例如用户的朝向方向。

我想你想要的东西类似于这个http://www.youtube.com/watch?v=L2YRZbRSD1k

我开发了一个48小时的gamejam …你可以在这里下载代码… http://archive.globalgamejam.org/2011/evil-god

我使用了类似于你的代码的东西来获得3D coords …但是我旋转了这个星球,玩家在同一个位置,我想你对这个生物运动感兴趣,是这样的:

  // To add movement protected override void LocalUpdate(float seconds) { Creature.Alfa += Direction.X * seconds * Speed; Creature.Beta += Direction.Y * seconds * Speed; } // To calculate position World.Planet.GetCartesian(Alfa, Beta, out Position); // as you do Matrix PositionMatrix = Matrix.CreateTranslation(Position) * World.Planet.RotationMatrix; LastPositionAbsolute = PositionAbsolute; Vector3 Up = PositionAbsolute = Vector3.Transform(Vector3.Zero, PositionMatrix); Up.Normalize(); // This is to add and offset to the creature model position PositionAbsolute += Up * 8; // calculate new forward vector if needed if ((PositionAbsolute - LastPositionAbsolute).Length() > 0.1f) { Forward = PositionAbsolute - LastPositionAbsolute; Forward.Normalize(); } // Calculate the world transform with position, forward vector and up vector Matrix LocalWorld = Matrix.CreateWorld(PositionAbsolute, Forward, Up); Transform = Matrix.CreateScale(Scale * ScaleFactor) * LocalWorld;