C# 和 XNA 围绕另一个对象旋转一个对象,保持偏移量(或如何为随机点蒙皮随机骨骼)

本文关键字:随机 一个对象 偏移量 XNA 旋转 | 更新日期: 2023-09-27 18:22:04

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

这是他们在时间零的位置,在时间1他们改变自己的位置。物体Y绕它的轴旋转一定角度,我知道它是新的四元数,它是Y_New。X 相对于 Y 旋转,以保持偏移量保持在时间 0。我需要的基本上是X_New。

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

如有任何建议,将不胜感激。

再澄清一点:

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

C# 和 XNA 围绕另一个对象旋转一个对象,保持偏移量(或如何为随机点蒙皮随机骨骼)

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

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

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

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

  4. 在初始化中,我还计算

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

    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 姿势位置和地球的 T 姿势位置之间(:

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

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

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

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

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

你可能在"四元数"中迷失了我,但我见过这个问题的许多 2D 示例,并且总有一个简单的解决方法:

基本上,您需要对两个对象使用完全相同的originrotation,以便它们之间自动保持恒定的偏移量。

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

对于太阳系,您需要为太阳和地球分配一个世界矩阵。 太阳的位置使其中心位于世界原点[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;