Branchless Antipodality Handling

1 minute read.

Won­der­land En­gine us­es du­al quater­nions for the scene­graph and in the ver­tex shaders. As a re­sult, chos­ing Du­al Quater­nion skin­ning over ma­trix in­ter­po­la­tions was ob­vi­ous, as all the Du­al Quater­nion math was al­ready im­ple­ment­ed in GLSL any­way.

Fol­low­ing the Im­ple­men­ta­tion by the Au­thors of “Geo­met­ric Skin­ning with Ap­prox­i­mate Du­al Quater­nion Blend­ing” 1 , I made a sim­ple op­ti­miza­tion to their “most ro­bust, but not the most ef­fi­cient way”.

They list:

/* [dq0-3 are the 4 joint transforms per vertex
 *  dq is a float2x4 (which has no glsl equivalent)
    [0] is the real (rotation) part and
    [1] is the dual (translation) part.] */
 if (dot(dq0[0], dq1[0]) < 0.0) dq1 *= -1.0;
 if (dot(dq0[0], dq2[0]) < 0.0) dq2 *= -1.0;
 if (dot(dq0[0], dq3[0]) < 0.0) dq3 *= -1.0;

which can be trans­formed in­to the fol­low­ing GLSL:

float copysign(float from, float to) {
    const uint firstBit = (1u << 31u);
    const uint otherBits = ~(1u << 31u);
    return uintBitsToFloat(
        /* Multiply the signs only */
        ((floatBitsToUint(from) ^ floatBitsToUint(to)) & firstBit) |
        /* Keep non-sign bits the same */
        (floatBitsToUint(to) & otherBits));
}

/* jointTransforms is an array of the following struct */
struct Quat2 {
    vec4 rot;
    vec4 loc;
};

/* Prepare the weights instead of multiplying with the dual quaternion directly */
float w[4] = float[](
    weights[0],
    copysign(dot(jointTransforms[0].rot, jointTransforms[1].rot), weights[1]),
    copysign(dot(jointTransforms[0].rot, jointTransforms[2].rot), weights[2]),
    copysign(dot(jointTransforms[0].rot, jointTransforms[3].rot), weights[3])
);

This saves the Du­al Quater­nion mul­ti­pli­ca­tions and branch­es. w can now be used as weights for the skin­ning as per usu­al.

This as­sumes sign is im­ple­ment­ed branch­less, of course, which is up to the driv­er.

1
Ka­van et al., 2008, Geo­met­ric Skin­ning with Ap­prox­i­mate Du­al Quater­nion Blend­ing