NEWS: This project is now hosted on GitHub https://github.com/Microsoft/DirectXTK. This site is being maintained for now, but please move to using GitHub https://github.com/Microsoft/DirectXTK/wiki/DirectXTK

This abstract interface controls skinning animation typically communicated to the shader via a dynamic constant buffer. Settings for this interface can influence the choice of shader permutation. This interface is implemented by DGSLEffect and SkinnedEffect.

Effects that implement this interface typically require BLENDINDICES and BLENDWEIGHT semantic data in the vertex input layout.

Obtaining the interface

There are two methods used in DirectX Tool Kit. For simple cases, just maintain a reference directly to the desired effect class:

std::shared_ptr<SkinnedEffect> effect;

...

...

effect->SetBoneTransforms( bones.get(), boneCount );

For more general cases where a number of effect classes can be in use (such as Model which uses a mix of BasicEffect, SkinnedEffect, and/or DGSLEffect), use RTTI to obtain the interface.

std::shared_ptr<IEffect> effect;

...

auto iskin = dynamic_cast<IEffectSkinning*>( part->effect.get() );
if ( iskin )
{
    iskin->SetBoneTransforms( bones.get(), boneCount );
}

Skinning

The skinning interface is primarily used to set the per-bone transformation matrices for rendering. This is accomplished through the SetBoneTransforms method. Because the method takes a pointer to XMMATRIX, the memory buffer must be 16-byte aligned. While this is the default of new and malloc on 64-bit platforms, this is not true by default for 32-bit platforms. Use of _aligned_malloc is recommended.

struct aligned_deleter { void operator()(void* p) { _aligned_free(p); } };

std::unique_ptr<XMMATRIX[], aligned_deleter> bones(
        reinterpret_cast<XMMATRIX*>( _aligned_malloc( sizeof(XMMATRIX) * boneCount, 16 ) ) );

...

// Simple time-based uniform scaling
float s = 1 + sin(time * 1.7f) * 0.5f;
XMMATRIX scale = XMMatrixScaling(s,s,s);

for (size_t j=0; j < boneCount; ++j )
{
    bones[ j ] = scale;
}

effect->SetBoneTransforms(bones.get(), boneCount);

Note that the maximum bone count must be <= MaxBones (72).

You can call ResetBoneTransforms to reset all per-bone transforms to the identity, which is also the default when the effect is newly created.

Finally, the SetWeightsPerVertex method is used as a way to optimize performance of the vertex shader. By default, it assumes that all 4 bones listed in the per-vertex BLENDINDICES0 and BLENDWEIGHT0 are used by the model. You can use this method to set the value to 1 or 2 which will choose a lighter-weight shader permutation that ignores the extra 3 or 2 bones influences per vertex, or back to the default of 4. The choice of this value is driven entirely by the content.

Built-in Effect Notes

BasicEffect, AlphaTestEffect, DualTextureEffect, EnvironmentMapEffect
These built-in effects do not implement skinning animation.

DGSLEffect
This built-in effect can be created with or without support for skinned animation via the enableSkinning parameter on it's constructor. If SetBoneTransforms is called on an instance of DGSEffect that was created with enableSkinning set to false, an exception is thrown.

SkinnedEffect
See http://blogs.msdn.com/b/shawnhar/archive/2010/04/30/built-in-effects-permutations-and-performance.aspx for performance costs of the various shader permutations.

Note: As an optimization, SkinnedEffect and DGSLEffect assume that all the matrices are affine transformations, and that the final column is (0 0 0 1). This means that the value of the last column is effectively ignored when set into the constant buffer containing the bone transformations (i.e. the shaders use float4x3)

Last edited Jul 28, 2015 at 8:08 PM by walbourn, version 10