public static Rhino.Commands.Result AddMesh(Rhino.RhinoDoc doc)
    {
        Rhino.Geometry.Mesh mesh = new Rhino.Geometry.Mesh();
        mesh.Vertices.Add(0.0, 0.0, 1.0); //0
        mesh.Vertices.Add(1.0, 0.0, 1.0); //1
        mesh.Vertices.Add(2.0, 0.0, 1.0); //2
        mesh.Vertices.Add(3.0, 0.0, 0.0); //3
        mesh.Vertices.Add(0.0, 1.0, 1.0); //4
        mesh.Vertices.Add(1.0, 1.0, 2.0); //5
        mesh.Vertices.Add(2.0, 1.0, 1.0); //6
        mesh.Vertices.Add(3.0, 1.0, 0.0); //7
        mesh.Vertices.Add(0.0, 2.0, 1.0); //8
        mesh.Vertices.Add(1.0, 2.0, 1.0); //9
        mesh.Vertices.Add(2.0, 2.0, 1.0); //10
        mesh.Vertices.Add(3.0, 2.0, 1.0); //11

        mesh.Faces.AddFace(0, 1, 5, 4);
        mesh.Faces.AddFace(1, 2, 6, 5);
        mesh.Faces.AddFace(2, 3, 7, 6);
        mesh.Faces.AddFace(4, 5, 9, 8);
        mesh.Faces.AddFace(5, 6, 10, 9);
        mesh.Faces.AddFace(6, 7, 11, 10);
        mesh.Normals.ComputeNormals();
        mesh.Compact();
        if (doc.Objects.AddMesh(mesh) != Guid.Empty)
        {
          doc.Views.Redraw();
          return Rhino.Commands.Result.Success;
        }
        return Rhino.Commands.Result.Failure;
    }
Example #2
0
 public static Rhino.Geometry.Mesh MeshBox(double x, double y, double z)
 {
     Rhino.Geometry.Mesh mesh = new Rhino.Geometry.Mesh();
     mesh.Vertices.Add(0, 0, 0);
     mesh.Vertices.Add(x, 0, 0);
     mesh.Vertices.Add(x, y, 0);
     mesh.Vertices.Add(0, y, 0);
     mesh.Vertices.Add(0, 0, z);
     mesh.Vertices.Add(x, 0, z);
     mesh.Vertices.Add(x, y, z);
     mesh.Vertices.Add(0, y, z);
     mesh.Faces.AddFace(3, 2, 1, 0);
     mesh.Faces.AddFace(4, 5, 6, 7);
     mesh.Faces.AddFace(0, 1, 5, 4);
     mesh.Faces.AddFace(1, 2, 6, 5);
     mesh.Faces.AddFace(2, 3, 7, 6);
     mesh.Faces.AddFace(3, 0, 4, 7);
     mesh.Normals.ComputeNormals();
     mesh.Compact();
     if (mesh.IsValid)
     {
         return(mesh);
     }
     return(null);
 }
Example #3
0
        public GltfMeshHolder Convert()
        {
            GltfMeshHolder meshHolder = new GltfMeshHolder(converter, doc);

            foreach (var primitive in mesh.Primitives)
            {
                Rhino.Geometry.Mesh rhinoMesh = GetMesh(primitive);

                if (rhinoMesh == null)
                {
                    continue;
                }

                rhinoMesh.Weld(0.01);

                rhinoMesh.Compact();

                if (!rhinoMesh.IsValidWithLog(out string log))
                {
                    Rhino.RhinoApp.WriteLine(log);
                }

                meshHolder.AddPrimitive(rhinoMesh, primitive.Material, mesh.Name);
            }

            return(meshHolder);
        }
