예제 #1
0
        /// <summary>
        ///
        /// </summary>
        private static void ZeroOutRotations(ProcessingCache cache, HSD_JOBJ root)
        {
            Dictionary <HSD_JOBJ, Matrix4> newWorldMatrices = new Dictionary <HSD_JOBJ, Matrix4>();

            ZeroOutRotations(cache, newWorldMatrices, root, Matrix4.Identity, Matrix4.Identity);

            cache.jobjToWorldTransform = newWorldMatrices;
            cache.jobjToInverseTransform.Clear();
            foreach (var v in newWorldMatrices)
            {
                cache.jobjToInverseTransform.Add(v.Key, v.Value.Inverted());
            }
        }
예제 #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="settings"></param>
        /// <param name="material"></param>
        /// <returns></returns>
        private static HSD_MOBJ GenerateMaterial(ProcessingCache cache, ModelImportSettings settings, Material material)
        {
            var Mobj = new HSD_MOBJ();

            Mobj.Material = new HSD_Material();
            Mobj.Material.AmbientColorRGBA  = 0x7F7F7FFF;
            Mobj.Material.DiffuseColorRGBA  = 0xFFFFFFFF;
            Mobj.Material.SpecularColorRGBA = 0xFFFFFFFF;
            Mobj.Material.Shininess         = 1;
            Mobj.Material.Alpha             = 1;
            Mobj.RenderFlags = RENDER_MODE.ALPHA_COMPAT | RENDER_MODE.DIFFSE_VTX;

            // Properties
            if (settings.ImportMaterialInfo)
            {
                if (material.HasShininess)
                {
                    Mobj.Material.Shininess = material.Shininess;
                }

                if (material.HasColorAmbient)
                {
                    Mobj.Material.AMB_A = ColorFloatToByte(material.ColorAmbient.A);
                    Mobj.Material.AMB_R = ColorFloatToByte(material.ColorAmbient.R);
                    Mobj.Material.AMB_G = ColorFloatToByte(material.ColorAmbient.G);
                    Mobj.Material.AMB_B = ColorFloatToByte(material.ColorAmbient.B);
                }
                if (material.HasColorDiffuse)
                {
                    Mobj.Material.DIF_A = ColorFloatToByte(material.ColorDiffuse.A);
                    Mobj.Material.DIF_R = ColorFloatToByte(material.ColorDiffuse.R);
                    Mobj.Material.DIF_G = ColorFloatToByte(material.ColorDiffuse.G);
                    Mobj.Material.DIF_B = ColorFloatToByte(material.ColorDiffuse.B);
                }
                if (material.HasColorSpecular)
                {
                    Mobj.Material.SPC_A = ColorFloatToByte(material.ColorSpecular.A);
                    Mobj.Material.SPC_R = ColorFloatToByte(material.ColorSpecular.R);
                    Mobj.Material.SPC_G = ColorFloatToByte(material.ColorSpecular.G);
                    Mobj.Material.SPC_B = ColorFloatToByte(material.ColorSpecular.B);
                }
            }

            // Textures
            if (settings.ImportTexture)
            {
                if (material.HasTextureDiffuse)
                {
                    var texturePath = Path.Combine(cache.FolderPath, material.TextureDiffuse.FilePath);

                    if (File.Exists(material.TextureDiffuse.FilePath))
                    {
                        texturePath = material.TextureDiffuse.FilePath;
                    }

                    /// 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))
                    {
                        Mobj.RenderFlags |= RENDER_MODE.TEX0;

                        var tobj = TOBJConverter.ImportTOBJFromFile(texturePath, settings.TextureFormat, settings.PaletteFormat);
                        tobj.Flags = TOBJ_FLAGS.LIGHTMAP_DIFFUSE | TOBJ_FLAGS.COORD_UV;

                        if (settings.ShadingType == ShadingType.VertexColor || settings.ShadingType == ShadingType.Material)
                        {
                            tobj.Flags |= TOBJ_FLAGS.COLORMAP_MODULATE;
                        }
                        else
                        {
                            tobj.Flags |= TOBJ_FLAGS.COLORMAP_REPLACE;
                        }

                        tobj.GXTexGenSrc = 4;
                        tobj.TexMapID    = GXTexMapID.GX_TEXMAP0;

                        tobj.WrapS = ToGXWrapMode(material.TextureDiffuse.WrapModeU);
                        tobj.WrapT = ToGXWrapMode(material.TextureDiffuse.WrapModeV);

                        Mobj.Textures = tobj;
                    }
                }
            }

            return(Mobj);
        }
