Reputation: 946
I am trying to switch my animation code from Matrices to dual quaternions. I've read the Ladislav Kavan's paper, and as I understand he offers a technique, where you transform your animation matrix into two special quaternions. Then you reconstruct the original matrix on the GPU. However, I am failing to get it to work. When I inserted the code in my app, all the animations got completely twisted, meaning that the reconstructed matrices are incorrect.
I've then written a c# console app to check that and it was indeed the case: matrices are completely different before and after the transformation. I did normalize the matrix before decomposition, but it does not matter, the reconstructed matrix is never the same. Am I missing something? Maybe the input matrix should be of a specific type?
Here is my console app code:
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();
}
}
}
Upvotes: 0
Views: 1052
Reputation: 4339
When you have a matrix filled with 16 random values (or even 12 if you considering the 4x3 portion, since your rightmost column is always going to be 0,0,0,1 in your UDQToMatrix
function), you are creating transforms that cannot be represented with dual quaternions.
Quaternions (and dual quaternions) cannot represent arbitrary non-orthogonal axes.
Instead of generating completely random values, generate matrices by randomizing operations of translation and rotation. Then you should be able to convert those reliably between matrix and dual quaternion
Upvotes: 2