Example #4
0
    public static Rhino.Commands.Result AddMesh(Rhino.RhinoDoc doc)
    {
        Rhino.Geometry.Mesh mesh = new Rhino.Geometry.Mesh();
        mesh.Vertices.Add(0.0, 0.0, 1.0); //0
        mesh.Vertices.Add(1.0, 0.0, 1.0); //1
        mesh.Vertices.Add(2.0, 0.0, 1.0); //2
        mesh.Vertices.Add(3.0, 0.0, 0.0); //3
        mesh.Vertices.Add(0.0, 1.0, 1.0); //4
        mesh.Vertices.Add(1.0, 1.0, 2.0); //5
        mesh.Vertices.Add(2.0, 1.0, 1.0); //6
        mesh.Vertices.Add(3.0, 1.0, 0.0); //7
        mesh.Vertices.Add(0.0, 2.0, 1.0); //8
        mesh.Vertices.Add(1.0, 2.0, 1.0); //9
        mesh.Vertices.Add(2.0, 2.0, 1.0); //10
        mesh.Vertices.Add(3.0, 2.0, 1.0); //11

        mesh.Faces.AddFace(0, 1, 5, 4);
        mesh.Faces.AddFace(1, 2, 6, 5);
        mesh.Faces.AddFace(2, 3, 7, 6);
        mesh.Faces.AddFace(4, 5, 9, 8);
        mesh.Faces.AddFace(5, 6, 10, 9);
        mesh.Faces.AddFace(6, 7, 11, 10);
        mesh.Normals.ComputeNormals();
        mesh.Compact();
        if (doc.Objects.AddMesh(mesh) != Guid.Empty)
        {
            doc.Views.Redraw();
            return(Rhino.Commands.Result.Success);
        }
        return(Rhino.Commands.Result.Failure);
    }
Example #5
0
        public static Rhino.Geometry.Mesh ConvertToRhinoMesh(DMesh3 mesh)
        {
            Rhino.Geometry.Mesh meshGH = new Rhino.Geometry.Mesh();

            var verticiG3   = mesh.Vertices();
            var triangoliG3 = mesh.Triangles();

            var facceGh   = triangoliG3.ToArray().Select(v => new Rhino.Geometry.MeshFace(v.a, v.b, v.c));
            var verticiGh = verticiG3.ToArray().Select(v => new Rhino.Geometry.Point3d(v.x, v.y, v.z));

            meshGH.Faces.AddFaces(facceGh);
            meshGH.Vertices.AddVertices(verticiGh);
            meshGH.Normals.ComputeNormals();
            meshGH.Compact();

            return(meshGH);
        }
Example #6
0
        public static Rhino.Geometry.Mesh ToRhinoGeo(this SketchUpNET.Mesh mesh, Transform t = null)
        {
            Rhino.Geometry.Mesh m = new Rhino.Geometry.Mesh();

            foreach (var v in mesh.Vertices)
            {
                m.Vertices.Add(v.ToRhinoGeo(t));
            }

            foreach (var v in mesh.Faces)
            {
                m.Faces.AddFace(v.A, v.B, v.C);
            }

            m.Normals.ComputeNormals();
            m.Compact();
            return(m);
        }
Example #7
0
        private static TriangleMesh BuildEmbreeMesh(Device device, Rhino.Geometry.Mesh mesh)
        {
            List <IEmbreePoint> vertices = new List <IEmbreePoint>();
            List <int>          indices  = new List <int>();

            mesh.Faces.ConvertQuadsToTriangles();
            mesh.Compact();


            foreach (var v in mesh.Vertices)
            {
                vertices.Add(new EPoint(v.X, v.Y, v.Z));
            }
            foreach (var f in mesh.Faces)
            {
                indices.Add(f.A);
                indices.Add(f.B);
                indices.Add(f.C);
            }
            return(new TriangleMesh(device, indices, vertices));
        }
 public static Rhino.Geometry.Mesh MeshBox(double x, double y, double z)
 {
   Rhino.Geometry.Mesh mesh = new Rhino.Geometry.Mesh();
   mesh.Vertices.Add(0, 0, 0);
   mesh.Vertices.Add(x, 0, 0);
   mesh.Vertices.Add(x, y, 0);
   mesh.Vertices.Add(0, y, 0);
   mesh.Vertices.Add(0, 0, z);
   mesh.Vertices.Add(x, 0, z);
   mesh.Vertices.Add(x, y, z);
   mesh.Vertices.Add(0, y, z);
   mesh.Faces.AddFace(3, 2, 1, 0);
   mesh.Faces.AddFace(4, 5, 6, 7);
   mesh.Faces.AddFace(0, 1, 5, 4);
   mesh.Faces.AddFace(1, 2, 6, 5);
   mesh.Faces.AddFace(2, 3, 7, 6);
   mesh.Faces.AddFace(3, 0, 4, 7);
   mesh.Normals.ComputeNormals();
   mesh.Compact();
   if (mesh.IsValid)
     return mesh;
   return null;
 }
