Hello,
I have regular matrix-based skinning on the GPU working for quite a while now and I stumbled upon an implementation of Dual Quaternion skinning.
I've had a go at implementing this in a shader and after spending a lot of time on making small changes to the formulas to make it work, I sort of got it working but there seems to be an issue when blending bones.
I found this pretty old topic on GameDev.net (
) which, I think, describes my problem pretty well but I haven't been able to find the problem.
Like in that post, if the blendweight of a vertex is 1, there is no problem. Once there is blending, I get artifacts
Just for the sake of just focussing on the shader side of things first, I upload the dual quaternions to GPU which are converted from regular matrices (because I knew they should work).
Below an image comparison between matrix skinning (left) and dual quaternion skinning (right):
As you can see, especially on the shoulders, there are some serious issues.
It might be because of a silly typo however I'm surprised some parts of the mesh look perfectly fine.
Below some snippets:
//Blend bones
float2x4 BlendBoneTransformsToDualQuaternion(float4 boneIndices, float4 boneWeights)
{
float2x4 dual = (float2x4)0;
float4 dq0 = cSkinDualQuaternions[boneIndices.x][0];
for(int i = 0; i < MAX_BONES_PER_VERTEX; ++i)
{
if(boneIndices[i] == -1)
{
break;
}
if(dot(dq0, cSkinDualQuaternions[boneIndices[i]][0]) < 0)
{
boneWeights[i] *= -1;
}
dual += boneWeights[i] * cSkinDualQuaternions[boneIndices[i]];
}
return dual / length(dual[0]);
}
//Used to transform the normal/tangent
float3 QuaternionRotateVector(float3 v, float4 quatReal)
{
return v + 2.0f * cross(quatReal.xyz, quatReal.w * v + cross(quatReal.xyz, v));
}
//Used to transform the position
float3 DualQuatTransformPoint(float3 p, float4 quatReal, float4 quatDual)
{
float3 t = 2 * (quatReal.w * quatDual.xyz - quatDual.w * quatReal.xyz + cross(quatDual.xyz, quatReal.xyz));
return QuaternionRotateVector(p, quatReal) + t;
}
I've been staring at this for quite a while now so the solution might be obvious however I fail to see it.
Help would be hugely appreciated
Cheers