/// <summary> /// Traverses a skeleton depth-first and builds a list of its bones. /// </summary> public static IList <BoneContent> FlattenSkeleton(BoneContent skeleton) { if (skeleton == null) { throw new ArgumentNullException("skeleton"); } var results = new List <BoneContent>(); var work = new Stack <NodeContent>(new[] { skeleton }); while (work.Count > 0) { var top = work.Pop(); var bone = top as BoneContent; if (bone != null) { results.Add(bone); } for (var i = top.Children.Count - 1; i >= 0; i--) { work.Push(top.Children[i]); } } return(results); }
static void FlattenTransforms(NodeContent node, BoneContent skeleton) { foreach (NodeContent child in node.Children) { if (child == skeleton) continue; //Bake Local Transform into actual geometry. MeshHelper.TransformScene(child, child.Transform); //now we can set the local coordinate system back to identity. child.Transform = Matrix.Identity; //Recures FlattenTransforms(child, skeleton); } }
/// <summary> /// Bakes unwanted transforms into the model geometry, /// so everything ends up in the same coordinate system. /// </summary> static void FlattenTransforms(NodeContent node, BoneContent skeleton) { foreach (NodeContent child in node.Children) { // Don't process the skeleton, because that is special. if (child == skeleton) continue; // Bake the local transform into the actual geometry. MeshHelper.TransformScene(child, child.Transform); // Having baked it, we can now set the local // coordinate system back to identity. child.Transform = Matrix.Identity; // Recurse. FlattenTransforms(child, skeleton); } }
/// <summary> /// Bakes unwanted transforms into the model geometry, /// so everything ends up in the same coordinate system. /// </summary> public static void FlattenTransforms(NodeContent node, BoneContent skeleton) { foreach (NodeContent child in node.Children) { // Don't process the skeleton, because that is special. if (child == skeleton) continue; //------------------------------------------------ // TODO: Support static meshes parented to a bone // ----------------------------------------------- // What's this all about? // If Myre supported meshes which were not skinned, but still had a bone parent this would be important // But it doesn't, so we skip this. //// This is important: Don't bake in the transforms except //// for geometry that is part of a skinned mesh //if (!IsSkinned(child)) // continue; FlattenAllTransforms(child); } }
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(); } } }
public static IList<BoneContent> FlattenSkeleton(BoneContent skeleton) { throw new NotImplementedException(); }
/// <summary> /// Bakes unwanted transforms into the model geometry, /// so everything ends up in the same coordinate system. /// </summary> void FlattenTransforms(NodeContent node, BoneContent skeleton) { foreach (NodeContent child in node.Children) { // Don't process the skeleton, because that is special. if (child == skeleton) continue; // This is important: Don't bake in the transforms except // for geometry that is part of a skinned mesh if(IsSkinned(child)) { FlattenAllTransforms(child); } } }
/// <summary> /// 全てが同じ座標空間になるように、不必要な変換行列を /// モデル・ジオメトリに焼き付ける /// </summary> static void FlattenTransforms(NodeContent node, BoneContent skeleton) { foreach (NodeContent child in node.Children) { // スケルトンは処理しない if (child == skeleton) continue; // ローカル変換行列をジオメトリに焼きつける MeshHelper.TransformScene(child, child.Transform); // 焼き付けたので、ローカル座標変換行列は // 単位行列(Matrix.Identity)になる child.Transform = Matrix.Identity; // 再帰呼び出し FlattenTransforms(child, skeleton); } }
public static IList <BoneContent> FlattenSkeleton(BoneContent skeleton) { throw new NotImplementedException(); }
static void MergeAnimation(BoneContent rootBone, NodeContent input, ContentProcessorContext context, string mergeFile) { if (rootBone == null) { context.Logger.LogWarning(null, input.Identity, "Source model has no root bone."); return; } NodeContent mergeModel = context.BuildAndLoadAsset<NodeContent, NodeContent>(new ExternalReference<NodeContent>(mergeFile), null); BoneContent mergeRoot = MeshHelper.FindSkeleton(mergeModel); if (mergeRoot == null) { context.Logger.LogWarning(null, input.Identity, "Merge model '{0}' has no root bone.", mergeFile); return; } foreach (string animationName in mergeRoot.Animations.Keys) { if (rootBone.Animations.ContainsKey(animationName)) { context.Logger.LogWarning(null, input.Identity, "Cannot merge animation '{0}' from '{1}', because this animation already exists.", animationName, mergeFile); continue; } context.Logger.LogImportantMessage("Merging animation '{0}' from '{1}'.", animationName, mergeFile); rootBone.Animations.Add(animationName, mergeRoot.Animations[animationName]); } }
/// <summary> /// Bakes unwanted transforms into the model geometry, /// so everything ends up in the same coordinate system. /// </summary> void FlattenTransforms(NodeContent node, BoneContent skeleton) { foreach (NodeContent child in node.Children) { // Don't process the skeleton, because that is special. if (child == skeleton) continue; if(IsSkinned(child)) { FlattenAllTransforms(child); } } }
/// <summary> /// Creates a Skeleton from the specified bone content. /// </summary> private Skeleton ProcessSkeleton(BoneContent rootNode, ContentProcessorContext context) { // Get all bones as a list (FlattenSkeleton makes sure that the indices are the same as // the indices that will be used in the blend index channel). IList<BoneContent> bones = MeshHelper.FlattenSkeleton(rootNode); if (bones.Count > SkinnedEffect.MaxBones) { var message = string.Format("Skeleton has {0} bones, but the maximum supported is {1}.", bones.Count, SkinnedEffect.MaxBones); throw new InvalidContentException(message, rootNode.Identity); } // Create list of parent indices, bind pose transformations and bone names. List<int> boneParents = new List<int>(); List<SrtTransform> bindTransforms = new List<SrtTransform>(); List<string> boneNames = new List<string>(); foreach (BoneContent bone in bones) { int parentIndex = bones.IndexOf(bone.Parent as BoneContent); boneParents.Add(parentIndex); if (!SrtTransform.IsValid((Matrix44F)bone.Transform)) context.Logger.LogWarning(null, null, "Bone transform is not supported. Bone transform matrices may only contain scaling, rotation and translation."); bindTransforms.Add(SrtTransform.FromMatrix(bone.Transform)); boneNames.Add(bone.Name); } // Create and return a new skeleton instance. return new Skeleton(boneParents, boneNames, bindTransforms); }
private static void BakeTransforms(NodeContent node, BoneContent skeleton) { foreach (NodeContent child in node.Children) { // Don't process the skeleton, because that is special. if (child == skeleton) continue; MeshHelper.TransformScene(child, child.Transform); child.Transform = Matrix.Identity; BakeTransforms(child, skeleton); } }
/// <summary> /// Traverses a skeleton depth-first and builds a list of its bones. /// </summary> public static IList<BoneContent> FlattenSkeleton(BoneContent skeleton) { if (skeleton == null) throw new ArgumentNullException("skeleton"); var results = new List<BoneContent>(); var work = new Stack<NodeContent>(new[] { skeleton }); while (work.Count > 0) { var top = work.Pop(); var bone = top as BoneContent; if (bone != null) results.Add(bone); for (var i = top.Children.Count - 1; i >= 0; i--) work.Push(top.Children[i]); } return results; }
protected virtual SkinnedBone[] GetInverseBindPose(NodeContent input, ContentProcessorContext context, BoneContent skeleton) { if (skeleton == null) return null; IList<BoneContent> original = MeshHelper.FlattenSkeleton(skeleton); if (original.Count > maxNumBones_) throw new System.ArgumentException(String.Format( "The animation processor found {0} bones in the skeleton; a maximum of {1} is allowed.", original.Count, maxNumBones_)); List<SkinnedBone> inversePose = new List<SkinnedBone>(); foreach (BoneContent bc in original) { SkinnedBone sb = new SkinnedBone(); sb.Name = bc.Name; if (sb.Name == null) throw new System.ArgumentNullException("Bone with null name found."); sb.InverseBindTransform = Matrix.Invert(GetAbsoluteTransform(bc, null)); inversePose.Add(sb); } return inversePose.ToArray(); }
public void DefaultEffectTest() { NodeContent input; { input = new NodeContent(); var mesh = new MeshContent() { Name = "Mesh1" }; mesh.Positions.Add(new Vector3(0, 0, 0)); mesh.Positions.Add(new Vector3(1, 0, 0)); mesh.Positions.Add(new Vector3(1, 1, 1)); var geom = new GeometryContent(); geom.Vertices.Add(0); geom.Vertices.Add(1); geom.Vertices.Add(2); geom.Indices.Add(0); geom.Indices.Add(1); geom.Indices.Add(2); geom.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(0), new[] { new Vector2(0,0), new Vector2(1,0), new Vector2(1,1), }); var wieghts = new BoneWeightCollection(); wieghts.Add(new BoneWeight("bone1", 0.5f)); geom.Vertices.Channels.Add(VertexChannelNames.Weights(0), new[] { wieghts, wieghts, wieghts }); mesh.Geometry.Add(geom); input.Children.Add(mesh); var bone1 = new BoneContent { Name = "bone1", Transform = Matrix.CreateTranslation(0,1,0) }; input.Children.Add(bone1); var anim = new AnimationContent() { Name = "anim1", Duration = TimeSpan.Zero }; input.Animations.Add(anim.Name, anim); } var processorContext = new TestProcessorContext(TargetPlatform.Windows, "dummy.xnb"); var processor = new ModelProcessor { DefaultEffect = MaterialProcessorDefaultEffect.SkinnedEffect, }; var output = processor.Process(input, processorContext); // TODO: Not sure why, but XNA always returns a BasicMaterialContent // even when we specify SkinnedEffect as the default. We need to fix // the test first before we can enable the assert here. //Assert.IsInstanceOf(typeof(SkinnedMaterialContent), output.Meshes[0].MeshParts[0].Material); }