Example #9
0
        protected override Result RunCommand(RhinoDoc doc, RunMode mode)
        {
            Rhino.Geometry.Mesh mesh = new Rhino.Geometry.Mesh();

            mesh.Vertices.Add(new Rhino.Geometry.Point3d(0.5, 0.5, 0.5));
            mesh.Vertices.Add(new Rhino.Geometry.Point3d(0.5, 0.5, -0.5));
            mesh.Vertices.Add(new Rhino.Geometry.Point3d(0.5, -0.5, 0.5));
            mesh.Vertices.Add(new Rhino.Geometry.Point3d(0.5, -0.5, -0.5));
            mesh.Vertices.Add(new Rhino.Geometry.Point3d(-0.5, 0.5, 0.5));
            mesh.Vertices.Add(new Rhino.Geometry.Point3d(-0.5, 0.5, -0.5));
            mesh.Vertices.Add(new Rhino.Geometry.Point3d(-0.5, -0.5, 0.5));
            mesh.Vertices.Add(new Rhino.Geometry.Point3d(-0.5, -0.5, -0.5));

            mesh.Faces.AddFace(0, 1, 5, 4);
            mesh.Faces.AddFace(0, 4, 6, 2);
            mesh.Faces.AddFace(0, 2, 3, 1);
            mesh.Faces.AddFace(7, 3, 2, 6);
            mesh.Faces.AddFace(7, 6, 4, 5);
            mesh.Faces.AddFace(7, 5, 1, 3);

            // For vertex colors to "work", you must supply a color
            // for every vertex.
            for (int i = 0; i < mesh.Vertices.Count; i++)
            {
                mesh.VertexColors.Add(GetRandomColor());
            }

            mesh.FaceNormals.ComputeFaceNormals();
            mesh.Normals.ComputeNormals();
            mesh.Compact();

            doc.Objects.AddMesh(mesh);
            doc.Views.Redraw();

            return(Result.Success);
        }
