private BoneContent createSkel(aiNode root) { BoneContent BoneContent = null; if (ainodetocontent.ContainsKey(root.mName.Data)) { aiBone b = bones.Find((a) => a.mName.Data == root.mName.Data); if (b != null) { BoneContent = new BoneContent(); BoneContent.Name = b.mName.Data; BoneContent.Transform = tomatrix(b.mOffsetMatrix); foreach (var item in root.mChildren) { BoneContent bon = createSkel(item); if (bon != null) { BoneContent.Children.Add(bon); } } return(BoneContent); } } return(null); }
private static void FlattenTransforms(NodeContent node, BoneContent skeleton) { bool flag; IEnumerator <NodeContent> enumerator = node.Children.GetEnumerator(); try { while (true) { flag = enumerator.MoveNext(); if (!flag) { break; } NodeContent current = enumerator.Current; flag = current != skeleton; if (flag) { MeshHelper.TransformScene(current, current.Transform); current.Transform = Matrix.Identity; SkinnedModelProcessor.FlattenTransforms(current, skeleton); } } } finally { flag = enumerator == null; if (!flag) { enumerator.Dispose(); } } }
MeshData ProcessMesh(MeshContent mesh, ContentProcessorContext context, string rootPath, Dictionary <string, object> processedContent, SkeletonData skeletonData, AnimationData[] animations, ref int geometryCount) { MeshHelper.TransformScene(mesh, mesh.AbsoluteTransform); string[] normalMapNames = new string[] { "Bump0", "Bump", "NormalMap", "Normalmap", "Normals", "BumpMap" }; MeshHelper.OptimizeForCache(mesh); List <GeometryData> geometry = new List <GeometryData>(); BoneContent skeleton = MeshHelper.FindSkeleton(mesh); Dictionary <string, int> boneIndices = null; if (skeleton != null) { boneIndices = FlattenSkeleton(skeleton); } foreach (GeometryContent geom in mesh.Geometry) { this.ProcessVertexChannels(geom, context, rootPath, boneIndices, null); MeshHelper.MergeDuplicateVertices(geom); VertexBufferContent vb; VertexElement[] ve; geom.Vertices.CreateVertexBuffer(out vb, out ve, context.TargetPlatform); int[] indices = new int[geom.Indices.Count]; geom.Indices.CopyTo(indices, 0); geometry.Add(new GeometryData(geometryCount++, geom.Name, ve, vb.VertexData, indices, new MaterialData(), skeletonData, animations, context.TargetPlatform == TargetPlatform.Xbox360)); } return(new MeshData(mesh.Name, geometry.ToArray(), animations)); }
/// <summary> /// The main Process method converts an intermediate format content pipeline /// NodeContent tree to a ModelContent object with embedded animation data. /// </summary> public override ModelContent Process(NodeContent input, ContentProcessorContext context) { ValidateMesh(input, context, null); // Find the skeleton. BoneContent skeleton = MeshHelper.FindSkeleton(input); if (skeleton == null) { throw new InvalidContentException("Input skeleton not found."); } _isSkinned = true; // We don't want to have to worry about different parts of the model being // in different local coordinate systems, so let's just bake everything. FlattenTransforms(input, skeleton); // Read the bind pose and skeleton hierarchy data. IList <BoneContent> bones = MeshHelper.FlattenSkeleton(skeleton); if (bones.Count > SkinnedEffect.MaxBones) { throw new InvalidContentException(string.Format( "Skeleton has {0} bones, but the maximum supported is {1}.", bones.Count, SkinnedEffect.MaxBones)); } List <Matrix> bindPose = new List <Matrix>(); List <Matrix> inverseBindPose = new List <Matrix>(); List <int> skeletonHierarchy = new List <int>(); foreach (BoneContent bone in bones) { Matrix m = bone.Transform; //scale all translations m.Translation = m.Translation * Scale; bone.Transform = m; bindPose.Add(bone.Transform); inverseBindPose.Add(Matrix.Invert(bone.AbsoluteTransform)); skeletonHierarchy.Add(bones.IndexOf(bone.Parent as BoneContent)); } // Convert animation data to our runtime format. Dictionary <string, AnimationClip> animationClips; animationClips = ProcessAnimations(skeleton.Animations, bones); // Chain to the base ModelProcessor class so it can convert the model data. ModelContent model = base.Process(input, context); // Store our custom animation data in the Tag property of the model. MeshMetadata metadata = model.Tag as MeshMetadata; metadata.SkinningData = new SkinningData(animationClips, bindPose, inverseBindPose, skeletonHierarchy); return(model); }
public override ModelContent Process(NodeContent input, ContentProcessorContext context) { // Znajduje szkielet w modelu. BoneContent skeleton = MeshHelper.FindSkeleton(input); // Wczytuje domyœlne ustawienia koœci i hierarchiê. IList <BoneContent> bones = MeshHelper.FlattenSkeleton(skeleton); // Deklaracja list List <Matrix> bindPose = new List <Matrix>(); List <Matrix> inverseBindPose = new List <Matrix>(); List <int> skeletonHierarchy = new List <int>(); // Za³adowanie powy¿szych list foreach (BoneContent bone in bones) { bindPose.Add(bone.Transform); inverseBindPose.Add(Matrix.Invert(bone.AbsoluteTransform)); skeletonHierarchy.Add(bones.IndexOf(bone.Parent as BoneContent)); } // Konwersja animacji do formatu dictionary Dictionary <string, AnimationClip> animationClips; animationClips = ProcessAnimations(skeleton.Animations, bones); ModelContent modelContent = base.Process(input, context); modelContent.Tag = new SkinningData(animationClips, bindPose, inverseBindPose, skeletonHierarchy); return(modelContent); }
private static Dictionary <string, int> FlattenSkeleton(BoneContent skeleton) { //avatars require their bones to be sorted in a slighty strange order. //the order is not setup in the file //they must be sorted first by depth (so root first, then it's children, then all their children) //and within those groups, sorted by name. //this is done in a method ripped from the XNA samples... (XnaFlattenSkeleton) Dictionary <string, int> dictionary = new Dictionary <string, int>(); IList <BoneContent> list = XnaFlattenSkeleton(skeleton); int index = 0; for (int i = 0; i < list.Count; i++) { BoneContent content = list[i]; if (!string.IsNullOrEmpty(content.Name)) { if (dictionary.ContainsKey(content.Name)) { throw new InvalidContentException("Duplicate bone found: " + content.Name); } dictionary.Add(content.Name, index++); } } return(dictionary); }
public override ModelContent Process(NodeContent input, ContentProcessorContext context) { // Find the skeleton. BoneContent skeleton = MeshHelper.FindSkeleton(input); // Read the bind pose and skeleton hierarchy data. IList <BoneContent> bones = MeshHelper.FlattenSkeleton(skeleton); List <Matrix> bindPose = new List <Matrix>(); List <Matrix> inverseBindPose = new List <Matrix>(); List <int> skeletonHierarchy = new List <int>(); // Extract the bind pose transform, inverse bind pose transform, // and parent bone index of each bone in order foreach (BoneContent bone in bones) { bindPose.Add(bone.Transform); inverseBindPose.Add(Matrix.Invert(bone.AbsoluteTransform)); skeletonHierarchy.Add(bones.IndexOf(bone.Parent as BoneContent)); } // Convert animation data to our runtime format. Dictionary <string, AnimationClip> animationClips; animationClips = ProcessAnimations(skeleton.Animations, bones); // Chain to the base ModelProcessor class so it can convert the model data. ModelContent model = base.Process(input, context); // Store our custom animation data in the Tag property of the model. model.Tag = new SkinningData(animationClips, bindPose, inverseBindPose, skeletonHierarchy); return(model); }
private bool ValidateModel(NodeContent input, BoneContent rootBone, ContentProcessorContext context) { // Finds the root bone if (rootBone == null) { throw new InvalidContentException("Input model does not contain a skeleton."); } // Validate maximum supported bones IList <BoneContent> boneList = MeshHelper.FlattenSkeleton(rootBone); if (boneList.Count > MaxBones) { throw new InvalidContentException(string.Format( "Model's skeleton has {0} bones, but the maximum supported is {1}.", boneList.Count, MaxBones)); } // Find animations AnimationContentDictionary animationDictionary = rootBone.Animations; if (animationDictionary.Count == 0) { context.Logger.LogWarning(null, rootBone.Identity, "Input model does not contain any animation."); } return(true); }
/// <summary> /// Converts incoming graphics data into our custom model format. /// </summary> public override MyreModelContent Process(NodeContent input, ContentProcessorContext context) { this.context = context; directory = Path.GetDirectoryName(input.Identity.SourceFilename); // Find the skeleton. BoneContent skeleton = MeshHelper.FindSkeleton(input); // We don't want to have to worry about different parts of the model being // in different local coordinate systems, so let's just bake everything. FlattenTransforms(input, skeleton); outputModel = new MyreModelContent(); //if (skeleton != null) // outputModel.Skeleton = MeshHelper.FlattenSkeleton(skeleton).ToArray(); //else // outputModel.Skeleton = new BoneContent[0]; ProcessNode(input); return(outputModel); }
void BuildBoneHirachy(BoneContent bone, int boneIndex, List <BoneData> structure, Dictionary <string, int> indices, BoneData[] allBones, Matrix[] transforms) { if (bone.Name != null && indices.ContainsKey(bone.Name)) { List <BoneData> children = new List <BoneData>(); foreach (NodeContent child in bone.Children) { if (child is BoneContent) { BuildBoneHirachy((BoneContent)child, indices[bone.Name], children, indices, allBones, transforms); } } int[] childIndices = new int[children.Count]; for (int i = 0; i < children.Count; i++) { childIndices[i] = indices[children[i].Name]; } int index = indices[bone.Name]; BoneData data = new BoneData(bone.Name, index, boneIndex, childIndices); if (structure != null) { structure.Add(data); } allBones[index] = data; transforms[index] = bone.Transform; } }
// Import the skeleton for Skeleton-Animation private BoneContent ImportSkeleton(NodeContent input) { BoneContent skeleton = MeshHelper.FindSkeleton(input); if (skeleton == null) { return(null); } FlattenTransforms(input, skeleton); List <NodeContent> nodes = FlattenHeirarchy(input); IList <BoneContent> bones = MeshHelper.FlattenSkeleton(skeleton); // Create a dictionary to convert a node to an index into the array of nodes Dictionary <NodeContent, int> nodeToIndex = new Dictionary <NodeContent, int>(); for (int i = 0; i < nodes.Count; i++) { nodeToIndex[nodes[i]] = i; } foreach (BoneContent bone in bones) { animationData.Skeleton.Add(nodeToIndex[bone]); } return(skeleton); }
static void ProcessWeightsChannel(GeometryContent geometry, int vertexChannelIndex) { // create a map of Name->Index of the bones BoneContent skeleton = MeshHelper.FindSkeleton(geometry.Parent); Dictionary <string, int> boneIndices = new Dictionary <string, int>(); IList <BoneContent> flattenedBones = MeshHelper.FlattenSkeleton(skeleton); for (int i = 0; i < flattenedBones.Count; i++) { boneIndices.Add(flattenedBones[i].Name, i); } // convert all of our bone weights into the correct indices and weight values VertexChannel <BoneWeightCollection> inputWeights = geometry.Vertices.Channels[vertexChannelIndex] as VertexChannel <BoneWeightCollection>; Vector4[] outputIndices = new Vector4[inputWeights.Count]; Vector4[] outputWeights = new Vector4[inputWeights.Count]; for (int i = 0; i < inputWeights.Count; i++) { ConvertWeights(inputWeights[i], boneIndices, outputIndices, outputWeights, i, geometry); } // create our new channel names int usageIndex = VertexChannelNames.DecodeUsageIndex(inputWeights.Name); string indicesName = VertexChannelNames.EncodeName(VertexElementUsage.BlendIndices, usageIndex); string weightsName = VertexChannelNames.EncodeName(VertexElementUsage.BlendWeight, usageIndex); // add in the index and weight channels geometry.Vertices.Channels.Insert(vertexChannelIndex + 1, indicesName, outputIndices); geometry.Vertices.Channels.Insert(vertexChannelIndex + 2, weightsName, outputWeights); // remove the original weights channel geometry.Vertices.Channels.RemoveAt(vertexChannelIndex); }
private BoneContent BuildSkeleton(Node node, BoneContent parent) { BoneContent bone = new BoneContent(node.Name, (uint)_bones.Count, ConvertMatrix(node.Transform), parent); _bones.Add(bone); _namesToBones[bone.Name] = bone; bone.InverseAbsoluteTransform = OpenTK.Matrix4.Invert(bone.Transform); BoneContent p = bone.Parent; while (p != null) { bone.InverseAbsoluteTransform *= p.Transform; p = p.Parent; } if (node.HasChildren) { foreach (Node n in node.Children) { BoneContent child = BuildSkeleton(n, bone); bone.Children.Add(child); } } return(bone); }
public override ModelContent Process(NodeContent input, ContentProcessorContext context) { CompileRegularExpressions(); context.Logger.LogMessage("Output Platform: {0}", context.TargetPlatform); maxScale_ = 0; maxOffset_ = 0; BoneContent skeleton = MeshHelper.FindSkeleton(input); FlattenTransforms(input, skeleton, context); SkinnedBone[] inverseBindPose = GetInverseBindPose(input, context, skeleton); context.Logger.LogMessage("Found {0} skinned bones in skeleton.", (inverseBindPose == null) ? 0 : inverseBindPose.Length); ModelContent output = base.Process(input, context); if (output.Tag == null) { output.Tag = new Dictionary <string, object>(); } if (FoundSkinning) { #if DEBUG StringBuilder strb = new StringBuilder(); #endif if (inverseBindPose == null) { throw new System.Exception("Could not find skeleton although there is skinned data."); } for (int i = 0; i != inverseBindPose.Length; ++i) { SkinnedBone sb = inverseBindPose[i]; int q = 0; sb.Index = -1; foreach (ModelBoneContent mbc in output.Bones) { if (mbc.Name == sb.Name) { sb.Index = mbc.Index; break; } ++q; } if (sb.Index == -1) { throw new System.ArgumentException( String.Format("Can't find the index for animated bone named {0}.", sb.Name)); } inverseBindPose[i] = sb; } ((Dictionary <string, object>)output.Tag).Add("InverseBindPose", inverseBindPose); } ((Dictionary <string, object>)output.Tag).Add("AnimationSet", BuildAnimationSet(input, ref output, context)); ((Dictionary <string, object>)output.Tag).Add("BoundsInfo", new BoundsInfo(maxScale_, maxOffset_)); return(output); }
/// <summary> /// The main Process method converts an intermediate format content pipeline /// NodeContent tree to a ModelContent object with embedded animation data. /// </summary> public override ModelContent Process(NodeContent input, ContentProcessorContext context) { if (string.IsNullOrEmpty(this.EffectFileName)) { this.EffectFileName = "Effects\\Animation.fx"; } ValidateMesh(input, context, null); // Find the skeleton. BoneContent skeleton = MeshHelper.FindSkeleton(input); if (skeleton == null) { throw new InvalidContentException("Input skeleton not found."); } // We don't want to have to worry about different parts of the model being // in different local coordinate systems, so let's just bake everything. FlattenTransforms(input, skeleton); // Read the bind pose and skeleton hierarchy data. IList <BoneContent> bones = MeshHelper.FlattenSkeleton(skeleton); if (bones.Count > this.maxBones) { throw new InvalidContentException(string.Format("Skeleton has {0} bones, but the maximum supported is {1}.", bones.Count, this.maxBones)); } Dictionary <string, int> boneMap = new Dictionary <string, int>(); List <Matrix> bindPose = new List <Matrix>(); List <Matrix> inverseBindPose = new List <Matrix>(); List <int> skeletonHierarchy = new List <int>(); int i = 0; foreach (BoneContent bone in bones) { boneMap.Add(bone.Name, i); bindPose.Add(bone.Transform); inverseBindPose.Add(Matrix.Invert(bone.AbsoluteTransform)); skeletonHierarchy.Add(bones.IndexOf(bone.Parent as BoneContent)); i++; } // Convert animation data to our runtime format. Dictionary <string, Clip> animationClips; animationClips = ProcessAnimations(skeleton.Animations, bones); // Chain to the base ModelProcessor class so it can convert the model data. ModelContent model = base.Process(input, context); // Store our custom animation data in the Tag property of the model. model.Tag = new SkinningData(boneMap, animationClips, bindPose, inverseBindPose, skeletonHierarchy); return(model); }
/// <summary> /// The main Process method converts an intermediate format content pipeline /// NodeContent tree to a ModelContent object with embedded animation data. /// </summary> public override ModelContent Process(NodeContent input, ContentProcessorContext context) { ValidateMesh(input, context, null); // Find the skeleton. BoneContent skeleton = MeshHelper.FindSkeleton(input); if (skeleton == null) { throw new InvalidContentException("Input skeleton not found."); } // We don't want to have to worry about different parts of the model being in different local coordinate systems, so let's just bake everything. FlattenTransforms(input, skeleton); // Read the bind pose and skeleton hierarchy data. IList <BoneContent> bones = MeshHelper.FlattenSkeleton(skeleton); if (bones.Count > ModelAnimationClip.MaxBones) { throw new InvalidContentException(string.Format("Skeleton has {0} bones, but the maximum supported is {1}.", bones.Count, ModelAnimationClip.MaxBones)); } List <Matrix> bindPose = new List <Matrix>(); List <Matrix> inverseBindPose = new List <Matrix>(); List <int> skeletonHierarchy = new List <int>(); Dictionary <string, int> boneIndices = new Dictionary <string, int>(); foreach (BoneContent bone in bones) { bindPose.Add(bone.Transform); inverseBindPose.Add(Matrix.Invert(bone.AbsoluteTransform)); skeletonHierarchy.Add(bones.IndexOf(bone.Parent as BoneContent)); boneIndices.Add(bone.Name, boneIndices.Count); } // Convert animation data to our runtime format. Dictionary <string, ModelAnimationClip> modelAnimationClips = ProcessAnimations(skeleton.Animations, bones, context); Dictionary <string, RootAnimationClip> rootAnimationClips = new Dictionary <string, RootAnimationClip>(); // Chain to the base ModelProcessor class so it can convert the model data. ModelContent model = base.Process(input, context); // Convert each animation in the root of the object foreach (KeyValuePair <string, AnimationContent> animation in input.Animations) { RootAnimationClip processed = RigidModelProcessor.ProcessRootAnimation(animation.Value, model.Bones[0].Name); rootAnimationClips.Add(animation.Key, processed); } // Store our custom animation data in the Tag property of the model. model.Tag = new ModelAnimationData(modelAnimationClips, rootAnimationClips, bindPose, inverseBindPose, skeletonHierarchy, boneIndices); return(model); } // Process
/// <summary> /// Extract and processes all the bones (BoneContent) of the model generating a /// SkinnedModelBoneCollection. /// </summary> private SkinnedModelBoneContentCollection ProcessBones(BoneContent rootBone, ContentProcessorContext context) { List <SkinnedModelBoneContent> skinnedBoneList = new List <SkinnedModelBoneContent>(MaxBones); ProcessBones(rootBone, null, skinnedBoneList, context); return(new SkinnedModelBoneContentCollection(skinnedBoneList)); }
public override Dictionary <string, BoneAnimationClip> Process(NodeContent input, ContentProcessorContext context) { ModelSkeletonProcessor skeletonProcessor = new ModelSkeletonProcessor(); skeletonProcessor.RotationX = RotationX; skeletonProcessor.RotationY = RotationY; skeletonProcessor.RotationZ = RotationZ; skeletonProcessor.Scale = Scale; Skeleton = skeletonProcessor.Process(input, context); this.context = context; if (FramesPerSecond <= 0) { throw new ArgumentOutOfRangeException("FramesPerSecond"); } BoneContent skeleton = MeshHelper.FindSkeleton(input); // Flattern input node content List <NodeContent> nodes = new List <NodeContent>(); FlattenNodeContent(input, nodes); // Process animations Dictionary <string, AnimationClip> animations = new Dictionary <string, AnimationClip>(); ProcessAnimation(input, animations, nodes); if (animations.Count <= 0) { return(null); } // Sort keyframes foreach (AnimationClip clip in animations.Values) { clip.Keyframes.Sort(CompareKeyframeTimes); } // Convert to BoneAnimationClip format Dictionary <string, BoneAnimationClip> boneAnimations = new Dictionary <string, BoneAnimationClip>(); foreach (string key in animations.Keys) { boneAnimations.Add(key, ConvertAnimationClip(animations[key])); } ClampAnimationsAndApplyTransform(boneAnimations); return(boneAnimations); }
public override ModelContent Process(NodeContent input, ContentProcessorContext context) { SkinnedModelProcessor.ValidateMesh(input, context, null); BoneContent boneContent = MeshHelper.FindSkeleton(input); bool count = boneContent != null; if (count) { SkinnedModelProcessor.FlattenTransforms(input, boneContent); IList <BoneContent> boneContents = MeshHelper.FlattenSkeleton(boneContent); count = boneContents.Count <= 59; if (count) { List <Matrix> matrices = new List <Matrix>(); List <Matrix> matrices1 = new List <Matrix>(); List <int> nums = new List <int>(); IEnumerator <BoneContent> enumerator = boneContents.GetEnumerator(); try { while (true) { count = enumerator.MoveNext(); if (!count) { break; } BoneContent current = enumerator.Current; matrices.Add(current.Transform); matrices1.Add(Matrix.Invert(current.AbsoluteTransform)); nums.Add(boneContents.IndexOf(current.Parent as BoneContent)); } } finally { count = enumerator == null; if (!count) { enumerator.Dispose(); } } Dictionary <string, AnimationClip> strs = SkinnedModelProcessor.ProcessAnimations(boneContent.Animations, boneContents); ModelContent modelContent = base.Process(input, context); modelContent.Tag = new SkinningData(strs, matrices, matrices1, nums); ModelContent modelContent1 = modelContent; return(modelContent1); } else { throw new InvalidContentException(string.Format("Skeleton has {0} bones, but the maximum supported is {1}.", boneContents.Count, 59)); } } else { throw new InvalidContentException("Input skeleton not found."); } }
// A frame can store any data, but is constrained such that each frame must haveB // a transform matrix for .X meshes. // template Frame // { // [...] // } /// <summary> /// Imports a data Node in a directx file, usually a Frame node. /// </summary> /// <returns>The imported node</returns> private NodeContent ImportNode() { NodeContent c; if (meshes.Count == 0) { c = new NodeContent(); } else { c = new BoneContent(); } c.Name = tokens.ReadName(); if (c.Name == null) { c.Name = "Node" + c.GetHashCode(); } // process all of this frame's children for (string next = tokens.NextToken(); next != "}"; next = tokens.NextToken()) { if (next == "Frame") { c.Children.Add(ImportNode()); } else if (next == "FrameTransformMatrix") { c.Transform = ImportFrameTransformMatrix(); } else if (next == "Mesh") { XMeshImporter meshImporter = new XMeshImporter(this); c.Children.Add(meshImporter.ImportMesh()); } // Ignore templates, which define new structure that store data // for now, we only will work with the standard directx templates else if (next == "template") { tokens.SkipName().SkipNode(); } // Skin weight nodes can exist either inside meshes or inside frames. // When they exist in a frame, they will refer to a universal mesh else if (next == "SkinWeights") { meshes[0].ImportSkinWeights(); } // an data node that we are uninterested in else if (next == "{") { tokens.SkipNode(); } } return(c); }
static void CreateChildBones(BoneContent xnaParentBone, SerializableBone parentBone, SerializableSkeleton skeleton) { foreach (BoneContent xnaChildBone in xnaParentBone.Children) { SerializableBone childBone = new SerializableBone(); childBone.name = xnaChildBone.Name; childBone.matrixLocalTransform = xnaChildBone.Transform; parentBone.children.Add(childBone); skeleton.AddBone(childBone); CreateChildBones(xnaChildBone, childBone, skeleton); } }
private NodeContent WalkHierarchy(Node aiNode, NodeContent xnaParent, Matrix4x4 parentXform) { var transform = Matrix4x4.Identity; Node walk = aiNode; while (walk != null && walk.Name != xnaParent.Name) { transform *= walk.Transform; walk = walk.Parent; } NodeContent node = null; if (!aiNode.Name.Contains("_$AssimpFbx$")) // Ignore pivot nodes { const string mangling = "_$AssimpFbxNull$"; // Null leaf nodes are helpers if (_skeletonNodes.Contains(aiNode.Name)) { node = new BoneContent { Name = aiNode.Name } } ; else if (aiNode.Name.Contains(mangling)) { node = new NodeContent { Name = aiNode.Name.Replace(mangling, string.Empty) } } ; // Only emit XNA nodes for concrete nodes if (node != null) { node.Transform = ToXna(transform); xnaParent.Children.Add(node); // For the children, this is the new parent. xnaParent = node; } } // Children foreach (var child in aiNode.Children) { WalkHierarchy(child, xnaParent, transform); } return(node); }
// Function to process a model from normal content to a model with animation data public override ModelContent Process(NodeContent input, ContentProcessorContext context) { SetSkinnedEffect(input); BoneContent skeleton = ImportSkeleton(input); model = base.Process(input, context); AnimationDataImport(model, input, context); model.Tag = animationData; return(model); }
public override AnimationsContent Process(NodeContent input, ContentProcessorContext context) { if (_fixRealBoneRoot) { MGFixRealBoneRoot(input, context); } ValidateMesh(input, context, null); // Find the skeleton. BoneContent skeleton = MeshHelper.FindSkeleton(input); if (skeleton == null) { throw new InvalidContentException("Input skeleton not found."); } // We don't want to have to worry about different parts of the model being // in different local coordinate systems, so let's just bake everything. FlattenTransforms(input, skeleton); // Read the bind pose and skeleton hierarchy data. IList <BoneContent> bones = MeshHelper.FlattenSkeleton(skeleton); if (bones.Count > MaxBones) { throw new InvalidContentException(string.Format("Skeleton has {0} bones, but the maximum supported is {1}.", bones.Count, MaxBones)); } List <Matrix> bindPose = new List <Matrix>(); List <Matrix> invBindPose = new List <Matrix>(); List <int> skeletonHierarchy = new List <int>(); List <string> boneNames = new List <string>(); foreach (var bone in bones) { bindPose.Add(bone.Transform); invBindPose.Add(Matrix.Invert(bone.AbsoluteTransform)); skeletonHierarchy.Add(bones.IndexOf(bone.Parent as BoneContent)); boneNames.Add(bone.Name); } // Convert animation data to our runtime format. Dictionary <string, ClipContent> clips; clips = ProcessAnimations(input, context, skeleton.Animations, bones, GenerateKeyframesFrequency); return(new AnimationsContent(bindPose, invBindPose, skeletonHierarchy, boneNames, clips)); }
private bool ValidateBone(NodeContent nodeContent, ContentProcessorContext context) { BoneContent boneContent = nodeContent as BoneContent; if (boneContent == null) { context.Logger.LogWarning(null, nodeContent.Identity, string.Format( "Node {0} is invalid inside the model's skeleton and will be skipped.", nodeContent.Name)); return(false); } return(true); }
/// <summary> /// The function to process a model from original content into model content for export /// </summary> /// <param name="input"></param> /// <param name="context"></param> /// <returns></returns> public override ModelContent Process(NodeContent input, ContentProcessorContext context) { // Process the skeleton for skinned character animation BoneContent skeleton = ProcessSkeleton(input); SwapSkinnedMaterial(input); model = base.Process(input, context); ProcessAnimations(model, input, context); // Add the extra content to the model model.Tag = modelExtra; return(model); }
/// <summary> /// The main Process method converts an intermediate format content pipeline /// NodeContent tree to a ModelContent object with embedded animation data. /// </summary> public SkinningData Process(NodeContent input, ContentProcessorContext context) { SkinnedModelHelper.ValidateMesh(input, context, null); // Find the skeleton. BoneContent skeleton = MeshHelper.FindSkeleton(input); if (skeleton == null) { return(null); } // We don't want to have to worry about different parts of the model being // in different local coordinate systems, so let's just bake everything. SkinnedModelHelper.FlattenTransforms(input, skeleton); // Read the bind pose and skeleton hierarchy data. IList <BoneContent> bones = MeshHelper.FlattenSkeleton(skeleton); if (bones.Count > MaxBones) { throw new InvalidContentException(string.Format( "Skeleton has {0} bones, but the maximum supported is {1}.", bones.Count, MaxBones)); } List <Matrix> bindPose = new List <Matrix>(); List <Matrix> inverseBindPose = new List <Matrix>(); List <int> skeletonHierarchy = new List <int>(); foreach (BoneContent bone in bones) { bindPose.Add(bone.Transform); inverseBindPose.Add(Matrix.Invert(bone.AbsoluteTransform)); skeletonHierarchy.Add(bones.IndexOf(bone.Parent as BoneContent)); } // Convert animation data to our runtime format. Dictionary <string, AnimationClip> animationClips; animationClips = SkinnedModelHelper.ProcessAnimations(skeleton.Animations, bones); // Store our custom animation data in the Tag property of the model. return(new SkinningData(animationClips, bindPose, inverseBindPose, skeletonHierarchy)); }
public override SerializableModel Process(NodeContent xnaInputNode, ContentProcessorContext context) { //System.Diagnostics.Debugger.Launch(); this.context = context; outputModel = new SerializableModel(); outputModel.name = RemoveFileExtension(GetFileName(context)); ValidateMesh(xnaInputNode, context, null); // Find the root. BoneContent xnaRootBone = MeshHelper.FindSkeleton(xnaInputNode); if (xnaRootBone == null) { throw new InvalidContentException("Input skeleton not found."); } // We don't want to have to worry about different parts of the model being // in different local coordinate systems, so let's just bake everything. FlattenTransforms(xnaInputNode, xnaRootBone); // Read the bind pose and skeleton hierarchy data. IList <BoneContent> xnaBoneList = MeshHelper.FlattenSkeleton(xnaRootBone); if (xnaBoneList.Count > MAX_BONES) { throw new InvalidContentException(string.Format("Skeleton has {0} bones, but the maximum supported is {1}.", xnaBoneList.Count, MAX_BONES)); } SerializableSkeleton skeleton = new SerializableSkeleton(); SerializableBone root = new SerializableBone(); root.name = xnaRootBone.Name; root.matrixLocalTransform = xnaRootBone.Transform; skeleton.rootBone = root; skeleton.AddBone(root); outputModel.skeleton = skeleton; CreateChildBones(xnaRootBone, root, skeleton); ProcessNode(xnaInputNode); ProcessAnimations(xnaRootBone.Animations, outputModel); return(outputModel); }
/// <summary> /// Recursively process each BoneContent of the model generating a new SkinnedModelBone /// </summary> private SkinnedModelBoneContent ProcessBones(BoneContent boneContent, SkinnedModelBoneContent skinnedModelParentBone, List <SkinnedModelBoneContent> skinnedBoneList, ContentProcessorContext context) { // Add the current boneContent to the skinned boneContent list ushort boneIndex = (ushort)skinnedBoneList.Count; // Decompose boneContent bind pose from the transform matrix Pose bindPose; boneContent.Transform.Decompose(out bindPose.Scale, out bindPose.Orientation, out bindPose.Translation); // Calculates boneContent inverse bind pose Matrix inverseBindPose = Matrix.Invert(boneContent.AbsoluteTransform); // Create the skinned model's boneContent and add it to the skinned model's boneContent list SkinnedModelBoneContent skinnedModelBone = new SkinnedModelBoneContent(boneIndex, boneContent.Name, bindPose, inverseBindPose); skinnedBoneList.Add(skinnedModelBone); // Process all children List <SkinnedModelBoneContent> skinnedBoneChildrenList = new List <SkinnedModelBoneContent>(); foreach (NodeContent nodeContent in boneContent.Children) { // Validate the bone if (!ValidateBone(nodeContent, context)) { continue; } BoneContent childBoneContent = nodeContent as BoneContent; SkinnedModelBoneContent skinnedBoneChild = ProcessBones(childBoneContent, skinnedModelBone, skinnedBoneList, context); skinnedBoneChildrenList.Add(skinnedBoneChild); } // Sets boneContent parent and children skinnedModelBone.Parent = skinnedModelParentBone; skinnedModelBone.Children = new SkinnedModelBoneContentCollection(skinnedBoneChildrenList); return(skinnedModelBone); }
BoneContent CreateSkeleton(Joint joint) { var bone = new BoneContent(); bone.Name = GetJointKey(joint); bone.Transform = joint.Transform; if (joint.Children != null && joint.Children.Count > 0) { foreach (var childJoint in joint.Children) { bone.Children.Add(CreateSkeleton(childJoint)); } } return(bone); }