public static SBSkeleton Open(string FileName, SBScene Scene) { SsbhFile File; if (Ssbh.TryParseSsbhFile(FileName, out File)) { if (File is Skel skel) { var Skeleton = new SBSkeleton(); Scene.Skeleton = Skeleton; Dictionary <int, SBBone> idToBone = new Dictionary <int, SBBone>(); Dictionary <SBBone, int> needParent = new Dictionary <SBBone, int>(); foreach (var b in skel.BoneEntries) { SBBone bone = new SBBone(); bone.Name = b.Name; bone.Type = b.Type; bone.Transform = Skel_to_TKMatrix(skel.Transform[b.Id]); idToBone.Add(b.Id, bone); if (b.ParentId == -1) { Skeleton.AddRoot(bone); } else { needParent.Add(bone, b.ParentId); } } foreach (var v in needParent) { v.Key.Parent = idToBone[v.Value]; } return(Skeleton); } } return(null); }
public static void Open(string FileName, SBScene Scene) { ISSBH_File File; if (SSBH.TryParseSSBHFile(FileName, out File)) { if (File is SKEL skel) { var Skeleton = new SBSkeleton(); Scene.Skeleton = Skeleton; Dictionary <int, SBBone> idToBone = new Dictionary <int, SBBone>(); Dictionary <SBBone, int> needParent = new Dictionary <SBBone, int>(); foreach (var b in skel.BoneEntries) { SBBone bone = new SBBone(); bone.Name = b.Name; bone.Type = b.Type; bone.Transform = Skel_to_TKMatrix(skel.Transform[b.ID]); idToBone.Add(b.ID, bone); if (b.ParentID == -1) { Skeleton.AddRoot(bone); } else { needParent.Add(bone, b.ParentID); } } foreach (var v in needParent) { v.Key.Parent = idToBone[v.Value]; } } } }
public IOModel ImportIOModel(string FileName) { IOModel model = new IOModel(); SBSkeleton skeleton = new SBSkeleton(); model.Skeleton = skeleton; var test = Fbx.FbxIO.ReadBinary(FileName); if (test.Version != Fbx.FbxVersion.v7_4) { throw new NotSupportedException($"Only FBX version 7.4 is currently supported: Imported version = {test.Version}"); } // global settings float Scale = 1; // read global settings var settings = test.GetNodesByName("GlobalSettings"); if (settings.Length != 0) { var prop70 = settings[0].GetNodesByName("Properties70"); if (prop70.Length != 0) { foreach (var property in prop70[0].Nodes) { if (property == null) { continue; } if (property.Properties.Count > 0 && property.Name == "P") { //TODO: this is inaccurate... //if (property.Properties[0].Equals("UnitScaleFactor")) // Scale = (float)(double)property.Properties[4]; } } } } FbxAccessor accessor = new FbxAccessor(FileName); //Bones var limbs = accessor.GetLimbNodes(); SBConsole.WriteLine($"Limb Node Count: {limbs.Length}"); foreach (var limb in limbs) { skeleton.AddRoot(ConvertLimbToSBBone(limb)); } foreach (var root in skeleton.Roots) { root.Scale *= Scale; } // Fast access to bone indices Dictionary <string, int> BoneNameToIndex = new Dictionary <string, int>(); foreach (var b in skeleton.Bones) { BoneNameToIndex.Add(b.Name, skeleton.IndexOfBone(b)); } // Mesh var models = accessor.GetModels(); SBConsole.WriteLine($"Model Node Count: {models.Count}"); int YupAxis = accessor.GetOriginalXAxis(); SBConsole.WriteLine("Yup: " + YupAxis); foreach (var mod in models) { // rotation 90 Matrix4 transform = (ImportSettings.Rotate90 ? Matrix4.CreateRotationX(-90 * DegToRag) : Matrix4.Identity) * GetModelTransform(mod); foreach (var geom in mod.Geometries) { IOMesh mesh = new IOMesh(); mesh.Name = mod.Name; model.Meshes.Add(mesh); // Create Rigging information Vector4[] BoneIndices = new Vector4[geom.Vertices.Length]; Vector4[] BoneWeights = new Vector4[geom.Vertices.Length]; foreach (var deformer in geom.Deformers) { //TODO: this shouldn't happen... if (!BoneNameToIndex.ContainsKey(deformer.Name)) { continue; } int index = BoneNameToIndex[deformer.Name]; for (int i = 0; i < deformer.Indices.Length; i++) { int vertexIndex = deformer.Indices[i]; for (int j = 0; j < 4; j++) { if (BoneWeights[vertexIndex][j] == 0) { BoneIndices[vertexIndex][j] = index; BoneWeights[vertexIndex][j] = (float)deformer.Weights[i]; break; } } } //SBConsole.WriteLine(deformer.Name + " " + deformer.Weights.Length + " " + deformer.Indices.Length + " " + index); } // Explanation: // negative values are used to indicate a stopping point for the face // so every 3rd index needed to be adjusted for (int i = 0; i < geom.Indices.Length; i += 3) { mesh.Indices.Add((uint)i); mesh.Indices.Add((uint)i + 1); mesh.Indices.Add((uint)i + 2); mesh.Vertices.Add(CreateVertex(transform, geom, i, BoneIndices, BoneWeights, Scale)); mesh.Vertices.Add(CreateVertex(transform, geom, i + 1, BoneIndices, BoneWeights, Scale)); mesh.Vertices.Add(CreateVertex(transform, geom, i + 2, BoneIndices, BoneWeights, Scale)); } mesh.HasPositions = true; //SBConsole.WriteLine(geom.Vertices.Length); foreach (var layer in geom.Layers) { switch (layer.Name) { case "LayerElementNormal": case "LayerElementUV": case "LayerElementColor": break; default: SBConsole.WriteLine(layer.Name + " " + layer.ReferenceInformationType + " " + layer.Data.Length + " " + (layer.ReferenceInformationType.Equals("IndexToDirect") ? layer.Indices.Length.ToString() : "")); break; } } mesh.Optimize(); } } return(model); }
public IOModel ImportIOModel(string FileName) { IOModel model = new IOModel(); SBSkeleton skeleton = new SBSkeleton(); Dictionary <int, SBBone> indexToBone = new Dictionary <int, SBBone>(); Dictionary <string, IOMesh> materialToMesh = new Dictionary <string, IOMesh>(); List <SBBone> PostProcessBones = new List <SBBone>(); List <int> boneParents = new List <int>(); string[] lines = File.ReadAllLines(FileName); string CurrentSection = ""; for (int i = 0; i < lines.Length; i++) { string[] args = Regex.Replace(lines[i].Trim(), @"\s+", " ").Split(' '); if (args[0].Equals("end")) { CurrentSection = ""; } else if (args[0].Equals("time")) { } else if (args[0].Equals("nodes")) { CurrentSection = args[0]; } else if (args[0].Equals("skeleton")) { CurrentSection = args[0]; } else if (args[0].Equals("triangles")) { CurrentSection = args[0]; } else { switch (CurrentSection) { case "nodes": var bone = new SBBone(); bone.Name = args[1].Replace("\"", ""); Console.WriteLine(bone.Name + " " + args[2]); boneParents.Add(int.Parse(args[2])); PostProcessBones.Add(bone); indexToBone.Add(int.Parse(args[0]), bone); break; case "skeleton": var skel = PostProcessBones[int.Parse(args[0])]; skel.Transform = Matrix4.Identity; skel.X = float.Parse(args[1]); skel.Y = float.Parse(args[2]); skel.Z = float.Parse(args[3]); skel.RX = float.Parse(args[4]); skel.RY = float.Parse(args[5]); skel.RZ = float.Parse(args[6]); break; case "triangles": string material = args[0]; if (!materialToMesh.ContainsKey(material)) { var iomesh = new IOMesh(); iomesh.HasPositions = true; iomesh.HasNormals = true; iomesh.HasUV0 = true; iomesh.HasBoneWeights = true; iomesh.Name = material; materialToMesh.Add(material, iomesh); } var mesh = materialToMesh[material]; mesh.Vertices.Add(ReadVertex(Regex.Replace(lines[i + 1].Trim(), @"\s+", " ").Split(' '))); mesh.Vertices.Add(ReadVertex(Regex.Replace(lines[i + 2].Trim(), @"\s+", " ").Split(' '))); mesh.Vertices.Add(ReadVertex(Regex.Replace(lines[i + 3].Trim(), @"\s+", " ").Split(' '))); i += 3; break; } } } //PostProcessBones int boneIndex = 0; foreach (var bone in PostProcessBones) { if (boneParents[boneIndex] == -1) { skeleton.AddRoot(bone); } else { bone.Parent = indexToBone[boneParents[boneIndex]]; } boneIndex++; } model.Skeleton = skeleton; // finalize meshes foreach (var pair in materialToMesh) { model.Meshes.Add(pair.Value); pair.Value.Optimize(); SBConsole.WriteLine($"Imported {pair.Key} from SMD"); //finalize rigging for (int i = 0; i < pair.Value.Vertices.Count; i++) { var vertex = pair.Value.Vertices[i]; vertex.BoneIndices.X = model.Skeleton.IndexOfBone(indexToBone[(int)vertex.BoneIndices.X]); vertex.BoneIndices.Y = model.Skeleton.IndexOfBone(indexToBone[(int)vertex.BoneIndices.Y]); vertex.BoneIndices.Z = model.Skeleton.IndexOfBone(indexToBone[(int)vertex.BoneIndices.Z]); vertex.BoneIndices.W = model.Skeleton.IndexOfBone(indexToBone[(int)vertex.BoneIndices.W]); pair.Value.Vertices[i] = vertex; } } return(model); }