Example #10
0
        protected override Result RunCommand(RhinoDoc doc, RunMode mode)
        {
            bool bHavePreselectedObjects = false;

            const ObjectType geometryFilter = ObjectType.MeshFace;

            OptionDouble  minEdgeLengthOption     = new OptionDouble(minEdgeLength, 0.001, 200);
            OptionDouble  maxEdgeLengthOption     = new OptionDouble(maxEdgeLength, 0.001, 200);
            OptionDouble  constriantAngleOption   = new OptionDouble(constriantAngle, 0.001, 360);
            OptionInteger smoothStepsOptions      = new OptionInteger(smoothSteps, 0, 100);
            OptionDouble  smoothSpeedOption       = new OptionDouble(smoothSpeed, 0.01, 1.0);
            OptionDouble  projectAmountOption     = new OptionDouble(projectedAmount, 0.01, 1.0);
            OptionDouble  projectedDistanceOption = new OptionDouble(projectedDistance, 0.01, 100000.0);

            GetObject go = new GetObject();

            go.SetCommandPrompt("Select mesh faces to project onto another mesh");
            go.GeometryFilter = geometryFilter;

            go.AddOptionDouble("ConstraintAngle", ref constriantAngleOption);
            go.AddOptionDouble("MinEdge", ref minEdgeLengthOption);
            go.AddOptionDouble("MaxEdge", ref maxEdgeLengthOption);
            go.AddOptionInteger("SmoothSteps", ref smoothStepsOptions);
            go.AddOptionDouble("SmoothSpeed", ref smoothSpeedOption);

            go.GroupSelect     = true;
            go.SubObjectSelect = true;

            for (; ;)
            {
                GetResult faceres = go.GetMultiple(1, 0);

                if (faceres == GetResult.Option)
                {
                    go.EnablePreSelect(false, true);
                    continue;
                }

                else if (go.CommandResult() != Result.Success)
                {
                    return(go.CommandResult());
                }

                if (go.ObjectsWerePreselected)
                {
                    bHavePreselectedObjects = true;
                    go.EnablePreSelect(false, true);
                    continue;
                }

                break;
            }

            minEdgeLength   = minEdgeLengthOption.CurrentValue;
            maxEdgeLength   = maxEdgeLengthOption.CurrentValue;
            constriantAngle = constriantAngleOption.CurrentValue;
            smoothSteps     = smoothStepsOptions.CurrentValue;
            smoothSpeed     = smoothSpeedOption.CurrentValue;

            //System.Collections.Generic.List<System.Guid> meshes = new System.Collections.Generic.List<System.Guid>();

            System.Guid rhinoMesh = System.Guid.Empty;

            System.Collections.Generic.List <int> removeFaces = new System.Collections.Generic.List <int>();

            g3.DMesh3 projectFaces = new g3.DMesh3(true, false, false, false);

            Rhino.Geometry.Mesh rhinoInputMesh = new Rhino.Geometry.Mesh();

            for (int i = 0; i < go.ObjectCount; i++)
            {
                ObjRef obj = go.Object(i);

                if (rhinoMesh == System.Guid.Empty)
                {
                    rhinoMesh      = obj.ObjectId;
                    rhinoInputMesh = obj.Mesh();

                    for (int j = 0; j < rhinoInputMesh.Vertices.Count; j++)
                    {
                        var vertex = new g3.NewVertexInfo();
                        vertex.n = new g3.Vector3f(rhinoInputMesh.Normals[j].X, rhinoInputMesh.Normals[j].Y, rhinoInputMesh.Normals[j].Z);
                        vertex.v = new g3.Vector3d(rhinoInputMesh.Vertices[j].X, rhinoInputMesh.Vertices[j].Y, rhinoInputMesh.Vertices[j].Z);
                        projectFaces.AppendVertex(vertex);
                    }
                }

                var m = rhinoInputMesh;

                if (rhinoMesh != obj.ObjectId)
                {
                    continue;
                }

                removeFaces.Add(obj.GeometryComponentIndex.Index);

                var mf = rhinoInputMesh.Faces[obj.GeometryComponentIndex.Index];


                if (mf.IsQuad)
                {
                    double dist1 = m.Vertices[mf.A].DistanceTo(m.Vertices[mf.C]);
                    double dist2 = m.Vertices[mf.B].DistanceTo(m.Vertices[mf.D]);
                    if (dist1 > dist2)
                    {
                        projectFaces.AppendTriangle(mf.A, mf.B, mf.D);
                        projectFaces.AppendTriangle(mf.B, mf.C, mf.D);
                    }
                    else
                    {
                        projectFaces.AppendTriangle(mf.A, mf.B, mf.C);
                        projectFaces.AppendTriangle(mf.A, mf.C, mf.D);
                    }
                }
                else
                {
                    projectFaces.AppendTriangle(mf.A, mf.B, mf.C);
                }
            }

            if (rhinoInputMesh == null)
            {
                return(Result.Failure);
            }

            removeFaces.Sort();
            removeFaces.Reverse();

            foreach (var removeFace in removeFaces)
            {
                rhinoInputMesh.Faces.RemoveAt(removeFace);
            }

            rhinoInputMesh.Compact();

            GetObject goProjected = new GetObject();

            goProjected.EnablePreSelect(false, true);
            goProjected.SetCommandPrompt("Select mesh to project to");
            goProjected.GeometryFilter = ObjectType.Mesh;
            goProjected.AddOptionDouble("ConstraintAngle", ref constriantAngleOption);
            goProjected.AddOptionDouble("MinEdge", ref minEdgeLengthOption);
            goProjected.AddOptionDouble("MaxEdge", ref maxEdgeLengthOption);
            goProjected.AddOptionInteger("SmoothSteps", ref smoothStepsOptions);
            goProjected.AddOptionDouble("SmoothSpeed", ref smoothSpeedOption);
            goProjected.AddOptionDouble("ProjectAmount", ref projectAmountOption);
            goProjected.AddOptionDouble("ProjectDistance", ref projectedDistanceOption);

            goProjected.GroupSelect     = true;
            goProjected.SubObjectSelect = false;
            goProjected.EnableClearObjectsOnEntry(false);
            goProjected.EnableUnselectObjectsOnExit(false);


            for (; ;)
            {
                GetResult resProject = goProjected.Get();

                if (resProject == GetResult.Option)
                {
                    continue;
                }
                else if (goProjected.CommandResult() != Result.Success)
                {
                    return(goProjected.CommandResult());
                }

                break;
            }


            minEdgeLength     = minEdgeLengthOption.CurrentValue;
            maxEdgeLength     = maxEdgeLengthOption.CurrentValue;
            constriantAngle   = constriantAngleOption.CurrentValue;
            smoothSteps       = smoothStepsOptions.CurrentValue;
            smoothSpeed       = smoothSpeedOption.CurrentValue;
            projectedAmount   = projectAmountOption.CurrentValue;
            projectedDistance = projectedDistanceOption.CurrentValue;

            if (bHavePreselectedObjects)
            {
                // Normally, pre-selected objects will remain selected, when a
                // command finishes, and post-selected objects will be unselected.
                // This this way of picking, it is possible to have a combination
                // of pre-selected and post-selected. So, to make sure everything
                // "looks the same", lets unselect everything before finishing
                // the command.
                for (int i = 0; i < go.ObjectCount; i++)
                {
                    RhinoObject rhinoObject = go.Object(i).Object();
                    if (null != rhinoObject)
                    {
                        rhinoObject.Select(false);
                    }
                }
                doc.Views.Redraw();
            }

            bool result = false;

            if (goProjected.ObjectCount < 1)
            {
                return(Result.Failure);
            }


            var rhinoMeshProject = goProjected.Object(0).Mesh();

            if (rhinoMeshProject == null || !rhinoMeshProject.IsValid)
            {
                return(Result.Failure);
            }

            var meshProjected = GopherUtil.ConvertToD3Mesh(rhinoMeshProject);

            var res = GopherUtil.RemeshMesh(projectFaces, (float)minEdgeLength, (float)maxEdgeLength, (float)constriantAngle, (float)smoothSpeed, smoothSteps, meshProjected, (float)projectedAmount, (float)projectedDistance);

            var newRhinoMesh = GopherUtil.ConvertToRhinoMesh(res);

            if (newRhinoMesh != null && newRhinoMesh.IsValid)
            {
                newRhinoMesh.Append(rhinoInputMesh);

                result |= doc.Objects.Replace(rhinoMesh, newRhinoMesh);
            }

            doc.Views.Redraw();

            return(Result.Success);
        }
