0

我有一个对象 X,它位于世界空间中,由它的四元数表示,我们称之为后者 X_Base。我有另一个对象 Y,它从对象 X 偏移,并由其称为 Y_Base 的四元数矩阵呈现。

那是他们在时间 0 的位置,在时间 1 他们改变了他们的位置。对象 Y 围绕它的轴旋转了某个角度,我知道它是新的四元数,它是 Y_New。X 相对于 Y 旋转,以便将偏移量保持在时间 0。我需要的基本上是 X_New。

在英语中,我正在尝试手动为模型蒙皮。我有一个从骨骼偏移一段距离的网格,我需要它在骨骼旋转时保持这个偏移。不知何故,我找不到关于我需要使用什么公式的明确答案。

将不胜感激任何建议。

再澄清一点:

想象一个太阳系,地球围绕太阳和它的轴旋转。让我们这样说吧,这样月球不会绕地球旋转,而是偏离地球,无论你如何改变地球的位置,它都会保持这种偏移。我需要的是找出月球在时间 1 的位置,同时知道它在时间 0 的位置以及地球在时间 0 和时间 1 的位置。

4

3 回答 3

1

我能够为我的模型蒙皮。这是我所做的:

  1. “太阳”是我模特的骨头。它可以平移(在世界空间中)和旋转。“地球”是模型上的一个自定义点,它随着模型旋转/平移,因为我的目标意味着我不能只选择任何点并对其进行蒙皮,我需要后者与模型一起移动。

  2. 我的应用程序中有两种方法:一种启动一次(初始化),另一种启动每帧(更新)。在初始化方法中,我的模型始终处于 T-Pose。

  3. 在 Initialize 方法中,我将太阳和地球的位置读取为 2 XNA Matrix

  4. 在初始化我也计算

    Vector3 Difference = TPoseEarth.Translation - TPoseSun.Translation;
    
  5. 最后在初始化中,我分解了太阳的矩阵以获得纯太阳的旋转矩阵(没有平移)。我这样做是因为我的模型的骨骼 Sun 显然有一个非恒等矩阵分配给它,即使在 T-Pose 也是如此。像这样:

    Vector3 scale;
    Quaternion rotation;
    Vector3 tra;
    TPoseSun.Decompose(out scale, out rotation, out tra);
    
    BaseSunRot = Matrix.CreateFromQuaternion(rotation);
    
  6. 在更新方法中,我得到地球和太阳的当前世界位置。我分解太阳矩阵以获得纯旋转(再次!)。

    Vector3 scale;
    Quaternion rotation;
    Vector3 tra;
    Sun.Decompose(out scale, out rotation, out tra);
    
    Matrix SunRot = Matrix.CreateFromQuaternion(rotation);
    
  7. 我通过将我的基本旋转的倒数乘以我的新旋转来计算独特的骨骼-太阳旋转:

    Matrix UniqueRot = Matrix.Invert(BaseSunRot) * SunRot;
    
  8. 我将地球的平移设置为差值(在太阳的 T-Pose 位置和地球的 T-Pose 位置之间):

    Matrix Earth = Matrix.Identity;
    Earth.Translation = Difference;
    
  9. 我将地球矩阵乘以独特的骨骼(太阳)旋转:

    Earth *= UniqueRot;
    
  10. 我添加 Sun 的 CURRENT 位置以提供帧之间可能的转换:

    Earth += Sun.Translation;
    
  11. 结束。地球矩阵包含有关蒙皮顶点的所有必要信息。

我不是 100% 确定,但我觉得这基本上是一本关于如何针对世界上任何骨骼对任何给定点进行蒙皮的手册(即旋转/平移保持初始偏移)。问题是,代码没有优化:)。如果有人对如何优化它有任何想法,我将不胜感激。

特别是我想知道我是否可以跳过双矩阵分解并简单地将完整的 ScaleRotationTranslation 矩阵相乘?我正在尝试但没有任何成功。

于 2013-07-16T18:22:35.347 回答
0

对于初学者,我认为如果您使用矩阵而不是四元数,您会发现这个问题更直接。四元数仅包含旋转,因此您需要将平移(位置)分别存储在向量中,而矩阵同时包含旋转和平移。

对于太阳系,您可以为太阳和地球分配一个世界矩阵。太阳的位置使其中心位于世界原点 [0,0,0]。太阳的矩阵将包含它围绕 y 轴的旋转(使其转动)。

sun.World = Matrix.CreateRotationY(angle);

地球将有一个相对于太阳的位置。该值将保持不变并用于创建平移矩阵。如果然后将此矩阵与太阳的世界矩阵相乘,您将得到地球的世界矩阵:

earth.World =
    Matrix.CreateTranslation(earth.Position) *
    sun.World;

注意矩阵乘法的顺序很重要。随着时间的推移,这将旋转地球围绕太阳的位置。也可以对地球进行旋转,使其绕轴自转,如下所示:

earth.World =
    Matrix.CreateRotationY(angle) *
    Matrix.CreateTranslation(earth.Position) *
    sun.World;

要将月球定位在围绕地球的轨道上,可以应用相同的原理:

moon.World =
    Matrix.CreateTranslation(moon.Position) *
    earth.World;

如果您需要使用四元数,您可以将它们转换为矩阵和从矩阵转换:

Quaternion quaternion = Quaternion.CreateFromRotationMatrix(matrix);
Vector3 translation = matrix.Translation;

Matrix matrix = Matrix.CreateFromQuaternion(quaternion);
matrix = Matrix.CreateTranslation(translation) * matrix;
于 2013-07-12T09:23:01.940 回答
0

您可能在“四元数”中迷失了我,但是我已经看到了许多有关此问题的 2D 示例,并且总是有一种简单的方法来解决它:

基本上,您需要对两个对象使用完全相同的originand rotation,这样它们就会自动在它们之间保持恒定的偏移量。

于 2013-07-12T09:20:44.853 回答