/// <summary> /// /// </summary> /// <param name="jobj"></param> public static void CalculateCollisionFlags(this KAR_grCollisionNode coll) { var verts = coll.Vertices; var tris = coll.Triangles; foreach (var tri in tris) { // calculate surface normal var v0 = GXTranslator.toVector3(verts[tri.V1]); var v1 = GXTranslator.toVector3(verts[tri.V2]); var v2 = GXTranslator.toVector3(verts[tri.V3]); var faceNrm = Vector3.Cross(v1 - v0, v2 - v0).Normalized(); tri.Flags &= ~0x7; // guess flag if (faceNrm.Y > 0.5f) { tri.Flags |= 0x04; } else if (faceNrm.Y <= 0.5f && faceNrm.Y > -0.5f) { tri.Flags |= 0x02; } else { tri.Flags |= 0x01; } } coll.Triangles = tris; }
public void Render(HSDAccessor a, int windowWidth, int windowHeight) { if (a is KAR_grCollisionNode cn && cn != Node) { Node = cn; Vertices = Node.Vertices; Triangles = Node.Triangles; Joints = Node.Joints; ZoneVertices = Node.ZoneVertices; ZoneTriangles = Node.ZoneTriangles; ZoneJoints = Node.ZoneJoints; } if (Node == null) { return; } GL.PushAttrib(AttribMask.AllAttribBits); GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); GL.Begin(PrimitiveType.Triangles); foreach (var t in Triangles) { if ((t.Flags & 0x1) == 0x1) { GL.Color4(1f, 0f, 0f, 0.5f); } if ((t.Flags & 0x2) == 0x2) { GL.Color4(0f, 1f, 0f, 0.5f); } if ((t.Flags & 0x4) == 0x4) { GL.Color4(0f, 0f, 1f, 0.5f); } GL.Vertex3(GXTranslator.toVector3(Vertices[t.V1])); GL.Vertex3(GXTranslator.toVector3(Vertices[t.V2])); GL.Vertex3(GXTranslator.toVector3(Vertices[t.V3])); } GL.End(); GL.PopAttrib(); }
/// <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="mobj"></param> public void BindMOBJ(Shader shader, HSD_MOBJ mobj, HSD_JOBJ parentJOBJ, MatAnimManager animation) { if (mobj == null) { return; } GL.Enable(EnableCap.Texture2D); GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); GL.Enable(EnableCap.AlphaTest); GL.AlphaFunc(AlphaFunction.Greater, 0f); GL.DepthMask(!mobj.RenderFlags.HasFlag(RENDER_MODE.NO_ZUPDATE)); // Pixel Processing shader.SetInt("alphaOp", -1); // none shader.SetInt("alphaComp0", 7); // always shader.SetInt("alphaComp1", 7); // Materials var color = mobj.Material; if (color != null) { MaterialState.Ambient.X = color.AMB_R / 255f; MaterialState.Ambient.Y = color.AMB_G / 255f; MaterialState.Ambient.Z = color.AMB_B / 255f; MaterialState.Ambient.W = color.AMB_A / 255f; MaterialState.Diffuse.X = color.DIF_R / 255f; MaterialState.Diffuse.Y = color.DIF_G / 255f; MaterialState.Diffuse.Z = color.DIF_B / 255f; MaterialState.Diffuse.W = color.DIF_A / 255f; MaterialState.Specular.X = color.SPC_R / 255f; MaterialState.Specular.Y = color.SPC_G / 255f; MaterialState.Specular.Z = color.SPC_B / 255f; MaterialState.Specular.W = color.SPC_A / 255f; MaterialState.Shininess = color.Shininess; MaterialState.Alpha = color.Alpha; if (animation != null) { animation.GetMaterialState(mobj, ref MaterialState); } shader.SetVector4("ambientColor", MaterialState.Ambient); shader.SetVector4("diffuseColor", MaterialState.Diffuse); shader.SetVector4("specularColor", MaterialState.Specular); shader.SetFloat("shinniness", MaterialState.Shininess); shader.SetFloat("alpha", MaterialState.Alpha); } var pp = mobj.PEDesc; if (pp != null) { MaterialState.Ref0 = pp.AlphaRef0 / 255f; MaterialState.Ref1 = pp.AlphaRef1 / 255f; if (animation != null) { animation.GetMaterialState(mobj, ref MaterialState); } GL.BlendFunc(GXTranslator.toBlendingFactor(pp.SrcFactor), GXTranslator.toBlendingFactor(pp.DstFactor)); GL.DepthFunc(GXTranslator.toDepthFunction(pp.DepthFunction)); shader.SetInt("alphaOp", (int)pp.AlphaOp); shader.SetInt("alphaComp0", (int)pp.AlphaComp0); shader.SetInt("alphaComp1", (int)pp.AlphaComp1); shader.SetFloat("alphaRef0", MaterialState.Ref0); shader.SetFloat("alphaRef1", MaterialState.Ref1); } var enableAll = mobj.RenderFlags.HasFlag(RENDER_MODE.DF_ALL); shader.SetBoolToInt("no_zupdate", mobj.RenderFlags.HasFlag(RENDER_MODE.NO_ZUPDATE)); shader.SetBoolToInt("enableSpecular", parentJOBJ.Flags.HasFlag(JOBJ_FLAG.SPECULAR) && mobj.RenderFlags.HasFlag(RENDER_MODE.SPECULAR)); shader.SetBoolToInt("enableDiffuse", parentJOBJ.Flags.HasFlag(JOBJ_FLAG.LIGHTING) && mobj.RenderFlags.HasFlag(RENDER_MODE.DIFFUSE)); shader.SetBoolToInt("useConstant", mobj.RenderFlags.HasFlag(RENDER_MODE.CONSTANT)); shader.SetBoolToInt("useVertexColor", mobj.RenderFlags.HasFlag(RENDER_MODE.VERTEX)); shader.SetBoolToInt("useToonShading", mobj.RenderFlags.HasFlag(RENDER_MODE.TOON)); // Textures for (int i = 0; i < MAX_TEX; i++) { shader.SetBoolToInt($"hasTEX[{i}]", mobj.RenderFlags.HasFlag(RENDER_MODE.TEX0 + (i << 4)) || enableAll); } shader.SetInt("BumpTexture", -1); //LoadTextureConstants(shader); // Bind Textures if (mobj.Textures != null) { var textures = mobj.Textures.List; for (int i = 0; i < textures.Count; i++) { if (i > MAX_TEX) { break; } var tex = textures[i]; var displayTex = tex; if (tex.ImageData == null) { continue; } var blending = tex.Blending; var transform = Matrix4.CreateScale(tex.SX, tex.SY, tex.SZ) * Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(tex.RZ, tex.RY, tex.RX)) * Matrix4.CreateTranslation(tex.TX, tex.TY, tex.TZ); if (tex.SY != 0 && tex.SX != 0 && tex.SZ != 0) { transform.Invert(); } if (animation != null) { var state = animation.GetTextureAnimState(tex); if (state != null) { displayTex = state.TOBJ; blending = state.Blending; transform = state.Transform; } } // make sure texture is loaded PreLoadTexture(displayTex); // grab texture id var texid = TextureManager.Get(imageBufferTextureIndex[displayTex.ImageData.ImageData]); // set texture GL.ActiveTexture(TextureUnit.Texture0 + i); GL.BindTexture(TextureTarget.Texture2D, texid); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)GXTranslator.toWrapMode(tex.WrapS)); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)GXTranslator.toWrapMode(tex.WrapT)); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)GXTranslator.toMagFilter(tex.MagFilter)); var wscale = tex.WScale; var hscale = tex.HScale; var mirrorX = tex.WrapS == GXWrapMode.MIRROR; var mirrorY = tex.WrapT == GXWrapMode.MIRROR; var flags = tex.Flags; int coordType = (int)flags & 0xF; int colorOP = ((int)flags >> 16) & 0xF; int alphaOP = ((int)flags >> 20) & 0xF; if (flags.HasFlag(TOBJ_FLAGS.BUMP)) { colorOP = 4; } shader.SetInt($"sampler{i}", i); shader.SetInt($"TEX[{i}].gensrc", (int)tex.GXTexGenSrc); shader.SetBoolToInt($"TEX[{i}].is_ambient", flags.HasFlag(TOBJ_FLAGS.LIGHTMAP_AMBIENT)); shader.SetBoolToInt($"TEX[{i}].is_diffuse", flags.HasFlag(TOBJ_FLAGS.LIGHTMAP_DIFFUSE)); shader.SetBoolToInt($"TEX[{i}].is_specular", flags.HasFlag(TOBJ_FLAGS.LIGHTMAP_SPECULAR)); shader.SetBoolToInt($"TEX[{i}].is_ext", flags.HasFlag(TOBJ_FLAGS.LIGHTMAP_EXT)); shader.SetBoolToInt($"TEX[{i}].is_bump", flags.HasFlag(TOBJ_FLAGS.BUMP)); shader.SetInt($"TEX[{i}].color_operation", colorOP); shader.SetInt($"TEX[{i}].alpha_operation", alphaOP); shader.SetInt($"TEX[{i}].coord_type", coordType); shader.SetFloat($"TEX[{i}].blend", blending); shader.SetBoolToInt($"TEX[{i}].mirror_fix", mirrorY); shader.SetVector2($"TEX[{i}].uv_scale", wscale, hscale); shader.SetMatrix4x4($"TEX[{i}].transform", ref transform); var tev = tex.TEV; bool useTev = tev != null && tev.active.HasFlag(TOBJ_TEVREG_ACTIVE.COLOR_TEV); shader.SetBoolToInt($"hasTev[{i}]", useTev); if (useTev) { shader.SetInt($"Tev[{i}].color_op", (int)tev.color_op); shader.SetInt($"Tev[{i}].color_bias", (int)tev.color_bias); shader.SetInt($"Tev[{i}].color_scale", (int)tev.color_scale); shader.SetBoolToInt($"Tev[{i}].color_clamp", tev.color_clamp); shader.SetInt($"Tev[{i}].color_a", (int)tev.color_a_in); shader.SetInt($"Tev[{i}].color_b", (int)tev.color_b_in); shader.SetInt($"Tev[{i}].color_c", (int)tev.color_c_in); shader.SetInt($"Tev[{i}].color_d", (int)tev.color_d_in); shader.SetInt($"Tev[{i}].alpha_op", (int)tev.alpha_op); shader.SetInt($"Tev[{i}].alpha_bias", (int)tev.alpha_bias); shader.SetInt($"Tev[{i}].alpha_scale", (int)tev.alpha_scale); shader.SetBoolToInt($"Tev[{i}].alpha_clamp", tev.alpha_clamp); shader.SetInt($"Tev[{i}].alpha_a", (int)tev.alpha_a_in); shader.SetInt($"Tev[{i}].alpha_b", (int)tev.alpha_b_in); shader.SetInt($"Tev[{i}].alpha_c", (int)tev.alpha_c_in); shader.SetInt($"Tev[{i}].alpha_d", (int)tev.alpha_d_in); shader.SetColor($"Tev[{i}].konst", tev.constant, tev.constantAlpha); shader.SetColor($"Tev[{i}].tev0", tev.tev0, tev.tev0Alpha); shader.SetColor($"Tev[{i}].tev1", tev.tev1, tev.tev1Alpha); } } } }
/// <summary> /// /// </summary> /// <returns></returns> private static HSD_DOBJ GetMeshes(ProcessingCache cache, ModelImportSettings settings, Scene scene, Node node) { HSD_DOBJ root = null; HSD_DOBJ prev = null; Console.WriteLine("Processing " + node.Name); foreach (int index in node.MeshIndices) { Mesh mesh = scene.Meshes[index]; var material = scene.Materials[mesh.MaterialIndex]; Console.WriteLine(mesh.Name + " " + material.Name); // Generate DOBJ HSD_DOBJ dobj = new HSD_DOBJ(); // hack to make dobjs merged by texture if (settings.ImportTexture && settings.ForceMergeObjects == ForceGroupModes.Texture && material.HasTextureDiffuse && cache.TextureToDOBJ.ContainsKey(material.TextureDiffuse.FilePath)) { dobj = cache.TextureToDOBJ[material.TextureDiffuse.FilePath]; } else { if (root == null) { root = dobj; } else { prev.Next = dobj; } prev = dobj; dobj.Mobj = GenerateMaterial(cache, settings, material); if (settings.ForceMergeObjects == ForceGroupModes.Texture && material.HasTextureDiffuse && settings.ImportTexture) { cache.TextureToDOBJ.Add(material.TextureDiffuse.FilePath, dobj); } } if (root != null && settings.ForceMergeObjects == ForceGroupModes.MeshGroup) { dobj = root; } // Assessment if (!mesh.HasFaces) { continue; } // Assess needed attributes based on the material MOBJ // reflective mobjs do not use uvs var hasReflection = false; // bump maps need tangents and bitangents var hasBump = false; 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; } } } List <GXAttribName> Attributes = new List <GXAttribName>(); // todo: rigging List <HSD_JOBJ>[] jobjs = new List <HSD_JOBJ> [mesh.Vertices.Count]; List <float>[] weights = new List <float> [mesh.Vertices.Count]; if (mesh.HasBones) { Attributes.Add(GXAttribName.GX_VA_PNMTXIDX); foreach (var v in mesh.Bones) { var jobj = cache.NameToJOBJ[v.Name]; if (!cache.EnvelopedJOBJs.Contains(jobj)) { cache.EnvelopedJOBJs.Add(jobj); } if (v.HasVertexWeights) { foreach (var vw in v.VertexWeights) { if (jobjs[vw.VertexID] == null) { jobjs[vw.VertexID] = new List <HSD_JOBJ>(); } if (weights[vw.VertexID] == null) { weights[vw.VertexID] = new List <float>(); } if (vw.Weight > 0) { jobjs[vw.VertexID].Add(jobj); weights[vw.VertexID].Add(vw.Weight); } } } } } if (hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX0MTXIDX); } if (mesh.HasVertices) { Attributes.Add(GXAttribName.GX_VA_POS); } if (mesh.HasVertexColors(0) && settings.ShadingType == ShadingType.VertexColor) { Attributes.Add(GXAttribName.GX_VA_CLR0); } //if (mesh.HasVertexColors(1) && settings.ImportVertexColors) // Attributes.Add(GXAttribName.GX_VA_CLR1); if (!hasBump && mesh.HasNormals && settings.ShadingType == ShadingType.Material) { Attributes.Add(GXAttribName.GX_VA_NRM); } if (hasBump) { Attributes.Add(GXAttribName.GX_VA_NBT); } if (mesh.HasTextureCoords(0) && !hasReflection) { Attributes.Add(GXAttribName.GX_VA_TEX0); } //if (mesh.HasTextureCoords(1)) // Attributes.Add(GXAttribName.GX_VA_TEX1); var vertices = new List <GX_Vertex>(); var jobjList = new List <HSD_JOBJ[]>(vertices.Count); var wList = new List <float[]>(vertices.Count); foreach (var face in mesh.Faces) { PrimitiveType faceMode; switch (face.IndexCount) { case 1: faceMode = PrimitiveType.Point; break; case 2: faceMode = PrimitiveType.Line; break; case 3: faceMode = PrimitiveType.Triangle; break; default: faceMode = PrimitiveType.Polygon; break; } if (faceMode != PrimitiveType.Triangle) { continue; //throw new NotSupportedException($"Non triangle primitive types not supported at this time {faceMode}"); } for (int i = 0; i < face.IndexCount; i++) { int indicie = face.Indices[i]; GX_Vertex vertex = new GX_Vertex(); if (mesh.HasBones) { jobjList.Add(jobjs[indicie].ToArray()); wList.Add(weights[indicie].ToArray()); // Single Binds Get Inverted var tkvert = new Vector3(mesh.Vertices[indicie].X, mesh.Vertices[indicie].Y, mesh.Vertices[indicie].Z) * settings.Scale; var tknrm = new Vector3(mesh.Normals[indicie].X, mesh.Normals[indicie].Y, mesh.Normals[indicie].Z); Vector3 tktan = Vector3.Zero; Vector3 tkbitan = Vector3.Zero; if (mesh.HasTangentBasis) { tktan = new Vector3(mesh.Tangents[indicie].X, mesh.Tangents[indicie].Y, mesh.Tangents[indicie].Z); tkbitan = new Vector3(mesh.BiTangents[indicie].X, mesh.BiTangents[indicie].Y, mesh.BiTangents[indicie].Z); } if (jobjs[indicie].Count == 1 || weights[indicie][0] == 1) { tkvert = Vector3.TransformPosition(tkvert, cache.jobjToInverseTransform[jobjs[indicie][0]]); tknrm = Vector3.TransformNormal(tknrm, cache.jobjToInverseTransform[jobjs[indicie][0]]); if (mesh.HasTangentBasis) { tktan = Vector3.TransformNormal(tktan, cache.jobjToInverseTransform[jobjs[indicie][0]]); tkbitan = Vector3.TransformNormal(tkbitan, cache.jobjToInverseTransform[jobjs[indicie][0]]); } } vertex.POS = GXTranslator.fromVector3(tkvert); vertex.NRM = GXTranslator.fromVector3(tknrm); vertex.TAN = GXTranslator.fromVector3(tktan); vertex.BITAN = GXTranslator.fromVector3(tkbitan); } else { if (mesh.HasVertices) { vertex.POS = new GXVector3(mesh.Vertices[indicie].X * settings.Scale, mesh.Vertices[indicie].Y * settings.Scale, mesh.Vertices[indicie].Z * settings.Scale); } if (mesh.HasNormals) { vertex.NRM = new GXVector3(mesh.Normals[indicie].X, mesh.Normals[indicie].Y, mesh.Normals[indicie].Z); } if (mesh.HasTangentBasis) { vertex.TAN = new GXVector3(mesh.Tangents[indicie].X, mesh.Tangents[indicie].Y, mesh.Tangents[indicie].Z); vertex.BITAN = new GXVector3(mesh.BiTangents[indicie].X, mesh.BiTangents[indicie].Y, mesh.BiTangents[indicie].Z); } } if (settings.InvertNormals) { vertex.NRM.X *= -1; vertex.NRM.Y *= -1; vertex.NRM.Z *= -1; } if (mesh.HasTextureCoords(0)) { vertex.TEX0 = new GXVector2( mesh.TextureCoordinateChannels[0][indicie].X, mesh.TextureCoordinateChannels[0][indicie].Y); } if (mesh.HasTextureCoords(1)) { vertex.TEX1 = new GXVector2( mesh.TextureCoordinateChannels[1][indicie].X, mesh.TextureCoordinateChannels[1][indicie].Y); } if (mesh.HasVertexColors(0)) { vertex.CLR0 = new GXColor4( mesh.VertexColorChannels[0][indicie].R, mesh.VertexColorChannels[0][indicie].G, mesh.VertexColorChannels[0][indicie].B, settings.ImportVertexAlpha ? mesh.VertexColorChannels[0][indicie].A : 1); } if (mesh.HasVertexColors(1)) { vertex.CLR0 = new GXColor4( mesh.VertexColorChannels[1][indicie].R, mesh.VertexColorChannels[1][indicie].G, mesh.VertexColorChannels[1][indicie].B, settings.ImportVertexAlpha ? mesh.VertexColorChannels[1][indicie].A : 1); } vertices.Add(vertex); } } HSD_POBJ pobj = null; if (mesh.HasBones) { pobj = cache.POBJGen.CreatePOBJsFromTriangleList(vertices, Attributes.ToArray(), jobjList, wList); } else { pobj = cache.POBJGen.CreatePOBJsFromTriangleList(vertices, Attributes.ToArray(), null); } if (pobj != null) { if (dobj.Pobj == null) { dobj.Pobj = pobj; } else { dobj.Pobj.Add(pobj); } } } return(root); }
/// <summary> /// /// </summary> /// <param name="pobj"></param> private Mesh ProcessPOBJ(HSD_POBJ pobj, HSD_JOBJ parent, HSD_JOBJ singleBind) { Mesh m = new Mesh(); m.Name = "pobj"; m.PrimitiveType = PrimitiveType.Triangle; m.MaterialIndex = 0; var dl = pobj.ToDisplayList(); var envelopes = pobj.EnvelopeWeights; var parentTransform = Matrix4.Identity; if (parent != null) { parentTransform = WorldTransforms[jobjToIndex[parent]]; } var singleBindTransform = Matrix4.Identity; if (singleBind != null) { singleBindTransform = WorldTransforms[jobjToIndex[singleBind]]; } Dictionary <HSD_JOBJ, Bone> jobjToBone = new Dictionary <HSD_JOBJ, Bone>(); if (envelopes != null) { foreach (var jobj in Jobjs) { var bone = new Bone(); bone.Name = JobjNodes[jobjToIndex[jobj]].Name; bone.OffsetMatrix = Matrix4ToMatrix4x4(WorldTransforms[jobjToIndex[jobj]].Inverted()); m.Bones.Add(bone); jobjToBone.Add(jobj, bone); } } /*foreach (var en in envelopes) * { * foreach (var jobj in en.JOBJs) * { * if (!jobjToBone.ContainsKey(jobj)) * { * var bone = new Bone(); * bone.Name = JobjNodes[jobjToIndex[jobj]].Name; * bone.OffsetMatrix = Matrix4ToMatrix4x4(WorldTransforms[jobjToIndex[jobj]].Inverted()); * m.Bones.Add(bone); * jobjToBone.Add(jobj, bone); * } * } * }*/ if (singleBind != null && !jobjToBone.ContainsKey(singleBind)) { var bone = new Bone(); bone.Name = JobjNodes[jobjToIndex[singleBind]].Name; bone.OffsetMatrix = Matrix4ToMatrix4x4(WorldTransforms[jobjToIndex[singleBind]].Inverted()); m.Bones.Add(bone); jobjToBone.Add(singleBind, bone); } int offset = 0; var vIndex = -1; foreach (var prim in dl.Primitives) { var verts = dl.Vertices.GetRange(offset, prim.Count); offset += prim.Count; switch (prim.PrimitiveType) { case GXPrimitiveType.Quads: verts = TriangleConverter.QuadToList(verts); break; case GXPrimitiveType.TriangleStrip: verts = TriangleConverter.StripToList(verts); break; case GXPrimitiveType.Triangles: break; default: Console.WriteLine(prim.PrimitiveType); break; } for (int i = m.VertexCount; i < m.VertexCount + verts.Count; i += 3) { var f = new Face(); f.Indices.Add(i); f.Indices.Add(i + 1); f.Indices.Add(i + 2); m.Faces.Add(f); } foreach (var v in verts) { vIndex++; if (singleBind != null) { var vertexWeight = new VertexWeight(); vertexWeight.VertexID = vIndex; vertexWeight.Weight = 1; jobjToBone[singleBind].VertexWeights.Add(vertexWeight); } Matrix4 weight = Matrix4.Identity; foreach (var a in pobj.Attributes) { switch (a.AttributeName) { case GXAttribName.GX_VA_PNMTXIDX: var en = envelopes[v.PNMTXIDX / 3]; for (int w = 0; w < en.EnvelopeCount; w++) { var vertexWeight = new VertexWeight(); vertexWeight.VertexID = vIndex; vertexWeight.Weight = en.Weights[w]; jobjToBone[en.JOBJs[w]].VertexWeights.Add(vertexWeight); } if (en.EnvelopeCount == 1 && jobjToIndex[parent] == 0) { weight = WorldTransforms[jobjToIndex[en.JOBJs[0]]]; } break; case GXAttribName.GX_VA_POS: var vert = Vector3.TransformPosition(GXTranslator.toVector3(v.POS), parentTransform); vert = Vector3.TransformPosition(vert, weight); vert = Vector3.TransformPosition(vert, singleBindTransform); m.Vertices.Add(new Vector3D(vert.X, vert.Y, vert.Z)); break; case GXAttribName.GX_VA_NRM: var nrm = Vector3.TransformNormal(GXTranslator.toVector3(v.NRM), parentTransform); nrm = Vector3.TransformNormal(nrm, weight); nrm = Vector3.TransformNormal(nrm, singleBindTransform); m.Normals.Add(new Vector3D(nrm.X, nrm.Y, nrm.Z)); break; case GXAttribName.GX_VA_CLR0: m.VertexColorChannels[0].Add(new Color4D(v.CLR0.R, v.CLR0.G, v.CLR0.B, v.CLR0.A)); break; case GXAttribName.GX_VA_CLR1: m.VertexColorChannels[1].Add(new Color4D(v.CLR1.R, v.CLR1.G, v.CLR1.B, v.CLR1.A)); break; case GXAttribName.GX_VA_TEX0: m.TextureCoordinateChannels[0].Add(new Vector3D(v.TEX0.X, v.TEX0.Y, 1)); break; case GXAttribName.GX_VA_TEX1: m.TextureCoordinateChannels[1].Add(new Vector3D(v.TEX1.X, v.TEX1.Y, 1)); break; case GXAttribName.GX_VA_TEX2: m.TextureCoordinateChannels[2].Add(new Vector3D(v.TEX2.X, v.TEX2.Y, 1)); break; case GXAttribName.GX_VA_TEX3: m.TextureCoordinateChannels[3].Add(new Vector3D(v.TEX3.X, v.TEX3.Y, 1)); break; case GXAttribName.GX_VA_TEX4: m.TextureCoordinateChannels[4].Add(new Vector3D(v.TEX4.X, v.TEX4.Y, 1)); break; case GXAttribName.GX_VA_TEX5: m.TextureCoordinateChannels[5].Add(new Vector3D(v.TEX5.X, v.TEX5.Y, 1)); break; case GXAttribName.GX_VA_TEX6: m.TextureCoordinateChannels[6].Add(new Vector3D(v.TEX6.X, v.TEX6.Y, 1)); break; case GXAttribName.GX_VA_TEX7: m.TextureCoordinateChannels[7].Add(new Vector3D(v.TEX7.X, v.TEX7.Y, 1)); break; } } } } return(m); }