Example #11
0
        public static void OptToRhino(OptFile opt, string rhinoPath, bool scale)
        {
            if (opt == null)
            {
                throw new ArgumentNullException("opt");
            }

            string rhinoDirectory = Path.GetDirectoryName(rhinoPath);
            string rhinoName      = Path.GetFileNameWithoutExtension(rhinoPath);

            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++)
            {
                using (var file = new Rhino.FileIO.File3dm())
                {
                    file.Settings.ModelUnitSystem = Rhino.UnitSystem.Meters;

                    int           objectsIndex = 0;
                    List <string> textureNames = new List <string>();

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

                        if (lod == null)
                        {
                            continue;
                        }

                        foreach (var textureName in lod.FaceGroups
                                 .Where(t => t.Textures.Count > 0)
                                 .Select(t => t.Textures[0]))
                        {
                            if (!textureNames.Contains(textureName))
                            {
                                textureNames.Add(textureName);
                            }
                        }

                        string meshName = string.Format(CultureInfo.InvariantCulture, "{0}.{1:D3}", mesh.Descriptor.MeshType, objectsIndex);

                        using (var layer = new Rhino.DocObjects.Layer())
                        {
                            layer.Name = meshName;

                            file.Layers.Add(layer);
                        }

                        foreach (var faceGroup in lod.FaceGroups)
                        {
                            using (var rhinoMesh = new Rhino.Geometry.Mesh())
                                using (var rhinoAttributes = new Rhino.DocObjects.ObjectAttributes())
                                {
                                    rhinoAttributes.Name       = meshName;
                                    rhinoAttributes.LayerIndex = objectsIndex;

                                    if (faceGroup.Textures.Count > 0)
                                    {
                                        rhinoAttributes.MaterialIndex = textureNames.IndexOf(faceGroup.Textures[0]);
                                    }

                                    Action <Vector> addVertex;

                                    if (scale)
                                    {
                                        addVertex = vertex => rhinoMesh.Vertices.Add(vertex.X * OptFile.ScaleFactor, vertex.Y * OptFile.ScaleFactor, vertex.Z * OptFile.ScaleFactor);
                                    }
                                    else
                                    {
                                        addVertex = vertex => rhinoMesh.Vertices.Add(vertex.X, vertex.Y, vertex.Z);
                                    }

                                    Action <TextureCoordinates> addTexCoords = texCoords => rhinoMesh.TextureCoordinates.Add(texCoords.U, -texCoords.V);

                                    Action <Vector> addNormal = normal => rhinoMesh.Normals.Add(normal.X, normal.Y, normal.Z);

                                    int facesIndex = 0;

                                    foreach (var face in faceGroup.Faces)
                                    {
                                        var verticesIndex  = face.VerticesIndex;
                                        var texCoordsIndex = face.TextureCoordinatesIndex;
                                        var normalsIndex   = face.VertexNormalsIndex;

                                        addVertex(mesh.Vertices[verticesIndex.A]);
                                        addTexCoords(mesh.TextureCoordinates[texCoordsIndex.A]);
                                        addNormal(mesh.VertexNormals[normalsIndex.A]);
                                        facesIndex++;

                                        addVertex(mesh.Vertices[verticesIndex.B]);
                                        addTexCoords(mesh.TextureCoordinates[texCoordsIndex.B]);
                                        addNormal(mesh.VertexNormals[normalsIndex.B]);
                                        facesIndex++;

                                        addVertex(mesh.Vertices[verticesIndex.C]);
                                        addTexCoords(mesh.TextureCoordinates[texCoordsIndex.C]);
                                        addNormal(mesh.VertexNormals[normalsIndex.C]);
                                        facesIndex++;

                                        if (verticesIndex.D >= 0)
                                        {
                                            addVertex(mesh.Vertices[verticesIndex.D]);
                                            addTexCoords(mesh.TextureCoordinates[texCoordsIndex.D]);
                                            addNormal(mesh.VertexNormals[normalsIndex.D]);
                                            facesIndex++;
                                        }

                                        if (verticesIndex.D < 0)
                                        {
                                            rhinoMesh.Faces.AddFace(facesIndex - 1, facesIndex - 2, facesIndex - 3);
                                        }
                                        else
                                        {
                                            rhinoMesh.Faces.AddFace(facesIndex - 1, facesIndex - 2, facesIndex - 3, facesIndex - 4);
                                        }
                                    }

                                    rhinoMesh.Compact();

                                    file.Objects.AddMesh(rhinoMesh, rhinoAttributes);
                                }
                        }

                        objectsIndex++;
                    }

                    foreach (var textureName in textureNames)
                    {
                        Texture texture;
                        opt.Textures.TryGetValue(textureName, out texture);

                        using (var material = new Rhino.DocObjects.Material())
                        {
                            material.Name = textureName;

                            if (texture == null)
                            {
                                material.DiffuseColor = System.Drawing.Color.White;
                            }
                            else
                            {
                                texture.Save(Path.Combine(rhinoDirectory, textureName + ".png"));
                                material.SetBitmapTexture(textureName + ".png");

                                if (texture.HasAlpha)
                                {
                                    texture.SaveAlphaMap(Path.Combine(rhinoDirectory, textureName + "_alpha.png"));
                                    material.SetTransparencyTexture(textureName + "_alpha.png");
                                }
                            }

                            file.Materials.Add(material);
                        }
                    }

                    file.Write(Path.Combine(rhinoDirectory, string.Format(CultureInfo.InvariantCulture, "{0}_{1}.3dm", rhinoName, distance)), 4);
                }
            }
        }
