public override IOModel GetIOModel() { var iomodel = new IOModel(); iomodel.Skeleton = (SBSkeleton)Skeleton; List <SBHsdBone> bones = new List <SBHsdBone>(); foreach (SBHsdBone bone in Skeleton.Bones) { bones.Add(bone); } Dictionary <HSDStruct, string> tobjToName = new Dictionary <HSDStruct, string>(); foreach (var tex in tobjToSurface) { tex.Value.Name = $"TOBJ_{iomodel.Textures.Count}"; tobjToName.Add(tex.Key, tex.Value.Name); iomodel.Textures.Add(tex.Value); } foreach (SBHsdMesh me in GetMeshObjects()) { var dobj = me.DOBJ; var parent = Skeleton.Bones[0]; foreach (var b in Skeleton.Bones) { if (b is SBHsdBone bone) { if (bone.GetJOBJ().Dobj != null) { if (bone.GetJOBJ().Dobj.List.Contains(dobj)) { parent = b; break; } } } } var iomesh = new IOMesh(); iomesh.Name = me.Name; iomodel.Meshes.Add(iomesh); iomesh.HasPositions = true; iomesh.HasColor = true; iomesh.HasNormals = true; iomesh.HasBoneWeights = true; iomesh.HasUV0 = true; if (dobj.Pobj != null) { foreach (var pobj in dobj.Pobj.List) { var dl = pobj.ToDisplayList(); var vertices = GX_VertexAccessor.GetDecodedVertices(dl, pobj); HSD_Envelope[] bindGroups = null;; if (pobj.EnvelopeWeights != null) { bindGroups = pobj.EnvelopeWeights; } var offset = 0; foreach (var v in dl.Primitives) { List <GX_Vertex> strip = new List <GX_Vertex>(); for (int i = 0; i < v.Count; i++) { strip.Add(vertices[offset + i]); } offset += v.Count; iomesh.Vertices.AddRange(ConvertGXDLtoTriangleList(v.PrimitiveType, SBHsdMesh.GXVertexToHsdVertex(strip, bones, bindGroups), (SBHsdBone)parent)); } } } iomesh.Optimize(); // flip faces var temp = iomesh.Indices.ToArray(); iomesh.Indices.Clear(); for (int i = 0; i < temp.Length; i += 3) { if (i + 2 < temp.Length) { iomesh.Indices.Add(temp[i + 2]); iomesh.Indices.Add(temp[i + 1]); iomesh.Indices.Add(temp[i]); } else { break; } } iomesh.MaterialIndex = iomodel.Materials.Count; IOMaterialPhong mat = new IOMaterialPhong(); mat.Name = iomesh.Name + "_material"; if (dobj.Mobj.Material != null) { mat.DiffuseColor = dobj.Mobj.Material.DiffuseColor; mat.SpecularColor = dobj.Mobj.Material.SpecularColor; mat.AmbientColor = dobj.Mobj.Material.AmbientColor; } if (dobj.Mobj.Textures != null) { mat.DiffuseTexture = tobjToName[dobj.Mobj.Textures._s]; } iomodel.Materials.Add(mat); } return(iomodel); }
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); }