Esempio n. 1
0
        /**
         * Write a set of meshes to an ASCII string in STL format.
         */
        public static string WriteString(IList <Mesh> meshes, bool convertToRightHandedCoordinates = true)
        {
            StringBuilder sb = new StringBuilder();

            string name = meshes.Count == 1 ? meshes[0].name : "Composite Mesh";

            sb.AppendLine(string.Format("solid {0}", name));

            foreach (Mesh mesh in meshes)
            {
                Vector3[] v = mesh.vertices;
                Vector3[] n = mesh.normals;
                int[]     t = mesh.triangles;

                if (convertToRightHandedCoordinates)
                {
                    for (int i = 0, c = v.Length; i < c; i++)
                    {
                        v[i] = Stl.ToCoordinateSpace(v[i], CoordinateSpace.Right);
                        n[i] = Stl.ToCoordinateSpace(n[i], CoordinateSpace.Right);
                    }

                    System.Array.Reverse(t);
                }

                int triLen = t.Length;

                for (int i = 0; i < triLen; i += 3)
                {
                    int a = t[i];
                    int b = t[i + 1];
                    int c = t[i + 2];

                    Vector3 nrm = AvgNrm(n[a], n[b], n[c]);

                    sb.AppendLine(string.Format("facet normal {0} {1} {2}", nrm.x, nrm.y, nrm.z));

                    sb.AppendLine("outer loop");

                    sb.AppendLine(string.Format("\tvertex {0} {1} {2}", v[a].x, v[a].y, v[a].z));
                    sb.AppendLine(string.Format("\tvertex {0} {1} {2}", v[b].x, v[b].y, v[b].z));
                    sb.AppendLine(string.Format("\tvertex {0} {1} {2}", v[c].x, v[c].y, v[c].z));

                    sb.AppendLine("endloop");

                    sb.AppendLine("endfacet");
                }
            }

            sb.AppendLine(string.Format("endsolid {0}", name));

            return(sb.ToString());
        }
Esempio n. 2
0
        static StlMesh[] ImportHardNormals(IEnumerable <Facet> faces, CoordinateSpace modelCoordinateSpace, UpAxis modelUpAxis, IndexFormat indexFormat)
        {
            var facets = faces as Facet[] ?? faces.ToArray();
            int faceCount = facets.Length, f = 0;
            int maxFacetsPerMesh = indexFormat == IndexFormat.UInt32 ? MaxFacetsPerMesh32 : MaxFacetsPerMesh16;
            int maxVertexCount   = maxFacetsPerMesh * 3;

            StlMesh[] meshes = new StlMesh[faceCount / maxFacetsPerMesh + 1];

            for (int meshIndex = 0; meshIndex < meshes.Length; meshIndex++)
            {
                int          len = System.Math.Min(maxVertexCount, (faceCount - f) * 3);
                StlVector3[] v   = new StlVector3[len];
                StlVector3[] n   = new StlVector3[len];
                int[]        t   = new int[len];

                for (int it = 0; it < len; it += 3)
                {
                    v[it]     = facets[f].a;
                    v[it + 1] = facets[f].b;
                    v[it + 2] = facets[f].c;

                    n[it]     = facets[f].normal;
                    n[it + 1] = facets[f].normal;
                    n[it + 2] = facets[f].normal;

                    t[it]     = it + 0;
                    t[it + 1] = it + 1;
                    t[it + 2] = it + 2;

                    f++;
                }

                if (modelCoordinateSpace == CoordinateSpace.Right)
                {
                    for (int i = 0; i < len; i += 3)
                    {
                        v[i + 0] = Stl.ToCoordinateSpace(v[i + 0], CoordinateSpace.Left);
                        v[i + 1] = Stl.ToCoordinateSpace(v[i + 1], CoordinateSpace.Left);
                        v[i + 2] = Stl.ToCoordinateSpace(v[i + 2], CoordinateSpace.Left);

                        n[i + 0] = Stl.ToCoordinateSpace(n[i + 0], CoordinateSpace.Left);
                        n[i + 1] = Stl.ToCoordinateSpace(n[i + 1], CoordinateSpace.Left);
                        n[i + 2] = Stl.ToCoordinateSpace(n[i + 2], CoordinateSpace.Left);

                        var a = t[i + 2];
                        t[i + 2] = t[i];
                        t[i]     = a;
                    }
                }

                meshes[meshIndex] = new StlMesh
                {
                    vertices    = v,
                    normals     = n,
                    triangles   = t,
                    indexFormat = indexFormat
                };
            }

            return(meshes);
        }
