/// <summary> /// /// </summary> /// <returns></returns> private string GenerateGeometry(IOMesh mesh) { // convert mesh to triangles to simplify mesh.MakeTriangles(); // create a unique geometry id var geomID = GetUniqueID(mesh.Name + "-geometry"); // create geometry element Geometry geom = new Geometry() { ID = geomID, Name = mesh.Name }; geom.Mesh = new Mesh(); // generate sources SourceGenerator srcgen = new SourceGenerator(); srcgen.AddSourceData( geomID, Input_Semantic.POSITION, mesh.Vertices.SelectMany(e => new float[] { e.Position.X, e.Position.Y, e.Position.Z }).ToArray()); srcgen.AddSourceData( geomID, Input_Semantic.NORMAL, mesh.Vertices.SelectMany(e => new float[] { e.Normal.X, e.Normal.Y, e.Normal.Z }).ToArray()); for (int i = 0; i < 7; i++) { if (mesh.HasUVSet(i)) { srcgen.AddSourceData( geomID, Input_Semantic.TEXCOORD, mesh.Vertices.SelectMany(e => new float[] { e.UVs[i].X, e.UVs[i].Y }).ToArray(), i); } } for (int i = 0; i < 7; i++) { if (mesh.HasColorSet(i)) { srcgen.AddSourceData( geomID, Input_Semantic.COLOR, mesh.Vertices.SelectMany(e => new float[] { e.Colors[i].X, e.Colors[i].Y, e.Colors[i].Z, e.Colors[i].W }).ToArray(), i); } } // fill in vertex info geom.Mesh.Vertices = new Vertices() { ID = GetUniqueID(mesh.Name + "-vertices"), Input = new Input_Unshared[] { new Input_Unshared() { Semantic = IONET.Collada.Enums.Input_Semantic.POSITION, source = "#" + srcgen.GetID(Input_Semantic.POSITION) } } }; // fill in triangles var polyIndex = 0; geom.Mesh.Triangles = new Triangles[mesh.Polygons.Count]; foreach (var poly in mesh.Polygons) { if (poly.PrimitiveType != IOPrimitive.TRIANGLE) { System.Diagnostics.Debug.WriteLine("Warning: " + poly.PrimitiveType + " not currently supported"); continue; } Triangles tri = new Triangles() { Count = poly.Indicies.Count / 3, Material = poly.MaterialName }; List <Input_Shared> inputs = new List <Input_Shared>(); inputs.Add(new Input_Shared() { Semantic = Input_Semantic.VERTEX, Offset = inputs.Count, source = "#" + geom.Mesh.Vertices.ID }); inputs.Add(new Input_Shared() { Semantic = Input_Semantic.NORMAL, Offset = inputs.Count, source = "#" + srcgen.GetID(Input_Semantic.NORMAL) }); for (int i = 0; i < 7; i++) { if (mesh.HasUVSet(i)) { inputs.Add(new Input_Shared() { Semantic = Input_Semantic.TEXCOORD, source = "#" + srcgen.GetID(Input_Semantic.TEXCOORD, i), Offset = inputs.Count, Set = i }); } } for (int i = 0; i < 7; i++) { if (mesh.HasColorSet(i)) { inputs.Add(new Input_Shared() { Semantic = Input_Semantic.COLOR, source = "#" + srcgen.GetID(Input_Semantic.COLOR, i), Offset = inputs.Count, Set = i }); } } tri.Input = inputs.ToArray(); tri.P = new IONET.Collada.Types.Int_Array_String() { Value_As_String = string.Join(" ", srcgen.Remap(poly.Indicies)) }; geom.Mesh.Triangles[polyIndex++] = tri; } // generate sources geom.Mesh.Source = srcgen.GetSources(); // add geometry element to document if (_collada.Library_Geometries == null) { _collada.Library_Geometries = new Library_Geometries(); } if (_collada.Library_Geometries.Geometry == null) { _collada.Library_Geometries.Geometry = new Geometry[0]; } Array.Resize(ref _collada.Library_Geometries.Geometry, _collada.Library_Geometries.Geometry.Length + 1); _collada.Library_Geometries.Geometry[_collada.Library_Geometries.Geometry.Length - 1] = geom; // return geometry id return(geomID); }
/// <summary> /// /// </summary> /// <returns></returns> private void ProcessMesh(IOScene scene, IOMesh mesh, HSD_JOBJ rootnode) { HSD_JOBJ parent = rootnode; HashSet <HSD_JOBJ> nodes = new HashSet <HSD_JOBJ>(); foreach (var j in rootnode.BreathFirstList) { nodes.Add(j); } if (mesh.ParentBone != null && _cache.NameToJOBJ.ContainsKey(mesh.ParentBone.Name)) { parent = _cache.NameToJOBJ[mesh.ParentBone.Name]; } HSD_DOBJ root = null; HSD_DOBJ prev = null; //var skeleton = rootnode.BreathFirstList; Console.WriteLine("Processing " + mesh.Name); bool singleBinded = mesh.Name.Contains("SINGLE"); foreach (var poly in mesh.Polygons) { // Skip Empty Polygon if (poly.Indicies.Count == 0) { continue; } // convert to triangles poly.ToTriangles(mesh); if (poly.PrimitiveType != IOPrimitive.TRIANGLE) { continue; } // Generate DOBJ HSD_DOBJ dobj = new HSD_DOBJ(); if (Settings.ImportMeshNames) { dobj.ClassName = mesh.Name; } if (root == null) { root = dobj; } else { prev.Next = dobj; } prev = dobj; // generate material var material = scene.Materials.Find(e => e.Name == poly.MaterialName); dobj.Mobj = GenerateMaterial(material); Console.WriteLine(mesh.Name + " " + material?.Name); // reflective mobjs do not use uvs var hasReflection = false; // bump maps need tangents and bitangents var hasBump = false; // Assess needed attributes based on the material MOBJ if (mesh.Name.Contains("REFLECTIVE")) { hasReflection = true; } #if DEBUG if (Settings.MetalModel) { hasReflection = true; } #endif if (mesh.Name.Contains("BUMP")) { hasBump = true; } if (dobj.Mobj.Textures != null) { foreach (var t in dobj.Mobj.Textures.List) { if (t.Flags.HasFlag(TOBJ_FLAGS.COORD_REFLECTION)) { hasReflection = true; } if (t.Flags.HasFlag(TOBJ_FLAGS.BUMP)) { hasBump = true; } } } // assess attributes List <GXAttribName> Attributes = new List <GXAttribName>(); if (mesh.HasEnvelopes() && Settings.ImportRigging && !singleBinded) { Attributes.Add(GXAttribName.GX_VA_PNMTXIDX); if (hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX0MTXIDX); if (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 1) { Attributes.Add(GXAttribName.GX_VA_TEX1MTXIDX); } #if DEBUG if (Settings.MetalModel && !Attributes.Contains(GXAttribName.GX_VA_TEX1MTXIDX)) { Attributes.Add(GXAttribName.GX_VA_TEX1MTXIDX); } #endif } } Attributes.Add(GXAttribName.GX_VA_POS); if (hasBump) { Attributes.Add(GXAttribName.GX_VA_NBT); } else if (mesh.HasNormals && Settings.ImportNormals) { Attributes.Add(GXAttribName.GX_VA_NRM); } if (mesh.HasColorSet(0) && Settings.ImportVertexColor) { Attributes.Add(GXAttribName.GX_VA_CLR0); } if (mesh.HasColorSet(1) && Settings.ImportVertexColor) { Attributes.Add(GXAttribName.GX_VA_CLR1); } if (mesh.HasUVSet(0) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX0); } if ((mesh.HasUVSet(1) || (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 1)) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX1); } if ((mesh.HasUVSet(2) || (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 2)) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX2); } if ((mesh.HasUVSet(3) || (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 3)) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX3); } if ((mesh.HasUVSet(4) || (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 4)) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX4); } if ((mesh.HasUVSet(5) || (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 5)) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX5); } if ((mesh.HasUVSet(6) || (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 6)) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX6); } if ((mesh.HasUVSet(7) || (dobj.Mobj.Textures != null && dobj.Mobj.Textures.List.Count > 7)) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX7); } var vertices = new List <GX_Vertex>(); var jobjList = new List <HSD_JOBJ[]>(); var weightList = new List <float[]>(); foreach (var face in poly.Indicies) { var v = mesh.Vertices[face]; GX_Vertex vertex = new GX_Vertex(); var tkvert = new Vector3(v.Position.X, v.Position.Y, v.Position.Z); var tknrm = new Vector3(v.Normal.X, v.Normal.Y, v.Normal.Z); var tktan = new Vector3(v.Tangent.X, v.Tangent.Y, v.Tangent.Z); var tkbitan = new Vector3(v.Binormal.X, v.Binormal.Y, v.Binormal.Z); var parentTransform = _cache.jobjToWorldTransform[parent].Inverted(); if (_cache.jobjToWorldTransform[parent] != Matrix4.Identity) { tkvert = Vector3.TransformPosition(tkvert, parentTransform); tknrm = Vector3.TransformNormal(tknrm, parentTransform).Normalized(); tktan = Vector3.TransformNormal(tktan, parentTransform).Normalized(); tkbitan = Vector3.TransformNormal(tkbitan, parentTransform).Normalized(); } if (mesh.HasEnvelopes() && Settings.ImportRigging) { // create weighting lists List <float> weight = new List <float>(); List <HSD_JOBJ> bones = new List <HSD_JOBJ>(); if (v.Envelope.Weights.Count == 0) { weight.Add(1); bones.Add(rootnode); } if (v.Envelope.Weights.Count > 4) { throw new Exception($"Too many weights! {v.Envelope.Weights.Count} in {mesh.Name}"); } foreach (var bw in v.Envelope.Weights) { // check if skeleton actually contains bone if (_cache.NameToJOBJ.ContainsKey(bw.BoneName) && nodes.Contains(_cache.NameToJOBJ[bw.BoneName])) { // add envelope bones.Add(_cache.NameToJOBJ[bw.BoneName]); weight.Add(bw.Weight); // indicate enveloped jobjs if (!_cache.EnvelopedJOBJs.Contains(_cache.NameToJOBJ[bw.BoneName])) { _cache.EnvelopedJOBJs.Add(_cache.NameToJOBJ[bw.BoneName]); } } else { throw new Exception($"Bone not found \"{bw.BoneName}\" Weight: {bw.Weight} in {mesh.Name}"); } } jobjList.Add(bones.ToArray()); weightList.Add(weight.ToArray()); // invert single binds if (v.Envelope.Weights.Count == 1) { var inv = _cache.jobjToWorldTransform[_cache.NameToJOBJ[v.Envelope.Weights[0].BoneName]].Inverted(); tkvert = Vector3.TransformPosition(tkvert, inv); tknrm = Vector3.TransformNormal(tknrm, inv).Normalized(); tktan = Vector3.TransformNormal(tknrm, inv).Normalized(); tkbitan = Vector3.TransformNormal(tknrm, inv).Normalized(); } } vertex.POS = GXTranslator.fromVector3(tkvert); vertex.NRM = GXTranslator.fromVector3(tknrm.Normalized()); vertex.TAN = GXTranslator.fromVector3(tktan); vertex.BITAN = GXTranslator.fromVector3(tkbitan); if (Settings.InvertNormals) { vertex.NRM.X *= -1; vertex.NRM.Y *= -1; vertex.NRM.Z *= -1; vertex.TAN.X *= -1; vertex.TAN.Y *= -1; vertex.TAN.Z *= -1; vertex.BITAN.X *= -1; vertex.BITAN.Y *= -1; vertex.BITAN.Z *= -1; } if (mesh.HasUVSet(0)) { vertex.TEX0 = new GXVector2(v.UVs[0].X, v.UVs[0].Y); } if (mesh.HasUVSet(1)) { vertex.TEX1 = new GXVector2(v.UVs[1].X, v.UVs[1].Y); } if (mesh.HasUVSet(2)) { vertex.TEX2 = new GXVector2(v.UVs[2].X, v.UVs[2].Y); } if (mesh.HasUVSet(3)) { vertex.TEX3 = new GXVector2(v.UVs[3].X, v.UVs[3].Y); } if (mesh.HasUVSet(4)) { vertex.TEX4 = new GXVector2(v.UVs[4].X, v.UVs[4].Y); } if (mesh.HasUVSet(5)) { vertex.TEX5 = new GXVector2(v.UVs[5].X, v.UVs[5].Y); } if (mesh.HasUVSet(6)) { vertex.TEX6 = new GXVector2(v.UVs[6].X, v.UVs[6].Y); } if (mesh.HasUVSet(7)) { vertex.TEX7 = new GXVector2(v.UVs[7].X, v.UVs[7].Y); } if (mesh.HasColorSet(0)) { vertex.CLR0 = new GXColor4( v.Colors[0].X * (Settings.MultiplyVertexColorBy2 ? 2 : 1), v.Colors[0].Y * (Settings.MultiplyVertexColorBy2 ? 2 : 1), v.Colors[0].Z * (Settings.MultiplyVertexColorBy2 ? 2 : 1), Settings.ImportVertexAlpha ? v.Colors[0].W : 1); } if (mesh.HasColorSet(1)) { vertex.CLR1 = new GXColor4( v.Colors[1].X * (Settings.MultiplyVertexColorBy2 ? 2 : 1), v.Colors[1].Y * (Settings.MultiplyVertexColorBy2 ? 2 : 1), v.Colors[1].Z * (Settings.MultiplyVertexColorBy2 ? 2 : 1), Settings.ImportVertexAlpha ? v.Colors[1].W : 1); } vertices.Add(vertex); } // generate pobjs HSD_POBJ pobj = null; if (mesh.HasEnvelopes() && Settings.ImportRigging && !singleBinded) { pobj = _cache.POBJGen.CreatePOBJsFromTriangleList(vertices, Attributes.ToArray(), jobjList, weightList); } else { pobj = _cache.POBJGen.CreatePOBJsFromTriangleList(vertices, Attributes.ToArray(), null); } if (singleBinded && jobjList.Count > 0 && jobjList[0].Length > 0) { parent = jobjList[0][0]; } if (pobj != null) { if (dobj.Pobj == null) { dobj.Pobj = pobj; } else { dobj.Pobj.Add(pobj); } } } if (parent.Dobj == null) { parent.Dobj = root; } else { parent.Dobj.Add(root); } }
/// <summary> /// /// </summary> /// <param name="settings"></param> /// <param name="material"></param> /// <returns></returns> private HSD_MOBJ GenerateMaterial(IOMesh mesh, IOMaterial material) { // create blank mobj var Mobj = new HSD_MOBJ(); Mobj.Material = new HSD_Material() { AMB_A = 0xFF, AMB_R = 0x7F, AMB_G = 0x7F, AMB_B = 0x7F, DiffuseColor = System.Drawing.Color.White, SpecularColor = System.Drawing.Color.White, Shininess = 50, Alpha = 1 }; // detect and set flags if (Settings.ImportVertexColor && (mesh.HasColorSet(0) || mesh.HasColorSet(1))) { Mobj.RenderFlags |= RENDER_MODE.VERTEX; } if (Settings.EnableDiffuse) { Mobj.RenderFlags |= RENDER_MODE.DIFFUSE; } if (Settings.EnableConstant) { Mobj.RenderFlags |= RENDER_MODE.CONSTANT; } // Properties if (material != null && Settings.ImportMaterialInfo) { Mobj.Material.Shininess = material.Shininess; Mobj.Material.Alpha = material.Alpha; Mobj.Material.AMB_R = (byte)(material.AmbientColor.X * 255); Mobj.Material.AMB_G = (byte)(material.AmbientColor.Y * 255); Mobj.Material.AMB_B = (byte)(material.AmbientColor.Z * 255); Mobj.Material.AMB_A = (byte)(material.AmbientColor.W * 255); Mobj.Material.DIF_R = (byte)(material.DiffuseColor.X * 255); Mobj.Material.DIF_G = (byte)(material.DiffuseColor.Y * 255); Mobj.Material.DIF_B = (byte)(material.DiffuseColor.Z * 255); Mobj.Material.DIF_A = (byte)(material.DiffuseColor.W * 255); Mobj.Material.SPC_R = (byte)(material.SpecularColor.X * 255); Mobj.Material.SPC_G = (byte)(material.SpecularColor.Y * 255); Mobj.Material.SPC_B = (byte)(material.SpecularColor.Z * 255); Mobj.Material.SPC_A = (byte)(material.SpecularColor.W * 255); } // Textures if (material != null && Settings.ImportTexture) { if (material.DiffuseMap != null && !string.IsNullOrEmpty(material.DiffuseMap.FilePath)) { var texturePath = material.DiffuseMap.FilePath; if (texturePath.Contains("file://")) { texturePath = texturePath.Replace("file://", ""); } if (File.Exists(Path.Combine(_cache.FolderPath, texturePath))) { texturePath = Path.Combine(_cache.FolderPath, texturePath); } if (File.Exists(material.DiffuseMap.FilePath)) { texturePath = material.DiffuseMap.FilePath; } if (File.Exists(texturePath + ".png")) { texturePath = texturePath + ".png"; } var mobjPath = Path.Combine(Path.GetDirectoryName(texturePath), Path.GetFileNameWithoutExtension(texturePath)) + ".mobj"; if (Settings.ImportMOBJ && File.Exists(mobjPath)) { var dat = new HSDRaw.HSDRawFile(mobjPath); Mobj._s = dat.Roots[0].Data._s; return(Mobj); } else /// special mobj loading if (Path.GetExtension(texturePath).ToLower() == ".mobj") { var dat = new HSDRaw.HSDRawFile(texturePath); Mobj._s = dat.Roots[0].Data._s; return(Mobj); } else if (File.Exists(texturePath) && (texturePath.ToLower().EndsWith(".png") || texturePath.ToLower().EndsWith(".bmp"))) { Mobj.RenderFlags |= RENDER_MODE.TEX0; var tobj = TOBJConverter.ImportTOBJFromFile(texturePath, Settings.TextureFormat, Settings.PaletteFormat); tobj.Flags = TOBJ_FLAGS.LIGHTMAP_DIFFUSE | TOBJ_FLAGS.COORD_UV | TOBJ_FLAGS.COLORMAP_MODULATE; tobj.GXTexGenSrc = GXTexGenSrc.GX_TG_TEX0; tobj.TexMapID = GXTexMapID.GX_TEXMAP0; tobj.WrapS = ToGXWrapMode(material.DiffuseMap.WrapS); tobj.WrapT = ToGXWrapMode(material.DiffuseMap.WrapT); if (TOBJConverter.IsTransparent(tobj)) { _cache.HasXLU = true; Mobj.RenderFlags |= RENDER_MODE.XLU; tobj.Flags |= TOBJ_FLAGS.ALPHAMAP_MODULATE; } Mobj.Textures = tobj; } } } return(Mobj); }