예제 #3
0
        /// <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);
        }
예제 #4
0
        /// <summary>
        /// Recursivly processing nodes and convert data into JOBJ
        /// </summary>
        /// <param name="scene"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        private static HSD_JOBJ RecursiveProcess(ProcessingCache cache, ModelImportSettings settings, Scene scene, Node node)
        {
            if (node.Name.EndsWith("_end"))
            {
                return(null);
            }

            // node transform's translation is bugged
            Vector3D tr, s;

            Assimp.Quaternion q;
            node.Transform.Decompose(out s, out q, out tr);
            var translation = new Vector3(tr.X, tr.Y, tr.Z);
            var scale       = new Vector3(s.X, s.Y, s.Z);
            var rotation    = Math3D.ToEulerAngles(new OpenTK.Quaternion(q.X, q.Y, q.Z, q.W).Inverted());

            if (settings.SetScaleToOne)
            {
                scale = Vector3.One;
            }

            translation *= settings.Scale;

            var t = Matrix4.CreateScale(scale)
                    * Matrix4.CreateFromQuaternion(new OpenTK.Quaternion(q.X, q.Y, q.Z, q.W))
                    * Matrix4.CreateTranslation(translation);

            HSD_JOBJ jobj = new HSD_JOBJ();

            if (node.Parent != null)
            {
                t = t * cache.jobjToWorldTransform[cache.NameToJOBJ[node.Parent.Name]];
            }
            cache.NameToJOBJ.Add(node.Name, jobj);
            cache.jobjToWorldTransform.Add(jobj, t);
            cache.jobjToInverseTransform.Add(jobj, t.Inverted());

            jobj.ClassName = node.Name;
            jobj.Flags     = JOBJ_FLAG.CLASSICAL_SCALING;
            jobj.TX        = translation.X;
            jobj.TY        = translation.Y;
            jobj.TZ        = translation.Z;
            jobj.RX        = rotation.X;
            jobj.RY        = rotation.Y;
            jobj.RZ        = rotation.Z;
            jobj.SX        = scale.X;
            jobj.SY        = scale.Y;
            jobj.SZ        = scale.Z;

            if (node.HasMeshes)
            {
                cache.MeshNodes.Add(node);
            }

            foreach (var child in node.Children)
            {
                Console.WriteLine(child.Name);
                jobj.AddChild(RecursiveProcess(cache, settings, scene, child));
            }

            return(jobj);
        }
예제 #5
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="cache"></param>
        /// <param name="newWorldMatrices"></param>
        /// <param name="root"></param>
        /// <param name="parentTransform"></param>
        private static void ZeroOutRotations(ProcessingCache cache, Dictionary <HSD_JOBJ, Matrix4> newWorldMatrices, HSD_JOBJ root, Matrix4 oldParent, Matrix4 parentTransform)
        {
            var targetPoint = Vector3.TransformPosition(Vector3.Zero, cache.jobjToWorldTransform[root]);

            //targetPoint -= Vector3.TransformPosition(Vector3.Zero, oldParent);
            var trimName = root.ClassName.Replace("Armature_", "");

            if (FighterDefaults.ContainsKey(trimName))
            {
                root.TX = 0;
                root.TY = 0;
                root.TZ = 0;
                root.RX = FighterDefaults[trimName].X;
                root.RY = FighterDefaults[trimName].Y;
                root.RZ = FighterDefaults[trimName].Z;
                root.SX = 1;
                root.SY = 1;
                root.SZ = 1;
            }
            else
            {
                root.TX = 0;
                root.TY = 0;
                root.TZ = 0;
                root.RX = 0;
                root.RY = 0;
                root.RZ = 0;
                root.SX = 1;
                root.SY = 1;
                root.SZ = 1;
            }

            Matrix4 currentTransform =
                Matrix4.CreateScale(root.SX, root.SY, root.SZ) *
                Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(root.RZ, root.RY, root.RX)) *
                parentTransform;

            var relPoint = Vector3.TransformPosition(targetPoint, parentTransform.Inverted());

            root.TX = relPoint.X;
            root.TY = relPoint.Y;
            root.TZ = relPoint.Z;

            if (trimName.Equals("TransN")) // special case
            {
                root.TX = 0;
                root.TY = 0;
                root.TZ = 0;
            }

            var finalTransform =
                Matrix4.CreateScale(root.SX, root.SY, root.SZ) *
                Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(root.RZ, root.RY, root.RX)) *
                Matrix4.CreateTranslation(root.TX, root.TY, root.TZ) * parentTransform;

            newWorldMatrices.Add(root, finalTransform);

            foreach (var c in root.Children)
            {
                ZeroOutRotations(cache, newWorldMatrices, c, cache.jobjToWorldTransform[root], finalTransform);
            }
        }