Esempio n. 3
0
        static StlMesh[] ImportSmoothNormals(IEnumerable <Facet> faces, CoordinateSpace modelCoordinateSpace, UpAxis modelUpAxis, IndexFormat indexFormat)
        {
            var facets         = faces as Facet[] ?? faces.ToArray();
            int maxVertexCount = indexFormat == IndexFormat.UInt32 ? MaxFacetsPerMesh32 * 3 : MaxFacetsPerMesh16 * 3;
            int triangleCount  = facets.Length * 3;

            //Dictionary<StlVector3, StlVector3> smoothNormals = new Dictionary<StlVector3, StlVector3>(triangleCount / 2);

            //// In case meshes are split, we need to calculate smooth normals first
            //foreach(var face in faces)
            //{
            //	var x = (StlVector3) face.a;
            //	var y = (StlVector3) face.b;
            //	var z = (StlVector3) face.c;
            //	var normal = face.normal;

            //	if(smoothNormals.ContainsKey(x))
            //		smoothNormals[x] += normal;
            //	else
            //		smoothNormals.Add(x, normal);

            //	if(smoothNormals.ContainsKey(y))
            //		smoothNormals[y] += normal;
            //	else
            //		smoothNormals.Add(y, normal);

            //	if(smoothNormals.ContainsKey(z))
            //		smoothNormals[z] += normal;
            //	else
            //		smoothNormals.Add(z, normal);
            //}

            int numProcs         = Environment.ProcessorCount;
            int concurrencyLevel = numProcs * 2;
            ConcurrentDictionary <StlVector3, StlVector3> smoothNormals = new ConcurrentDictionary <StlVector3, StlVector3>(concurrencyLevel, triangleCount / 2);

            // In case meshes are split, we need to calculate smooth normals first
            Parallel.ForEach(faces, (face) => {
                var x      = face.a;
                var y      = face.b;
                var z      = face.c;
                var normal = face.normal;

                if (smoothNormals.ContainsKey(x))
                {
                    smoothNormals[x] += normal;
                }
                else
                {
                    smoothNormals.TryAdd(x, normal);
                }

                if (smoothNormals.ContainsKey(y))
                {
                    smoothNormals[y] += normal;
                }
                else
                {
                    smoothNormals.TryAdd(y, normal);
                }

                if (smoothNormals.ContainsKey(z))
                {
                    smoothNormals[z] += normal;
                }
                else
                {
                    smoothNormals.TryAdd(z, normal);
                }
            });


            List <StlMesh> meshes = new List <StlMesh>();

            List <StlVector3>            pos = new List <StlVector3>(Math.Min(maxVertexCount, triangleCount));
            List <StlVector3>            nrm = new List <StlVector3>(Math.Min(maxVertexCount, triangleCount));
            List <int>                   tri = new List <int>(triangleCount);
            Dictionary <StlVector3, int> map = new Dictionary <StlVector3, int>();
            int vertex = 0;

            StlVector3[] points = new StlVector3[3];

            foreach (var face in facets)
            {
                if (vertex + 3 > maxVertexCount)
                {
                    var mesh = new StlMesh
                    {
                        vertices    = pos.ToArray(),
                        normals     = nrm.ToArray(),
                        indexFormat = indexFormat
                    };
                    if (modelCoordinateSpace == CoordinateSpace.Right)
                    {
                        tri.Reverse();
                    }
                    mesh.triangles = tri.ToArray();
                    meshes.Add(mesh);

                    vertex = 0;

                    pos.Clear();
                    nrm.Clear();
                    tri.Clear();
                    map.Clear();
                }

                points[0] = face.a;
                points[1] = face.b;
                points[2] = face.c;

                for (int i = 0; i < 3; i++)
                {
                    int index = -1;
                    var hash  = points[i];

                    if (!map.TryGetValue(hash, out index))
                    {
                        if (modelCoordinateSpace == CoordinateSpace.Right)
                        {
                            pos.Add(Stl.ToCoordinateSpace(points[i], CoordinateSpace.Left));
                            nrm.Add(Stl.ToCoordinateSpace(smoothNormals[hash].normalized, CoordinateSpace.Left));
                        }
                        else
                        {
                            pos.Add(points[i]);
                            nrm.Add(smoothNormals[hash].normalized);
                        }

                        tri.Add(vertex);
                        map.Add(hash, vertex++);
                    }
                    else
                    {
                        tri.Add(index);
                    }
                }
            }


            if (vertex > 0)
            {
                var mesh = new StlMesh
                {
                    vertices    = pos.ToArray(),
                    normals     = nrm.ToArray(),
                    indexFormat = indexFormat
                };
                if (modelCoordinateSpace == CoordinateSpace.Right)
                {
                    tri.Reverse();
                }
                mesh.triangles = tri.ToArray();
                meshes.Add(mesh);

                vertex = 0;

                pos.Clear();
                nrm.Clear();
                tri.Clear();
                map.Clear();
            }

            return(meshes.ToArray());
        }
