예제 #1
0
        public static void OptToObj(OptFile opt, string objPath, bool scale)
        {
            if (opt == null)
            {
                throw new ArgumentNullException("opt");
            }

            string objDirectory = Path.GetDirectoryName(objPath);
            string objName = Path.GetFileNameWithoutExtension(objPath);

            var objMaterials = new ObjMaterialDictionary();

            foreach (var texture in opt.Textures.Values)
            {
                var material = new ObjMaterial
                {
                    Name = texture.Name,
                    DiffuseMapFileName = string.Format(CultureInfo.InvariantCulture, "{0}.png", texture.Name)
                };

                texture.Save(Path.Combine(objDirectory, material.DiffuseMapFileName));

                if (texture.HasAlpha)
                {
                    material.AlphaMapFileName = string.Format(CultureInfo.InvariantCulture, "{0}_alpha.png", texture.Name);

                    texture.SaveAlphaMap(Path.Combine(objDirectory, material.AlphaMapFileName));
                }

                objMaterials.Add(texture.Name, material);
            }

            objMaterials.Save(Path.ChangeExtension(objPath, "mtl"));

            var distances = opt.Meshes
                .SelectMany(t => t.Lods)
                .Select(t => t.Distance)
                .Distinct()
                .OrderByDescending(t => t)
                .ToArray();

            for (int distance = 0; distance < distances.Length; distance++)
            {
                var obj = new ObjFile();

                int objectsIndex = 0;
                int verticesIndex = 0;
                int verticesTexIndex = 0;
                int verticesNormalIndex = 0;

                foreach (var mesh in opt.Meshes)
                {
                    var lod = mesh.Lods.FirstOrDefault(t => t.Distance <= distances[distance]);

                    if (lod == null)
                    {
                        continue;
                    }

                    var objMesh = new ObjMesh(string.Format(CultureInfo.InvariantCulture, "{0}.{1:D3}", mesh.Descriptor.MeshType, objectsIndex));
                    obj.Meshes.Add(objMesh);
                    objectsIndex++;

                    if (scale)
                    {
                        foreach (var v in mesh.Vertices)
                        {
                            obj.Vertices.Add(new ObjVector3(v.X * OptFile.ScaleFactor, v.Z * OptFile.ScaleFactor, v.Y * OptFile.ScaleFactor));
                        }
                    }
                    else
                    {
                        foreach (var v in mesh.Vertices)
                        {
                            obj.Vertices.Add(new ObjVector3(v.X, v.Z, v.Y));
                        }
                    }

                    foreach (var v in mesh.TextureCoordinates)
                    {
                        obj.VertexTexCoords.Add(new ObjVector2(v.U, -v.V));
                    }

                    foreach (var v in mesh.VertexNormals)
                    {
                        obj.VertexNormals.Add(new ObjVector3(v.X, v.Z, v.Y));
                    }

                    foreach (var faceGroup in lod.FaceGroups)
                    {
                        var objFaceGroup = new ObjFaceGroup();

                        if (faceGroup.Textures.Count > 0)
                        {
                            objFaceGroup.MaterialName = faceGroup.Textures[0];
                        }

                        objMesh.FaceGroups.Add(objFaceGroup);

                        foreach (var face in faceGroup.Faces)
                        {
                            if (face.VerticesIndex.D < 0)
                            {
                                objFaceGroup.Faces.Add(new ObjFace()
                                {
                                    VerticesIndex = new ObjIndex(
                                        verticesIndex + face.VerticesIndex.A,
                                        verticesIndex + face.VerticesIndex.B,
                                        verticesIndex + face.VerticesIndex.C
                                        ),

                                    VertexTexCoordsIndex = new ObjIndex(
                                        verticesTexIndex + face.TextureCoordinatesIndex.A,
                                        verticesTexIndex + face.TextureCoordinatesIndex.B,
                                        verticesTexIndex + face.TextureCoordinatesIndex.C),

                                    VertexNormalsIndex = new ObjIndex(
                                        verticesNormalIndex + face.VertexNormalsIndex.A,
                                        verticesNormalIndex + face.VertexNormalsIndex.B,
                                        verticesNormalIndex + face.VertexNormalsIndex.C)
                                });
                            }
                            else
                            {
                                objFaceGroup.Faces.Add(new ObjFace()
                                {
                                    VerticesIndex = new ObjIndex(
                                        verticesIndex + face.VerticesIndex.A,
                                        verticesIndex + face.VerticesIndex.B,
                                        verticesIndex + face.VerticesIndex.C,
                                        verticesIndex + face.VerticesIndex.D
                                        ),

                                    VertexTexCoordsIndex = new ObjIndex(
                                        verticesTexIndex + face.TextureCoordinatesIndex.A,
                                        verticesTexIndex + face.TextureCoordinatesIndex.B,
                                        verticesTexIndex + face.TextureCoordinatesIndex.C,
                                        verticesTexIndex + face.TextureCoordinatesIndex.D),

                                    VertexNormalsIndex = new ObjIndex(
                                        verticesNormalIndex + face.VertexNormalsIndex.A,
                                        verticesNormalIndex + face.VertexNormalsIndex.B,
                                        verticesNormalIndex + face.VertexNormalsIndex.C,
                                        verticesNormalIndex + face.VertexNormalsIndex.D)
                                });
                            }
                        }
                    }

                    verticesIndex += mesh.Vertices.Count;
                    verticesTexIndex += mesh.TextureCoordinates.Count;
                    verticesNormalIndex += mesh.VertexNormals.Count;
                }

                obj.Save(Path.Combine(objDirectory, string.Format(CultureInfo.InvariantCulture, "{0}_{1}.obj", objName, distance)), objName);
            }
        }
