protected void WriteMorphKeyframe( BinaryWriter writer, VertexMorphKeyFrame keyFrame ) { var start_offset = writer.Seek( 0, SeekOrigin.Current ); WriteChunk( writer, MeshChunkID.AnimationMorphKeyframe, 0 ); WriteFloat( writer, keyFrame.Time ); var vBuffer = keyFrame.VertexBuffer; var vBufferPtr = vBuffer.Lock( BufferLocking.ReadOnly ); WriteFloats( writer, vBuffer.VertexCount*3, vBufferPtr ); vBuffer.Unlock(); var end_offset = writer.Seek( 0, SeekOrigin.Current ); writer.Seek( (int)start_offset, SeekOrigin.Begin ); WriteChunk( writer, MeshChunkID.AnimationMorphKeyframe, (int)( end_offset - start_offset ) ); writer.Seek( (int)end_offset, SeekOrigin.Begin ); }
/// <summary> /// As the 'apply' method but applies to specified VertexData instead of /// associated data. /// </summary> public void ApplyToVertexData(VertexData data, float time, float weight, List <Pose> poseList) { // Nothing to do if no keyframes if (keyFrameList.Count == 0) { return; } // Get keyframes KeyFrame kf1, kf2; ushort firstKeyIndex; float t = GetKeyFramesAtTime(time, out kf1, out kf2, out firstKeyIndex); if (animationType == VertexAnimationType.Morph) { VertexMorphKeyFrame vkf1 = (VertexMorphKeyFrame)kf1; VertexMorphKeyFrame vkf2 = (VertexMorphKeyFrame)kf2; if (targetMode == VertexAnimationTargetMode.Hardware) { // If target mode is hardware, need to bind our 2 keyframe buffers, // one to main pos, one to morph target texcoord Debug.Assert(data.HWAnimationDataList.Count == 0, "Haven't set up hardware vertex animation elements!"); // no use for TempBlendedBufferInfo here btw // NB we assume that position buffer is unshared // VertexDeclaration::getAutoOrganisedDeclaration should see to that VertexElement posElem = data.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); // Set keyframe1 data as original position data.vertexBufferBinding.SetBinding(posElem.Source, vkf1.VertexBuffer); // Set keyframe2 data as derived data.vertexBufferBinding.SetBinding(data.HWAnimationDataList[0].TargetVertexElement.Source, vkf2.VertexBuffer); // save T for use later data.HWAnimationDataList[0].Parametric = t; } else { // If target mode is software, need to software interpolate each vertex Mesh.SoftwareVertexMorph(t, vkf1.VertexBuffer, vkf2.VertexBuffer, data); } } else { // Pose VertexPoseKeyFrame vkf1 = (VertexPoseKeyFrame)kf1; VertexPoseKeyFrame vkf2 = (VertexPoseKeyFrame)kf2; // For each pose reference in key 1, we need to locate the entry in // key 2 and interpolate the influence List <PoseRef> poseRefList1 = vkf1.PoseRefs; List <PoseRef> poseRefList2 = vkf2.PoseRefs; foreach (PoseRef p1 in poseRefList1) { float startInfluence = p1.Influence; float endInfluence = 0; // Search for entry in keyframe 2 list (if not there, will be 0) foreach (PoseRef p2 in poseRefList2) { if (p1.PoseIndex == p2.PoseIndex) { endInfluence = p2.Influence; break; } } // Interpolate influence float influence = startInfluence + t * (endInfluence - startInfluence); // Scale by animation weight influence = weight * influence; // Get pose Debug.Assert(p1.PoseIndex <= poseList.Count); Pose pose = poseList[p1.PoseIndex]; // apply ApplyPoseToVertexData(pose, data, influence); } // Now deal with any poses in key 2 which are not in key 1 foreach (PoseRef p2 in poseRefList2) { bool found = false; foreach (PoseRef p1 in poseRefList1) { if (p1.PoseIndex == p2.PoseIndex) { found = true; break; } } if (!found) { // Need to apply this pose too, scaled from 0 start float influence = t * p2.Influence; // Scale by animation weight influence = weight * influence; // Get pose Debug.Assert(p2.PoseIndex <= poseList.Count); Pose pose = poseList[p2.PoseIndex]; // apply ApplyPoseToVertexData(pose, data, influence); } } // key 2 iteration } // morph or pose animation }