예제 #6
0
        /// <summary>
        /// Imports supported model format into Root JOBJ
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static HSD_JOBJ ImportModel(string filePath, ModelImportSettings settings = null)
        {
            // settings
            if (settings == null)
            {
                settings = new ModelImportSettings();
            }

            ProcessingCache cache = new ProcessingCache();

            cache.FolderPath = Path.GetDirectoryName(filePath);

            var processFlags = PostProcessPreset.TargetRealTimeMaximumQuality
                               | PostProcessSteps.Triangulate
                               | PostProcessSteps.LimitBoneWeights
                               | PostProcessSteps.FlipWindingOrder
                               | PostProcessSteps.CalculateTangentSpace;

            if (settings.FlipUVs)
            {
                processFlags |= PostProcessSteps.FlipUVs;
            }

            System.Diagnostics.Debug.WriteLine("Importing Model...");
            // import
            AssimpContext importer = new AssimpContext();

            if (settings.SmoothNormals)
            {
                importer.SetConfig(new NormalSmoothingAngleConfig(66.0f));
            }
            importer.SetConfig(new VertexBoneWeightLimitConfig(4));
            var importmodel = importer.ImportFile(filePath, processFlags);

            System.Diagnostics.Debug.WriteLine("Processing Nodes...");
            // process nodes
            var rootNode = importmodel.RootNode;
            var rootjobj = RecursiveProcess(cache, settings, importmodel, importmodel.RootNode);

            // Clear rotations
            if (settings.ZeroOutRotationsAndApplyFighterTransforms)
            {
                ZeroOutRotations(cache, rootjobj);
            }

            // get root of skeleton
            rootjobj = rootjobj.Child;

            rootjobj.Flags |= JOBJ_FLAG.SKELETON_ROOT;

            // no need for excess nodes
            //if (filePath.ToLower().EndsWith(".obj"))
            rootjobj.Next = null;

            // process mesh
            System.Diagnostics.Debug.WriteLine("Processing Mesh...");
            foreach (var mesh in cache.MeshNodes)
            {
                var Dobj = GetMeshes(cache, settings, importmodel, mesh);

                if (rootjobj.Dobj == null)
                {
                    rootjobj.Dobj = Dobj;
                }
                else
                {
                    rootjobj.Dobj.Add(Dobj);
                }

                System.Diagnostics.Debug.WriteLine($"Processing Mesh {rootjobj.Dobj.List.Count} {cache.MeshNodes.Count + 1}...");

                rootjobj.Flags |= JOBJ_FLAG.OPA;

                //TODO:
                //if (c.Flags.HasFlag(JOBJ_FLAG.OPA) || c.Flags.HasFlag(JOBJ_FLAG.ROOT_OPA))
                //    jobj.Flags |= JOBJ_FLAG.ROOT_OPA;

                if (settings.ShadingType == ShadingType.Material)
                {
                    rootjobj.Flags |= JOBJ_FLAG.LIGHTING;
                    foreach (var dobj in rootjobj.Dobj.List)
                    {
                        dobj.Mobj.RenderFlags |= RENDER_MODE.DIFFUSE;
                    }
                }
            }

            // SKELETON
            if (cache.EnvelopedJOBJs.Count > 0)
            {
                rootjobj.Flags |= JOBJ_FLAG.ENVELOPE_MODEL;
            }

            foreach (var jobj in cache.EnvelopedJOBJs)
            {
                jobj.Flags |= JOBJ_FLAG.SKELETON;
                jobj.InverseWorldTransform = Matrix4ToHSDMatrix(cache.jobjToInverseTransform[jobj]);
            }

            if (settings.ApplyNarutoMaterials)
            {
                ApplyNarutoMaterials(rootjobj);
            }

            // SAVE POBJ buffers
            System.Diagnostics.Debug.WriteLine("Saving Changes...");
            cache.POBJGen.SaveChanges();

            System.Diagnostics.Debug.WriteLine("Done!");

            // done
            return(rootjobj);
        }