Example #12
0
        public static void OptToRhino(OptFile opt, string rhinoPath, bool scale)
        {
            if (opt == null)
            {
                throw new ArgumentNullException("opt");
            }

            string rhinoDirectory = Path.GetDirectoryName(rhinoPath);
            string rhinoName = Path.GetFileNameWithoutExtension(rhinoPath);

            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++)
            {
                using (var file = new Rhino.FileIO.File3dm())
                {
                    file.Settings.ModelUnitSystem = Rhino.UnitSystem.Meters;

                    int objectsIndex = 0;
                    List<string> textureNames = new List<string>();

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

                        if (lod == null)
                        {
                            continue;
                        }

                        foreach (var textureName in lod.FaceGroups
                            .Where(t => t.Textures.Count > 0)
                            .Select(t => t.Textures[0]))
                        {
                            if (!textureNames.Contains(textureName))
                            {
                                textureNames.Add(textureName);
                            }
                        }

                        string meshName = string.Format(CultureInfo.InvariantCulture, "{0}.{1:D3}", mesh.Descriptor.MeshType, objectsIndex);

                        using (var layer = new Rhino.DocObjects.Layer())
                        {
                            layer.Name = meshName;

                            file.Layers.Add(layer);
                        }

                        foreach (var faceGroup in lod.FaceGroups)
                        {
                            using (var rhinoMesh = new Rhino.Geometry.Mesh())
                            using (var rhinoAttributes = new Rhino.DocObjects.ObjectAttributes())
                            {
                                rhinoAttributes.Name = meshName;
                                rhinoAttributes.LayerIndex = objectsIndex;

                                if (faceGroup.Textures.Count > 0)
                                {
                                    rhinoAttributes.MaterialIndex = textureNames.IndexOf(faceGroup.Textures[0]);
                                }

                                Action<Vector> addVertex;

                                if (scale)
                                {
                                    addVertex = vertex => rhinoMesh.Vertices.Add(vertex.X * OptFile.ScaleFactor, vertex.Y * OptFile.ScaleFactor, vertex.Z * OptFile.ScaleFactor);
                                }
                                else
                                {
                                    addVertex = vertex => rhinoMesh.Vertices.Add(vertex.X, vertex.Y, vertex.Z);
                                }

                                Action<TextureCoordinates> addTexCoords = texCoords => rhinoMesh.TextureCoordinates.Add(texCoords.U, -texCoords.V);

                                Action<Vector> addNormal = normal => rhinoMesh.Normals.Add(normal.X, normal.Y, normal.Z);

                                int facesIndex = 0;

                                foreach (var face in faceGroup.Faces)
                                {
                                    var verticesIndex = face.VerticesIndex;
                                    var texCoordsIndex = face.TextureCoordinatesIndex;
                                    var normalsIndex = face.VertexNormalsIndex;

                                    addVertex(mesh.Vertices[verticesIndex.A]);
                                    addTexCoords(mesh.TextureCoordinates[texCoordsIndex.A]);
                                    addNormal(mesh.VertexNormals[normalsIndex.A]);
                                    facesIndex++;

                                    addVertex(mesh.Vertices[verticesIndex.B]);
                                    addTexCoords(mesh.TextureCoordinates[texCoordsIndex.B]);
                                    addNormal(mesh.VertexNormals[normalsIndex.B]);
                                    facesIndex++;

                                    addVertex(mesh.Vertices[verticesIndex.C]);
                                    addTexCoords(mesh.TextureCoordinates[texCoordsIndex.C]);
                                    addNormal(mesh.VertexNormals[normalsIndex.C]);
                                    facesIndex++;

                                    if (verticesIndex.D >= 0)
                                    {
                                        addVertex(mesh.Vertices[verticesIndex.D]);
                                        addTexCoords(mesh.TextureCoordinates[texCoordsIndex.D]);
                                        addNormal(mesh.VertexNormals[normalsIndex.D]);
                                        facesIndex++;
                                    }

                                    if (verticesIndex.D < 0)
                                    {
                                        rhinoMesh.Faces.AddFace(facesIndex - 1, facesIndex - 2, facesIndex - 3);
                                    }
                                    else
                                    {
                                        rhinoMesh.Faces.AddFace(facesIndex - 1, facesIndex - 2, facesIndex - 3, facesIndex - 4);
                                    }
                                }

                                rhinoMesh.Compact();

                                file.Objects.AddMesh(rhinoMesh, rhinoAttributes);
                            }
                        }

                        objectsIndex++;
                    }

                    foreach (var textureName in textureNames)
                    {
                        Texture texture;
                        opt.Textures.TryGetValue(textureName, out texture);

                        using (var material = new Rhino.DocObjects.Material())
                        {
                            material.Name = textureName;

                            if (texture == null)
                            {
                                material.DiffuseColor = System.Drawing.Color.White;
                            }
                            else
                            {
                                texture.Save(Path.Combine(rhinoDirectory, textureName + ".png"));
                                material.SetBitmapTexture(textureName + ".png");

                                if (texture.HasAlpha)
                                {
                                    texture.SaveAlphaMap(Path.Combine(rhinoDirectory, textureName + "_alpha.png"));
                                    material.SetTransparencyTexture(textureName + "_alpha.png");
                                }
                            }

                            file.Materials.Add(material);
                        }
                    }

                    file.Write(Path.Combine(rhinoDirectory, string.Format(CultureInfo.InvariantCulture, "{0}_{1}.3dm", rhinoName, distance)), 4);
                }
            }
        }