Esempio n. 4
0
		static Mesh[] ImportSmoothNormals(IEnumerable<Facet> faces, CoordinateSpace modelCoordinateSpace, UpAxis modelUpAxis, IndexFormat indexFormat)
		{
			var facets = faces as Facet[] ?? faces.ToArray();
			int maxVertexCount = indexFormat == IndexFormat.UInt32 ? MaxFacetsPerMesh32 * 3 : MaxFacetsPerMesh16 * 3;
			int triangleCount = facets.Length * 3;

			Dictionary<StlVector3, Vector3> smoothNormals = new Dictionary<StlVector3, Vector3>(triangleCount / 2);

			// In case meshes are split, we need to calculate smooth normals first
			foreach(var face in faces)
			{
				var x = (StlVector3) face.a;
				var y = (StlVector3) face.b;
				var z = (StlVector3) face.c;
				var normal = face.normal;

				if(smoothNormals.ContainsKey(x))
					smoothNormals[x] += normal;
				else
					smoothNormals.Add(x, normal);

				if(smoothNormals.ContainsKey(y))
					smoothNormals[y] += normal;
				else
					smoothNormals.Add(y, normal);

				if(smoothNormals.ContainsKey(z))
					smoothNormals[z] += normal;
				else
					smoothNormals.Add(z, normal);
			}

			List<Mesh> meshes = new List<Mesh>();

			List<Vector3> pos = new List<Vector3>(Math.Min(maxVertexCount, triangleCount));
			List<Vector3> nrm = new List<Vector3>(Math.Min(maxVertexCount, triangleCount));
			List<int> tri = new List<int>(triangleCount);
			Dictionary<StlVector3, int> map = new Dictionary<StlVector3, int>();
			int vertex = 0;
			Vector3[] points = new Vector3[3];

			foreach(var face in facets)
			{
				if(vertex + 3 > maxVertexCount)
				{
					var mesh = new Mesh
					{
						vertices = pos.ToArray(),
						normals = nrm.ToArray(),
						indexFormat = indexFormat
					};
					if(modelCoordinateSpace == CoordinateSpace.Right)
						tri.Reverse();
					mesh.triangles = tri.ToArray();
					meshes.Add(mesh);

					vertex = 0;

					pos.Clear();
					nrm.Clear();
					tri.Clear();
					map.Clear();
				}

				points[0] = face.a;
				points[1] = face.b;
				points[2] = face.c;

				for(int i = 0; i < 3; i++)
				{
					int index = -1;
					var hash = (StlVector3) points[i];

					if(!map.TryGetValue(hash, out index))
					{
						if(modelCoordinateSpace == CoordinateSpace.Right)
						{
							pos.Add(Stl.ToCoordinateSpace(points[i], CoordinateSpace.Left));
							nrm.Add(Stl.ToCoordinateSpace(smoothNormals[hash].normalized, CoordinateSpace.Left));
						}
						else
						{
							pos.Add(points[i]);
							nrm.Add(smoothNormals[hash].normalized);
						}

						tri.Add(vertex);
						map.Add(hash, vertex++);
					}
					else
					{
						tri.Add(index);
					}
				}
			}

			if(vertex > 0)
			{
				var mesh = new Mesh
				{
					vertices = pos.ToArray(),
					normals = nrm.ToArray(),
					indexFormat = indexFormat
				};
				if(modelCoordinateSpace == CoordinateSpace.Right)
					tri.Reverse();
				mesh.triangles = tri.ToArray();
				meshes.Add(mesh);

				vertex = 0;

				pos.Clear();
				nrm.Clear();
				tri.Clear();
				map.Clear();
			}

			return meshes.ToArray();
		}
