public static Assimp.Matrix4x4 AssimpCalculateInverseMatrix(STBone bone) { Assimp.Matrix4x4 transf; //Get parent transform for a smooth matrix if (bone.Parent != null && bone.Parent is STBone) { transf = AssimpCalculateInverseMatrix((STBone)bone.Parent); } else { transf = Assimp.Matrix4x4.Identity; } //Now calculate the matrix with TK matrices var trans = Assimp.Matrix4x4.FromTranslation(new Vector3D(bone.position[0], bone.position[1], bone.position[2])); var scale = Assimp.Matrix4x4.FromScaling(new Vector3D(bone.scale[0], bone.scale[1], bone.scale[2])); var rotX = Assimp.Matrix4x4.FromRotationX(bone.rotation[0]); var rotY = Assimp.Matrix4x4.FromRotationY(bone.rotation[1]); var rotZ = Assimp.Matrix4x4.FromRotationZ(bone.rotation[2]); var result = scale * (rotX * rotY * rotZ) * trans; result.Inverse(); return(transf); }
public static Matrix4x4 GetBoneMatrix(STBone bone) { var pos = Matrix4x4.FromTranslation(new Vector3D(bone.position[0], bone.position[1], bone.position[2])); var rotx = Matrix4x4.FromRotationX(bone.rotation[0]); var roty = Matrix4x4.FromRotationY(bone.rotation[1]); var rotz = Matrix4x4.FromRotationZ(bone.rotation[2]); var sca = Matrix4x4.FromScaling(new Vector3D(bone.scale[0], bone.scale[1], bone.scale[2])); return(sca * (rotx * roty * rotz) * pos); }
private void SaveBones(Node parentBone, STBone bone, STSkeleton skeleton) { Node boneNode = new Node(bone.Text); parentBone.Children.Add(boneNode); boneNode.Transform = AssimpHelper.GetBoneMatrix(bone); foreach (STBone child in bone.GetChildren()) { SaveBones(boneNode, child, skeleton); } }
public void update(bool reset = false) { Updated = true; List <STBone> nodesToProcess = new List <STBone>(); // Add all root nodes from the VBN foreach (STBone b in bones) { if (b.Parent == null) { nodesToProcess.Add(b); } } // some special processing for the root bones before we start foreach (STBone b in nodesToProcess) { b.transform = Matrix4.CreateScale(b.sca) * Matrix4.CreateFromQuaternion(b.rot) * Matrix4.CreateTranslation(b.pos); // scale down the model in its entirety only when mid-animation (i.e. reset == false) if (!reset) { b.transform *= Matrix4.CreateScale(1); } } // Process as a tree from the root node's children and beyond. These // all use the same processing, unlike the root nodes. int numRootNodes = nodesToProcess.Count; for (int i = 0; i < numRootNodes; i++) { nodesToProcess.AddRange(nodesToProcess[0].GetChildren()); nodesToProcess.RemoveAt(0); } while (nodesToProcess.Count > 0) { // DFS STBone currentBone = nodesToProcess[0]; nodesToProcess.RemoveAt(0); nodesToProcess.AddRange(currentBone.GetChildren()); // Process this node currentBone.transform = Matrix4.CreateScale(currentBone.sca) * Matrix4.CreateFromQuaternion(currentBone.rot) * Matrix4.CreateTranslation(currentBone.pos); if (currentBone.Parent != null) { currentBone.transform = currentBone.transform * ((STBone)currentBone.Parent).transform; } } }
public List <STBone> getBoneTreeOrder() { List <STBone> bone = new List <STBone>(); Queue <STBone> q = new Queue <STBone>(); q.Enqueue(bones[0]); while (q.Count > 0) { STBone b = q.Dequeue(); foreach (STBone bo in b.GetChildren()) { q.Enqueue(bo); } bone.Add(b); } return(bone); }
public void SetKeyFromBone(float frame, STBone bone) { Vector3 rot = ANIM.quattoeul(bone.rot); if (rot.X != bone.rotation[0] || rot.Y != bone.rotation[1] || rot.Z != bone.rotation[2]) { XROT.GetKeyFrame(frame).Value = bone.rot.X; YROT.GetKeyFrame(frame).Value = bone.rot.Y; ZROT.GetKeyFrame(frame).Value = bone.rot.Z; WROT.GetKeyFrame(frame).Value = bone.rot.W; } if (bone.pos.X != bone.position[0] || bone.pos.Y != bone.position[1] || bone.pos.Z != bone.position[2]) { XPOS.GetKeyFrame(frame).Value = bone.pos.X; YPOS.GetKeyFrame(frame).Value = bone.pos.Y; ZPOS.GetKeyFrame(frame).Value = bone.pos.Z; } if (bone.sca.X != bone.scale[0] || bone.sca.Y != bone.scale[1] || bone.sca.Z != bone.scale[2]) { XSCA.GetKeyFrame(frame).Value = bone.sca.X; YSCA.GetKeyFrame(frame).Value = bone.sca.Y; ZSCA.GetKeyFrame(frame).Value = bone.sca.Z; } }
private void CreateByNode(Node node, STSkeleton skeleton, short SmoothIndex, short RigidIndex, bool IsRoot, ref Assimp.Matrix4x4 rootTransform) { Matrix4x4 trafo = node.Transform; Matrix4x4 world = trafo * rootTransform; var transformMat = AssimpHelper.TKMatrix(world); int matchedBoneIndex = skeleton.bones.FindIndex(item => item.Name == node.Name); if (matchedBoneIndex < 0) { tempBoneNodes.Add(node); STBone bone = new STBone(); bone.skeletonParent = skeleton; skeleton.bones.Add(bone); bone.Text = node.Name; bone.SmoothMatrixIndex = (short)skeleton.bones.IndexOf(bone); bone.RigidMatrixIndex = -1; //Todo calculate these STConsole.WriteLine($"-".Repeat(30)); STConsole.WriteLine($"Processing Bone {bone.Text}"); STConsole.WriteLine($"SmoothMatrixIndex {bone.SmoothMatrixIndex}"); STConsole.WriteLine($"RigidMatrixIndex {bone.RigidMatrixIndex}"); STConsole.WriteLine($"Transform Matrix {transformMat}"); STConsole.WriteLine($"-".Repeat(30)); if (IsRoot) { bone.parentIndex = -1; transformMat = AssimpHelper.TKMatrix(world * Matrix4x4.FromRotationX(MathHelper.DegreesToRadians(BoneRotation))); } else { if (tempBoneNodes.Contains(node.Parent)) { bone.parentIndex = tempBoneNodes.IndexOf(node.Parent); } } var scale = transformMat.ExtractScale(); var rotation = transformMat.ExtractRotation(); var position = transformMat.ExtractTranslation(); var rotEular = AssimpHelper.ToEular(rotation); bone.position = new float[] { position.X, position.Y, position.Z }; bone.scale = new float[] { scale.X, scale.Y, scale.Z }; bone.rotation = new float[] { rotEular.X, rotEular.Y, rotEular.Z, 0 }; } else { STConsole.WriteLine($"Duplicate node name found for bone {node.Name}!", Color.Red); } foreach (Node child in node.Children) { CreateByNode(child, skeleton, SmoothIndex, RigidIndex, false, ref rootTransform); } }
private Mesh SaveMesh(STGenericObject genericObj, int index, STSkeleton skeleton, List <int> NodeArray) { //Assimp is weird so use mesh_# for the name. We'll change it back after save Mesh mesh = new Mesh($"mesh_{ index }", PrimitiveType.Triangle); mesh.MaterialIndex = genericObj.MaterialIndex; List <Vector3D> textureCoords0 = new List <Vector3D>(); List <Vector3D> textureCoords1 = new List <Vector3D>(); List <Vector3D> textureCoords2 = new List <Vector3D>(); List <Color4D> vertexColors = new List <Color4D>(); int vertexID = 0; foreach (Vertex v in genericObj.vertices) { mesh.Vertices.Add(new Vector3D(v.pos.X, v.pos.Y, v.pos.Z)); mesh.Normals.Add(new Vector3D(v.nrm.X, v.nrm.Y, v.nrm.Z)); textureCoords0.Add(new Vector3D(v.uv0.X, v.uv0.Y, 0)); textureCoords1.Add(new Vector3D(v.uv1.X, v.uv1.Y, 0)); textureCoords2.Add(new Vector3D(v.uv2.X, v.uv2.Y, 0)); vertexColors.Add(new Color4D(v.col.X, v.col.Y, v.col.Z, v.col.W)); mesh.TextureCoordinateChannels[0] = textureCoords0; mesh.TextureCoordinateChannels[1] = textureCoords1; mesh.TextureCoordinateChannels[2] = textureCoords2; mesh.VertexColorChannels[0] = vertexColors; if (skeleton != null) { for (int j = 0; j < v.boneIds.Count; j++) { if (j < genericObj.VertexSkinCount) { //Get the bone via the node array and bone index from the vertex STBone STbone = skeleton.bones[NodeArray[v.boneIds[j]]]; //Find the index of a bone. If it doesn't exist then we add it int boneInd = mesh.Bones.FindIndex(x => x.Name == STbone.Text); if (boneInd == -1) { var matrices = Switch_Toolbox.Library.IO.MatrixExenstion.CalculateInverseMatrix(STbone); //Set the inverse matrix Matrix4x4 transform = matrices.inverse.FromNumerics(); //Create a new assimp bone Bone bone = new Bone(); bone.Name = STbone.Text; bone.OffsetMatrix = STbone.invert.ToMatrix4x4(); mesh.Bones.Add(bone); BoneNames.Add(bone.Name); boneInd = mesh.Bones.IndexOf(bone); //Set the index of the bone for the vertex weight } int MinWeightAmount = 0; //Check if the max amount of weights is higher than the current bone id if (v.boneWeights.Count > j && v.boneWeights[j] > MinWeightAmount) { if (v.boneWeights[j] <= 1) { mesh.Bones[boneInd].VertexWeights.Add(new VertexWeight(vertexID, v.boneWeights[j])); } else { mesh.Bones[boneInd].VertexWeights.Add(new VertexWeight(vertexID, 1)); } } else if (v.boneWeights.Count == 0 || v.boneWeights[j] > MinWeightAmount) { mesh.Bones[boneInd].VertexWeights.Add(new VertexWeight(vertexID, 1)); } } } } vertexID++; } List <int> faces = genericObj.lodMeshes[genericObj.DisplayLODIndex].faces; for (int f = 0; f < faces.Count; f++) { mesh.Faces.Add(new Face(new int[] { faces[f++], faces[f++], faces[f] })); } mesh.TextureCoordinateChannels.SetValue(textureCoords0, 0); return(mesh); }
public void NextFrame(STSkeleton skeleton, bool isChild = false) { if (Frame >= FrameCount) { return; } if (Frame == 0 && !isChild) { skeleton.reset(); } foreach (object child in Children) { if (child is Animation) { ((Animation)child).SetFrame(Frame); ((Animation)child).NextFrame(skeleton, isChild: true); } } bool Updated = false; // no need to update skeleton of animations that didn't change foreach (KeyNode node in Bones) { // Get Skeleton Node STBone b = null; b = skeleton.getBone(node.Text); if (b == null) { continue; } Updated = true; b.pos.X = node.XPOS.GetValue(Frame); b.pos.Y = node.YPOS.GetValue(Frame); b.pos.Z = node.ZPOS.GetValue(Frame); if (node.XSCA.HasAnimation()) { b.sca.X = node.XSCA.GetValue(Frame); } else { b.sca.X = 1; } if (node.YSCA.HasAnimation()) { b.sca.Y = node.YSCA.GetValue(Frame); } else { b.sca.Y = 1; } if (node.ZSCA.HasAnimation()) { b.sca.Z = node.ZSCA.GetValue(Frame); } else { b.sca.Z = 1; } if (node.XROT.HasAnimation() || node.YROT.HasAnimation() || node.ZROT.HasAnimation()) { if (node.RotType == RotationType.QUATERNION) { KeyFrame[] x = node.XROT.GetFrame(Frame); KeyFrame[] y = node.YROT.GetFrame(Frame); KeyFrame[] z = node.ZROT.GetFrame(Frame); KeyFrame[] w = node.WROT.GetFrame(Frame); Quaternion q1 = new Quaternion(x[0].Value, y[0].Value, z[0].Value, w[0].Value); Quaternion q2 = new Quaternion(x[1].Value, y[1].Value, z[1].Value, w[1].Value); if (x[0].Frame == Frame) { b.rot = q1; } else if (x[1].Frame == Frame) { b.rot = q2; } else { b.rot = Quaternion.Slerp(q1, q2, (Frame - x[0].Frame) / (x[1].Frame - x[0].Frame)); } } else if (node.RotType == RotationType.EULER) { float x = node.XROT.HasAnimation() ? node.XROT.GetValue(Frame) : b.rotation[0]; float y = node.YROT.HasAnimation() ? node.YROT.GetValue(Frame) : b.rotation[1]; float z = node.ZROT.HasAnimation() ? node.ZROT.GetValue(Frame) : b.rotation[2]; b.rot = EulerToQuat(z, y, x); } } } Frame += 1f; if (Frame >= FrameCount) { Frame = 0; } if (!isChild && Updated) { skeleton.update(); } }
public static Syroot.Maths.Matrix3x4 CalculateInverseMatrix(STBone bone) { return(FromAssimpMatrix(AssimpCalculateInverseMatrix(bone))); }
private void SaveMeshes(Scene scene, STGenericModel model, STSkeleton skeleton, string FileName, List <int> NodeArray) { int MeshIndex = 0; foreach (var obj in model.Nodes[0].Nodes) { var genericObj = (STGenericObject)obj; Mesh mesh = new Mesh(genericObj.Text, PrimitiveType.Triangle); mesh.MaterialIndex = genericObj.MaterialIndex; List <Vector3D> textureCoords0 = new List <Vector3D>(); List <Vector3D> textureCoords1 = new List <Vector3D>(); List <Vector3D> textureCoords2 = new List <Vector3D>(); List <Color4D> vertexColors = new List <Color4D>(); int vertexID = 0; foreach (Vertex v in genericObj.vertices) { mesh.Vertices.Add(new Vector3D(v.pos.X, v.pos.Y, v.pos.Z)); mesh.Normals.Add(new Vector3D(v.nrm.X, v.nrm.Y, v.nrm.Z)); textureCoords0.Add(new Vector3D(v.uv0.X, v.uv0.Y, 0)); textureCoords1.Add(new Vector3D(v.uv1.X, v.uv1.Y, 0)); textureCoords2.Add(new Vector3D(v.uv2.X, v.uv2.Y, 0)); vertexColors.Add(new Color4D(v.col.X, v.col.Y, v.col.Z, v.col.W)); mesh.TextureCoordinateChannels[0] = textureCoords0; mesh.TextureCoordinateChannels[1] = textureCoords1; mesh.TextureCoordinateChannels[2] = textureCoords2; mesh.VertexColorChannels[0] = vertexColors; for (int j = 0; j < v.boneIds.Count; j++) { if (j < genericObj.VertexSkinCount) { //Get the bone via the node array and bone index from the vertex STBone STbone = skeleton.bones[NodeArray[v.boneIds[j]]]; //Find the index of a bone. If it doesn't exist then we add it int boneInd = mesh.Bones.FindIndex(x => x.Name == STbone.Text); if (boneInd == -1) { var matrices = Switch_Toolbox.Library.IO.MatrixExenstion.CalculateInverseMatrix(STbone); //Set the inverse matrix Matrix4x4 transform = matrices.inverse.FromNumerics(); //Create a new assimp bone Bone bone = new Bone(); bone.Name = STbone.Text; bone.OffsetMatrix = transform; mesh.Bones.Add(bone); BoneNames.Add(bone.Name); boneInd = mesh.Bones.IndexOf(bone); //Set the index of the bone for the vertex weight } //Check if the max amount of weights is higher than the current bone id if (v.boneWeights.Count > j) { if (v.boneWeights[j] <= 1) { mesh.Bones[boneInd].VertexWeights.Add(new VertexWeight(vertexID, v.boneWeights[j])); } else { mesh.Bones[boneInd].VertexWeights.Add(new VertexWeight(vertexID, 1)); } } else { mesh.Bones[boneInd].VertexWeights.Add(new VertexWeight(vertexID, 1)); } } } vertexID++; } List <int> faces = genericObj.lodMeshes[genericObj.DisplayLODIndex].faces; for (int f = 0; f < faces.Count; f++) { mesh.Faces.Add(new Face(new int[] { faces[f++], faces[f++], faces[f] })); } mesh.TextureCoordinateChannels.SetValue(textureCoords0, 0); scene.Meshes.Add(mesh); MeshIndex++; } Node geomNode = new Node(Path.GetFileNameWithoutExtension(FileName), scene.RootNode); for (int ob = 0; ob < scene.MeshCount; ob++) { geomNode.MeshIndices.Add(ob); } scene.RootNode.Children.Add(geomNode); }