public JNT1(Assimp.Scene scene) { BoneNameIndices = new Dictionary <string, int>(); FlatSkeleton = new List <Rigging.Bone>(); Assimp.Node root = null; for (int i = 0; i < scene.RootNode.ChildCount; i++) { if (scene.RootNode.Children[i].Name.ToLowerInvariant() == "skeleton_root") { root = scene.RootNode.Children[i].Children[0]; break; } } if (root == null) { throw new Exception("Skeleton root was not found. Please make sure the root is under a node called \"skeleton_root.\""); } SkeletonRoot = AssimpNodesToBonesRecursive(root, null, FlatSkeleton); foreach (Rigging.Bone bone in FlatSkeleton) { BoneNameIndices.Add(bone.Name, FlatSkeleton.IndexOf(bone)); } }
/// <summary> /// Recursively calculates the bounding box of the whole model. /// </summary> private void ComputeBoundingBox(Scene scene, Node node, ref Vector3 min, ref Vector3 max, ref Matrix transform) { var previousTransform = transform; transform = Matrix.Multiply(previousTransform, node.Transform.ToMatrix()); if (node.HasMeshes) { foreach (int index in node.MeshIndices) { Mesh mesh = scene.Meshes[index]; for (int i = 0; i < mesh.VertexCount; i++) { var tmp = mesh.Vertices[i].ToVector3(); Vector4 result; Vector3.Transform(ref tmp, ref transform, out result); min.X = System.Math.Min(min.X, result.X); min.Y = System.Math.Min(min.Y, result.Y); min.Z = System.Math.Min(min.Z, result.Z); max.X = System.Math.Max(max.X, result.X); max.Y = System.Math.Max(max.Y, result.Y); max.Z = System.Math.Max(max.Z, result.Z); } } } // Go down the hierarchy if children are present. for (int i = 0; i < node.ChildCount; i++) ComputeBoundingBox(scene, node.Children[i], ref min, ref max, ref transform); transform = previousTransform; }
public void SetNode(MainWindow mainWindow, Scene scene, Node node) { _node = node; _scene = scene; var matrix4X4 = _node.Transform; trafoMatrixViewControlLocal.SetMatrix(ref matrix4X4); var mat = Matrix4x4.Identity; var cur = node; while(cur != null) { var trafo = cur.Transform; trafo.Transpose(); mat = trafo * mat; cur = cur.Parent; } mat.Transpose(); trafoMatrixViewControlGlobal.SetMatrix(ref mat); Text = node.Name + " - Node Details"; // populate statistics labelMeshesDirect.Text = node.MeshCount.ToString(CultureInfo.InvariantCulture); labelChildrenDirect.Text = node.ChildCount.ToString(CultureInfo.InvariantCulture); var meshTotal = 0; var childTotal = 0; CountMeshAndChildrenTotal(node, ref meshTotal, ref childTotal); labelMeshesTotal.Text = node.MeshCount.ToString(CultureInfo.InvariantCulture); labelChildrenTotal.Text = node.ChildCount.ToString(CultureInfo.InvariantCulture); }
private Bone CreateBoneTree(ref Skeleton skele, Node node, Bone parent) { var internalNode = new Bone { Name = node.Name, Parent = parent, }; if (boneNames.ContainsKey (node.Name)) { boneNames [node.Name].OffsetMatrix.Transpose (); internalNode.Offset = FromMatrix (boneNames [node.Name].OffsetMatrix); }if (internalNode.Name == "") { internalNode.Name = "bone_" + _i++; } //skele[internalNode.Name] = internalNode; var trans = node.Transform; trans.Transpose(); //drectx stuff internalNode.LocalTransform =FromMatrix(trans); internalNode.OriginalLocalTransform = internalNode.LocalTransform; CalculateBoneToWorldTransform(internalNode); internalNode.Children = new List<Bone> (); for (var i = 0; i < node.ChildCount; i++) { var child = CreateBoneTree(ref skele,node.Children[i], internalNode); if (child != null) { internalNode.Children.Add(child); } } return internalNode; }
/// <summary> /// Determines the best target scene node for the mesh. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="aiMesh"></param> /// <param name="aiNode"></param> /// <param name="nodeSearchFunc"></param> /// <param name="fallback"></param> /// <returns></returns> public static T DetermineBestTargetNode <T>(Assimp.Mesh aiMesh, Assimp.Node aiNode, Func <string, T> nodeSearchFunc, T fallback) { if (aiMesh.BoneCount > 1) { // Select node to which the mesh is weighted most var boneWeightCoverage = CalculateBoneWeightCoverage(aiMesh); var maxCoverage = boneWeightCoverage.Max(x => x.Coverage); var bestTargetBone = boneWeightCoverage.First(x => x.Coverage == maxCoverage).Bone; return(nodeSearchFunc(bestTargetBone.Name)); } else if (aiMesh.BoneCount == 1) { // Use our only bone as the target node return(nodeSearchFunc(aiMesh.Bones[0].Name)); } else { // Try to find a parent of the mesh's ainode that exists within the existing hierarchy var aiNodeParent = aiNode.Parent; while (aiNodeParent != null) { var nodeParent = nodeSearchFunc(aiNodeParent.Name); if (nodeParent != null) { return(nodeParent); } aiNodeParent = aiNodeParent.Parent; } // Return fallback return(fallback); } }
private static int GetTargetIdForNode(Ai.Node rootNode, string nodeName) { int targetId = 0; bool GetTargetIdForNodeRecursive(Ai.Node node) { if (node.Name == nodeName) { return(true); } ++targetId; foreach (var child in node.Children) { if (GetTargetIdForNodeRecursive(child)) { return(true); } } return(false); } if (GetTargetIdForNodeRecursive(rootNode)) { return(targetId); } else { return(-1); } }
private void ProcessNode(GraphEntity3D root, Assimp.Node s, List <VMesh> ml) { GraphEntity3D r1 = new GraphEntity3D(); root.Sub.Add(r1); r1.Top = root; r1.Name = s.Name; //r1.LocalTurn = new OpenTK.Matrix4(s.Transform.A1, s.Transform.A2, s.Transform.A3, s.Transform.A4, s.Transform.B1, s.Transform.B2, s.Transform.B3, s.Transform.B4, s.Transform.C1, s.Transform.C2, s.Transform.C3, s.Transform.C4, s.Transform.D1, s.Transform.D2, s.Transform.D3, s.Transform.D4); r1.LocalTurn = new OpenTK.Matrix4(s.Transform.A1, s.Transform.B1, s.Transform.C1, s.Transform.D1, s.Transform.A2, s.Transform.B2, s.Transform.C2, s.Transform.D2, s.Transform.A3, s.Transform.B3, s.Transform.C3, s.Transform.D3, s.Transform.A4, s.Transform.B4, s.Transform.C4, s.Transform.D4); var lt = r1.LocalTurn; r1.LocalTurn = lt.ClearTranslation(); r1.LocalTurn = r1.LocalTurn.ClearScale(); r1.LocalPos = lt.ExtractTranslation(); r1.LocalScale = lt.ExtractScale(); // r1.LocalPos = new OpenTK.Vector3(r1.LocalPos.X + 100, 0, 0); for (int i = 0; i < s.MeshCount; i++) { r1.AddMesh(ml[s.MeshIndices[i]]); } if (s.HasChildren) { foreach (var pn in s.Children) { ProcessNode(r1, pn, ml); } } }
private Node AddChildBone(string fingerType, string boneType, Hand hand, Node parentNode) { Node boneNode = new Node(); boneNode.Name = GetNodeBoneName(fingerType, boneType, hand); parentNode.Children.Add(boneNode); return (boneNode); }
/// <summary> /// Build a Node hierachy into the scene property 'mainScene' from a Hand object /// </summary> /// <param name="hand"></param> private void CreateNodeHierarchy(Hand hand, Scene handScene) { Node rootNode = handScene.RootNode = new Node(); Node handNode = new Node(); handNode.Name = GetNodeHandName(hand.Id.ToString()); rootNode.Children.Add(handNode); NodeAnimationChannel bonetest = new NodeAnimationChannel(); bonetest.NodeName = GetNodeHandName(hand.Id.ToString()); handScene.Animations[0].NodeAnimationChannels.Add(bonetest); foreach (Finger finger in hand.Fingers) { Node fingerNode = handNode; foreach (Leap.Bone.BoneType boneType in (Leap.Bone.BoneType[])Enum.GetValues(typeof(Leap.Bone.BoneType))) { string fingerType = finger.Type.ToString(); //Add a node hierarchy fingerNode = AddChildBone(fingerType, boneType.ToString(), hand, fingerNode); //Fill the NodeAnimChannel NodeAnimationChannel bone = new NodeAnimationChannel(); bone.NodeName = GetNodeBoneName(fingerType, boneType.ToString(), hand); handScene.Animations[0].NodeAnimationChannels.Add(bone); } } }
public override IAsset Import(string pathToFile) { boneNames = new Dictionary <string, Assimp.Bone>(); //rootBones = new List<Node> (); Assimp.Node rootBone = null; foreach (var mesh in scene.Meshes) { foreach (var bone in mesh.Bones) { boneNames.Add(bone.Name, bone); } } foreach (var boneName in boneNames.Keys) { var boneNode = scene.RootNode.FindNode(boneName); if (boneNode.Parent == null || !boneNames.ContainsKey(boneNode.Parent.Name)) { rootBone = boneNode.Parent; break; } } var skele = new Skeleton(); skele.Name = "_Skeleton"; skele[rootBone.Name] = CreateBoneTree(ref skele, rootBone, null); //bvh_to_vertices (skele[rootBone.Name],); //Console.WriteLine ("/n Start bone list: /n"+rootBone.Name); return(skele); }
private static Object ConvertObjectFromAiNode(Ai.Node aiNode, Ai.Scene aiScene, Matrix4x4 parentTransformation, string texturesDirectory, TextureSet textureSet) { var obj = new Object { Name = aiNode.Name, Skin = new Skin() }; var boneMap = new Dictionary <string, int>(StringComparer.OrdinalIgnoreCase); var materialMap = new Dictionary <string, int>(StringComparer.OrdinalIgnoreCase); ConvertMeshesFromAiNodesRecursively(obj, aiNode, aiScene, parentTransformation, boneMap, materialMap, texturesDirectory, textureSet); if (obj.Skin.Bones.Count == 0) { obj.Skin = null; } obj.BoundingSphere = new AxisAlignedBoundingBox(obj.Meshes.SelectMany(x => x.Vertices)).ToBoundingSphere(); return(obj.Meshes.Count != 0 ? obj : null); }
private void ProcessNode(Entity3D root, Assimp.Node s, List <Mesh3D> ml) { Entity3D r1 = new Entity3D(); root.Sub.Add(r1); r1.Top = root; r1.Name = s.Name; if (s.Name.ToLower().Contains("root")) { r1.Name = r1.Name + "*"; r1.BreakTop = true; } //r1.LocalTurn = new OpenTK.Matrix4(s.Transform.A1, s.Transform.A2, s.Transform.A3, s.Transform.A4, s.Transform.B1, s.Transform.B2, s.Transform.B3, s.Transform.B4, s.Transform.C1, s.Transform.C2, s.Transform.C3, s.Transform.C4, s.Transform.D1, s.Transform.D2, s.Transform.D3, s.Transform.D4); r1.LocalTurn = new OpenTK.Matrix4(s.Transform.A1, s.Transform.B1, s.Transform.C1, s.Transform.D1, s.Transform.A2, s.Transform.B2, s.Transform.C2, s.Transform.D2, s.Transform.A3, s.Transform.B3, s.Transform.C3, s.Transform.D3, s.Transform.A4, s.Transform.B4, s.Transform.C4, s.Transform.D4); OpenTK.Matrix4 lt = r1.LocalTurn; r1.LocalTurn = lt.ClearTranslation(); r1.LocalTurn = r1.LocalTurn.ClearScale(); r1.LocalPos = lt.ExtractTranslation(); r1.LocalScale = lt.ExtractScale(); // r1.LocalPos = new OpenTK.Vector3(r1.LocalPos.X + 100, 0, 0); for (int i = 0; i < s.MeshCount; i++) { r1.AddMesh(ml[s.MeshIndices[i]]); } if (s.HasChildren) { foreach (Node pn in s.Children) { ProcessNode(r1, pn, ml); } } }
public JNT1(Assimp.Scene scene, VTX1 vertexData) { BoneNameIndices = new Dictionary <string, int>(); FlatSkeleton = new List <Rigging.Bone>(); Assimp.Node root = null; for (int i = 0; i < scene.RootNode.ChildCount; i++) { if (scene.RootNode.Children[i].Name.ToLowerInvariant() == "skeleton_root") { root = scene.RootNode.Children[i].Children[0]; break; } } if (root == null) { SkeletonRoot = new Rigging.Bone("root"); SkeletonRoot.Bounds.GetBoundsValues(vertexData.Attributes.Positions); FlatSkeleton.Add(SkeletonRoot); BoneNameIndices.Add("root", 0); } else { SkeletonRoot = AssimpNodesToBonesRecursive(root, null, FlatSkeleton); foreach (Rigging.Bone bone in FlatSkeleton) { BoneNameIndices.Add(bone.Name, FlatSkeleton.IndexOf(bone)); } } }
//recursively calculates the bounding box of the whole model private void ComputeBoundingBox(Scene scene, Node node, ref Vector3 min, ref Vector3 max, ref Matrix transform) { Matrix previousTransform = transform; transform = Matrix.Multiply(previousTransform, FromMatrix(node.Transform)); if (node.HasMeshes) { foreach (int index in node.MeshIndices) { Assimp.Mesh mesh = scene.Meshes[index]; for (int i = 0; i < mesh.VertexCount; i++) { Vector3 tmp = FromVector(mesh.Vertices[i]); Vector4 result; Vector3.Transform(ref tmp, ref transform, out result); min.X = Math.Min(min.X, result.X); min.Y = Math.Min(min.Y, result.Y); min.Z = Math.Min(min.Z, result.Z); max.X = Math.Max(max.X, result.X); max.Y = Math.Max(max.Y, result.Y); max.Z = Math.Max(max.Z, result.Z); } } } //go down the hierarchy if children are present for (int i = 0; i < node.ChildCount; i++) { ComputeBoundingBox(scene, node.Children[i], ref min, ref max, ref transform); } transform = previousTransform; }
public static Node GetRootNode(Node myNode) { Node parent = myNode.Parent; if (myNode.Parent != null) return GetRootNode(parent); return (parent); }
// -------------------------------------------------------------------- private SceneObject ParseNode(Assimp.Node node, bool preview, SceneObject parent) { string nodeName = GetSafeFileName(node.Name); SceneObject mySceneObject = new SceneObject(nodeName); mySceneObject.Parent = parent; mySceneObject.Transform.FromMatrix(node.Transform.ToOnyx3D()); if (!preview) mySceneObject.Transform.LocalPosition = mySceneObject.Transform.LocalPosition * sMeshScalar; if (node.HasMeshes) { for(int i=0; i < node.MeshCount; ++i) { MeshRenderer meshRenderer = mySceneObject.AddComponent<MeshRenderer>(); if (preview) { mCurrentModel.Meshes[node.MeshIndices[i]].Name = nodeName; meshRenderer.Mesh = mCurrentModel.Meshes[node.MeshIndices[i]].ToOnyx3D(); meshRenderer.Material = new DefaultMaterial(); }else { meshRenderer.Mesh = Onyx3DEngine.Instance.Resources.GetMesh(mLoadedMeshesGuids[node.MeshIndices[i]]); meshRenderer.Material = Onyx3DEngine.Instance.Resources.GetMaterial(BuiltInMaterial.Default); } } } foreach (Node child in node.Children) { SceneObject childSceneObject = ParseNode(child, preview, mySceneObject); } return mySceneObject; }
private static void CreateAiNodesFromBoneInfos(List <BoneInfo> boneInfos, Ai.Scene aiScene, Ai.Node aiParentBone, BoneInfo parentBoneInfo, Dictionary <string, Ai.Node> convertedBones) { foreach (var boneInfo in boneInfos) { if (boneInfo.Parent != parentBoneInfo) { continue; } if (!convertedBones.TryGetValue(boneInfo.Name, out var aiBoneNode)) { aiBoneNode = CreateAiNodeFromBoneInfo(boneInfo, parentBoneInfo?.InverseBindPoseMatrix ?? Matrix4x4.Identity); if (aiParentBone == null) { aiScene.RootNode.Children.Add(aiBoneNode); } else { aiParentBone.Children.Add(aiBoneNode); } convertedBones.Add(boneInfo.Name, aiBoneNode); } CreateAiNodesFromBoneInfos(boneInfos, aiScene, aiBoneNode, boneInfo, convertedBones); } }
public NodeInfo(Ai.Node aiNode, Node node, int index, bool isMesh) { AssimpNode = aiNode; Node = node; Index = index; IsMeshAttachment = isMesh; }
private static void ProcessAssimpNodeMeshesRecursively(Ai.Node aiNode, Ai.Scene aiScene, Dictionary <string, NodeInfo> nodeLookup, ref int nextBoneIndex, Dictionary <int, List <int> > nodeToBoneIndices, List <Matrix4x4> boneInverseBindMatrices, List <Vector3> transformedVertices, ModelConverterOptions options) { if (aiNode.HasMeshes) { var nodeInfo = nodeLookup[AssimpConverterCommon.UnescapeName(aiNode.Name)]; var node = nodeInfo.Node; var nodeWorldTransform = node.WorldTransform; Matrix4x4.Invert(nodeWorldTransform, out var nodeInverseWorldTransform); foreach (var aiMeshIndex in aiNode.MeshIndices) { var aiMesh = aiScene.Meshes[aiMeshIndex]; var aiMaterial = aiScene.Materials[aiMesh.MaterialIndex]; var geometry = ConvertAssimpMeshToGeometry(aiMesh, aiMaterial, nodeLookup, ref nextBoneIndex, nodeToBoneIndices, boneInverseBindMatrices, ref nodeWorldTransform, ref nodeInverseWorldTransform, transformedVertices, options); if (!nodeInfo.IsMeshAttachment) { node.Attachments.Add(new NodeMeshAttachment(geometry)); } else { node.Parent.Attachments.Add(new NodeMeshAttachment(geometry)); node.Parent.RemoveChildNode(node); } } } foreach (var aiNodeChild in aiNode.Children) { ProcessAssimpNodeMeshesRecursively(aiNodeChild, aiScene, nodeLookup, ref nextBoneIndex, nodeToBoneIndices, boneInverseBindMatrices, transformedVertices, options); } }
private static Ai.Node CreateAiNodeFromObject(Object obj, Ai.Scene aiScene) { var aiObjectNode = new Ai.Node(obj.Name); foreach (var mesh in obj.Meshes) { for (int i = 0; i < mesh.SubMeshes.Count; i++) { var subMesh = mesh.SubMeshes[i]; string name = mesh.Name; if (i > 0) { name += "." + i.ToString("D3"); } var aiSubMeshNode = new Ai.Node(name); var aiMesh = CreateAiMeshFromSubMesh(subMesh, mesh, obj, aiScene, name); aiSubMeshNode.MeshIndices.Add(aiScene.Meshes.Count); aiScene.Meshes.Add(aiMesh); aiObjectNode.Children.Add(aiSubMeshNode); } } return(aiObjectNode); }
private Node AddChildNode(Node parentNode, Joint childJoint) { Node newChildNode = new Node(); newChildNode.Name = GetNodeIdName(childJoint.JointType); parentNode.Children.Add(newChildNode); return (newChildNode); }
private Ai.Node ConvertNode(Scene scene, Node node, Ai.Node aiParent) { var aiNode = new Ai.Node(AssimpConverterCommon.EscapeName(node.Name), aiParent) { Transform = new Ai.Matrix4x4(node.LocalTransform.M11, node.LocalTransform.M21, node.LocalTransform.M31, node.LocalTransform.M41, node.LocalTransform.M12, node.LocalTransform.M22, node.LocalTransform.M32, node.LocalTransform.M42, node.LocalTransform.M13, node.LocalTransform.M23, node.LocalTransform.M33, node.LocalTransform.M43, node.LocalTransform.M14, node.LocalTransform.M24, node.LocalTransform.M34, node.LocalTransform.M44) }; if (node.HasProperties) { ConvertNodeProperties(node.Properties, aiNode); } if (node.HasAttachments) { ConvertNodeAttachments(scene, node, aiNode); } if (node.HasChildren) { foreach (var childNode in node.Children) { aiNode.Children.Add(ConvertNode(scene, childNode, aiNode)); } } return(aiNode); }
void get_bounding_box_for_node(Assimp.Node nd, Vector3 min, Vector3 max) { //Matrix4x4 prev; //uint n = 0, t; //for (; n < nd.MeshCount; ++n) { // Assimp.Mesh mesh = scene.Meshes[nd.Children.IndexOf(n)]; //mMeshes[nd->mMeshes[n]]; ////////////////////////////////////////////////////////////////////////// // for (t = 0; t < mesh->mNumVertices; ++t) { // aiVector3D tmp = mesh->mVertices[t]; // min->x = aisgl_min(min->x,tmp.x); // min->y = aisgl_min(min->y,tmp.y); // min->z = aisgl_min(min->z,tmp.z); // max->x = aisgl_max(max->x,tmp.x); // max->y = aisgl_max(max->y,tmp.y); // max->z = aisgl_max(max->z,tmp.z); // } //} //for (n = 0; n < nd->mNumChildren; ++n) { // get_bounding_box_for_node(nd->mChildren[n],min,max); //} }
private static bool IsMeshAttachmentNode(Ai.Node node) { bool isMeshAttachmentNode = node.Parent != null && // definitely not a mesh attachment if it doesnt have a parent -> RootNode node.Parent.Name != "RootNode" && // probably not a mesh attachment if its part of the scene root AssimpConverterCommon.MeshAttachmentNameRegex.IsMatch(node.Name) && // match name regex NearlyEquals(node.Transform, Ai.Matrix4x4.Identity); // transform must be identity return(isMeshAttachmentNode); }
/// <summary> /// Gets a <see cref="DomainBone"/> for a given <see cref="AssimpNode"/>. /// </summary> /// <param name="node">The <see cref="AssimpNode"/> to get a skeleton node from.</param> /// <param name="isRootNode">A value indicating if this is the root skeleton node.</param> /// <returns>The resulting <see cref="DomainBone"/>.</returns> private DomainBone GetSkeletonNode(AssimpNode node, bool isRootNode) { var childrenBones = node.Children.Select(child => GetSkeletonNode(child, false)).ToArray(); return(new DomainBone(GetNumericsMatrix4x4(node.Transform), node.Name, new ReadOnlyCollection <DomainBone>(childrenBones), computeWorldToBindMatrices: isRootNode)); }
public static void DrawNormals(Node node, int meshIndex, Mesh mesh, CpuSkinningEvaluator skinner, float invGlobalScale, Matrix4 transform) { if (!mesh.HasNormals) { return; } // The normal directions are transformed using the transpose(inverse(transform)). // This ensures correct direction is used when non-uniform scaling is present. Matrix4 normalMatrix = transform; normalMatrix.Invert(); normalMatrix.Transpose(); // Scale by scene size because the scene will be resized to fit // the unit box, but the normals should have a fixed length. var scale = invGlobalScale * 0.05f; GL.Begin(BeginMode.Lines); GL.Disable(EnableCap.Lighting); GL.Disable(EnableCap.Texture2D); GL.Enable(EnableCap.ColorMaterial); GL.Color4(new Color4(0.0f, 1.0f, 0.0f, 1.0f)); for (uint i = 0; i < mesh.VertexCount; ++i) { Vector3 v; if (skinner != null && mesh.HasBones) { skinner.GetTransformedVertexPosition(node, mesh, i, out v); } else { v = AssimpToOpenTk.FromVector(mesh.Vertices[(int)i]); } v = Vector4.Transform(new Vector4(v, 1.0f), transform).Xyz; // Skip dividing by W component. It should always be 1, here. Vector3 n; if (skinner != null) { skinner.GetTransformedVertexNormal(node, mesh, i, out n); } else { n = AssimpToOpenTk.FromVector(mesh.Normals[(int)i]); } n = Vector4.Transform(new Vector4(n, 0.0f), normalMatrix).Xyz; // Toss the W component. It is non-sensical for normals. n.Normalize(); GL.Vertex3(v); GL.Vertex3(v + n * scale); } GL.End(); GL.Disable(EnableCap.ColorMaterial); }
/// <summary> /// Counts recursively the number of nodes in a node architecture.<br /> /// Each node contains a pointer to the next nodes in a node architecture. /// </summary> /// <param name="node">The node to be counted and containing the next nodes as pointers in the node architecture, as a Asssimp.Node.</param> /// <param name="nodeNumber">The number of nodes to be updated as the algorithm goes deeper into the node architecture, as an Integer.</param> private static void CountNodeNumber(Node node, ref int nodeNumber) { if (node != null) { nodeNumber += 1; for (int i = 0; i < node.ChildCount; i++) CountNodeNumber(node.Children[i], ref nodeNumber); } }
/// <summary> /// Creates an Assimp.Animation by copying the given source Assimp.Animation content.<br /> /// </summary> /// <param name="rootNode"></param> /// <param name="sourceAnimation">The source Assimp.Animation to copy.</param> /// <returns></returns> private static Assimp.Animation CreateAssimpAnimation(Node rootNode, Assimp.Animation sourceAnimation) { Assimp.Animation animation = new Assimp.Animation(); animation.DurationInTicks = sourceAnimation.DurationInTicks; animation.Name = sourceAnimation.Name; animation.TicksPerSecond = sourceAnimation.TicksPerSecond; CreateNodeAnimationChannels(animation, sourceAnimation.NodeAnimationChannels, rootNode); return animation; }
private void ConvertNodeAttachments(Model model, Node node, Ai.Node aiNode) { for (int i = 0; i < node.Attachments.Count; i++) { var attachment = node.Attachments[i]; switch (attachment.Type) { case NodeAttachmentType.Mesh: { var mesh = ConvertGeometry(model, node, attachment.GetValue <Mesh>()); mesh.Name = $"{AssimpConverterCommon.EscapeName(node.Name)}_Attachment{i}_Mesh"; aiNode.MeshIndices.Add(mAiScene.Meshes.Count); mAiScene.Meshes.Add(mesh); } break; case NodeAttachmentType.Camera: { var camera = attachment.GetValue <Camera>(); mAiScene.Cameras.Add(new Ai.Camera { Name = node.Name, Position = camera.Position.ToAssimp(), Up = camera.Up.ToAssimp(), Direction = -camera.Direction.ToAssimp(), FieldOfview = MathHelper.DegreesToRadians(camera.FieldOfView), ClipPlaneNear = camera.ClipPlaneNear, ClipPlaneFar = camera.ClipPlaneFar, AspectRatio = camera.AspectRatio }); } break; case NodeAttachmentType.Light: { var light = attachment.GetValue <Light>(); mAiScene.Lights.Add(new Ai.Light { Name = node.Name, AngleInnerCone = light.AngleInnerCone, AngleOuterCone = light.AngleOuterCone, ColorAmbient = light.AmbientColor.ToAssimpAsColor3D(), ColorDiffuse = light.DiffuseColor.ToAssimpAsColor3D(), ColorSpecular = light.SpecularColor.ToAssimpAsColor3D(), LightType = light.Type == LightType.Point ? Ai.LightSourceType.Point : light.Type == LightType.Spot ? Ai.LightSourceType.Spot : Ai.LightSourceType.Directional, }); } break; default: //throw new NotImplementedException(); break; } } }
private static void CopyNodeTree(Node oriParentNode, Node copyRootNode) { foreach (Node oriChildNode in oriParentNode.Children) { //We could use a CopyNode method later if its necessary to add more metadata inside. Node newNode = new Node(oriChildNode.Name); copyRootNode.Children.Add(newNode); CopyNodeTree(oriChildNode, newNode); } }
/// <summary> /// Creates an Assimp.NodeAnimationChannel from the given NodeAnimationChannel list and Assimp.Node.<br /> /// Adds the Assimp.NodeAnimationChannel to the given Assimp.Animation /// </summary> /// <param name="node"></param> /// <param name="channel"></param> private static void CreateNodeAnimationChannels(Assimp.Animation animation, List<NodeAnimationChannel> sourceNodeAnimationChannels, Node node) { NodeAnimationChannel nodeAnimationChannel = new NodeAnimationChannel(); nodeAnimationChannel = sourceNodeAnimationChannels[animation.NodeAnimationChannelCount]; nodeAnimationChannel.NodeName = node.Name; animation.NodeAnimationChannels.Add(nodeAnimationChannel); for (int i = 0; i < node.ChildCount; i++) CreateNodeAnimationChannels(animation, sourceNodeAnimationChannels, node.Children[i]); }
private static Ai.Node CreateAiNodeFromBoneInfo(BoneInfo boneInfo, Matrix4x4 inverseParentTransformation) { var aiNode = new Ai.Node(boneInfo.Name); Matrix4x4.Invert(boneInfo.InverseBindPoseMatrix, out var transformation); aiNode.Transform = Matrix4x4.Multiply(transformation, inverseParentTransformation).ToAssimpTransposed(); return(aiNode); }
private static Node ConvertAssimpNodeRecursively(Ai.Node aiNode, Dictionary <string, NodeInfo> nodeLookup, ref int nextIndex) { aiNode.Transform.Decompose(out var scale, out var rotation, out var translation); // Create node var node = new Node(AssimpConverterCommon.UnescapeName(aiNode.Name), new Vector3(translation.X, translation.Y, translation.Z), new Quaternion(rotation.X, rotation.Y, rotation.Z, rotation.W), new Vector3(scale.X, scale.Y, scale.Z)); if (!IsMeshAttachmentNode(aiNode)) { // Convert properties ConvertAssimpMetadataToProperties(aiNode.Metadata, node); if (!nodeLookup.ContainsKey(node.Name)) { // Add to lookup nodeLookup.Add(node.Name, new NodeInfo(aiNode, node, nextIndex++, false)); } else { throw new Exception($"Duplicate node name '{node.Name}'"); } // Process children foreach (var aiNodeChild in aiNode.Children) { if (aiNodeChild.Name == "RootNode") { // For compatibility with old exports // Merge children of 'RootNode' node with actual root node foreach (var aiFakeRootNodeChild in aiNodeChild.Children) { var childNode = ConvertAssimpNodeRecursively(aiFakeRootNodeChild, nodeLookup, ref nextIndex); node.AddChildNode(childNode); } } else { var childNode = ConvertAssimpNodeRecursively(aiNodeChild, nodeLookup, ref nextIndex); node.AddChildNode(childNode); } } } else { nodeLookup.Add(node.Name, new NodeInfo(aiNode, node, -1, true)); } return(node); }
/// <summary> /// Generate weights and skeleton Nodes from an assimp skeleton Node. /// However pinocchio does not looks to be very good with /// that Method. /// It takes a /// </summary> /// <param name="modelPath">The original model Path</param> /// <param name="scene"></param> /// <param name="skeletalAnim"></param> /// <param name="rootSkeletalAnim"></param> public void AutomaticRiggingFromSkeleton(string modelPath, Scene scene, Animation skeletalAnim, Node rootSkeletalAnim) { string skelPathFile = Path.Combine(Path.Combine(projectPath, PINOCCHIO_TMP_DIR_INPUT), "skeleton.out"); ExportToPinocchioFormat(projectPath, skeletalAnim, rootSkeletalAnim, 0); LaunchPinocchioBinary(modelPath, skelPathFile); //Import Data that pinocchio did generated //There is a problem here since we dont have a way to associate AssimpNodes and Bones in the attachement.out for now() BuildBones(scene.Meshes[0], rootSkeletalAnim); BuildBonesWeight(scene); }
private static void ConvertAiNodesFromBonesRecursively(Ai.Node parent, Matrix4x4 inverseParentTransform, string parentName, List <Bone> bones, Dictionary <string, string> boneParentMap, bool appendTags = false) { foreach (var bone in bones) { if (boneParentMap[bone.Name] == parentName) { var boneNode = ConvertAiNodeFromBone(parent, inverseParentTransform, bone, appendTags); ConvertAiNodesFromBonesRecursively(boneNode, bone.Matrix, bone.Name, bones, boneParentMap, appendTags); } } }
public static void DrawSkeletonBone(Node node, float invGlobalScale, bool highlight) { var target = new Vector3(node.Transform.A4, node.Transform.B4, node.Transform.C4); if (!(target.LengthSquared > 1e-6f)) { return; } GL.Disable(EnableCap.Lighting); GL.Disable(EnableCap.Texture2D); GL.Enable(EnableCap.ColorMaterial); GL.Disable(EnableCap.DepthTest); GL.Color4(highlight ? new Color4(0.0f, 1.0f, 0.5f, 1.0f) : new Color4(0.0f, 0.5f, 1.0f, 1.0f)); var right = new Vector3(1, 0, 0); var targetNorm = target; targetNorm.Normalize(); Vector3 up; Vector3.Cross(ref targetNorm, ref right, out up); Vector3.Cross(ref up, ref targetNorm, out right); up *= invGlobalScale; right *= invGlobalScale; const float jointWidth = 0.03f; GL.Begin(BeginMode.LineLoop); GL.Vertex3(-jointWidth * up + -jointWidth * right); GL.Vertex3(-jointWidth * up + jointWidth * right); GL.Vertex3(jointWidth * up + jointWidth * right); GL.Vertex3(jointWidth * up + -jointWidth * right); GL.End(); GL.Begin(BeginMode.Lines); GL.Vertex3(-jointWidth * up + -jointWidth * right); GL.Vertex3(target); GL.Vertex3(-jointWidth * up + jointWidth * right); GL.Vertex3(target); GL.Vertex3(jointWidth * up + jointWidth * right); GL.Vertex3(target); GL.Vertex3(jointWidth * up + -jointWidth * right); GL.Vertex3(target); GL.Color4(highlight ? new Color4(1.0f, 0.0f, 0.0f, 1.0f) : new Color4(1.0f, 1.0f, 0.0f, 1.0f)); GL.Vertex3(Vector3.Zero); GL.Vertex3(target); GL.End(); GL.Disable(EnableCap.ColorMaterial); GL.Enable(EnableCap.DepthTest); }
private static Ai.Matrix4x4 GetGlobalTransformation(Ai.Node aiNode) { var transform = Ai.Matrix4x4.Identity; for (var node = aiNode; aiNode != null; aiNode = aiNode.Parent) { transform = transform * aiNode.Transform; } return(transform); }
private static Matrix4x4 GetWorldTransform(Ai.Node aiNode) { var transform = aiNode.Transform; while ((aiNode = aiNode.Parent) != null) { transform *= aiNode.Transform; } return(transform.ToNumericsTransposed()); }
private static Object CreateObjectFromAiNode(Ai.Node aiNode, Ai.Scene aiScene, ObjectSet objectSet, string texturesDirectoryPath) { var obj = new Object(); obj.Name = aiNode.Name; obj.Id = MurmurHash.Calculate(aiNode.Name); obj.Skin = new Skin(); var aabb = new AxisAlignedBoundingBox(); CreateRecursively(aiNode); void CreateRecursively(Ai.Node aiChildNode) { if (aiChildNode.HasMeshes) { var meshes = CreateMeshesFromAiNode(aiChildNode, aiScene, obj, ref aabb, objectSet, texturesDirectoryPath); if (meshes?.Count > 0) { obj.Meshes.AddRange(meshes); } } foreach (var aiAlsoChildNode in aiChildNode.Children) { CreateRecursively(aiAlsoChildNode); } } obj.BoundingSphere = aabb.ToBoundingSphere(); if (obj.Skin.Bones.Count > 0) { foreach (var boneInfo in obj.Skin.Bones) { var aiBoneNode = aiScene.RootNode.FindNode(boneInfo.Name); if (aiBoneNode.Parent == null || aiBoneNode.Parent == aiScene.RootNode) { continue; } boneInfo.Parent = obj.Skin.Bones.FirstOrDefault(x => x.Name == aiBoneNode.Parent.Name); } } else { obj.Skin = null; } return(obj); }
private static void ConvertNodeProperties(UserPropertyCollection properties, Ai.Node aiNode) { var stringBuilder = new StringBuilder(); foreach (var property in properties.Values) { // Todo: Assign to 3ds max user properties stringBuilder.Append($"{property.ToUserPropertyString()}&cr;&lf;"); } aiNode.Metadata["UDP3DSMAX"] = new Ai.Metadata.Entry(Ai.MetaDataType.String, stringBuilder.ToString()); }
private Rigging.Bone AssimpNodesToBonesRecursive(Assimp.Node node, Rigging.Bone parent, List <Rigging.Bone> boneList) { Rigging.Bone newBone = new Rigging.Bone(node, parent); boneList.Add(newBone); for (int i = 0; i < node.ChildCount; i++) { newBone.Children.Add(AssimpNodesToBonesRecursive(node.Children[i], newBone, boneList)); } return(newBone); }
public static Ai.Scene ExportToAiScene(ObjectSet objectSet) { if (objectSet.TextureSet != null) { foreach (var texture in objectSet.TextureSet.Textures .Where(texture => string.IsNullOrEmpty(texture.Name))) { texture.Name = Guid.NewGuid().ToString(); } } var aiScene = new Ai.Scene { RootNode = new Ai.Node("RootNode") }; var convertedMaterials = new HashSet <string>(); foreach (var obj in objectSet.Objects) { foreach (var material in obj.Materials) { var aiMaterial = CreateAiMaterialFromMaterial(material, objectSet.TextureSet); if (convertedMaterials.Contains(aiMaterial.Name)) { aiMaterial.Name += "+" + material.Name; } aiScene.Materials.Add(aiMaterial); convertedMaterials.Add(aiMaterial.Name); } } var convertedBones = new Dictionary <string, Ai.Node>(); var gblctrNode = new Ai.Node("gblctr"); foreach (var obj in objectSet.Objects) { if (obj.Skin != null) { CreateAiNodesFromBoneInfos(obj.Skin.Bones, aiScene, gblctrNode, null, convertedBones); } aiScene.RootNode.Children.Add(CreateAiNodeFromObject(obj, aiScene)); } if (gblctrNode.HasChildren) { aiScene.RootNode.Children.Add(gblctrNode); } return(aiScene); }
private void proccessNode(ai.Node node, ai.Scene scene, MeshLoader loader) { foreach (int index in node.MeshIndices) { ai.Mesh mesh = scene.Meshes[index]; Meshes.Add(loader(mesh, scene)); } foreach (ai.Node child in node.Children) { proccessNode(child, scene, loader); } }
private void ProcessNode(Assimp.Node node, Assimp.Scene scene) { for (int i = 0; i < node.MeshCount; i++) { Assimp.Mesh amesh = scene.Meshes[node.MeshIndices[i]]; _meshes.Add(ProcessMesh(amesh, scene)); } for (int i = 0; i < node.ChildCount; i++) { ProcessNode(node.Children[i], scene); } }
private static Ai.Matrix4x4 GetWorldTransform(Ai.Node aiNode) { var transform = aiNode.Transform; var parent = aiNode.Parent; while (parent != null) { transform *= parent.Transform; parent = parent.Parent; } return(transform); }
/// <summary> /// Sets the contents of the info pop-up given an assimp node. /// /// At the time this method is called, the node info popup's /// location has already been adjusted by the caller. /// </summary> public void Populate(Assimp.Scene scene, Node node, NodePurpose purpose) { Debug.Assert(scene != null); Debug.Assert(node != null); Debug.Assert(_owner != null); switch (purpose) { case NodePurpose.Joint: labelCaption.Text = "Joint"; break; case NodePurpose.ImporterGenerated: labelCaption.Text = "Root"; break; case NodePurpose.GenericMeshHolder: labelCaption.Text = "Node"; break; case NodePurpose.Camera: labelCaption.Text = "Camera"; break; case NodePurpose.Light: labelCaption.Text = "Light"; break; default: Debug.Assert(false); break; } // count children recursively var children = 0; CountChildren(node, ref children); var animated = false; // check whether there are any animation channels for this node for (var i = 0; i < scene.AnimationCount && !animated; ++i ) { var anim = scene.Animations[i]; for(var j = 0; j < anim.NodeAnimationChannelCount; ++j) { if(anim.NodeAnimationChannels[j].NodeName == node.Name) { animated = true; break; } } } labelInfo.Text = string.Format("{0} Children\n{1}", children, (animated ? "Animated" : "Not animated")); }
public static void DrawNormals(Node node, int meshIndex, Mesh mesh, CpuSkinningEvaluator skinner, float invGlobalScale) { if (!mesh.HasNormals) { return; } // Scale by scene size because the scene will be resized to fit // the unit box but the normals should have a fixed length var scale = invGlobalScale * 0.05f; GL.Begin(BeginMode.Lines); GL.Disable(EnableCap.Lighting); GL.Disable(EnableCap.Texture2D); GL.Enable(EnableCap.ColorMaterial); GL.Color4(new Color4(0.0f, 1.0f, 0.0f, 1.0f)); for (uint i = 0; i < mesh.VertexCount; ++i) { Vector3 v; if (skinner != null && mesh.HasBones) { skinner.GetTransformedVertexPosition(node, meshIndex, i, out v); } else { v = AssimpToOpenTk.FromVector(mesh.Vertices[(int)i]); } Vector3 n; if (skinner != null) { skinner.GetTransformedVertexNormal(node, meshIndex, i, out n); } else { n = AssimpToOpenTk.FromVector(mesh.Normals[(int)i]); } GL.Vertex3(v); GL.Vertex3(v + n * scale); } GL.End(); GL.Disable(EnableCap.ColorMaterial); }
static Node LookForMatch(Node root, string name) { string namelow = name.ToLower(); if (root.Name.ToLower() == namelow) { return root; } for (int i = 0; i < root.ChildCount; i++) { Node found = LookForMatch(root.Children[i], name); if (found != null) { return found; } } return null; }
public void GetTransformedVertexPosition(Node node, uint vertexIndex, out Vector3 pos) { // note: the scenario in which a skinned mesh is referenced by multiple nodes // is not currently implemented properly. It works, but it prevents caching. if (node != _lastNode) { _lastNode = node; _dirty = true; } if(_dirty) { Cache(); } Debug.Assert(!_dirty); Debug.Assert(vertexIndex < _cachedPositions.Length); pos = _cachedPositions[vertexIndex]; }
/// <summary> /// Constructs a new Node. /// </summary> /// <param name="aiNode">Unmanaged AiNode structure</param> /// <param name="parent">Parent of this node or null</param> internal Node(AiNode aiNode, Node parent) { _name = aiNode.Name.GetString(); _transform = aiNode.Transformation; _parent = parent; if(aiNode.NumChildren > 0 && aiNode.Children != IntPtr.Zero) { AiNode[] childNodes = MemoryHelper.MarshalArray<AiNode>(aiNode.Children, (int) aiNode.NumChildren, true); _children = new Node[childNodes.Length]; for(int i = 0; i < _children.Length; i++) { _children[i] = new Node(childNodes[i], this); } } if(aiNode.NumMeshes > 0 && aiNode.Meshes != IntPtr.Zero) { _meshes = MemoryHelper.MarshalArray<int>(aiNode.Meshes, (int) aiNode.NumMeshes); } }
/// <summary> /// Allows to merge 2 Node hierarchy /// </summary> /// <param name="rootNode1">The root Node of the first Node Hierarchy</param> /// <param name="mergeNodeName1">The name of the node that we want to merge with mergeNodeName2</param> /// <param name="rootNode2">The root Node of the first Node Hierarchy</param> /// <param name="mergeNodeName2">The name of the node that we want to merge with mergdeNodeName1</param> /// <param name="childrenCopy">Should we make a simple jointure or only copy the nodes childrens</param> public static Node MergeNodeStructure(Node rootNode1, string mergeNodeName1, Node rootNode2, string mergeNodeName2, ref MergeBehaviour mergeBehav) { Node rootNode1Copy = rootNode1; if (mergeBehav.copyTreeNode1) rootNode1Copy = AssimpUtil.DuplicateNodeTree(rootNode1); Node rootNode2Copy = rootNode2; if (mergeBehav.copyTreeNode2) rootNode2Copy = AssimpUtil.DuplicateNodeTree(rootNode2); Node mergeNode1 = rootNode1Copy.FindNode(mergeNodeName1); Node mergeNode2 = rootNode2Copy.FindNode(mergeNodeName2); if (mergeBehav.childrenCopy) { foreach (Node tmp in mergeNode2.Children) mergeNode1.Children.Add(tmp); } else mergeNode1.Children.Add(mergeNode2); return rootNode1Copy; }
/// <summary> /// Rename node to the given new name. /// /// Does not create UndoStack entries itself, caller must do this. /// </summary> /// <param name="node"></param> /// <param name="newName"></param> public void RenameNode(Node node, string newName) { if (newName == node.Name) { return; } var oldName = node.Name; node.Name = newName; // Update references from bones foreach (var mesh in _scene.Raw.Meshes) { foreach (var bone in mesh.Bones) { if (bone.Name == oldName) { bone.Name = newName; } } } // Update references from node animation channels foreach (var anim in _scene.Raw.Animations) { foreach (var channel in anim.NodeAnimationChannels) { if (channel.NodeName == oldName) { channel.NodeName = newName; } } } // SceneAnimator is - unfortunately - name based. _scene.SceneAnimator.RenameNode(oldName, newName); }
/// <summary> /// Icrtavanje objekata u sceni koji su reprezentovani datim cvorom, kao i njegovim pod-cvorovima. /// U zavisnosti od karakteristika objekata podesavaju se odgovarajuce promenjive stanja (GL_LIGHTING, GL_COLOR_MATERIAL, GL_TEXTURE_2D). /// </summary> /// <param name="node">Cvor koji ce biti iscrtan.</param> private void RenderNode(Node node) { Gl.glPushMatrix(); // Primena tranformacija vezanih za dati cvor. float[] matrix = new float[16] { node.Transform.A1, node.Transform.B1, node.Transform.C1, node.Transform.D1, node.Transform.A2, node.Transform.B2, node.Transform.C2, node.Transform.D2, node.Transform.A3, node.Transform.B3, node.Transform.C3, node.Transform.D3, node.Transform.A4, node.Transform.B4, node.Transform.C4, node.Transform.D4 }; Gl.glMultMatrixf(matrix); // Iscrtavanje objekata u sceni koji su reprezentovani datim cvorom. if (node.HasMeshes) { foreach (int index in node.MeshIndices) { Mesh mesh = m_scene.Meshes[index]; Material material = m_scene.Materials[mesh.MaterialIndex]; // Primena komponenti materijala datog objekta. ApplyMaterial(material); // Primena teksture u slucaju da je ista definisana za dati materijal. if (material.GetAllTextures().Length > 0) Gl.glBindTexture(Gl.GL_TEXTURE_2D, m_texMappings[material.GetAllTextures()[0]]); // Podesavanje proracuna osvetljenja za dati objekat. bool hasNormals = mesh.HasNormals; if (hasNormals) Gl.glEnable(Gl.GL_LIGHTING); else Gl.glDisable(Gl.GL_LIGHTING); // Podesavanje color tracking mehanizma za dati objekat. bool hasColors = mesh.HasVertexColors(0); if (hasColors) Gl.glEnable(Gl.GL_COLOR_MATERIAL); else Gl.glDisable(Gl.GL_COLOR_MATERIAL); // Podesavanje rezima mapiranja na teksture. bool hasTexCoords = material.GetAllTextures().Length > 0 && mesh.HasTextureCoords(0); if (hasTexCoords) Gl.glEnable(Gl.GL_TEXTURE_2D); else Gl.glDisable(Gl.GL_TEXTURE_2D); // Iscrtavanje primitiva koji cine dati objekat. // U zavisnosti od broja temena, moguce je iscrtavanje tacaka, linija, trouglova ili poligona. foreach (Face face in mesh.Faces) { switch (face.IndexCount) { case 1: Gl.glBegin(Gl.GL_POINTS); break; case 2: Gl.glBegin(Gl.GL_LINES); break; case 3: Gl.glBegin(Gl.GL_TRIANGLES); break; default: Gl.glBegin(Gl.GL_POLYGON); break; } for (int i = 0; i < face.IndexCount; i++) { uint indice = face.Indices[i]; // Definisanje boje temena. if (hasColors) Gl.glColor4f(mesh.GetVertexColors(0)[indice].R, mesh.GetVertexColors(0)[indice].G, mesh.GetVertexColors(0)[indice].B, mesh.GetVertexColors(0)[indice].A); // Definisanje normale temena. if (hasNormals) Gl.glNormal3f(mesh.Normals[indice].X, mesh.Normals[indice].Y, mesh.Normals[indice].Z); // Definisanje koordinata teksture temena. if (hasTexCoords) Gl.glTexCoord2f(mesh.GetTextureCoords(0)[indice].X, 1 - mesh.GetTextureCoords(0)[indice].Y); // Definisanje temena primitive. Gl.glVertex3f(mesh.Vertices[indice].X, mesh.Vertices[indice].Y, mesh.Vertices[indice].Z); } Gl.glEnd(); } } } // Rekurzivno iscrtavanje cvorova potomaka tekuceg cvora for (int i = 0; i < node.ChildCount; i++) { RenderNode(node.Children[i]); } Gl.glPopMatrix(); }
private NodeState CreateNodeTree(Node rootNode, NodeState parent) { var outNode = new NodeState {LocalTransform = AssimpToOpenTk.FromMatrix(rootNode.Transform)}; outNode.Parent = parent; // calculate transforms outNode.GlobalTransform = parent != null ? parent.GlobalTransform * outNode.LocalTransform : outNode.LocalTransform; // populate by-name map to quickly map nodes to their state _nodeStateByName[rootNode.Name] = outNode; // find the index of the animation track affecting this node, if any outNode.ChannelIndex = -1; if (ActiveAnimation != -1) { var channels = _raw.Animations[ActiveAnimation].NodeAnimationChannels; for (int i = 0; i < channels.Count; ++i) { if (channels[i].NodeName != rootNode.Name) { continue; } outNode.ChannelIndex = i; break; } } outNode.Children = new NodeState[rootNode.ChildCount]; // recursively add up children for (int i = 0; i < rootNode.ChildCount; ++i) { outNode.Children[i] = CreateNodeTree(rootNode.Children[i], outNode); } return outNode; }
/// <summary> /// Obtain the bone matrices for a given node mesh index at the /// current time. Calling this is costly, redundant invocations /// should thus be avoided. /// </summary> /// <param name="node">Node for which to query bone matrices</param> /// <param name="mesh">Mesh for which to query bone matrices. Must be /// one of the meshes attached to the node.</param> /// <returns>For each bone of the mesh the bone transformation /// matrix. The returned array is only valid for the rest of /// the frame or till the next call to GetBoneMatricesForMesh(). /// It may contain more entries than the mesh has bones, the extra entries /// should be ignored in this case.</returns> public Matrix4[] GetBoneMatricesForMesh(Node node, Mesh mesh) { Debug.Assert(node != null); Debug.Assert(mesh != null); // calculate the mesh's inverse global transform Matrix4 globalInverseMeshTransform; GetGlobalTransform( node, out globalInverseMeshTransform ); globalInverseMeshTransform.Invert(); // Bone matrices transform from mesh coordinates in bind pose to mesh coordinates in skinned pose // Therefore the formula is offsetMatrix * currentGlobalTransform * inverseCurrentMeshTransform for( int a = 0; a < mesh.BoneCount; ++a) { var bone = mesh.Bones[a]; Matrix4 currentGlobalTransform; GetGlobalTransform( bone.Name, out currentGlobalTransform ); _boneMatrices[a] = globalInverseMeshTransform * currentGlobalTransform * AssimpToOpenTk.FromMatrix(bone.OffsetMatrix); // TODO for some reason, all OpenTk matrices need a ^T - clarify our conventions somewhere _boneMatrices[a].Transpose(); } return _boneMatrices; }
/// <summary> /// Obtain the current local transformation matrix for a node /// </summary> /// <param name="node">Node</param> /// <param name="outTrafo">Receives the transformation matrix</param> public void GetLocalTransform(Node node, out Matrix4 outTrafo) { GetLocalTransform(node.Name, out outTrafo); }
private SEAMesh AppendMesh(Scene scene, Node node, List<Mesh> meshes, SEAObject3D parent) { int sIndex = GetIndexByTag(node); if (sIndex != -1) return (SEAMesh)Writer.Objects[sIndex]; List<Animation> anmList = GetAnimation(scene, node.Name); SEAGeometry geo = AppendGeometry(scene, node, meshes); if (geo != null) { SEAMesh seaMesh = new SEAMesh(node.Name); /*if (meshes[0].HasMeshAnimationAttachments) { }*/ Mesh mesh = meshes[0]; if (Modifiers && geo.jointPerVertex > 0) { seaMesh.modifiers.Add((uint)GetIndex(AppendSkeleton(scene, mesh))); seaMesh.animations.Add((uint)GetIndex(AppendSkeletonAnimation(scene, mesh))); } if (mesh.MaterialIndex != -1) { seaMesh.materials.Add(GetIndex(AppendMaterial(scene, scene.Materials[mesh.MaterialIndex]))); } seaMesh.parent = parent != null ? GetIndex(parent) : -1; objects.Add(seaMesh); Writer.AddObject(seaMesh); seaMesh.transform = To3x4Array( node.Transform ); seaMesh.geometry = GetIndex(geo); seaMesh.tag = node; return seaMesh; } return null; }
private object GetUnrelatedObjectByNode(Node node, Scene scene) { foreach (Light light in scene.Lights) { if (light.Name == node.Name) return light; } foreach (Camera camera in scene.Cameras) { if (camera.Name == node.Name) return camera; } return null; }
private SEAObject3D AppendObject3D(Scene scene, Node node) { return AppendObject3D(scene, node, null); }
private SEAObject3D AppendObject3D(Scene scene, Node node, SEAObject3D parent) { SEAObject3D object3d = null; /* mtx.e00 / scale.x, mtx.e10 / scale.x, mtx.e20 / scale.x, mtx.e01 / scale.y, mtx.e11 / scale.y, mtx.e21 / scale.y, mtx.e02 / scale.z, mtx.e12 / scale.z, mtx.e22 / scale.z */ //node.Transform = node.Transform * Matrix4x4.FromEulerAnglesXYZ(-90, 0, 0); if (node.MeshCount > 0) { object3d = AppendMesh(scene, node, scene.Meshes, parent); } else if (!MeshOnly && scene.RootNode != node) { object unrelatedObject = GetUnrelatedObjectByNode(node, scene); if (unrelatedObject is Light) { object3d = AppendLight(scene, node, (Light)unrelatedObject, parent); } else if (unrelatedObject is Camera) { object3d = AppendCamera(scene, node, (Camera)unrelatedObject, parent); } else if (EnabledDummy) { object3d = AppendDummy(scene, node, parent); } } foreach (Node children in node.Children) { AppendObject3D(scene, children, object3d); } return null; }