Matrix GetParentBoneMatrix(FLVER2 f, FLVER.Bone bone) { FLVER.Bone parent = bone; var boneParentMatrix = Matrix.Identity; do { boneParentMatrix *= Matrix.CreateScale(parent.Scale.X, parent.Scale.Y, parent.Scale.Z); boneParentMatrix *= Matrix.CreateRotationX(parent.Rotation.X); boneParentMatrix *= Matrix.CreateRotationZ(parent.Rotation.Z); boneParentMatrix *= Matrix.CreateRotationY(parent.Rotation.Y); //boneParentMatrix *= Matrix.CreateRotationY(parent.EulerRadian.Y); //boneParentMatrix *= Matrix.CreateRotationZ(parent.EulerRadian.Z); //boneParentMatrix *= Matrix.CreateRotationX(parent.EulerRadian.X); boneParentMatrix *= Matrix.CreateTranslation(parent.Translation.X, parent.Translation.Y, parent.Translation.Z); //boneParentMatrix *= Matrix.CreateScale(parent.Scale); if (parent.ParentIndex >= 0) { parent = f.Bones[parent.ParentIndex]; } else { parent = null; } }while (parent != null); return(boneParentMatrix); }
public static NMatrix GetNMatrix(this FLVER.Bone b) { return(NMatrix.CreateScale(b.Scale) * NMatrix.CreateRotationX(b.Rotation.X) * NMatrix.CreateRotationZ(b.Rotation.Z) * NMatrix.CreateRotationY(b.Rotation.Y) * NMatrix.CreateTranslation(b.Translation)); }
public DsBone(FLVER.Bone flverBone, FLVER2 flver) { HkxBoneIndex = -1; Name = flverBone.Name; ParentName = flverBone.ParentIndex > 0 ? flver.Bones[flverBone.ParentIndex].Name : null; }
public static FLVER.Bone GetParent(this FLVER.Bone b, List <FLVER.Bone> bones) { if (b.ParentIndex >= 0 && b.ParentIndex < bones.Count) { return(bones[b.ParentIndex]); } else { return(null); } }
public DsBoneData(DsBone bone, FLVER.Bone flverBone, FbxScene scene) { FbxSkeleton fbxBone = FbxSkeleton.Create(scene, bone.Name + "Bone"); fbxBone.SetSkeletonType(flverBone.ChildIndex >= 0 ? FbxSkeleton.EType.eLimbNode : FbxSkeleton.EType.eEffector); fbxBone.Size.Set(flverBone.Translation.Length()); exportData = fbxBone.CreateExportDataWithScene(bone, scene); this.flverBone = flverBone; }
public static NMatrix GetAbsoluteNMatrix(this FLVER.Bone b, List <FLVER.Bone> bones) { NMatrix result = NMatrix.Identity; var parentBone = b; while (parentBone != null) { var m = parentBone.GetNMatrix(); result *= m; parentBone = parentBone.GetParent(bones); } return(result); }
public FlverBoneInfo(FLVER.Bone bone, List <FLVER.Bone> boneList) { Matrix GetBoneMatrix(SoulsFormats.FLVER.Bone b) { SoulsFormats.FLVER.Bone parentBone = b; var result = Matrix.Identity; do { result *= Matrix.CreateScale(parentBone.Scale.X, parentBone.Scale.Y, parentBone.Scale.Z); result *= Matrix.CreateRotationX(parentBone.Rotation.X); result *= Matrix.CreateRotationZ(parentBone.Rotation.Z); result *= Matrix.CreateRotationY(parentBone.Rotation.Y); result *= Matrix.CreateTranslation(parentBone.Translation.X, parentBone.Translation.Y, parentBone.Translation.Z); if (parentBone.ParentIndex >= 0) { parentBone = boneList[parentBone.ParentIndex]; } else { parentBone = null; } }while (parentBone != null); return(result); } ReferenceMatrix = GetBoneMatrix(bone); Name = bone.Name; if (bone.Unk3C == 0) { BonePrim = new DbgPrimWireBone(bone.Name, new Transform(ReferenceMatrix), DBG.COLOR_FLVER_BONE) { Category = DbgPrimCategory.FlverBone, }; BoundingBoxPrim = new DbgPrimWireBox(Transform.Default, new Vector3(bone.BoundingBoxMin.X, bone.BoundingBoxMin.Y, bone.BoundingBoxMin.Z), new Vector3(bone.BoundingBoxMax.X, bone.BoundingBoxMax.Y, bone.BoundingBoxMax.Z), DBG.COLOR_FLVER_BONE_BBOX) { Category = DbgPrimCategory.FlverBoneBoundingBox, }; } }
private void SetBoneBoundingBox(FLVER2 f, FLVER.Bone b) { var bb = GetBoundingBox(GetVerticesParentedToBone(f, b).Select(v => new Vector3(v.Position.X, v.Position.Y, v.Position.Z)).ToList()); if (bb.Max.LengthSquared() != 0 || bb.Min.LengthSquared() != 0) { var matrix = GetParentBoneMatrix(f, b); b.BoundingBoxMin = Vector3.Transform(bb.Min, Matrix.Invert(matrix)).ToNumerics(); b.BoundingBoxMax = Vector3.Transform(bb.Max, Matrix.Invert(matrix)).ToNumerics(); } else { b.BoundingBoxMin = new System.Numerics.Vector3(float.MaxValue, float.MaxValue, float.MaxValue); b.BoundingBoxMax = new System.Numerics.Vector3(float.MinValue, float.MinValue, float.MinValue); } }
private List <FLVER.Vertex> GetVerticesParentedToBone(FLVER2 f, FLVER.Bone b) { var result = new List <FLVER.Vertex>(); foreach (var sm in f.Meshes) { foreach (var v in sm.Vertices) { var bonesReferencedByThisShit = GetAllBonesReferencedByVertex(f, sm, v); if (bonesReferencedByThisShit.Contains(b)) { result.Add(v); } } } return(result); }
public static void UpdateBoundingBox(this FLVER.Bone b, List <FLVER.Bone> bones, NVector3 vertexPos) { var boneAbsoluteMatrix = b.GetAbsoluteNMatrix(bones); if (NMatrix.Invert(boneAbsoluteMatrix, out NMatrix invertexBoneMat)) { var posForBBox = NVector3.Transform(vertexPos, invertexBoneMat); var minX = Math.Min(b.BoundingBoxMin.X, posForBBox.X); var minY = Math.Min(b.BoundingBoxMin.Y, posForBBox.Y); var minZ = Math.Min(b.BoundingBoxMin.Z, posForBBox.Z); var maxX = Math.Max(b.BoundingBoxMax.X, posForBBox.X); var maxY = Math.Max(b.BoundingBoxMax.Y, posForBBox.Y); var maxZ = Math.Max(b.BoundingBoxMax.Z, posForBBox.Z); b.BoundingBoxMin = new NVector3(minX, minY, minZ); b.BoundingBoxMax = new NVector3(maxX, maxY, maxZ); } //ErrorTODO: when this fails, else {} }
public DsSkeleton ParseSkeleton() { List <DsBoneData> boneDatas = bones.Select( bone => { FLVER.Bone flverBone = Flver.Bones.Single(flverBone => flverBone.Name == bone.Name); return(new DsBoneData(bone, flverBone, Scene)); } ).ToList(); //exportData.FbxNode.LclTranslation.Set(flverBone.Translation.ToFbxDouble3()); //exportData.FbxNode.LclRotation.Set(flverBone.Rotation.ToFbxDouble3()); //exportData.FbxNode.LclScaling.Set(flverBone.Scale.ToFbxDouble3()); for (int boneIndex = 0; boneIndex < bones.Count; ++boneIndex) { DsBoneData boneData = boneDatas[boneIndex]; DsBoneData parentBoneData = boneDatas.Find(parentBoneData => parentBoneData.exportData.SoulsData.Name == boneData.exportData.SoulsData.ParentName); boneData.SetParent(parentBoneData); } Func <DsBoneData, Matrix4x4> calculateTransform = (boneData) => { Matrix4x4 rawGlobalTransform = CalculateGlobalTransform(boneData, Flver, hkaSkeleton); var preFixupMatrix = Matrix4x4.CreateRotationZ((float)(-Math.PI / 2)); // Matrix4x4.CreateScale(new Vector3(1, 1, 1)); // * Matrix4x4.CreateRotationX((float)(-Math.PI)) * Matrix4x4.CreateRotationY((float)(-Math.PI / 2)) * Matrix4x4.CreateRotationZ((float)(Math.PI / 2)); var postFixupMatrix = Matrix4x4.CreateScale(1, 1, 1); // Matrix4x4.CreateRotationZ((float)(Math.PI / 2)); // Matrix4x4.CreateScale(new Vector3(1, 1, 1));// * Matrix4x4.CreateRotationX((float)(-Math.PI / 2)) * Matrix4x4.CreateRotationZ((float)(Math.PI / 2)); if (boneData.parent == null) { Matrix4x4 preFixupParent = Matrix4x4.Identity; Matrix4x4 postFixupParent = Matrix4x4.Identity; // * Matrix4x4.CreateRotationX((float)(-Math.PI / 2)) * Matrix4x4.CreateRotationZ((float)(Math.PI / 2)); ; //* Matrix4x4.CreateScale(1,1,-1); preFixupMatrix *= preFixupParent; postFixupMatrix *= postFixupParent; } else { } //var t = rawGlobalTransform.Translation; //t.Z = -t.Z; //rawGlobalTransform.Translation = t; var fixedTransform = preFixupMatrix * rawGlobalTransform * postFixupMatrix; var btr = new NewBlendableTransform(fixedTransform); btr.Translation.Z = -btr.Translation.Z; btr.Rotation.X = -btr.Rotation.X; btr.Rotation.Y = -btr.Rotation.Y; return(btr.GetMatrix()); }; //Func<DsBoneData, Matrix4x4> calculateParentTransform = (boneData) => //{ // Matrix4x4 rawGlobalTransform = CalculateGlobalTransform(boneData, Flver, hkaSkeleton); // var preFixupMatrix = Matrix4x4.CreateScale(new Vector3(1, 1, 1)); // * Matrix4x4.CreateRotationX((float)(-Math.PI)) * Matrix4x4.CreateRotationY((float)(-Math.PI / 2)) * Matrix4x4.CreateRotationZ((float)(Math.PI / 2)); // var postFixupMatrix = Matrix4x4.CreateScale(new Vector3(1, 1, 1)); // * Matrix4x4.CreateRotationX((float)(-Math.PI / 2)) * Matrix4x4.CreateRotationZ((float)(Math.PI / 2)); // if (boneData.parent == null) // { // postFixupMatrix *= Matrix4x4.CreateRotationX((float)(-Math.PI / 2)) * Matrix4x4.CreateRotationZ((float)(Math.PI / 2)); // } // else // { // //postFixupMatrix *= Matrix4x4.CreateScale(1, 1, -1); // } // return preFixupMatrix * rawGlobalTransform * postFixupMatrix; //}; foreach (var boneData in boneDatas) { var globalTransform = calculateTransform(boneData); if (boneData.parent != null) { var globalParentTransform = calculateTransform(boneData.parent); Matrix4x4 invertedGlobalParentTransform; if (Matrix4x4.Invert(globalParentTransform, out invertedGlobalParentTransform)) { globalTransform *= invertedGlobalParentTransform; } else { throw new Exception(); } } else { } Vector3 scale; Quaternion rotation; Vector3 translation; if (Matrix4x4.Decompose(globalTransform, out scale, out rotation, out translation)) { boneData.exportData.FbxNode.LclTranslation.Set(translation.ToFbxDouble3()); Vector3 euler = rotation.QuaternionToEuler(); boneData.exportData.FbxNode.LclRotation.Set(euler.ToFbxDouble3()); boneData.exportData.FbxNode.LclScaling.Set(scale.ToFbxDouble3()); } else { throw new Exception(); } } //FbxSkeleton skeletonRoot = FbxSkeleton.Create(Scene, "ActualRoot"); //FbxNode skeletonRootNode = skeletonRoot.CreateNode(); foreach (var root in boneDatas.Where(bone => bone.parent == null)) { Scene.GetRootNode().AddChild(root.exportData.FbxNode); } return(new DsSkeleton(null, boneDatas)); }
public DsBone(FLVER.Bone flverBone, FLVER2 flver, HKX.Bone hkxBone, HKX.HKASkeleton hkaSkeleton) : this(flverBone, flver) { HkxBoneIndex = hkaSkeleton.Bones.GetArrayData().Elements.IndexOf(hkxBone); ParentName = InitializeHkxParentName(hkxBone, hkaSkeleton); }
public static FLVERMetaskeleton GenerateFlverMetaskeletonFromRootNode( Node rootNode, Matrix4x4 rootNodeAbsoluteMatrix, float importScale) { var bonesAssimp = new List <Node>(); var skel = new FLVERMetaskeleton(); var dummyAttachBoneNames = new List <string>(); NMatrix matrixScale = NMatrix.CreateScale(importScale, importScale, importScale); // Returns index of bone in master bone list if boneNode is a bone. // Returns -1 if boneNode is a DummyPoly (denoted with a node name starting with "DUMMY_POLY"). int AddBone(Node boneNode, Node parentBoneNode, Matrix4x4 parentAbsoluteMatrix) { short parentBoneIndex = (short)(bonesAssimp.IndexOf(parentBoneNode)); var thisBoneMatrix = boneNode.Transform; var thisNodeAbsoluteMatrix = thisBoneMatrix * parentAbsoluteMatrix; var boneTrans = FLVERBoneTransform.FromMatrix4x4( (parentBoneIndex == -1 ? thisNodeAbsoluteMatrix : thisBoneMatrix), true); if (boneNode.Name.StartsWith("DUMMY_POLY")) { // TODO thisNodeAbsoluteMatrix.Decompose(out Vector3D dummyScale, out Quaternion dummyQuat, out Vector3D dummyTranslation); var dmy = new FLVER.Dummy(); dmy.ParentBoneIndex = parentBoneIndex; dmy.Position = dummyTranslation.ToNumerics(); // Format: "DUMMY_POLY|<RefID>|<AttachBoneName>" // Example: "DUMMY_POLY|220|Spine1" string[] dummyNameParts = boneNode.Name.Split('|'); //ErrorTODO: TryParse dmy.ReferenceID = short.Parse(dummyNameParts[1].Trim()); if (dummyNameParts.Length == 3) { dummyAttachBoneNames.Add(dummyNameParts[2]); } else { dummyAttachBoneNames.Add(null); } //NOTE: Maybe this should be specifiable? I forget what the point of false is here. dmy.UseUpwardVector = true; var sceneRotation = NMatrix.CreateRotationX(boneTrans.Rotation.X) * NMatrix.CreateRotationZ(boneTrans.Rotation.Z) * NMatrix.CreateRotationY(boneTrans.Rotation.Y); dmy.Upward = NVector3.Transform(new NVector3(0, 1, 0), sceneRotation); //TODO: Check if forward vector3 should be 1 or -1; dmy.Forward = NVector3.Transform(new NVector3(0, 0, 1), sceneRotation); skel.DummyPoly.Add(dmy); return(-1); } else { bonesAssimp.Add(boneNode); int thisBoneIndex = bonesAssimp.Count - 1; var flverBone = new FLVER.Bone(); if (parentBoneNode != null) { flverBone.ParentIndex = parentBoneIndex; } flverBone.Name = boneNode.Name; flverBone.BoundingBoxMin = new NVector3(float.MaxValue, float.MaxValue, float.MaxValue); flverBone.BoundingBoxMax = new NVector3(float.MinValue, float.MinValue, float.MinValue); flverBone.Translation = boneTrans.Translation * importScale; flverBone.Rotation = boneTrans.Rotation; flverBone.Scale = boneTrans.Scale; skel.Bones.Add(flverBone); List <int> childBoneIndices = new List <int>(); foreach (var c in boneNode.Children) { int cIndex = AddBone(c, boneNode, thisNodeAbsoluteMatrix); //cIndex will be -1 if the child node was a DummyPoly instead of a bone. if (cIndex >= 0) { childBoneIndices.Add(cIndex); } } if (childBoneIndices.Count > 0) { flverBone.ChildIndex = (short)childBoneIndices[0]; for (int i = 0; i < childBoneIndices.Count; i++) { var thisChildBone = skel.Bones[childBoneIndices[i]]; if (i == 0) { thisChildBone.PreviousSiblingIndex = -1; } else { thisChildBone.PreviousSiblingIndex = (short)(childBoneIndices[i - 1]); } if (i == childBoneIndices.Count - 1) { thisChildBone.NextSiblingIndex = -1; } else { thisChildBone.NextSiblingIndex = (short)(childBoneIndices[i + 1]); } } } return(thisBoneIndex); } } //if (rootNode.Children == null) // throw new InvalidDataException("Assimp scene has no heirarchy."); var root = rootNode; //var master = root.Children[0]; //foreach (var c in root.Children) //{ // AddBone(c, null, root.Transform * rootNodeAbsoluteMatrix); //} AddBone(root, null, rootNodeAbsoluteMatrix); // Apply parent bone transforms to DummyPoly foreach (var d in skel.DummyPoly) { if (d.ParentBoneIndex >= 0) { var parentMat = skel.Bones[d.ParentBoneIndex].GetAbsoluteNMatrix(skel.Bones); d.Position = NVector3.Transform(d.Position, parentMat); d.Upward = NVector3.TransformNormal(d.Upward, parentMat); d.Forward = NVector3.TransformNormal(d.Forward, parentMat); } } return(skel); }
protected override FbxSkin GenerateFbx() { MeshExportData meshData = Souls.meshData.SoulsData; ICollection <BoneIndexToWeightPair> rawBoneDeformerData = new List <BoneIndexToWeightPair>(); for (int vertexIndex = 0; vertexIndex < meshData.mesh.Vertices.Count; ++vertexIndex) { FLVER.Vertex vertex = meshData.mesh.Vertices[vertexIndex]; const int maxVertexDeformations = 4; for (int vertexDeformationIndex = 0; vertexDeformationIndex < maxVertexDeformations; ++vertexDeformationIndex) { BoneIndexToWeightPair weightData = new BoneIndexToWeightPair() { flverBoneIndex = vertex.BoneIndices[vertexDeformationIndex], boneWeight = vertex.BoneWeights[vertexDeformationIndex], vertexIndex = vertexIndex }; if (weightData.flverBoneIndex > 0 && weightData.boneWeight > 0) { rawBoneDeformerData.Add(weightData); } } } foreach (var ddd in rawBoneDeformerData.GroupBy(boneDeformerData => boneDeformerData.vertexIndex).Select(boneDeformedGroup => (vertexIndex: boneDeformedGroup.Key, affectingBonesCount: boneDeformedGroup.Count())).Where((ddd) => ddd.affectingBonesCount > 4)) { System.Console.WriteLine($"Vertex {ddd.vertexIndex} : {ddd.affectingBonesCount}"); } foreach (var ddd in rawBoneDeformerData.GroupBy(boneDeformedData => boneDeformedData.flverBoneIndex).Select(boneDeformerGroup => (boneIndex: boneDeformerGroup.Key, affectingVerticesCount: boneDeformerGroup.Count(), uniqueAffectingVerticesCount: boneDeformerGroup.Select(boneDeformerData => boneDeformerData.vertexIndex).Distinct().Count()))) { if (ddd.affectingVerticesCount != ddd.uniqueAffectingVerticesCount) { System.Console.WriteLine($"Bone {ddd.boneIndex} : vertices {ddd.affectingVerticesCount} : unique {ddd.uniqueAffectingVerticesCount}"); } } FbxSkin skin = FbxSkin.Create(Owner, meshData.meshRoot.Name + "_Skin"); System.Console.WriteLine($"Generating {meshData.meshRoot.Name}"); foreach (var deformerData in rawBoneDeformerData.ToLookup(boneDeformerData => boneDeformerData.flverBoneIndex)) { FLVER2 flver = Souls.flver; FLVER.Bone flverBone = flver.Bones[deformerData.Key]; DsBoneData boneData = Souls.skeleton.boneDatas.Single(boneData => boneData.flverBone == flverBone); //System.Console.WriteLine($"Exporting {deformerData.Key} : {flverBone.Name} with {deformerData.Count(weight=>weight.boneWeight > 0)} vertices"); FbxCluster boneCluster = FbxCluster.Create(skin, meshData.meshRoot.Name + "_" + boneData.exportData.SoulsData.Name + "_Cluster"); boneCluster.SetLink(boneData.exportData.FbxNode); boneCluster.SetLinkMode(FbxCluster.ELinkMode.eTotalOne); boneCluster.SetControlPointIWCount(deformerData.Count()); boneCluster.SetTransformMatrix(Souls.meshData.FbxNode.EvaluateGlobalTransform()); boneCluster.SetTransformLinkMatrix(boneData.exportData.FbxNode.EvaluateGlobalTransform()); foreach (BoneIndexToWeightPair boneWeightPair in deformerData) { boneCluster.AddControlPointIndex(boneWeightPair.vertexIndex, boneWeightPair.boneWeight); //Console.WriteLine("Bone {0} has vertex {1} with weight {2}", flverBone.Name, boneWeightPair.vertexIndex, boneWeightPair.boneWeight); } skin.AddCluster(boneCluster); } //foreach (var dd in rawBoneDeformerData.GroupBy(biwp => biwp.vertexIndex).Where(group => group.Count() > 2)) //{ //System.Console.WriteLine($"Vertex {dd.Key} : {dd.Count()}"); //} //var set = new HashSet<int>(); //for (int vertexIndex = 0; vertexIndex < meshData.mesh.Vertices.Count; ++vertexIndex) //{ // if (!rawBoneDeformerData.Any(x=>x.vertexIndex == vertexIndex)) // { // set.Add(vertexIndex); // } //} //System.Console.WriteLine($"Total {set.Count} unweighted nodes"); return(skin); }