protected void LinkMeshToSkeleton(FbxScene scene, FbxNode meshNode, FbxNode skelRootNode) { FbxNode limb1 = skelRootNode.GetChild(0); FbxNode limb2 = limb1.GetChild(0); FbxCluster rootCluster = FbxCluster.Create(scene, "RootCluster"); rootCluster.SetLink(skelRootNode); rootCluster.SetLinkMode(FbxCluster.ELinkMode.eTotalOne); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { rootCluster.AddControlPointIndex(4 * i + j, 1.0 - 0.25 * i); } } FbxCluster limb1Cluster = FbxCluster.Create(scene, "Limb1Cluster"); limb1Cluster.SetLink(limb1); limb1Cluster.SetLinkMode(FbxCluster.ELinkMode.eTotalOne); for (int i = 1; i < 6; i++) { for (int j = 0; j < 4; j++) { limb1Cluster.AddControlPointIndex(4 * i + j, (i == 1 || i == 5 ? 0.25 : 0.5)); } } FbxCluster limb2Cluster = FbxCluster.Create(scene, "Limb2Cluster"); limb2Cluster.SetLink(limb2); limb2Cluster.SetLinkMode(FbxCluster.ELinkMode.eTotalOne); for (int i = 3; i < 7; i++) { for (int j = 0; j < 4; j++) { limb2Cluster.AddControlPointIndex(4 * i + j, 0.25 * (i - 2)); } } FbxAMatrix globalTransform = meshNode.EvaluateGlobalTransform(); rootCluster.SetTransformMatrix(globalTransform); limb1Cluster.SetTransformMatrix(globalTransform); limb2Cluster.SetTransformMatrix(globalTransform); rootCluster.SetTransformLinkMatrix(skelRootNode.EvaluateGlobalTransform()); limb1Cluster.SetTransformLinkMatrix(limb1.EvaluateGlobalTransform()); limb2Cluster.SetTransformLinkMatrix(limb2.EvaluateGlobalTransform()); FbxSkin skin = FbxSkin.Create(scene, "Skin"); skin.AddCluster(rootCluster); skin.AddCluster(limb1Cluster); skin.AddCluster(limb2Cluster); meshNode.GetMesh().AddDeformer(skin); }
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); }