解决helix.toolkit obj模型贴图查找失败导致的异常

前言

helix.toolkit封装了模型加载的操作,由于按照了标准模型的读取,出现材质或者贴图找不到的情况,容易模型加载异常。因此解决办法是,如果相关资源没找到的话,默认赋上默认材质来解决。

附上本文demo

(10条消息) helix.toolkit封装了模型加载的操作,由于按照了标准模型的读取,出现材质或者贴图找不到的情况,容易模型加载异常。因此解-C#文档类资源-CSDN文库

详细内容

helix中封装了对模型类型文件的读取操作,如下

 private async Task<Model3DGroup> LoadAsync(string model3DPath, bool freeze)
        {
            return await Task.Factory.StartNew(() =>
            {
                var mi = new ModelImporter2.ModelImporter();

                if (freeze)
                {
                    // Alt 1. - freeze the model 
                    return mi.Load(model3DPath, null, true);
                }

                // Alt. 2 - create the model on the UI dispatcher
                return mi.Load(model3DPath, this.dispatcher);
            });
        }

f12进去看,能够看到ObjReader层级,问题就出来了ObjReader默认加载模型自带的贴图或者材质,如果找不到,模型就加载不出来,因此解决办法自然是“让代码正常运行”先。给模型加载默认的材质。

 /// <summary>
        /// Loads a model from the specified path.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="dispatcher">The dispatcher used to create the model.</param>
        /// <param name="freeze">Freeze the model if set to <c>true</c>.</param>
        /// <returns>A model.</returns>
        /// <exception cref="System.InvalidOperationException">File format not supported.</exception>
        public Model3DGroup Load(string path, Dispatcher dispatcher = null, bool freeze = false)
        {
            if (path == null)
            {
                return null;
            }

            if (dispatcher == null)
            {
                dispatcher = Dispatcher.CurrentDispatcher;
            }

            Model3DGroup model;
            var ext = Path.GetExtension(path);
            if (ext != null)
            {
                ext = ext.ToLower();
            }

            switch (ext)
            {
                case ".3ds":
                    {
                        var r = new StudioReader(dispatcher) { DefaultMaterial = this.DefaultMaterial, Freeze = freeze };
                        model = r.Read(path);
                        break;
                    }

                case ".lwo":
                    {
                        var r = new LwoReader(dispatcher) { DefaultMaterial = this.DefaultMaterial, Freeze = freeze };
                        model = r.Read(path);

                        break;
                    }

                case ".obj":
                    {
                        var r = new ObjReader2(dispatcher) { DefaultMaterial = this.DefaultMaterial, Freeze = freeze };
                        model = r.Read(path);
                        break;
                    }

                case ".objz":
                    {
                        var r = new ObjReader(dispatcher) { DefaultMaterial = this.DefaultMaterial, Freeze = freeze };
                        model = r.ReadZ(path);
                        break;
                    }

                case ".stl":
                    {
                        var r = new StLReader(dispatcher) { DefaultMaterial = this.DefaultMaterial, Freeze = freeze };
                        model = r.Read(path);
                        break;
                    }

                case ".off":
                    {
                        var r = new OffReader(dispatcher) { DefaultMaterial = this.DefaultMaterial, Freeze = freeze };
                        model = r.Read(path);
                        break;
                    }
                case ".ply":
                    {
                        var r = new PlyReader(dispatcher) { DefaultMaterial = this.DefaultMaterial, Freeze = freeze };
                        model = r.Read(path);
                        break;
                    }
                default:
                    throw new InvalidOperationException("File format not supported.");
            }

            //if (!freeze)
            //{
            //    dispatcher.Invoke(new Action(() => model.SetName(Path.GetFileName(path))));
            //}

            return model;
        }

修改后的objreader实现如下:

public class ObjReader2 : ModelReader
    {
        private static readonly char[] Delimiters = new char[] { ' ' };
        /// <summary>
        /// The smoothing group maps.
        /// </summary>
        /// <remarks>
        /// The outer dictionary maps from a smoothing group number to a dictionary.
        /// The inner dictionary maps from an obj file (vertex, texture coordinates, normal) index to a vertex index in the current group.
        /// </remarks>
        private readonly Dictionary<long, Dictionary<Tuple<int, int, int>, int>> smoothingGroupMaps;

        /// <summary>
        /// The current smoothing group.
        /// </summary>
        private long currentSmoothingGroup;

        /// <summary>
        /// The line number of the line being parsed.
        /// </summary>
        private int currentLineNo;

        /// <summary>
        /// Initializes a new instance of the <see cref="ObjReader" /> class.
        /// </summary>
        /// <param name="dispatcher">The dispatcher.</param>
        public ObjReader2(Dispatcher dispatcher = null)
            : base(dispatcher)
        {
            this.IgnoreErrors = false;
            this.SwitchYZ = false;

            this.IsSmoothingDefault = true;
            this.SkipTransparencyValues = true;

            this.Points = new List<Point3D>();
            this.TextureCoordinates = new List<Point>();
            this.Normals = new List<Vector3D>();

            this.Groups = new List<Group>();
            this.Materials = new Dictionary<string, MaterialDefinition>();

            this.smoothingGroupMaps = new Dictionary<long, Dictionary<Tuple<int, int, int>, int>>();

            // File format specifications
            // http://en.wikipedia.org/wiki/Obj
            // http://en.wikipedia.org/wiki/Material_Template_Library
            // http://www.martinreddy.net/gfx/3d/OBJ.spec
            // http://www.eg-models.de/formats/Format_Obj.html
        }

        /// <summary>
        /// Gets or sets a value indicating whether to ignore errors.
        /// </summary>
        /// <value><c>true</c> if errors should be ignored; <c>false</c> if errors should throw an exception.</value>
        /// <remarks>
        /// The default value is on (true).
        /// </remarks>
        public bool IgnoreErrors { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether to switch Y and Z coordinates.
        /// </summary>
        public bool SwitchYZ { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether to skip transparency values in the material files.
        /// </summary>
        /// <value>
        /// <c>true</c> if transparency values should be skipped; otherwise, <c>false</c>.
        /// </value>
        /// <remarks>
        /// This option is added to allow disabling the <code>Tr</code> values in files where it has been defined incorrectly.
        /// The transparency values (<code>Tr</code>) are interpreted as 0 = transparent, 1 = opaque.
        /// The dissolve values (<code>d</code>) are interpreted as 0 = transparent, 1 = opaque.
        /// </remarks>
        public bool SkipTransparencyValues { get; set; }

        /// <summary>
        /// Sets a value indicating whether smoothing is default.
        /// </summary>
        /// <remarks>
        /// The default value is smoothing=on (true).
        /// </remarks>
        public bool IsSmoothingDefault
        {
            set
            {
                this.currentSmoothingGroup = value ? 1 : 0;
            }
        }

        /// <summary>
        /// Gets the groups of the file.
        /// </summary>
        /// <value>The groups.</value>
        public IList<Group> Groups { get; private set; }

        /// <summary>
        /// Gets the materials in the imported material files.
        /// </summary>
        /// <value>The materials.</value>
        public Dictionary<string, MaterialDefinition> Materials { get; private set; }

        /// <summary>
        /// Gets or sets the current material.
        /// </summary>
        private Material CurrentMaterial { get; set; }

        /// <summary>
        /// Gets the current group.
        /// </summary>
        private Group CurrentGroup
        {
            get
            {
                if (this.Groups.Count == 0)
                {
                    this.AddGroup("default");
                }

                return this.Groups[this.Groups.Count - 1];
            }
        }

        /// <summary>
        /// Gets or sets the normal vectors.
        /// </summary>
        private IList<Vector3D> Normals { get; set; }

        /// <summary>
        /// Gets or sets the points.
        /// </summary>
        private IList<Point3D> Points { get; set; }

        /// <summary>
        /// Gets or sets the stream reader.
        /// </summary>
        private StreamReader Reader { get; set; }

        /// <summary>
        /// Gets or sets the texture coordinates.
        /// </summary>
        private IList<Point> TextureCoordinates { get; set; }

        /// <summary>
        /// Reads the model and any associated materials from streams
        /// </summary>
        /// <param name="objStream">A model stream from the obj file</param>
        /// <param name="mtlStreams">Array of Material streams referenced in the obj file</param>
        /// <returns></returns>
        public Model3DGroup Read(Stream objStream, Stream[] mtlStreams)
        {
            foreach (var mtlStream in mtlStreams)
            {
                using (var mtlStreamReader = new StreamReader(mtlStream))
                {
                    ReadMaterial(mtlStreamReader);
                }
            }

            return Read(objStream);
        }

        /// <summary>
        /// Reads the model from the specified path.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns>The model.</returns>
        public override Model3DGroup Read(string path)
        {
            this.TexturePath = Path.GetDirectoryName(path);
            using (var s = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                return this.Read(s);
            }
        }

        /// <summary>
        /// Reads the model from the specified stream.
        /// </summary>
        /// <param name="s">The stream.</param>
        /// <returns>The model.</returns>
        public override Model3DGroup Read(Stream s)
        {
            using (this.Reader = new StreamReader(s))
            {
                this.currentLineNo = 0;
                while (!this.Reader.EndOfStream)
                {
                    this.currentLineNo++;
                    var line = this.Reader.ReadLine();
                    if (line == null)
                    {
                        break;
                    }

                    line = line.Trim();
                    while (line.EndsWith("\\"))
                    {
                        var nextLine = this.Reader.ReadLine();
                        while (nextLine.Length == 0)
                        {
                            nextLine = this.Reader.ReadLine();
                        }

                        line = line.TrimEnd('\\') + nextLine;
                    }

                    if (line.StartsWith("#") || line.Length == 0)
                    {
                        continue;
                    }

                    string keyword, values;
                    SplitLine(line, out keyword, out values);

                    switch (keyword.ToLower())
                    {
                        // Vertex data
                        case "v": // geometric vertices
                            this.AddVertex(values);
                            break;
                        case "vt": // texture vertices
                            this.AddTexCoord(values);
                            break;
                        case "vn": // vertex normals
                            this.AddNormal(values);
                            break;
                        case "vp": // parameter space vertices
                        case "cstype": // rational or non-rational forms of curve or surface type: basis matrix, Bezier, B-spline, Cardinal, Taylor
                        case "degree": // degree
                        case "bmat": // basis matrix
                        case "step": // step size
                            // not supported
                            break;

                        // Elements
                        case "f": // face
                            this.AddFace(values);
                            break;
                        case "p": // point
                        case "l": // line
                        case "curv": // curve
                        case "curv2": // 2D curve
                        case "surf": // surface
                            // not supported
                            break;

                        // Free-form curve/surface body statements
                        case "parm": // parameter name
                        case "trim": // outer trimming loop (trim)
                        case "hole": // inner trimming loop (hole)
                        case "scrv": // special curve (scrv)
                        case "sp":  // special point (sp)
                        case "end": // end statement (end)
                            // not supported
                            break;

                        // Connectivity between free-form surfaces
                        case "con": // connect
                            // not supported
                            break;

                        // Grouping
                        case "g": // group name
                            this.AddGroup(values);
                            break;
                        case "s": // smoothing group
                            this.SetSmoothingGroup(values);
                            break;
                        case "mg": // merging group
                            break;
                        case "o": // object name
                            // not supported
                            break;

                        // Display/render attributes
                        case "mtllib": // material library
                            this.LoadMaterialLib(values);
                            break;
                        case "usemtl": // material name
                            this.EnsureNewMesh();

                            this.SetMaterial(values);
                            break;
                        case "usemap": // texture map name
                            this.EnsureNewMesh();

                            break;
                        case "bevel": // bevel interpolation
                        case "c_interp": // color interpolation
                        case "d_interp": // dissolve interpolation
                        case "lod": // level of detail
                        case "shadow_obj": // shadow casting
                        case "trace_obj": // ray tracing
                        case "ctech": // curve approximation technique
                        case "stech": // surface approximation technique
                            // not supported
                            break;
                    }
                }
            }

            return this.BuildModel();
        }

        /// <summary>
        /// Reads a GZipStream compressed OBJ file.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns>A Model3D object containing the model.</returns>
        /// <remarks>This is a file format used by Helix Toolkit only.
        /// Use the GZipHelper class to compress an .obj file.</remarks>
        public Model3DGroup ReadZ(string path)
        {
            this.TexturePath = Path.GetDirectoryName(path);
            using (var s = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                var deflateStream = new GZipStream(s, CompressionMode.Decompress, true);
                return this.Read(deflateStream);
            }
        }

        /// <summary>
        /// Parses a color string.
        /// </summary>
        /// <param name="values">
        /// The input.
        /// </param>
        /// <returns>
        /// The parsed color.
        /// </returns>
        private static Color ColorParse(string values)
        {
            var fields = Split(values);
            return Color.FromRgb((byte)(fields[0] * 255), (byte)(fields[1] * 255), (byte)(fields[2] * 255));
        }

        /// <summary>
        /// Parse a string containing a double value.
        /// </summary>
        /// <param name="input">
        /// The input string.
        /// </param>
        /// <returns>
        /// The value.
        /// </returns>
        private static double DoubleParse(string input)
        {
            return double.Parse(input, CultureInfo.InvariantCulture);
        }

        /// <summary>
        /// Splits the specified string using whitespace(input) as separators.
        /// </summary>
        /// <param name="input">
        /// The input string.
        /// </param>
        /// <returns>
        /// List of input.
        /// </returns>
        private static IList<double> Split(string input)
        {
            input = input.Trim();
            var fields = input.Split(Delimiters, System.StringSplitOptions.RemoveEmptyEntries);
            var result = new double[fields.Length];
            for (int i = 0; i < fields.Length; i++)
            {
                result[i] = DoubleParse(fields[i]);
            }

            return result;
        }

        /// <summary>
        /// Splits a line in keyword and arguments.
        /// </summary>
        /// <param name="line">
        /// The line.
        /// </param>
        /// <param name="keyword">
        /// The keyword.
        /// </param>
        /// <param name="arguments">
        /// The arguments.
        /// </param>
        private static void SplitLine(string line, out string keyword, out string arguments)
        {
            int idx = line.IndexOf(' ');
            if (idx < 0)
            {
                keyword = line;
                arguments = null;
                return;
            }

            keyword = line.Substring(0, idx);
            arguments = line.Substring(idx + 1);
        }

        /// <summary>
        /// Adds a group with the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        private void AddGroup(string name)
        {
            this.Groups.Add(new Group(name, this.CurrentMaterial ?? this.DefaultMaterial));
            this.smoothingGroupMaps.Clear();
        }

        /// <summary>
        /// Ensures that a new mesh is created.
        /// </summary>
        private void EnsureNewMesh()
        {
            if (this.CurrentGroup.MeshBuilder.TriangleIndices.Count != 0)
            {
                this.CurrentGroup.AddMesh(this.CurrentMaterial ?? this.DefaultMaterial);
                this.smoothingGroupMaps.Clear();
            }
        }

        /// <summary>
        /// Sets the smoothing group number.
        /// </summary>
        /// <param name="values">The group number.</param>
        private void SetSmoothingGroup(string values)
        {
            if (values == "off")
            {
                this.currentSmoothingGroup = 0;
            }
            else
            {
                long smoothingGroup;
                if (long.TryParse(values, out smoothingGroup))
                {
                    this.currentSmoothingGroup = smoothingGroup;
                }
                else
                {
                    // invalid parameter
                    if (this.IgnoreErrors)
                    {
                        return;
                    }

                    throw new FileFormatException(string.Format("Invalid smoothing group ({0}) at line {1}.", values, this.currentLineNo));
                }
            }
        }

        /// <summary>
        /// Adds a face.
        /// </summary>
        /// <param name="values">
        /// The input values.
        /// </param>
        /// <remarks>
        /// Adds a polygonal face. The numbers are indexes into the arrays of vertex positions,
        /// texture coordinates, and normal vectors respectively. A number may be omitted if,
        /// for example, texture coordinates are not being defined in the model.
        /// There is no maximum number of vertices that a single polygon may contain.
        /// The .obj file specification says that each face must be flat and convex.
        /// </remarks>
        private void AddFace(string values)
        {
            var currentGroup = this.CurrentGroup;
            var builder = currentGroup.MeshBuilder;
            var positions = builder.Positions;
            var textureCoordinates = builder.TextureCoordinates;
            var normals = builder.Normals;

            Dictionary<Tuple<int, int, int>, int> smoothingGroupMap = null;

            // If a smoothing group is defined, get the map from obj-file-index to current-group-vertex-index.
            if (this.currentSmoothingGroup != 0)
            {
                if (!this.smoothingGroupMaps.TryGetValue(this.currentSmoothingGroup, out smoothingGroupMap))
                {
                    smoothingGroupMap = new Dictionary<Tuple<int, int, int>, int>();
                    this.smoothingGroupMaps.Add(this.currentSmoothingGroup, smoothingGroupMap);
                }
            }

            var fields = values.Split(Delimiters, System.StringSplitOptions.RemoveEmptyEntries);
            var faceIndices = new List<int>();
            foreach (var field in fields)
            {
                if (string.IsNullOrEmpty(field))
                {
                    continue;
                }

                var ff = field.Split('/');
                int vi = int.Parse(ff[0]);
                int vti = ff.Length > 1 && ff[1].Length > 0 ? int.Parse(ff[1]) : int.MaxValue;
                int vni = ff.Length > 2 && ff[2].Length > 0 ? int.Parse(ff[2]) : int.MaxValue;

                // Handle relative indices (negative numbers)
                if (vi < 0)
                {
                    vi = this.Points.Count + vi + 1;
                }

                if (vti < 0)
                {
                    vti = this.TextureCoordinates.Count + vti + 1;
                }

                if (vni < 0)
                {
                    vni = this.Normals.Count + vni + 1;
                }

                // Check if the indices are valid
                if (vi - 1 >= this.Points.Count)
                {
                    if (this.IgnoreErrors)
                    {
                        return;
                    }

                    throw new FileFormatException(string.Format("Invalid vertex index ({0}) on line {1}.", vi, this.currentLineNo));
                }

                if (vti == int.MaxValue)
                {
                    // turn off texture coordinates in the builder
                    builder.CreateTextureCoordinates = false;
                }

                if (vni == int.MaxValue)
                {
                    // turn off normals in the builder
                    builder.CreateNormals = false;
                }

                // check if the texture coordinate index is valid
                if (builder.CreateTextureCoordinates && vti - 1 >= this.TextureCoordinates.Count)
                {
                    if (this.IgnoreErrors)
                    {
                        return;
                    }

                    throw new FileFormatException(
                            string.Format(
                                "Invalid texture coordinate index ({0}) on line {1}.", vti, this.currentLineNo));
                }

                // check if the normal index is valid
                if (builder.CreateNormals && vni - 1 >= this.Normals.Count)
                {
                    if (this.IgnoreErrors)
                    {
                        return;
                    }

                    throw new FileFormatException(
                            string.Format("Invalid normal index ({0}) on line {1}.", vni, this.currentLineNo));
                }

                bool addVertex = true;

                if (smoothingGroupMap != null)
                {
                    var key = Tuple.Create(vi, vti, vni);

                    int vix;
                    if (smoothingGroupMap.TryGetValue(key, out vix))
                    {
                        // use the index of a previously defined vertex
                        addVertex = false;
                    }
                    else
                    {
                        // add a new vertex
                        vix = positions.Count;
                        smoothingGroupMap.Add(key, vix);
                    }

                    faceIndices.Add(vix);
                }
                else
                {
                    // if smoothing is off, always add a new vertex
                    faceIndices.Add(positions.Count);
                }

                if (addVertex)
                {
                    // add vertex
                    positions.Add(this.Points[vi - 1]);

                    // add texture coordinate (if enabled)
                    if (builder.CreateTextureCoordinates)
                    {
                        textureCoordinates.Add(this.TextureCoordinates[vti - 1]);
                    }

                    // add normal (if enabled)
                    if (builder.CreateNormals)
                    {
                        normals.Add(this.Normals[vni - 1]);
                    }
                }
            }

            if (faceIndices.Count <= 4)
            {
                // add triangles or quads
                builder.AddPolygon(faceIndices);
            }
            else
            {
                // add triangles by cutting ears algorithm
                // this algorithm is quite expensive...
                builder.AddPolygonByTriangulation(faceIndices);
            }
        }

        /// <summary>
        /// Adds a normal.
        /// </summary>
        /// <param name="values">
        /// The input values.
        /// </param>
        private void AddNormal(string values)
        {
            var fields = Split(values);
            if (SwitchYZ)
            {
                this.Normals.Add(new Vector3D(fields[0], -fields[2], fields[1]));
            }
            else
            {
                this.Normals.Add(new Vector3D(fields[0], fields[1], fields[2]));
            }
        }

        /// <summary>
        /// Adds a texture coordinate.
        /// </summary>
        /// <param name="values">
        /// The input values.
        /// </param>
        private void AddTexCoord(string values)
        {
            var fields = Split(values);
            this.TextureCoordinates.Add(new Point(fields[0], 1 - fields[1]));
        }

        /// <summary>
        /// Adds a vertex.
        /// </summary>
        /// <param name="values">
        /// The input values.
        /// </param>
        private void AddVertex(string values)
        {
            var fields = Split(values);
            if (SwitchYZ)
            {
                this.Points.Add(new Point3D(fields[0], -fields[2], fields[1]));
            }
            else
            {
                this.Points.Add(new Point3D(fields[0], fields[1], fields[2]));
            }
        }

        /// <summary>
        /// Builds the model.
        /// </summary>
        /// <returns>A Model3D object.</returns>
        private Model3DGroup BuildModel()
        {
            Model3DGroup modelGroup = null;
            this.Dispatch(() =>
            {
                modelGroup = new Model3DGroup();
                foreach (var g in this.Groups)
                {
                    foreach (var gm in g.CreateModels())
                    {
                        gm.SetName(g.Name);

                        if (this.Freeze)
                        {
                            gm.Freeze();
                        }

                        modelGroup.Children.Add(gm);
                    }
                }

                if (this.Freeze)
                {
                    modelGroup.Freeze();
                }
            });
            return modelGroup;
        }

        /// <summary>
        /// Gets the material with the specified name.
        /// </summary>
        /// <param name="materialName">
        /// The material name.
        /// </param>
        /// <returns>
        /// The material.
        /// </returns>
        private Material GetMaterial(string materialName)
        {
            MaterialDefinition mat;
            if (!string.IsNullOrEmpty(materialName) && this.Materials.TryGetValue(materialName, out mat))
            {
                Material m = null;
                this.Dispatch(() =>
                {
                    m = mat.GetMaterial(this.TexturePath);
                });
                return m;
            }

            return this.DefaultMaterial;
        }

        /// <summary>
        /// Loads a material library.
        /// </summary>
        /// <param name="mtlFile">
        /// The material file name.
        /// </param>
        private void LoadMaterialLib(string mtlFile)
        {
            string path = PathHelpers.GetFullPath(this.TexturePath, mtlFile);

            if (!File.Exists(path))
            {
                return;
            }

            using (var materialReader = new StreamReader(path))
            {
                ReadMaterial(materialReader);
            }
        }

        /// <summary>
        /// Loads the material library from a streamreader
        /// </summary>
        /// <param name="materialReader"></param>
        private void ReadMaterial(StreamReader materialReader)
        {
            MaterialDefinition currentMaterial = null;

            while (!materialReader.EndOfStream)
            {
                var line = materialReader.ReadLine();
                if (line == null)
                {
                    break;
                }

                line = line.Trim();

                if (line.StartsWith("#") || line.Length == 0)
                {
                    continue;
                }

                string keyword, value;
                SplitLine(line, out keyword, out value);

                switch (keyword.ToLower())
                {
                    case "newmtl":
                        if (value != null)
                        {
                            if (this.Materials.ContainsKey(value))
                            {
                                currentMaterial = null;
                            }
                            else
                            {
                                currentMaterial = new MaterialDefinition(value);
                                this.Materials.Add(value, currentMaterial);
                            }
                        }

                        break;
                    case "ka":
                        if (currentMaterial != null && value != null)
                        {
                            currentMaterial.Ambient = ColorParse(value);
                        }

                        break;
                    case "kd":
                        if (currentMaterial != null && value != null)
                        {
                            currentMaterial.Diffuse = ColorParse(value);
                        }

                        break;
                    case "ks":
                        if (currentMaterial != null && value != null)
                        {
                            currentMaterial.Specular = ColorParse(value);
                        }

                        break;
                    case "ns":
                        if (currentMaterial != null && value != null)
                        {
                            currentMaterial.SpecularCoefficient = DoubleParse(value);
                        }

                        break;
                    case "d":
                        if (currentMaterial != null && value != null)
                        {
                            currentMaterial.Dissolved = DoubleParse(value);
                        }

                        break;
                    case "tr":
                        if (!this.SkipTransparencyValues && currentMaterial != null && value != null)
                        {
                            currentMaterial.Dissolved = DoubleParse(value);
                        }

                        break;
                    case "illum":
                        if (currentMaterial != null && value != null)
                        {
                            currentMaterial.Illumination = int.Parse(value);
                        }

                        break;
                    case "map_ka":
                        if (currentMaterial != null)
                        {
                            currentMaterial.AmbientMap = value;
                        }

                        break;
                    case "map_kd":
                        if (currentMaterial != null)
                        {
                            currentMaterial.DiffuseMap = value;
                        }

                        break;
                    case "map_ks":
                        if (currentMaterial != null)
                        {
                            currentMaterial.SpecularMap = value;
                        }

                        break;
                    case "map_d":
                        if (currentMaterial != null)
                        {
                            currentMaterial.AlphaMap = value;
                        }

                        break;
                    case "map_bump":
                    case "bump":
                        if (currentMaterial != null)
                        {
                            currentMaterial.BumpMap = value;
                        }

                        break;
                }
            }
        }

        /// <summary>
        /// Sets the material for the current group.
        /// </summary>
        /// <param name="materialName">
        /// The material name.
        /// </param>
        private void SetMaterial(string materialName)
        {
            this.CurrentGroup.Material = this.CurrentMaterial = this.GetMaterial(materialName);
        }

        /// <summary>
        /// Represents a group in the obj file.
        /// </summary>
        public class Group
        {
            /// <summary>
            /// List of mesh builders.
            /// </summary>
            private readonly List<MeshBuilder> meshBuilders;

            /// <summary>
            /// List of materials.
            /// </summary>
            private readonly List<Material> materials;

            /// <summary>
            /// Initializes a new instance of the <see cref="Group"/> class.
            /// </summary>
            /// <param name="name">
            /// The name of the group.
            /// </param>
            /// <param name="material">The material of the group.</param>
            public Group(string name, Material material)
            {
                this.Name = name;
                this.meshBuilders = new List<MeshBuilder>();
                this.materials = new List<Material>();
                this.AddMesh(material);
            }

            /// <summary>
            /// Sets the material.
            /// </summary>
            /// <value>The material.</value>
            public Material Material
            {
                set
                {
                    this.materials[this.materials.Count - 1] = value;
                }
            }

            /// <summary>
            /// Gets the mesh builder for the current mesh.
            /// </summary>
            /// <value>The mesh builder.</value>
            public MeshBuilder MeshBuilder
            {
                get
                {
                    return this.meshBuilders[this.meshBuilders.Count - 1];
                }
            }

            /// <summary>
            /// Gets or sets the group name.
            /// </summary>
            /// <value>The name.</value>
            public string Name { get; set; }

            /// <summary>
            /// Adds a mesh.
            /// </summary>
            /// <param name="material">The material of the group.</param>
            public void AddMesh(Material material)
            {
                var meshBuilder = new MeshBuilder(true, true);
                this.meshBuilders.Add(meshBuilder);
                this.materials.Add(material);
            }

            /// <summary>
            /// Creates the models of the group.
            /// </summary>
            /// <returns>The models.</returns>
            public IEnumerable<Model3D> CreateModels()
            {
                for (int i = 0; i < this.meshBuilders.Count; i++)
                {

                    DiffuseMaterial DefaultMaterial2 = new DiffuseMaterial();
                    SolidColorBrush bursh = new SolidColorBrush(Color.FromRgb(23, 174, 204));
                    bursh.Opacity = 1;
                    DefaultMaterial2.Brush = bursh;
                    //DefaultMaterial2.Color = Color.FromRgb(80, 88, 99);
                    MaterialGroup materialgroup = new MaterialGroup();
                    materialgroup.Children.Add(DefaultMaterial2);

                    var material = this.materials[i];
                    var mesh = this.meshBuilders[i].ToMesh();
                    var model = new GeometryModel3D { Geometry = mesh,Material = materialgroup, BackMaterial = materialgroup };
                    yield return model;
                }
            }
        }

        /// <summary>
        /// A material definition.
        /// </summary>
        /// <remarks>
        /// The file format is documented in http://en.wikipedia.org/wiki/Material_Template_Library.
        /// </remarks>
        public class MaterialDefinition
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="MaterialDefinition" /> class.
            /// </summary>
            /// <param name="name">The name.</param>
            public MaterialDefinition(string name)
            {
                this.Name = name;
                this.Dissolved = 1.0;
            }

            /// <summary>
            /// Gets or sets the alpha map.
            /// </summary>
            /// <value>The alpha map.</value>
            public string AlphaMap { get; set; }

            /// <summary>
            /// Gets or sets the ambient color.
            /// </summary>
            /// <value>The ambient.</value>
            public Color Ambient { get; set; }

            /// <summary>
            /// Gets or sets the ambient map.
            /// </summary>
            /// <value>The ambient map.</value>
            public string AmbientMap { get; set; }

            /// <summary>
            /// Gets or sets the bump map.
            /// </summary>
            /// <value>The bump map.</value>
            public string BumpMap { get; set; }

            /// <summary>
            /// Gets or sets the diffuse color.
            /// </summary>
            /// <value>The diffuse.</value>
            public Color Diffuse { get; set; }

            /// <summary>
            /// Gets or sets the diffuse map.
            /// </summary>
            /// <value>The diffuse map.</value>
            public string DiffuseMap { get; set; }

            /// <summary>
            /// Gets or sets the opacity value.
            /// </summary>
            /// <value>The opacity.</value>
            /// <remarks>
            /// 0.0 is transparent, 1.0 is opaque.
            /// </remarks>
            public double Dissolved { get; set; }

            /// <summary>
            /// Gets or sets the illumination.
            /// </summary>
            /// <value>The illumination.</value>
            public int Illumination { get; set; }

            /// <summary>
            /// Gets or sets the name of the material.
            /// </summary>
            /// <value>
            /// The name.
            /// </value>
            public string Name { get; set; }

            /// <summary>
            /// Gets or sets the specular color.
            /// </summary>
            /// <value>The specular color.</value>
            public Color Specular { get; set; }

            /// <summary>
            /// Gets or sets the specular coefficient.
            /// </summary>
            /// <value>The specular coefficient.</value>
            public double SpecularCoefficient { get; set; }

            /// <summary>
            /// Gets or sets the specular map.
            /// </summary>
            /// <value>The specular map.</value>
            public string SpecularMap { get; set; }

            /// <summary>
            /// Gets or sets the material.
            /// </summary>
            /// <value>The material.</value>
            public Material Material { get; set; }

            /// <summary>
            /// Gets the material from the specified path.
            /// </summary>
            /// <param name="texturePath">
            /// The texture path.
            /// </param>
            /// <returns>
            /// The material.
            /// </returns>
            public Material GetMaterial(string texturePath)
            {
                if (this.Material == null)
                {
                    this.Material = this.CreateMaterial(texturePath);
                }

                return this.Material;
            }

            /// <summary>
            /// Creates the material.
            /// </summary>
            /// <param name="texturePath">The texture path.</param>
            /// <returns>A WPF material.</returns>
            private Material CreateMaterial(string texturePath)
            {
                var mg = new MaterialGroup();
                mg.SetName(this.Name);

                // add the diffuse component
                if (this.DiffuseMap == null)
                {
                    var diffuseBrush = new SolidColorBrush(this.Diffuse) { Opacity = this.Dissolved };
                    mg.Children.Add(new DiffuseMaterial(diffuseBrush));
                }
                else
                {
                    string path = PathHelpers.GetFullPath(texturePath, this.DiffuseMap);
                    if (File.Exists(path))
                    {
                        mg.Children.Add(new DiffuseMaterial(this.CreateTextureBrush(path)));
                    }
                }

                // add the ambient components
                if (this.AmbientMap == null)
                {
                    // ambient material is not supported by WPF?
                }
                else
                {
                    string path = PathHelpers.GetFullPath(texturePath, this.AmbientMap);
                    if (File.Exists(path))
                    {
                        mg.Children.Add(new EmissiveMaterial(this.CreateTextureBrush(path)));
                    }
                }

                // add the specular component
                if (this.Specular.R > 0 || this.Specular.G > 0 || this.Specular.B > 0)
                {
                    mg.Children.Add(new SpecularMaterial(new SolidColorBrush(this.Specular), this.SpecularCoefficient));
                }

                return mg.Children.Count != 1 ? mg : mg.Children[0];
            }

            /// <summary>
            /// Creates a texture brush.
            /// </summary>
            /// <param name="path">The path.</param>
            /// <returns>The brush.</returns>
            private ImageBrush CreateTextureBrush(string path)
            {
                var img = new BitmapImage(new Uri(path, UriKind.Relative));
                var textureBrush = new ImageBrush(img) { Opacity = this.Dissolved, ViewportUnits = BrushMappingMode.Absolute, TileMode = TileMode.Tile };
                return textureBrush;
            }
        }

        /// <summary>
        /// Path helpers.
        /// </summary>
        private static class PathHelpers
        {
            /// <summary>
            /// Gets a full path.
            /// </summary>
            /// <param name="basePath">
            /// The base path.
            /// </param>
            /// <param name="path">
            /// The path.
            /// </param>
            public static string GetFullPath(string basePath, string path)
            {
                if (path.Length > 1
                    && (path[0] == Path.DirectorySeparatorChar || path[0] == Path.AltDirectorySeparatorChar)
                    && (path[1] != Path.DirectorySeparatorChar && path[1] != Path.AltDirectorySeparatorChar))
                {
                    path = path.Substring(1);
                }

                return !string.IsNullOrWhiteSpace(basePath) ? Path.GetFullPath(Path.Combine(basePath, path)) : "";
            }
        }
    }

结果如图

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哦里 哦里哦里给

你的鼓支持是我分享的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值