コード例 #1
0
        public static void Export(string FileName, ExportSettings settings,
                                  List <STGenericMesh> Meshes, List <STGenericMaterial> Materials,
                                  List <STGenericTexture> Textures, STSkeleton skeleton = null, List <int> NodeArray = null)
        {
            if (Materials == null)
            {
                Materials = new List <STGenericMaterial>();
            }

            if (settings.RemoveDuplicateVertices)
            {
                foreach (var mesh in Meshes)
                {
                    mesh.RemoveDuplicateVertices();
                }
            }

            Console.WriteLine($"DAE Materials {Materials.Count}");

            List <string> failedTextureExport = new List <string>();
            Dictionary <string, STGenericMaterial> MaterialRemapper = new Dictionary <string, STGenericMaterial>();

            using (ColladaWriter writer = new ColladaWriter(FileName, settings))
            {
                writer.WriteAsset();

                if (Materials.Count > 0)
                {
                    List <string> textureNames = new List <string>();
                    for (int i = 0; i < Textures?.Count; i++)
                    {
                        if (!textureNames.Contains(Textures[i].Name))
                        {
                            textureNames.Add(Textures[i].Name);
                        }

                        if (settings.ExportTextures)
                        {
                            try
                            {
                                var bitmap = Textures[i].GetBitmap();
                                if (bitmap != null)
                                {
                                    string textureName = Textures[i].Name;
                                    if (textureName.RemoveIllegaleFileNameCharacters() != textureName)
                                    {
                                        string properName = textureName.RemoveIllegaleFileNameCharacters();
                                        for (int m = 0; m < Materials?.Count; m++)
                                        {
                                            foreach (var tex in Materials[m].TextureMaps)
                                            {
                                                if (tex.Name == textureName)
                                                {
                                                    tex.Name = properName;
                                                }
                                            }
                                        }

                                        textureName = properName;
                                    }

                                    if (settings.ImageFolder != "")
                                    {
                                        bitmap.Save($"{settings.ImageFolder}/{textureName}.png");
                                    }
                                    else
                                    {
                                        bitmap.Save($"{textureName}.png");
                                    }
                                    bitmap.Dispose();

                                    GC.Collect();
                                }
                            }
                            catch (Exception ex)
                            {
                                failedTextureExport.Add(Textures[i].Name);
                            }
                        }
                    }

                    for (int i = 0; i < Materials.Count; i++)
                    {
                        if (Materials[i].Name == null)
                        {
                            Materials[i].Name = $"Material{i}";
                        }
                    }

                    List <Material> materials = new List <Material>();
                    foreach (var mat in Materials)
                    {
                        Material material = new Material();
                        material.Name = mat.Name;

                        if (!MaterialRemapper.ContainsKey(mat.Name))
                        {
                            MaterialRemapper.Add(mat.Name, mat);
                        }
                        else
                        {
                            string name = Utils.RenameDuplicateString(mat.Name, MaterialRemapper.Keys.ToList());
                            MaterialRemapper.Add(name, mat);
                            material.Name = name;
                        }

                        if (mat.DiffuseColor != null)
                        {
                            material.DiffuseColor = new float[4] {
                                mat.DiffuseColor.R / 255.0F,
                                mat.DiffuseColor.G / 255.0F,
                                mat.DiffuseColor.B / 255.0F,
                                mat.DiffuseColor.A / 255.0F
                            }
                        }
                        ;

                        materials.Add(material);

                        foreach (var tex in mat.TextureMaps)
                        {
                            TextureMap texMap = new TextureMap();
                            texMap.Name = tex.Name;
                            if (tex.Type == STTextureType.Diffuse)
                            {
                                texMap.Type = PhongTextureType.diffuse;
                            }
                            else if (tex.Type == STTextureType.Normal)
                            {
                                texMap.Type = PhongTextureType.bump;
                            }
                            else if (tex.Type == STTextureType.Specular)
                            {
                                texMap.Type = PhongTextureType.specular;
                            }
                            else if (tex.Type == STTextureType.Emission)
                            {
                                texMap.Type = PhongTextureType.emission;
                            }
                            else
                            {
                                continue; //Skip adding unknown types
                            }
                            if (tex.WrapU == STTextureWrapMode.Repeat)
                            {
                                texMap.WrapModeS = SamplerWrapMode.WRAP;
                            }
                            else if (tex.WrapU == STTextureWrapMode.Mirror)
                            {
                                texMap.WrapModeS = SamplerWrapMode.MIRROR;
                            }
                            else if (tex.WrapU == STTextureWrapMode.Clamp)
                            {
                                texMap.WrapModeS = SamplerWrapMode.CLAMP;
                            }


                            if (tex.WrapV == STTextureWrapMode.Repeat)
                            {
                                texMap.WrapModeT = SamplerWrapMode.WRAP;
                            }
                            else if (tex.WrapV == STTextureWrapMode.Mirror)
                            {
                                texMap.WrapModeT = SamplerWrapMode.MIRROR;
                            }
                            else if (tex.WrapV == STTextureWrapMode.Clamp)
                            {
                                texMap.WrapModeT = SamplerWrapMode.CLAMP;
                            }


                            //If no textures are saved, still keep images references
                            //So the user can still dump textures after
                            if (Textures?.Count == 0 && !textureNames.Contains(texMap.Name))
                            {
                                textureNames.Add($"{texMap.Name}");
                            }

                            material.Textures.Add(texMap);
                        }
                    }

                    writer.WriteLibraryImages(textureNames.ToArray());

                    writer.WriteLibraryMaterials(materials);
                    writer.WriteLibraryEffects(materials);
                }
                else
                {
                    writer.WriteLibraryImages();
                }

                if (skeleton != null)
                {
                    for (int i = 0; i < skeleton.Bones.Count; i++)
                    {
                        if (skeleton.Bones[i].Name == null)
                        {
                            skeleton.Bones[i].Name = $"Bones{i}";
                        }
                    }

                    //Search for bones with rigging first
                    List <string> riggedBones = new List <string>();
                    if (settings.OnlyExportRiggedBones)
                    {
                        for (int i = 0; i < Meshes.Count; i++)
                        {
                            for (int v = 0; v < Meshes[i].Vertices.Count; v++)
                            {
                                var vertex = Meshes[i].Vertices[v];
                                for (int j = 0; j < vertex.BoneIndices.Count; j++)
                                {
                                    int id = -1;
                                    if (NodeArray != null && NodeArray.Count > vertex.BoneIndices[j])
                                    {
                                        id = NodeArray[vertex.BoneIndices[j]];
                                    }
                                    else
                                    {
                                        id = vertex.BoneIndices[j];
                                    }

                                    if (id < skeleton.Bones.Count && id != -1)
                                    {
                                        riggedBones.Add(skeleton.Bones[id].Name);
                                    }
                                }
                            }
                        }
                    }

                    foreach (var bone in skeleton.Bones)
                    {
                        if (settings.OnlyExportRiggedBones && !riggedBones.Contains(bone.Name))
                        {
                            Console.WriteLine("Skipping " + bone.Name);
                            continue;
                        }

                        //Set the inverse matrix
                        var inverse   = skeleton.GetBoneTransform(bone).Inverted();
                        var transform = bone.GetTransform();

                        float[] Transform = new float[] {
                            transform.M11, transform.M21, transform.M31, transform.M41,
                            transform.M12, transform.M22, transform.M32, transform.M42,
                            transform.M13, transform.M23, transform.M33, transform.M43,
                            transform.M14, transform.M24, transform.M34, transform.M44
                        };

                        float[] InvTransform = new float[] {
                            inverse.M11, inverse.M21, inverse.M31, inverse.M41,
                            inverse.M12, inverse.M22, inverse.M32, inverse.M42,
                            inverse.M13, inverse.M23, inverse.M33, inverse.M43,
                            inverse.M14, inverse.M24, inverse.M34, inverse.M44
                        };

                        writer.AddJoint(bone.Name, bone.ParentIndex == -1 ? "" :
                                        skeleton.Bones[bone.ParentIndex].Name, Transform, InvTransform,
                                        new float[3] {
                            bone.Position.X, bone.Position.Y, bone.Position.Z
                        },
                                        new float[3] {
                            bone.EulerRotation.X, bone.EulerRotation.Y, bone.EulerRotation.Z
                        },
                                        new float[3] {
                            bone.Scale.X, bone.Scale.Y, bone.Scale.Z
                        });
                    }
                }

                for (int i = 0; i < Meshes.Count; i++)
                {
                    if (Meshes[i].Name == null)
                    {
                        Meshes[i].Name = $"Mesh{i}";
                    }
                }

                int meshIndex = 0;

                writer.StartLibraryGeometries();
                foreach (var mesh in Meshes)
                {
                    int[] IndexTable = null;
                    if (NodeArray != null)
                    {
                        IndexTable = NodeArray.ToArray();
                    }

                    writer.StartGeometry(mesh.Name);

                    /* if (mesh.MaterialIndex != -1 && Materials.Count > mesh.MaterialIndex)
                     * {
                     *   writer.CurrentMaterial = Materials[mesh.MaterialIndex].Text;
                     *   Console.WriteLine($"MaterialIndex {mesh.MaterialIndex } {Materials[mesh.MaterialIndex].Text}");
                     * }*/

                    if (settings.TransformColorUVs)
                    {
                        List <STVertex> transformedVertices = new List <STVertex>();
                        foreach (var poly in mesh.PolygonGroups)
                        {
                            var mat = poly.Material;
                            if (mat == null)
                            {
                                continue;
                            }

                            var faces = poly.Faces;
                            for (int v = 0; v < poly.Faces.Count; v += 3)
                            {
                                if (faces.Count < v + 2)
                                {
                                    break;
                                }

                                var diffuse = mat.TextureMaps.FirstOrDefault(x => x.Type == STTextureType.Diffuse);
                                STTextureTransform transform = new STTextureTransform();
                                if (diffuse != null)
                                {
                                    transform = diffuse.Transform;
                                }

                                var vertexA = mesh.Vertices[(int)faces[v]];
                                var vertexB = mesh.Vertices[(int)faces[v + 1]];
                                var vertexC = mesh.Vertices[(int)faces[v + 2]];

                                if (!transformedVertices.Contains(vertexA))
                                {
                                    vertexA.TexCoords[0] = (vertexA.TexCoords[0] * transform.Scale) + transform.Translate;
                                    transformedVertices.Add(vertexA);
                                }
                                if (!transformedVertices.Contains(vertexB))
                                {
                                    vertexB.TexCoords[0] = (vertexB.TexCoords[0] * transform.Scale) + transform.Translate;
                                    transformedVertices.Add(vertexB);
                                }
                                if (!transformedVertices.Contains(vertexC))
                                {
                                    vertexC.TexCoords[0] = (vertexC.TexCoords[0] * transform.Scale) + transform.Translate;
                                    transformedVertices.Add(vertexC);
                                }
                            }
                        }
                    }

                    // collect sources
                    List <float>   Position    = new List <float>();
                    List <float>   Normal      = new List <float>();
                    List <float>   UV1         = new List <float>();
                    List <float>   UV2         = new List <float>();
                    List <float>   UV3         = new List <float>();
                    List <float>   Color       = new List <float>();
                    List <float>   Color2      = new List <float>();
                    List <int[]>   BoneIndices = new List <int[]>();
                    List <float[]> BoneWeights = new List <float[]>();

                    bool HasNormals = false;
                    bool HasColors  = false;
                    bool HasColors2 = false;
                    bool HasUV0     = false;
                    bool HasUV1     = false;
                    bool HasUV2     = false;
                    bool HasBoneIds = false;

                    mesh.OptimizeVertices();

                    foreach (var vertex in mesh.Vertices)
                    {
                        //Remove zero weights
                        if (settings.OptmizeZeroWeights)
                        {
                            float MaxWeight = 1;
                            for (int i = 0; i < 4; i++)
                            {
                                if (vertex.BoneWeights.Count <= i)
                                {
                                    continue;
                                }

                                if (vertex.BoneIndices.Count < i + 1)
                                {
                                    vertex.BoneWeights[i] = 0;
                                    MaxWeight             = 0;
                                }
                                else
                                {
                                    float weight = vertex.BoneWeights[i];
                                    if (vertex.BoneWeights.Count == i + 1)
                                    {
                                        weight = MaxWeight;
                                    }

                                    if (weight >= MaxWeight)
                                    {
                                        weight    = MaxWeight;
                                        MaxWeight = 0;
                                    }
                                    else
                                    {
                                        MaxWeight -= weight;
                                    }

                                    vertex.BoneWeights[i] = weight;
                                }
                            }
                        }


                        if (vertex.Normal != Vector3.Zero)
                        {
                            HasNormals = true;
                        }
                        if (vertex.Colors.Length > 0 && settings.UseVertexColors)
                        {
                            HasColors = true;
                        }
                        if (vertex.Colors.Length > 1 && settings.UseVertexColors)
                        {
                            HasColors2 = true;
                        }
                        if (vertex.TexCoords.Length > 0)
                        {
                            HasUV0 = true;
                        }
                        if (vertex.TexCoords.Length > 1)
                        {
                            HasUV1 = true;
                        }
                        if (vertex.TexCoords.Length > 2)
                        {
                            HasUV2 = true;
                        }
                        if (vertex.BoneIndices.Count > 0)
                        {
                            HasBoneIds = true;
                        }

                        Position.Add(vertex.Position.X); Position.Add(vertex.Position.Y); Position.Add(vertex.Position.Z);
                        Normal.Add(vertex.Normal.X); Normal.Add(vertex.Normal.Y); Normal.Add(vertex.Normal.Z);

                        for (int i = 0; i < vertex.TexCoords.Length; i++)
                        {
                            var texCoord = vertex.TexCoords[i];
                            if (settings.FlipTexCoordsVertical)
                            {
                                texCoord = new Vector2(texCoord.X, 1 - texCoord.Y);
                            }

                            if (i == 0)
                            {
                                UV1.Add(texCoord.X); UV1.Add(texCoord.Y);
                            }
                            if (i == 1)
                            {
                                UV2.Add(texCoord.X); UV2.Add(texCoord.Y);
                            }
                            if (i == 2)
                            {
                                UV3.Add(texCoord.X); UV3.Add(texCoord.Y);
                            }
                        }


                        if (vertex.Colors.Length > 0)
                        {
                            Color.AddRange(new float[] { vertex.Colors[0].X, vertex.Colors[0].Y, vertex.Colors[0].Z, vertex.Colors[0].W });
                        }
                        if (vertex.Colors.Length > 1)
                        {
                            Color2.AddRange(new float[] { vertex.Colors[1].X, vertex.Colors[1].Y, vertex.Colors[1].Z, vertex.Colors[1].W });
                        }

                        List <int>   bIndices = new List <int>();
                        List <float> bWeights = new List <float>();
                        for (int b = 0; b < vertex.BoneIndices.Count; b++)
                        {
                            if (b > mesh.VertexSkinCount - 1)
                            {
                                continue;
                            }

                            if (vertex.BoneWeights.Count > b)
                            {
                                if (vertex.BoneWeights[b] == 0)
                                {
                                    continue;
                                }
                            }

                            int index = -1;
                            if (IndexTable != null)
                            {
                                index = (int)IndexTable[vertex.BoneIndices[b]];
                            }
                            else
                            {
                                index = (int)vertex.BoneIndices[b];
                            }

                            if (index != -1 && index < skeleton?.Bones.Count)
                            {
                                bIndices.Add(index);
                            }

                            //Some models may only use indices (single bind, rigid skin)
                            if (vertex.BoneWeights.Count > b)
                            {
                                bWeights.Add(vertex.BoneWeights[b]);
                            }
                            else
                            {
                                bWeights.Add(1);
                            }
                        }

                        if (bIndices.Count == 0 && mesh.BoneIndex != -1)
                        {
                            HasBoneIds = true;
                            bIndices.Add(mesh.BoneIndex);
                            bWeights.Add(1);
                        }

                        BoneIndices.Add(bIndices.ToArray());
                        BoneWeights.Add(bWeights.ToArray());
                    }

                    List <TriangleList> triangleLists = new List <TriangleList>();
                    if (mesh.PolygonGroups.Count > 0)
                    {
                        foreach (var group in mesh.PolygonGroups)
                        {
                            TriangleList triangleList = new TriangleList();

                            triangleLists.Add(triangleList);

                            STGenericMaterial material = new STGenericMaterial();

                            if (group.MaterialIndex != -1 && Materials.Count > group.MaterialIndex)
                            {
                                material = Materials[group.MaterialIndex];
                            }

                            if (group.Material != null)
                            {
                                material = group.Material;
                            }

                            if (MaterialRemapper.Values.Any(x => x == material))
                            {
                                var key = MaterialRemapper.FirstOrDefault(x => x.Value == material).Key;
                                triangleList.Material = key;
                            }
                            else if (material.Name != string.Empty)
                            {
                                triangleList.Material = material.Name;
                            }

                            List <uint> faces = new List <uint>();
                            if (group.PrimitiveType == STPrimitiveType.TriangleStrips)
                            {
                                faces = TriangleConverter.ConvertTriangleStripsToTriangles(group.Faces);
                            }
                            else
                            {
                                faces = group.Faces;
                            }

                            for (int i = 0; i < faces.Count; i++)
                            {
                                triangleList.Indices.Add(faces[i]);
                            }
                        }
                    }

                    // write sources
                    writer.WriteGeometrySource(mesh.Name, SemanticType.POSITION, Position.ToArray(), triangleLists.ToArray());

                    if (HasNormals)
                    {
                        writer.WriteGeometrySource(mesh.Name, SemanticType.NORMAL, Normal.ToArray(), triangleLists.ToArray());
                    }

                    if (HasColors)
                    {
                        writer.WriteGeometrySource(mesh.Name, SemanticType.COLOR, Color.ToArray(), triangleLists.ToArray(), 0);
                    }

                    if (HasColors2)
                    {
                        writer.WriteGeometrySource(mesh.Name, SemanticType.COLOR, Color2.ToArray(), triangleLists.ToArray(), 1);
                    }

                    Console.WriteLine($"HasUV0 {HasUV0} {UV1.Count}");

                    if (HasUV0)
                    {
                        writer.WriteGeometrySource(mesh.Name, SemanticType.TEXCOORD, UV1.ToArray(), triangleLists.ToArray(), 0);
                    }

                    if (HasUV1)
                    {
                        writer.WriteGeometrySource(mesh.Name, SemanticType.TEXCOORD, UV2.ToArray(), triangleLists.ToArray(), 1);
                    }

                    if (HasUV2)
                    {
                        writer.WriteGeometrySource(mesh.Name, SemanticType.TEXCOORD, UV3.ToArray(), triangleLists.ToArray(), 2);
                    }

                    if (HasBoneIds)
                    {
                        writer.AttachGeometryController(BoneIndices, BoneWeights);
                    }

                    writer.EndGeometryMesh();
                }
                writer.EndGeometrySection();
            }
        }