Esempio n. 5
0
        static Mesh[] ImportHardNormals(IEnumerable <Facet> faces, CoordinateSpace modelCoordinateSpace, UpAxis modelUpAxis, IndexFormat indexFormat)
        {
            var facets = faces as Facet[] ?? faces.ToArray();
            int faceCount = facets.Length, f = 0;
            int maxFacetsPerMesh = indexFormat == IndexFormat.UInt32 ? MaxFacetsPerMesh32 : MaxFacetsPerMesh16;
            int maxVertexCount   = maxFacetsPerMesh * 3;

            Mesh[] meshes = new Mesh[faceCount / maxFacetsPerMesh + 1];

            for (int meshIndex = 0; meshIndex < meshes.Length; meshIndex++)
            {
                int       len     = System.Math.Min(maxVertexCount, (faceCount - f) * 3);
                Vector3[] v       = new Vector3[len];
                Vector3[] n       = new Vector3[len];
                int[]     indices = new int[len * 3];
                int[]     t       = new int[len];

                for (int it = 0; it < len; it += 3)
                {
                    v[it]     = facets[f].a;
                    v[it + 1] = facets[f].b;
                    v[it + 2] = facets[f].c;

                    n[it]     = facets[f].normal;
                    n[it + 1] = facets[f].normal;
                    n[it + 2] = facets[f].normal;

                    t[it]     = it + 0;
                    t[it + 1] = it + 1;
                    t[it + 2] = it + 2;

                    f++;
                }

                if (modelCoordinateSpace == CoordinateSpace.Right)
                {
                    for (int i = 0; i < len; i += 3)
                    {
                        v[i + 0] = Stl.ToCoordinateSpace(v[i + 0], CoordinateSpace.Left);
                        v[i + 1] = Stl.ToCoordinateSpace(v[i + 1], CoordinateSpace.Left);
                        v[i + 2] = Stl.ToCoordinateSpace(v[i + 2], CoordinateSpace.Left);

                        n[i + 0] = Stl.ToCoordinateSpace(n[i + 0], CoordinateSpace.Left);
                        n[i + 1] = Stl.ToCoordinateSpace(n[i + 1], CoordinateSpace.Left);
                        n[i + 2] = Stl.ToCoordinateSpace(n[i + 2], CoordinateSpace.Left);

                        var a = t[i + 2];
                        t[i + 2] = t[i];
                        t[i]     = a;
                    }
                }

                // auto detect mesh winding via calculating the mesh's volume
                float volume = 0;
                for (int it = 0; it < len; it += 3)
                {
                    Vector3 v1    = v[it];
                    Vector3 v2    = v[it + 1];
                    Vector3 v3    = v[it + 2];
                    Vector3 cross = Vector3.Cross(v1, v2);
                    volume -= Vector3.Dot(cross, v3);
                }

                if (volume < 0)
                {
                    for (int it = 0; it < len; it += 3)
                    {
                        indices[it * 3]     = it;
                        indices[it * 3 + 1] = it + 1;
                        indices[it * 3 + 2] = it + 2;
                    }
                }
                else
                {
                    for (int it = 0; it < len; it += 3)
                    {
                        indices[it * 3]     = it;
                        indices[it * 3 + 1] = it + 2;
                        indices[it * 3 + 2] = it + 1;
                    }
                }

                Mesh mesh = new Mesh()
                {
                    vertices    = v,
                    normals     = n,
                    triangles   = t,
                    indexFormat = indexFormat
                };

                mesh.SetIndices(indices, MeshTopology.Triangles, 0);
            }

            return(meshes);
        }
