public void UpdateAnimation()
{
if ( !this.HasSkeleton && !this.mesh.HasVertexAnimation )
{
return;
}
// we only do these tasks if they have not already been done this frame
Root root = Root.Instance;
ulong currentFrameNumber = root.CurrentFrameCount;
bool stencilShadows = false;
if ( this.CastShadows && root.SceneManager != null )
{
stencilShadows = root.SceneManager.IsShadowTechniqueStencilBased;
}
bool swAnimation = !this.hardwareAnimation || stencilShadows || this.softwareAnimationRequests > 0;
// Blend normals in s/w only if we're not using h/w animation,
// since shadows only require positions
bool blendNormals = !this.hardwareAnimation || this.softwareAnimationNormalsRequests > 0;
bool animationDirty = this.frameAnimationLastUpdated != currentFrameNumber
// || (HasSkeleton && Skeleton.ManualBonesDirty)
;
if ( animationDirty ||
( swAnimation && this.mesh.HasVertexAnimation && !this.TempVertexAnimBuffersBound() ) ||
( swAnimation && this.HasSkeleton && !this.TempSkelAnimBuffersBound( blendNormals ) ) )
{
if ( this.mesh.HasVertexAnimation )
{
if ( swAnimation )
{
// grab & bind temporary buffer for positions
if ( this.softwareVertexAnimVertexData != null &&
this.mesh.SharedVertexDataAnimationType != VertexAnimationType.None )
{
this.tempVertexAnimInfo.CheckoutTempCopies( true, false, false, false );
// NB we suppress hardware upload while doing blend if we're
// hardware animation, because the only reason for doing this
// is for shadow, which need only be uploaded then
this.tempVertexAnimInfo.BindTempCopies( this.softwareVertexAnimVertexData,
this.hardwareAnimation );
}
foreach ( SubEntity subEntity in this.subEntityList )
{
if ( subEntity.IsVisible && subEntity.SoftwareVertexAnimVertexData != null &&
subEntity.SubMesh.VertexAnimationType != VertexAnimationType.None )
{
subEntity.TempVertexAnimInfo.CheckoutTempCopies( true, false, false, false );
subEntity.TempVertexAnimInfo.BindTempCopies( subEntity.SoftwareVertexAnimVertexData,
this.hardwareAnimation );
}
}
}
this.ApplyVertexAnimation( this.hardwareAnimation, stencilShadows );
}
if ( this.HasSkeleton )
{
this.CacheBoneMatrices();
if ( swAnimation )
{
bool blendTangents = blendNormals;
bool blendBinormals = blendNormals;
if ( this.skelAnimVertexData != null )
{
// Blend shared geometry
// NB we suppress hardware upload while doing blend if we're
// hardware animation, because the only reason for doing this
// is for shadow, which need only be uploaded then
this.tempSkelAnimInfo.CheckoutTempCopies( true, blendNormals, blendTangents, blendBinormals );
this.tempSkelAnimInfo.BindTempCopies( this.skelAnimVertexData, this.hardwareAnimation );
// Blend, taking source from either mesh data or morph data
Mesh.SoftwareVertexBlend(
( this.mesh.SharedVertexDataAnimationType != VertexAnimationType.None
? this.softwareVertexAnimVertexData
: this.mesh.SharedVertexData ),
this.skelAnimVertexData,
this.boneMatrices,
blendNormals,
blendTangents,
blendBinormals );
}
// Now check the per subentity vertex data to see if it needs to be
// using software blend
foreach ( SubEntity subEntity in this.subEntityList )
{
// Blend dedicated geometry
if ( subEntity.IsVisible && subEntity.SkelAnimVertexData != null )
{
subEntity.TempSkelAnimInfo.CheckoutTempCopies( true,
blendNormals,
blendTangents,
blendBinormals );
subEntity.TempSkelAnimInfo.BindTempCopies( subEntity.SkelAnimVertexData,
this.hardwareAnimation );
// Blend, taking source from either mesh data or morph data
Mesh.SoftwareVertexBlend(
( subEntity.SubMesh.VertexAnimationType != VertexAnimationType.None
?
subEntity.SoftwareVertexAnimVertexData
: subEntity.SubMesh.vertexData ),
subEntity.SkelAnimVertexData,
this.boneMatrices,
blendNormals,
blendTangents,
blendBinormals );
}
}
}
}
// trigger update of bounding box if necessary
if ( this.childObjectList.Count != 0 )
{
this.parentNode.NeedUpdate();
}
// remember the last frame count
this.frameAnimationLastUpdated = currentFrameNumber;
}
// Need to update the child object's transforms when animation dirty
// or parent node transform has altered.
if ( HasSkeleton && animationDirty || lastParentXform != ParentNodeFullTransform )
{
lastParentXform = ParentNodeFullTransform;
for ( int i = 0; i < childObjectList.Count; i++ )
{
MovableObject child = childObjectList[ i ];
child.ParentNode.Update( true, true );
}
if ( hardwareAnimation && IsSkeletonAnimated )
{
numBoneMatrices = skeletonInstance.BoneCount;
if ( boneWorldMatrices == null )
{
boneWorldMatrices = new Matrix4[ numBoneMatrices ];
}
for ( int i = 0; i < numBoneMatrices; i++ )
{
boneWorldMatrices[ i ] = Matrix4.Multiply( lastParentXform, boneMatrices[ i ] );
}
}
}
}
protected internal Matrix4[] boneWorldMatrices;