Exemplo n.º 1
0
        /// <summary>
        /// Performs the specified operation on the provided meshes.
        /// </summary>
        /// <param name="first">The first mesh</param>
        /// <param name="second">The second mesh</param>
        /// <param name="operation">The mesh opration to perform on the two meshes</param>
        /// <returns>A triangular mesh resulting from performing the specified operation. If the resulting mesh is empty, will return null.</returns>
        public static Mesh3 PerformCSG(Mesh3 first, Mesh3 second, CSGOperations operation)
        {
            Mesh3 finalResult = null;

            unsafe
            {
                InteropMesh a            = new InteropMesh();
                InteropMesh b            = new InteropMesh();
                Vector3[]   aTransformed = first.GetTransformedVertices();
                Vector3[]   bTransformed = second.GetTransformedVertices();

                InteropMesh *result;

                fixed(Vector3 *aVerts = &aTransformed[0], bVerts = &bTransformed[0])
                {
                    fixed(int *aTris = &first.TriangleIndices[0], bTris = &second.TriangleIndices[0])
                    {
                        a.vertsArrayLength = first.Vertices.Length * 3;
                        a.triArrayLength   = first.TriangleIndices.Length;
                        a.vertices         = (double *)aVerts;
                        a.triangleIndices  = aTris;

                        b.vertsArrayLength = second.Vertices.Length * 3;
                        b.triArrayLength   = second.TriangleIndices.Length;
                        b.vertices         = (double *)bVerts;
                        b.triangleIndices  = bTris;

                        try
                        {
                            result = performCSG(ref a, ref b, operation);
                        }
                        catch (SEHException ex)
                        {
                            ArgumentException e = new ArgumentException("Carve has thrown an error. Possible reason is corrupt or self-intersecting meshes", ex);
                            throw e;
                        }
                    }
                }

                if (result->vertsArrayLength == 0)
                {
                    freeMesh(result);
                    return(null);
                }

                Vector3[] vertices        = new Vector3[result->vertsArrayLength / 3];
                int[]     triangleIndices = new int[result->triArrayLength];

                // Copy the results back in parallel
                Parallel.For(0, vertices.Length, i =>
                {
                    vertices[i] = new Vector3(result->vertices[3 * i], result->vertices[3 * i + 1], result->vertices[3 * i + 2]);
                });

                Parallel.For(0, triangleIndices.Length, i =>
                {
                    triangleIndices[i] = result->triangleIndices[i];
                });

                // If none of the vertices had colors, return whatever we have
                if (!first.HasColours && !second.HasColours)
                {
                    finalResult = new Mesh3(vertices, triangleIndices);
                    freeMesh(result);
                }
                else // Assign colors to the resulting mesh
                {
                    uint[] colors   = new uint[vertices.Length];
                    uint   grayCode = 4286611584; // The uint value of the color gray (representing no color)

                    // Assign the default gray to all vertices
                    Parallel.For(0, colors.Length, i =>
                    {
                        colors[i] = grayCode;
                    });

                    #region Worst practices of parallel coding

                    /**
                     * The procedure for color matching is creating a map of (vertex=>color) and then
                     * comparing all vertices of the resulting mesh (in parallel) with this map and
                     * assigning colors as necessary
                     */
                    if (first.HasColours)
                    {
                        ConcurrentDictionary <Vector3, uint> firstMap = new ConcurrentDictionary <Vector3, uint>();

                        // Create vertex to color map
                        Parallel.For(0, aTransformed.Length, i =>
                        {
                            firstMap[aTransformed[i]] = first.VertexColours[i];
                        });

                        // Assign colors
                        Parallel.For(0, vertices.Length, i =>
                        {
                            if (firstMap.ContainsKey(vertices[i]))
                            {
                                colors[i] = firstMap[vertices[i]];
                            }
                        });
                    }

                    if (second.HasColours)
                    {
                        ConcurrentDictionary <Vector3, uint> secondMap = new ConcurrentDictionary <Vector3, uint>();

                        Parallel.For(0, bTransformed.Length, i =>
                        {
                            secondMap[bTransformed[i]] = second.VertexColours[i];
                        });

                        Parallel.For(0, vertices.Length, i =>
                        {
                            if (secondMap.ContainsKey(vertices[i]))
                            {
                                colors[i] = secondMap[vertices[i]];
                            }
                        });
                    }
                    #endregion

                    finalResult = new Mesh3(vertices, triangleIndices, colors);
                }
            } // end-unsafe

            Matrix3 transform = first.Transform.Invert();
            finalResult = new Mesh3(finalResult.Vertices.Select(x => transform.Transform(x - first.Position)).ToArray(),
                                    finalResult.TriangleIndices, finalResult.VertexColours);
            finalResult.Position  = first.Position;
            finalResult.Transform = first.Transform;
            return(finalResult);
        }