protected void TransformSkeleton(Matrix4 unscaledTransform, float scale) { Matrix4 invExportTransform = unscaledTransform.Inverse(); Dictionary<string, Matrix4> fullInverseBoneTransforms = new Dictionary<string, Matrix4>(); Skeleton newSkeleton = new Skeleton(skeleton.Name); // Construct new versions of the bones, and build // the inverse bind matrix that will be needed. for (ushort i = 0; i < skeleton.BoneCount; ++i) { Bone bone = skeleton.GetBone(i); Bone newBone = newSkeleton.CreateBone(bone.Name, bone.Handle); fullInverseBoneTransforms[bone.Name] = bone.BindDerivedInverseTransform * invExportTransform; } // Build the parenting relationship for the new skeleton for (ushort i = 0; i < skeleton.BoneCount; ++i) { Bone bone = skeleton.GetBone(i); Bone newBone = newSkeleton.GetBone(i); Bone parentBone = (Bone)bone.Parent; if (parentBone != null) { Bone newParentBone = newSkeleton.GetBone(parentBone.Handle); newParentBone.AddChild(newBone); } } // Set the orientation and position for the various bones for (ushort i = 0; i < newSkeleton.BoneCount; ++i) { Bone bone = skeleton.GetBone(i); string boneName = bone.Name; string parentName = (bone.Parent == null) ? null : bone.Parent.Name; Matrix4 transform = GetLocalBindMatrix(fullInverseBoneTransforms, boneName, parentName, true); Quaternion orientation = GetRotation(transform); Bone newBone = newSkeleton.GetBone(i); newBone.Orientation = orientation; // newBone.Scale = transform.Scale; newBone.Position = scale * transform.Translation; } newSkeleton.SetBindingPose(); for (int i = 0; i < skeleton.AnimationCount; ++i) { Animation anim = skeleton.GetAnimation(i); Animation newAnim = newSkeleton.CreateAnimation(anim.Name, anim.Length); TransformAnimation(unscaledTransform, scale, newAnim, anim, newSkeleton); } skeleton = newSkeleton; }
public void Import(Skeleton skeleton) { // store a local reference to the skeleton for modification this.skeleton = skeleton; XmlDocument document = new XmlDocument(); document.Load(stream); foreach (XmlNode childNode in document.ChildNodes) { switch (childNode.Name) { case "skeleton": ReadSkeleton(childNode); break; default: DebugMessage(childNode); break; } } skeleton.SetBindingPose(); }
public void ImportSkeleton( Stream stream, Skeleton skeleton ) { // store a local reference to the mesh for modification this.skeleton = skeleton; BinaryReader reader = new BinaryReader( stream, System.Text.Encoding.UTF8 ); // start off by taking a look at the header ReadFileHeader( reader ); SkeletonChunkID chunkID = 0; while ( !IsEOF( reader ) ) { chunkID = ReadChunk( reader ); switch ( chunkID ) { case SkeletonChunkID.Bone: ReadBone( reader ); break; case SkeletonChunkID.BoneParent: ReadBoneParent( reader ); break; case SkeletonChunkID.Animation: ReadAnimation( reader ); break; case SkeletonChunkID.AttachmentPoint: ReadAttachmentPoint( reader ); break; default: LogManager.Instance.Write( "Can only parse bones, parents, and animations at the top level during skeleton loading." ); LogManager.Instance.Write( "Unexpected chunk: " + chunkID.ToString() ); break; } // switch } // while // assume bones are stored in binding pose skeleton.SetBindingPose(); }
/// <summary> /// Build the bind pose for the skeleton based on the bind pose of the /// various Controllers (skin clusters). /// This will also set up bones for the tag points. /// </summary> /// <param name="transform">the transform matrix to convert from the /// system used by the modeling tool to the /// system that will be used by multiverse</param> /// <param name="skeleton">Skeleton that will be built by this call</param> protected void BuildSkeletonAtBindPose( Matrix4 transform, Skeleton skeleton ) { // Construct a list of bones that are of interest to us // This will be every bone that influences the skin, including the // parent bones (since they indirectly influence the skin). List<string> boneNames = new List<string>(); foreach( Controller controller in Controllers.Values ) { SkinController skinController = controller as SkinController; if( skinController == null ) continue; foreach( string key in skinController.InverseBindMatrices.Keys ) { string boneName = key; // The entries in the skin controller may use sid. If so, // change these to use the bone name. if( NodeSidMap.ContainsKey( boneName ) ) boneName = NodeSidMap[ boneName ]; if( boneNames.Contains( boneName ) ) continue; boneNames.Add( boneName ); // Add all the parent bones string currentBone = boneName; while( BoneParents.ContainsKey( currentBone ) ) { string parentBone = BoneParents[ currentBone ]; if( parentBone == null ) break; if( !boneNames.Contains( parentBone ) ) boneNames.Add( parentBone ); currentBone = parentBone; } } } Matrix4 unitConversionMatrix = Matrix4.Identity; unitConversionMatrix.Scale = new Vector3( m_UnitConversion, m_UnitConversion, m_UnitConversion ); Matrix4 worldTransform = transform * unitConversionMatrix; // Build the invBindMatrices with the inverse bind matrices for // the bones Dictionary<string, Matrix4> invBindMatrices = new Dictionary<string, Matrix4>(); Quaternion worldRotate; Vector3 worldScale, worldTranslate; Matrix4.DecomposeMatrix( ref worldTransform, out worldTranslate, out worldRotate, out worldScale ); foreach( string boneName in boneNames ) { Matrix4 bonePoseTransform = GetBonePoseTransform( boneName ); Quaternion bonePoseRotate; Vector3 bonePoseTranslate, bonePoseScale; Matrix4.DecomposeMatrix( ref bonePoseTransform, out bonePoseTranslate, out bonePoseRotate, out bonePoseScale ); Vector3 boneTranslate = worldTranslate + worldRotate * MathHelpers.ScaleVector( worldScale, bonePoseTranslate ); Quaternion boneOrient = worldRotate * bonePoseRotate; Matrix4 boneTransform = Multiverse.MathLib.MathUtil.GetTransform( boneOrient, boneTranslate ); invBindMatrices[ boneName ] = boneTransform.Inverse(); } ProcessBones( invBindMatrices, skeleton, null ); skeleton.SetBindingPose(); }