The main idea of the linear blending method is to calculate the linear combination of
the joint (bone) matrices. By [Kavan 2007] and [Kavan 2008], the rigid transform is the composition of rotation
transform and translation transform. Evidently, the linear blending method is NOT correct,
since the linear combination of the rigid transformation matrices is NOT necessarily a rigid transformation
matrix. However, the linear blending method is still one of the most popular vertex
blending methods. By [Kavan 2007] and [Kavan 2008], perhaps this is only because there is no simple
alternative.
By the documents of Autodesk
3ds Max, we have the "candy-wrapper" artifact of the linear blending.
By "Equation (5.3)" of Quaternions for Computer Graphics, a
quaternion can be written as q=w+xi+yj+zk=[s,v] where
s=w
is a real number and v=[x,y,z] is a
vector in 3D space.
2-1-1. Multiplication
By "Equation (5.9)" of Quaternions for Computer Graphics, we
have the multiplication of quaternions q0q1=[s0,v0][s1,v1]=[s0s1−v0⋅v1,s0v1+s1v0+v0×v1].
2-1-2. Inner Product
By Inner Product Space of
Wikipedia, we have the inner product of the quaternions ⟨q0,q1⟩=⟨[s0,v0],[s1,v1]⟩=s0s1+v0⋅v1=w0w1+x0x1+y0y1+z0z1.
By the multiplication of quaternions, we have that (q0q1)∗=q1∗q0∗. The lengthy calculation is provided by "Equation (5.10)" and "Equation (5.11)" of Quaternions for Computer Graphics.
2-1-4. Norm
By "5.12 The Conjugate" of Quaternions for Computer Graphics, we
have the norm of a quaternion ∥q∥2=qq∗=[s,v][s,−v]=[s2−v⋅(−v),s(−v)+sv+v×(−v)]=[s2+∣v∣2,0]=s2+∥v∥2=w2+x2+y2+z2=⟨q,q⟩⇒∥q∥=⟨q,q⟩.
By "5.16 Inverse Quaternion" of Quaternions for Computer Graphics, we
have the inverse of the quaternion qq−1=1=[1,0]⇒q∗qq−1=q∗⇒(q∗q)q−1=q∗⇒∥q∥2q−1=q∗⇒q−1=∥q∥2q∗.
2-1-7. Bijection between
Rotation Transforms and Unit Quaternions
Each rotation transform can be represented by a unit quaternion, and conversely, each unit quaternion
can represent a rotation transform.
2-1-7-1. Mapping the Rotation
Transform to the Unit Quaternion
Let q=[cos2θ,sin2θn] where
n is a unit vector in 3D space.
First, we would like to prove that q is
a unit quaternion.
The norm of of q
is calculated as ∥q∥2=cos22θ+sin22θ∣n∣2=cos22θ+sin22θ=1. This means that the norm of q
is one. And thus, q
is a unit quaternion.
Second, we would like to prove that q
represents the rotation transform about the axis n by the angle θ.
Let p=[0,p] where
p is the position in 3D space.
Let p′=qpq−1=[s′,p′] where
p′ is the new position of the position p after the transfrom. Actually, we will later prove that we always have s′=0. Thus, this variable can be ignored.
The inverse of of q
is calculated as q−1=∥q∥2[cos2θ,−sin2θn]=[cos2θ,−sin2θn].
By the multiplication of quaternions, we have that p′=qpq−1=[cos2θ,sin2θn][0,p][cos2θ,−sin2θn]=[0,(1−cosθ)(n⋅p)p+cosθp+sinθn×p]. The
lengthy calculation is provided by "Equation (7.13)" of Quaternions for Computer Graphics.
This means that s′=0 and p′=(1−cosθ)(n⋅p)p+cosθp+sinθn×p.
By "Fig. 6.7" and "Fig. 6.8" of Quaternions for Computer Graphics,
we have p′ is exactly the new position of the position p after the rotation transform about the axis n by the angle θ.
Proof
TODO
2-1-7-2. Mapping the Unit
Quaternion to the Rotation Transform
Let q=[s,v] be the
unit quaternion, namely, s2+∥v∥2=1.
We would like to prove that there exists the θ and the n such that q=[cos2θ,sin2θn] and n is a unit vector in 3D space.
Since s2+∥v∥2=1, we can find the θ such that cos2θ=s and sin2θ=∥v∥. And let n=∥v∥v. Thus, we have
that q=[cos2θ,sin2θn]=[s,v].
This means that the rotation transform about the axis n by the angle θ is the rotation transform
represented by the unit quaternion q.
2-2. Dual Numbder
By "A.1 Dual Numbers" of [Kavan 2008], a dual number can be written as a^=a0+aϵϵ, where a0 and aϵ are real numbers, and ϵ is a basis element such that 1ϵ=ϵ1=ϵ and ϵϵ=0.
2-2-1. Multiplication
By "Equation (17)" of [Kavan 2008], we have the multiplication of dual numbers a^b^=(a0+aϵϵ)(b0+bϵϵ)=a0b0+(a0bϵ+b0aϵ)ϵ.
2-2-2. Conjugate
By "A.1 Dual Numbers" of [Kavan 2008], we have the conjugate of a dual number a^=a0+aϵϵ=a0−aϵϵ.
2-2-2-1. Distributive Property
By "Lemma 6" of [Kavan 2008], we have that a^b^=a^b^.
Proof
By the multiplication of dual numbers, we have that a^b^=(a0+aϵϵ)(b0+bϵϵ)=a0b0+(a0bϵ+b0aϵ)ϵ=a0b0−(a0bϵ+b0aϵ)ϵ=(a0−aϵϵ)(b0−bϵϵ)=a^b^.
2-2-3. Square Root
By "Equation (19)" of [Kavan 2008], for any dual number a^=a0+aϵϵ such that a0>0, we have the square root of the dual number
a^=a0+aϵϵ=a0+2a0aϵϵ.
Proof
We would like to find a dual number b^=b0+bϵϵ such that (b0+bϵϵ)(b0+bϵϵ)=a0+aϵϵ, namely, b^=a^.
By the multiplication of dual numbers, we have that a0+aϵϵ=(b0+bϵϵ)(b0+bϵϵ)=b02+2b0bϵϵ. Thus, we have that b02=a0 and aϵ=2b0bϵ. Since a0>0, we have b0=a0 and bϵ=2a0aϵ.
2-2-4. Inverse
By "Equation (18)" of [Kavan 2008], for any dual number a^=a0+aϵϵ such that a0=0, we have the inverse of the dual number a^−1=(a0+aϵϵ)−1=a01−∥a0∥2aϵϵ.
Proof
We would like to find a dual number b^=b0+bϵϵ such that (b0+bϵϵ)(a0+aϵϵ)=1+0ϵ,
namely, b^=a^−1.
By the multiplication of dual numbers, we have that 1+0ϵ=(b0+bϵϵ)(a0+aϵϵ)=b0a0+(bϵa0+aϵb0)ϵ.
Thus, we have that b0a0=1 and bϵa0+aϵb0=0. Since a0=0, we have b0=a01 and bϵ=−∥a0∥2aϵ.
2-3. Dual Quaternion
By "A.2 Dual Quaternions" of [Kavan 2008], a dual quaternion can be deemed not only a
quaternion whose elements are dual numbers, but also a dual number whose elements are quaternions. This means
that we have not only q^=qw^+qx^i+qy^j+qz^k
where qw^, qx^, qy^ and qz^ are dual numbers, but also q^=q0+qϵϵ where q0 and qϵ are quaternions.
2-3-1. Multiplication
Since a dual quaternion can be deemed a dual number whose elements are quaternions, by the
multiplication of the dual numbers, we have the multiplication of dual quaternions p^q^=(p0+pϵϵ)(q0+qϵϵ)=p0q0+(p0qϵ+pϵq0)ϵ
where p0q0, p0qϵ and pϵq0 are calculated by the multiplication of quaternions.
2-3-2. Conjugate
2-3-2-1. First Kind - Quaternion Style
By "A.2 Dual Quaternions" of [Kavan 2008], we have the quaternion style conjugate of a dual
quaternion q^∗=(q0+qϵϵ)∗=q0∗+qϵ∗ϵ.
2-3-2-2. Second Kind - Dual Number Style
By "A.2 Dual Quaternions" of [Kavan 2008], we have the dual number style conjugate of a dual
quaternion q^=q0+qϵϵ=q0−qϵϵ.
2-3-2-3. Commutative Property
By "A.2 Dual Quaternions" of [Kavan 2008], we have q^∗=q^∗=q0∗−qϵ∗ϵ. And thus, we do NOT distinguish
between q^∗ and q^∗ any more.
By "Lemma 10" of [Kavan 2008], we have that (p^q^)∗=q^∗p^∗.
Proof
By the multiplication of dual quaternions, we have that (p^q^)∗=((p0+pϵϵ)(q0+qϵϵ))∗=(p0q0+(p0qϵ+pϵq0)ϵ)∗.
By the quaternion style conjugate of the dual quaternion, we have that (p0q0+(p0qϵ+pϵq0)ϵ)∗=(p0q0)∗+(p0qϵ+pϵq0)∗ϵ.
By the distributive property of the conjugate of the quaternions, we have that (p0q0)∗+(p0qϵ+pϵq0)∗ϵ=(p0q0)∗+((p0qϵ)∗+(pϵq0)∗)ϵ=q0∗p0∗+(q0∗pϵ∗+qϵ∗p0∗)ϵ=(q0+qϵϵ)(p0+pϵϵ)=q^∗p^∗.
2-3-3. Norm
By "Equation (22)" of [Kavan 2008], for any dual quaternion q^=q0+qϵϵ such that ∥q0∥=0, we have the norm of the dual qunternion
∥q^∥=q^q^∗=(q0+qϵϵ)(q0−qϵϵ)=∥q0∥+∥q0∥⟨q0,qe⟩ϵ.
Proof
By the multiplication of dual quaternions, we have that (q0+qϵϵ)(q0−qϵϵ)=∥q0∥2+(q0qϵ∗+qϵq0∗)ϵ.
First, we would like to prove that q0qϵ∗+qϵq0∗=2(s0sϵ+v0⋅vϵ)=2⟨q0,qϵ⟩.
By the multiplication of quaternions, we have that q0qϵ∗+qϵq0∗=[s0,v0][sϵ,−vϵ]+[sϵ,vϵ][s0,−v0]=[s0sϵ−v0⋅(−vϵ),s0(−vϵ)+sϵv0+v0×(−vϵ)]+[sϵs0−vϵ⋅(−v0),sϵ(−v0)+s0vϵ+vϵ×(−v0)]=[s0sϵ−v0⋅(−vϵ)+sϵs0−vϵ⋅(−v0),s0(−vϵ)+sϵv0+v0×(−vϵ)+sϵ(−v0)+s0vϵ+vϵ×(−v0)]=[2(s0sϵ+v0⋅vϵ),0]=2(s0sϵ+v0⋅vϵ).
By the inner product of quaternions, we have that q0qϵ∗+qϵq0∗=2(s0sϵ+v0⋅vϵ)=2⟨q0,qϵ⟩.
Second, we would like to prove that ∥q0∥2+(q0qϵ∗+qϵq0∗)ϵ=∥q0∥+∥q^∥⟨q0,qe⟩ϵ.
Evidently, the real part of ∥q0∥2+(q0qϵ∗+qϵq0∗)ϵ is a real number. And since q0qϵ∗+qϵq0∗=2⟨q0,qϵ⟩, the dual part of ∥q0∥2+(q0qϵ∗+qϵq0∗)ϵ is a real number. This means that ∥q0∥2+(q0qϵ∗+qϵq0∗)ϵ is a dual number.
By the square root of the dual number, since ∥q0∥=0, we have that ∥q0∥2+(q0qϵ∗+qϵq0∗)ϵ=∥q0∥2+2⟨q0,qϵ⟩ϵ=∥q0∥+2∥q0∥22⟨q0,qϵ⟩ϵ=∥q0∥+∥q0∥⟨q0,qϵ⟩ϵ.
2-3-3-1. Distributive Property
By "Lemma 11" of [Kavan 2008], we have that ∥p^q^∥=∥p^∥∥q^∥.
Proof
By the distributive property of the quaternion style conjugate of the dual quaternions, we have
that ∥p^q^∥2=(p^q^)(p^q^)∗=(p^q^)(q^∗p^∗)=p^(q^q^∗)p^∗=p^∥q^∥2p^∗=∥q^∥2p^p^∗=∥q^∥2(p^p^∗)=∥q^∥2∥p^∥2=∥p^∥2∥q^∥2.
2-3-4. Unit Dual Quaternion
By "A.2 Dual Quaternions" of [Kavan 2008], a unit dual quaternion is a dual quaternion of
which the norm is one. By the norm of the dual quaternion, we have that ∥q0∥=1 and ⟨q0,qϵ⟩=0. This means that a unit dual quaternion is a
dual quaternion such that the real part is a unit quaternion and the inner product of the real part and the dual
part is zero.
2-3-5. Bijection between
Rigid Transforms and Unit Dual Quaternions
By "Lemma 12" of [Kavan 2008], we have that each rigid transform can be represented by a
unit dual quaternion, and conversely, each unit dual quaternion can represent a rigid transform.
2-3-5-1. Mapping the Rigid
Transform to the Unit Dual Quaternion
Let r^=r0+[0,0]ϵ where r0 is a unit quaternion, namely, ∥r0∥=1.
Let t^=[1,0]+[0,21t]ϵ where t is a vector in 3D space.
Let q^=t^r^.
First, we would like to prove that q^ is a unit dual quaternion.
The norm of of r^ is calculated as ∥r^∥=∥r0∥+∥r0∥⟨[0,0],r0⟩ϵ=1+10ϵ=1.
And the norm of t^ is calculated as ∥t^∥=∥[1,0]∥+[1,0]⟨[1,0],[0,21t]⟩ϵ=1+0ϵ=1. This means that the norm of t^ is one.
By the distributive property of the norm of the dual quaternions, we have that ∥q^∥=∥t^r^∥=∥t^∥∥r^∥=1. This means that the norm of q^ is one. And thus, q^ is a unit dual quaternion.
Second, we would like to prove that q^ represents the rigid transform composed of the rotation transform represented by the unit quaternion r0 and the translation transform represented by the 3D vector t.
Let p^=[1,0]+[0,p]ϵ where p is the position in 3D space.
Let p′^=q^p^q^∗=p′0+[s′,p′] where
p′ is the new position of the position p after the transfrom. Actually, we will later prove that we always have p′0=[1,0] and
s′=0. Thus, these two variables can be
ignored.
By the distributive property of the quaternion style conjugate of the dual quaternions, we have
that q^∗=(t^r^)∗=r^∗t^∗.
By the distributive property of the conjugate of dual numbers, we have that r^∗t^∗=r^∗t^∗.
By the commutative property of the conjugate of the dual quaternions, we have that r^∗=r0∗−rϵ∗ϵ=r0∗=1r0∗=∥r0∥2r0∗=r0−1 and t^∗=t0∗−tϵ∗ϵ=[1,0]−([0,21t])∗ϵ=[1,0]−[0,−21t]ϵ=[1,0]+[0,21t]ϵ.
Thus, we have that p′^=q^p^q^∗=(t^r^)p^(t^r^)∗=(t^r^)p^(r^∗t^∗)=(([1,0]+[0,21t]ϵ)r0)p^(r0−1([1,0]+[0,21t]ϵ))=(([1,0]+[0,21t]ϵ)(r0([1,0]+[0,p]ϵ)r0−1)([1,0]+[0,21t]ϵ)).
By the multiplication of quaternions, we have that (([1,0]+[0,21t]ϵ)(r0([1,0]+[0,p]ϵ)r0−1)([1,0]+[0,21t]ϵ))=(([1,0]+[0,21t]ϵ)([r0r0−1,0]+[0,r0pr0−1]ϵ)([1,0]+[0,21t]ϵ))=(([1,0]+[0,21t]ϵ)([1,0]+[0,r0pr0−1]ϵ)([1,0]+[0,21t]ϵ))=[1,0]+[0,r0pr0−1+21t+21t]ϵ=[1,0]+[0,r0pr0−1+t]ϵ. This means that p′0=[1,0], s′=0 and p′=r0pr0−1+t.
By the bijection between rotation transforms and unit quaternions, we have that r0p^r0−1 is the new position of the position p after the rotation transform represented by the unit quaternion r0.
Evidently, r0pr0−1+t is the new position of the position r0p^r0−1 after the translation transform represented by the vector t.
Here is C++ code of mapping the rigid transform to the unit dual quaternion.
//// Mapping the rigid transformation to the unit dual quaternion.//// [out] q: The unit dual quaternion of which the q[0] is the real part and the q[1] is the dual part.//// [in] r: The unit quaternion which represents the rotation transform of the rigid transformation.//// [in] t: The 3D vector which represnets the translation transform of the rigid transformation.//voidunit_dual_quaternion_from_rigid_transform(DirectX::XMFLOAT4 q[2], DirectX::XMFLOAT4 const& r, DirectX::XMFLOAT3 const& t){
// \hat{\boldsymbol{r}} = \boldsymbol{r_0} + [0, \overrightarrow{0}] ϵ// \hat{\boldsymbol{t}} = [1, \overrightarrow{0}] + [0, 0.5 \overrightarrow{t}] ϵ// \hat{\boldsymbol{q}} = \hat{\boldsymbol{t}} \hat{\boldsymbol{r}}
DirectX::XMFLOAT4 q_0 = r;
DirectX::XMFLOAT4 q_e;
#if 1// \hat{\boldsymbol{t}} \hat{\boldsymbol{r}} = \boldsymbol{r_0} + [0, 0.5 \overrightarrow{t}] \boldsymbol{r_0} ϵ
DirectX::XMFLOAT4 t_q = DirectX::XMFLOAT4(0.5F * t.x, 0.5F * t.y, 0.5F * t.z, 0.0F);
// NOTE: "XMQuaternionMultiply" returns "Q2*Q1" rather than "Q1*Q2"!
DirectX::XMStoreFloat4(&q_e, DirectX::XMQuaternionMultiply(DirectX::XMLoadFloat4(&r), DirectX::XMLoadFloat4(&t_q)));
#else// \boldsymbol{r_0} + [0, 0.5 \overrightarrow{t}] \boldsymbol{r_0} ϵ = \boldsymbol{r_0} + [0, 0.5 \overrightarrow{t}] [s_r, \overrightarrow{v_r}] = [-0.5 \overrightarrow{t} \cdot \overrightarrow{v_r}, 0.5 (s_r \overrightarrow{t} + \overrightarrow{t} \times \overrightarrow{v_r} )]float s_q_e;
DirectX::XMFLOAT3 v_q_e;
float s_r = r.w;
DirectX::XMFLOAT3 v_r = DirectX::XMFLOAT3(r.x, r.y, r.z);
DirectX::XMStoreFloat(&s_q_e, DirectX::XMVectorScale(DirectX::XMVector3Dot(DirectX::XMLoadFloat3(&t), DirectX::XMLoadFloat3(&v_r)), -0.5F));
DirectX::XMStoreFloat3(&v_q_e, DirectX::XMVectorScale(DirectX::XMVectorAdd(DirectX::XMVectorScale(DirectX::XMLoadFloat3(&t), s_r), DirectX::XMVector3Cross(DirectX::XMLoadFloat3(&t), DirectX::XMLoadFloat3(&v_r))), 0.5F));
q_e.w = s_q_e;
q_e.x = v_q_e.x;
q_e.y = v_q_e.y;
q_e.z = v_q_e.z;
#endif
q[0] = q_0;
q[1] = q_e;
}
Usually, the quaternion and the translation are provided by the animation engine. For example, the
getRotation and the getTranslation are provided by the
hkQsTransform of the Havok Animation. And if only the
matrix is provided by the animation engine, the matrix decomposition by PBR
Book can be used. The code of the matrix decomposition is implemented by XMMatrixDecompose
in DirectXMath.
2-3-5-2. Mapping the Unit Dual
Quaternion to the Rigid Transform
Let q^=q0+qϵϵ be the unit quaternion, namely,
∥q0∥=1 and ⟨q0,qϵ⟩=0.
We would like to prove that there exists the r0 and the t such that r^=r0+[0,0]ϵ, t^=[1,0]+[0,21t]ϵ, q^=t^r^ and r0 is a unit quaternion.
By the multiplication of dual quaternions, q^=t^r^=r0+[0,21t]r0ϵ.
Evidently, we find the r0 such that r0=q0. Since ∥q0∥=1, r0 is a unit quaternion.
And we would like to find the t such that [0,21t]r0=qϵ.
Since r0=q0 is a unit quaternion, we have that [0,21t]r0=qϵ⇔[0,21t]q0=qϵ⇔[0,21t]q0q0−1=qϵq0−1⇔[0,21t]=qϵq0−1=qϵ∥q0∥q0∗=qϵq0∗.
Let q0=[s0,v0].
Let qϵ=[sϵ,vϵ].
Since ⟨q0,qϵ⟩=0, by the multiplication of quaternions,
we have that qϵq0∗=[sϵ,vϵ][s0,−v0]=[sϵs0−vϵ(−v0),sϵ(−v0)+s0vϵ+vϵ×(−v0)]=[sϵs0+vϵv0,−sϵv0+s0vϵ−vϵ×v0]=[⟨qϵ,q0⟩,−sϵv0+s0vϵ−vϵ×v0]=[0,−sϵv0+s0vϵ−vϵ×v0].
Thus, we have that 21t=−sϵv0+s0vϵ−vϵ×v0⇒t=2(−sϵv0+s0vϵ−vϵ×v0).
This means that the rigid transform composed of the rotation transform represented by the unit
quaternion r0 and the translation transform represented by the 3D vector t is the rigid transform represented by the unit dual quaternion q^.
Here is HLSL code of mapping the rigid transform to the unit dual quaternion.
//
// Mapping the rigid transformation to the unit dual quaternion.
//
// [in] q: The unit dual quaternion of which the q[0] is the real part and the q[1] is the dual part.
//
// [out] r: The unit quaternion which represents the rotation transform of the rigid transformation.
//
// [out] t: The 3D vector which represnets the translation transform of the rigid transformation.
//
void unit_dual_quaternion_to_rigid_transform(in float2x4 q, out float4 r, out float3 t)
{
float4 q_0 = q[0];
float4 q_e = q[1];
// \boldsymbol{r_0} = \boldsymbol{q_0}
r = q_0;
// \overrightarrow{t} = 2 (- s_ϵ \overrightarrow{v_0} + s_0 \overrightarrow{v_ϵ} - \overrightarrow{v_ϵ} \times \overrightarrow{v_0}
// t = 2.0 * (- q_e.w * q_0.xyz + q_0.w * q_e.xyz - cross(q_e.xyz, q_0.xyz));
t = 2.0 * (q_0.w * q_e.xyz - q_e.w * q_0.xyz + cross(q_0.xyz, q_e.xyz));
}
3. DLB (Dual quaternion Linear Blending)
The DLB (Dual quaternion Linear Blending) method is proposed by [Kavan 2007] and [Kavan 2008].
Actually, another ScLERP (Screw Linear Interpolation) method is proposed by [Kavan 2008] as well. However, the
ScLERP method is too unwieldy to be used.
First, we would like to calculate the linear combination of the dual quaternions b^=i∑nwiqi^.
Second, we would like to calculate the normalization b′^=∥b^∥b^.
By the norm of the dual quaternion, we have that ∥b^∥=∥b0+bϵϵ∥=∥b0∥+∥b0∥⟨b0,bϵ⟩ϵ.
By "4 Implementation Notes" of [Kavan 2008], by the inverse of the dual number, we have
that ∥b^∥−1=(∥b0∥+∥b0∥⟨b0,bϵ⟩ϵ)−1=∥b0∥1−∥b0∥2∥b0∥⟨b0,bϵ⟩ϵ=∥b0∥1−∥b0∥3⟨b0,bϵ⟩ϵ.
Thus, we have that b′^=∥b^∥b^=b^∥b^∥1=(b0+bϵϵ)(∥b0∥1−∥b0∥3⟨b0,bϵ⟩ϵ)=∥b0∥b0+(∥b0∥bϵ−∥b0∥3b0⟨b0,bϵ⟩)ϵ.
Let b′0=∥b0∥b0.
Let b′ϵ=∥b0∥bϵ−∥b0∥3b0⟨b0,bϵ⟩.
By mapping the unit dual quaternion to the rigid transform, we have that r0=b′0=∥b0∥b0 and [0,21t]=b′ϵb′0∗=(∥b0∥bϵ−∥b0∥3b0⟨b0,bϵ⟩)(∥b0∥b0∗)=∥b0∥2bϵb0∗−∥b0∥2⟨b0,bϵ⟩.
Since the vector part of ∥b0∥2⟨b0,bϵ⟩ is zero, the
vector part of ∥b0∥2bϵb0∗−∥b0∥2⟨b0,bϵ⟩ is exactly the
vector part of ∥b0∥2bϵb0∗. This means
that the calculation of t does NOT requrie the calculation of ∥b0∥2⟨b0,bϵ⟩.
Thus, we merely need to calculate c^=∥b0∥b0+∥b0∥bϵϵ and calculate the vector part
of 2cϵc0∗ as t.
Here is HLSL code of DLB (Dual quaternion Linear Blending).
//
// DLB (Dual quaternion Linear Blending)
//
float2x4 dual_quaternion_linear_blending(in float2x4 q[MAX_BONE_COUNT], in uint4 blend_indices, in float4 blend_weights)
{
#if 1
// NOTE:
// The original DLB does NOT check the sign of the inner product of the unit quaternion q_x_0 and q_y_0(q_z_0 q_w_0).
// However, since the unit quaternion q and -q represent the same rotation transform, we may get the result of which the real part is zero.
float2x4 b = blend_weights.x * q[blend_indices.x] + blend_weights.y * sign(dot(q[blend_indices.x][0], q[blend_indices.y][0])) * q[blend_indices.y] + blend_weights.z * sign(dot(q[blend_indices.x][0], q[blend_indices.z][0])) * q[blend_indices.z] + blend_weights.w * sign(dot(q[blend_indices.x][0], q[blend_indices.w][0])) * q[blend_indices.w];
#else
float2x4 b = blend_weights.x * g_dualquat[blend_indices.x] + blend_weights.y * g_dualquat[blend_indices.y] + blend_weights.z * g_dualquat[blend_indices.z] + blend_weights.w * g_dualquat[blend_indices.w];
#endif
// "4 Implementation Notes" of [Ladislav Kavan, Steven Collins, Jiri Zara, Carol O'Sullivan. "Geometric Skinning with Approximate Dual Quaternion Blending." SIGGRAPH 2008.](http://www.cs.utah.edu/~ladislav/kavan08geometric/kavan08geometric.html)
// We do NOT need to calculate the exact dual part "\boldsymbol{q_\epsilon}", since the scalar part of the "\boldsymbol{q_\epsilon} {\boldsymbol{q_0}}^*" is ignored when we calculate the "\frac{1}{2}\overrightarrow{t}".
return (b / length(b[0]));
}
However, the scale is NOT supported by DLB (Dual quaternion Linear Blending). By "4.2 Non-rigid
Joint Transformations" of [Kavan 2008], we may separate the joint (bone) transform into scale transform
(represented by a 3D vector) and rigid transform (represented by a unit dual quaternion). In the first phase, we
linearly blend the 3D vector and apply the scale transform. In the second phase, we use the DLB (Dual quaternion
Linear Blending) and apply the rigid transform.