Esempio n. 6
0
        /**
         *	Write a collection of mesh assets to an STL file.
         *	No transformations are performed on meshes in this method.
         *	Eg, if you want to export a set of a meshes in a transform
         *	hierarchy the meshes should be transformed prior to this call.
         *
         *	string path - Where to write the file.
         *	IList<Mesh> meshes - The mesh assets to write.
         *	FileType type - How to format the file (in ASCII or binary).
         */
        public static bool WriteFile(string path, IList <Mesh> meshes, FileType type = FileType.Ascii, bool convertToRightHandedCoordinates = true)
        {
            try
            {
                switch (type)
                {
                case FileType.Binary:
                {
                    // http://paulbourke.net/dataformats/stl/
                    // http://www.fabbers.com/tech/STL_Format
                    using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create), new ASCIIEncoding()))
                    {
                        // 80 byte header
                        writer.Write(new byte[80]);

                        uint totalTriangleCount = (uint)(meshes.Sum(x => x.triangles.Length) / 3);

                        // unsigned long facet count (4 bytes)
                        writer.Write(totalTriangleCount);

                        foreach (Mesh mesh in meshes)
                        {
                            Vector3[] v = mesh.vertices;
                            Vector3[] n = mesh.normals;

                            if (convertToRightHandedCoordinates)
                            {
                                for (int i = 0, c = v.Length; i < c; i++)
                                {
                                    v[i] = Stl.ToCoordinateSpace(v[i], CoordinateSpace.Right);
                                    n[i] = Stl.ToCoordinateSpace(n[i], CoordinateSpace.Right);
                                }
                            }

                            int[] t             = mesh.triangles;
                            int   triangleCount = t.Length;
                            if (convertToRightHandedCoordinates)
                            {
                                System.Array.Reverse(t);
                            }

                            for (int i = 0; i < triangleCount; i += 3)
                            {
                                int a = t[i], b = t[i + 1], c = t[i + 2];

                                Vector3 avg = AvgNrm(n[a], n[b], n[c]);

                                writer.Write(avg.x);
                                writer.Write(avg.y);
                                writer.Write(avg.z);

                                writer.Write(v[a].x);
                                writer.Write(v[a].y);
                                writer.Write(v[a].z);

                                writer.Write(v[b].x);
                                writer.Write(v[b].y);
                                writer.Write(v[b].z);

                                writer.Write(v[c].x);
                                writer.Write(v[c].y);
                                writer.Write(v[c].z);

                                // specification says attribute byte count should be set to 0.
                                writer.Write((ushort)0);
                            }
                        }
                    }
                }
                break;

                default:
                    string model = WriteString(meshes);
                    File.WriteAllText(path, model);
                    break;
                }
            }
            catch (System.Exception e)
            {
                UnityEngine.Debug.LogError(e.ToString());
                return(false);
            }

            return(true);
        }