了解双四元数蒙皮

时间:2015-03-28 12:23:10

标签: matrix quaternions skinning

我正在尝试将动画代码从矩阵切换到双四元数。我已经阅读了Ladislav Kavan的论文,据我所知,他提供了一种技术,可以将动画矩阵转换为两个特殊的四元数。然后,您在GPU上重建原始矩阵。但是,我没能让它发挥作用。当我在我的应用程序中插入代码时,所有动画都完全扭曲,这意味着重建的矩阵是不正确的。

然后我编写了一个c#控制台应用来检查确实如此:矩阵在转换之前和之后完全不同。我在分解之前对矩阵进行了标准化,但没关系,重建的矩阵永远不会相同。我错过了什么吗?也许输入矩阵应该是特定类型的?

这是我的控制台应用代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;

namespace DualQuaternionTest
{
    class DualQuaternion
    {
        public Quaternion Ordinary;
        public Quaternion Dual;

        public static Matrix Normalize(Matrix m)
        {
            Vector3 v = new Vector3(m.M11, m.M21, m.M31);
            v.Normalize();
            m.M11 = v.X; m.M21 = v.Y; m.M31 = v.Z;

            v = new Vector3(m.M12, m.M22, m.M32);
            v.Normalize();
            m.M12 = v.X; m.M22 = v.Y; m.M32 = v.Z;

            v = new Vector3(m.M13, m.M23, m.M33);
            v.Normalize();
            m.M13 = v.X; m.M23 = v.Y; m.M33 = v.Z;

            return m;
        }

        public static DualQuaternion QuatTrans2UDQ(Quaternion q0, Vector3 t)
        {
            DualQuaternion dq = new DualQuaternion();
            dq.Ordinary = q0;        
            dq.Dual.W = -0.5f * (t.X * q0.X + t.Y * q0.Y + t.Z * q0.Z);
            dq.Dual.X = 0.5f * (t.X * q0.W + t.Y * q0.Z - t.Z * q0.Y);
            dq.Dual.Y = 0.5f * (-t.X * q0.Z + t.Y * q0.W + t.Z * q0.X);
            dq.Dual.Z = 0.5f * (t.X * q0.Y - t.Y * q0.X + t.Z * q0.W);
            return dq;
        }

        public static Matrix UDQToMatrix(DualQuaternion dq)
        {
            Matrix M;
            float len2 = Quaternion.Dot(dq.Ordinary, dq.Ordinary);
            float w = dq.Ordinary.W, x = dq.Ordinary.X, y = dq.Ordinary.Y, z = dq.Ordinary.Z;
            float t0 = dq.Dual.W, t1 = dq.Dual.X, t2 = dq.Dual.Y, t3 = dq.Dual.Z;

            M.M11 = w * w + x * x - y * y - z * z;
            M.M21 = 2 * x * y - 2 * w * z;
            M.M31 = 2 * x * z + 2 * w * y;
            M.M12 = 2 * x * y + 2 * w * z;
            M.M22 = w * w + y * y - x * x - z * z;
            M.M32 = 2 * y * z - 2 * w * x;
            M.M13 = 2 * x * z - 2 * w * y;
            M.M23 = 2 * y * z + 2 * w * x;
            M.M33 = w * w + z * z - x * x - y * y;

            M.M41 = -2 * t0 * x + 2 * w * t1 - 2 * t2 * z + 2 * y * t3;
            M.M42 = -2 * t0 * y + 2 * t1 * z - 2 * x * t3 + 2 * w * t2;
            M.M43 = -2 * t0 * z + 2 * x * t2 + 2 * w * t3 - 2 * t1 * y;

            M.M14 = 0;
            M.M24 = 0;
            M.M34 = 0;
            M.M44 = len2;

            M /= len2;

            return M;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Matrix BaseMatrix = Matrix.Identity;
            Random random = new Random();

            BaseMatrix.M11 = random.Next(-1000000, 1000000) * 0.001f;
            BaseMatrix.M12 = random.Next(-1000000, 1000000) * 0.001f;
            BaseMatrix.M13 = random.Next(-1000000, 1000000) * 0.001f;
            BaseMatrix.M14 = random.Next(-1000000, 1000000) * 0.001f;
            BaseMatrix.M21 = random.Next(-1000000, 1000000) * 0.001f;
            BaseMatrix.M22 = random.Next(-1000000, 1000000) * 0.001f;
            BaseMatrix.M23 = random.Next(-1000000, 1000000) * 0.001f;
            BaseMatrix.M24 = random.Next(-1000000, 1000000) * 0.001f;
            BaseMatrix.M31 = random.Next(-1000000, 1000000) * 0.001f;
            BaseMatrix.M32 = random.Next(-1000000, 1000000) * 0.001f;
            BaseMatrix.M33 = random.Next(-1000000, 1000000) * 0.001f;
            BaseMatrix.M34 = random.Next(-1000000, 1000000) * 0.001f;
            BaseMatrix.M41 = random.Next(-1000000, 1000000) * 0.001f;
            BaseMatrix.M42 = random.Next(-1000000, 1000000) * 0.001f;
            BaseMatrix.M43 = random.Next(-1000000, 1000000) * 0.001f;
            BaseMatrix.M44 = random.Next(-1000000, 1000000) * 0.001f;

            Matrix NormalizedBaseMatrix = DualQuaternion.Normalize(BaseMatrix);

            Quaternion[] qq = new Quaternion[2];
            DualQuaternion dualQuaternion = null;
            dualQuaternion = DualQuaternion.QuatTrans2UDQ(
                Quaternion.CreateFromRotationMatrix(NormalizedBaseMatrix),
                NormalizedBaseMatrix.Translation);

            ReconstructedMatrix = DualQuaternion.UDQToMatrix(dualQuaternion);

            Console.WriteLine(BaseMatrix.ToString());
            Console.WriteLine();
            Console.WriteLine(NormalizedBaseMatrix.ToString());
            Console.WriteLine();
            Console.WriteLine(ReconstructedMatrix.ToString());
            Console.ReadKey();
        }
    }
}

1 个答案:

答案 0 :(得分:1)

当你有一个矩阵填充了16个随机值(如果考虑4x3部分,甚至12个,因为你的最右边的列总是在你的UDQToMatrix函数中为0,0,0,1),您正在创建无法用双四元数表示的变换。

四元数(和双四元数)不能表示任意非正交轴。

不是生成完全随机的值,而是通过随机化平移和旋转操作来生成矩阵。那么你应该能够在矩阵和双四元数之间可靠地转换它们