예제 #2
0
        public static ObjFile FromFile(string fileName)
        {
            ObjFile obj = new ObjFile();

            obj.FileName = fileName;

            using (StreamReader file = new StreamReader(fileName))
            {
                string line;

                string materialName = null;

                ObjMesh mesh = new ObjMesh("unnamed");
                obj.Meshes.Add(mesh);

                ObjFaceGroup faceGroup = new ObjFaceGroup();
                mesh.FaceGroups.Add(faceGroup);

                while ((line = file.ReadLine()) != null)
                {
                    if (string.IsNullOrWhiteSpace(line))
                    {
                        continue;
                    }

                    line = line.Trim();

                    if (line.StartsWith("#", StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }

                    string[] values = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);

                    switch (values[0].ToUpperInvariant())
                    {
                        case "MTLLIB":
                            if (values.Length != 2)
                            {
                                throw new InvalidDataException("missing mtllib name");
                            }

                            if (obj.Materials.Count > 0)
                            {
                                throw new InvalidDataException("multiple mtllib");
                            }

                            obj.Materials = ObjMaterialDictionary.FromFile(Path.Combine(Path.GetDirectoryName(fileName), values[1]));
                            break;

                        case "V":
                            if (values.Length < 4)
                            {
                                throw new InvalidDataException("v must be x y z");
                            }

                            obj.Vertices.Add(new ObjVector3(
                                float.Parse(values[1], CultureInfo.InvariantCulture),
                                float.Parse(values[2], CultureInfo.InvariantCulture),
                                float.Parse(values[3], CultureInfo.InvariantCulture)));
                            break;

                        case "VT":
                            if (values.Length < 3)
                            {
                                throw new InvalidDataException("vt must be u v");
                            }

                            obj.VertexTexCoords.Add(new ObjVector2(
                                float.Parse(values[1], CultureInfo.InvariantCulture),
                                float.Parse(values[2], CultureInfo.InvariantCulture)));
                            break;

                        case "VN":
                            if (values.Length < 4)
                            {
                                throw new InvalidDataException("vn must be x y z");
                            }

                            obj.VertexNormals.Add(new ObjVector3(
                                float.Parse(values[1], CultureInfo.InvariantCulture),
                                float.Parse(values[2], CultureInfo.InvariantCulture),
                                float.Parse(values[3], CultureInfo.InvariantCulture)));
                            break;

                        case "O":
                        case "G":
                            if (values.Length < 2)
                            {
                                throw new InvalidDataException("missing object name");
                            }

                            if (faceGroup.Faces.Count == 0)
                            {
                                mesh.Name = values[1];
                            }
                            else
                            {
                                mesh = new ObjMesh(values[1]);
                                obj.Meshes.Add(mesh);

                                faceGroup = new ObjFaceGroup();
                                faceGroup.MaterialName = materialName;
                                mesh.FaceGroups.Add(faceGroup);
                            }
                            break;

                        case "USEMTL":
                            if (values.Length != 2)
                            {
                                throw new InvalidDataException("missing material name");
                            }

                            materialName = values[1];

                            if (faceGroup.Faces.Count == 0)
                            {
                                faceGroup.MaterialName = materialName;
                            }
                            else
                            {
                                faceGroup = new ObjFaceGroup();
                                faceGroup.MaterialName = materialName;
                                mesh.FaceGroups.Add(faceGroup);
                            }
                            break;

                        case "F":
                            if (values.Length == 4)
                            {
                                var v1 = ParseFaceVertex(values[1]);
                                var v2 = ParseFaceVertex(values[2]);
                                var v3 = ParseFaceVertex(values[3]);

                                var face = new ObjFace();
                                face.VerticesIndex = new ObjIndex(v1.Item1, v2.Item1, v3.Item1);
                                face.VertexTexCoordsIndex = new ObjIndex(v1.Item2, v2.Item2, v3.Item2);
                                face.VertexNormalsIndex = new ObjIndex(v1.Item3, v2.Item3, v3.Item3);

                                faceGroup.Faces.Add(face);
                            }
                            else if (values.Length == 5)
                            {
                                var v1 = ParseFaceVertex(values[1]);
                                var v2 = ParseFaceVertex(values[2]);
                                var v3 = ParseFaceVertex(values[3]);
                                var v4 = ParseFaceVertex(values[4]);

                                var face = new ObjFace();
                                face.VerticesIndex = new ObjIndex(v1.Item1, v2.Item1, v3.Item1, v4.Item1);
                                face.VertexTexCoordsIndex = new ObjIndex(v1.Item2, v2.Item2, v3.Item2, v4.Item2);
                                face.VertexNormalsIndex = new ObjIndex(v1.Item3, v2.Item3, v3.Item3, v4.Item3);

                                faceGroup.Faces.Add(face);
                            }
                            else
                            {
                                throw new InvalidDataException("invalid face");
                            }
                            break;
                    }
                }
            }

            return obj;
        }