コード例 #1
0
        /**
         * Calculate the Barycentric coordinate weight values u-v-w for Point p in respect to the provided
         * triangle. This is useful for computing new UV coordinates for arbitrary points.
         */
        public Vector3 Barycentric(Vector3 p)
        {
            Vector3 a = m_pos_a;
            Vector3 b = m_pos_b;
            Vector3 c = m_pos_c;

            Vector3 m = Vector3.Cross(b - a, c - a);

            float nu;
            float nv;
            float ood;

            float x = Mathf.Abs(m.x);
            float y = Mathf.Abs(m.y);
            float z = Mathf.Abs(m.z);

            // compute areas of plane with largest projections
            if (x >= y && x >= z)
            {
                // area of PBC in yz plane
                nu = Intersector.TriArea2D(p.y, p.z, b.y, b.z, c.y, c.z);
                // area of PCA in yz plane
                nv = Intersector.TriArea2D(p.y, p.z, c.y, c.z, a.y, a.z);
                // 1/2*area of ABC in yz plane
                ood = 1.0f / m.x;
            }
            else if (y >= x && y >= z)
            {
                // project in xz plane
                nu  = Intersector.TriArea2D(p.x, p.z, b.x, b.z, c.x, c.z);
                nv  = Intersector.TriArea2D(p.x, p.z, c.x, c.z, a.x, a.z);
                ood = 1.0f / -m.y;
            }
            else
            {
                // project in xy plane
                nu  = Intersector.TriArea2D(p.x, p.y, b.x, b.y, c.x, c.y);
                nv  = Intersector.TriArea2D(p.x, p.y, c.x, c.y, a.x, a.y);
                ood = 1.0f / m.z;
            }

            float u = nu * ood;
            float v = nv * ood;
            float w = 1.0f - u - v;

            return(new Vector3(u, v, w));
        }
コード例 #2
0
        /**
         * O(n log n) Convex Hull Algorithm.
         * Accepts a list of vertices as Vector3 and triangulates them according to a projection
         * plane defined as planeNormal. Algorithm will output vertices, indices and UV coordinates
         * as arrays
         */
        public static bool MonotoneChain(List <Vector3> vertices, Vector3 normal, out List <Triangle> tri, TextureRegion texRegion)
        {
            int count = vertices.Count;

            // we cannot triangulate less than 3 points. Use minimum of 3 points
            if (count < 3)
            {
                tri = null;
                return(false);
            }

            // first, we map from 3D points into a 2D plane represented by the provided normal
            Vector3 u = Vector3.Normalize(Vector3.Cross(normal, Vector3.up));

            if (Vector3.zero == u)
            {
                u = Vector3.Normalize(Vector3.Cross(normal, Vector3.forward));
            }
            Vector3 v = Vector3.Cross(u, normal);

            // generate an array of mapped values
            Mapped2D[] mapped = new Mapped2D[count];

            // these values will be used to generate new UV coordinates later on
            float maxDivX = float.MinValue;
            float maxDivY = float.MinValue;
            float minDivX = float.MaxValue;
            float minDivY = float.MaxValue;

            // map the 3D vertices into the 2D mapped values
            for (int i = 0; i < count; i++)
            {
                Vector3 vertToAdd = vertices[i];

                Mapped2D newMappedValue = new Mapped2D(vertToAdd, u, v);
                Vector2  mapVal         = newMappedValue.mappedValue;

                // grab our maximal values so we can map UV's in a proper range
                maxDivX = Mathf.Max(maxDivX, mapVal.x);
                maxDivY = Mathf.Max(maxDivY, mapVal.y);
                minDivX = Mathf.Min(minDivX, mapVal.x);
                minDivY = Mathf.Min(minDivY, mapVal.y);

                mapped[i] = newMappedValue;
            }

            // sort our newly generated array values
            Array.Sort <Mapped2D>(mapped, (a, b) => {
                Vector2 x = a.mappedValue;
                Vector2 p = b.mappedValue;

                return((x.x < p.x || (x.x == p.x && x.y < p.y)) ? -1 : 1);
            });

            // our final hull mappings will end up in here
            Mapped2D[] hulls = new Mapped2D[count + 1];

            int k = 0;

            // build the lower hull of the chain
            for (int i = 0; i < count; i++)
            {
                while (k >= 2)
                {
                    Vector2 mA = hulls[k - 2].mappedValue;
                    Vector2 mB = hulls[k - 1].mappedValue;
                    Vector2 mC = mapped[i].mappedValue;

                    if (Intersector.TriArea2D(mA.x, mA.y, mB.x, mB.y, mC.x, mC.y) > 0.0f)
                    {
                        break;
                    }

                    k--;
                }

                hulls[k++] = mapped[i];
            }

            // build the upper hull of the chain
            for (int i = count - 2, t = k + 1; i >= 0; i--)
            {
                while (k >= t)
                {
                    Vector2 mA = hulls[k - 2].mappedValue;
                    Vector2 mB = hulls[k - 1].mappedValue;
                    Vector2 mC = mapped[i].mappedValue;

                    if (Intersector.TriArea2D(mA.x, mA.y, mB.x, mB.y, mC.x, mC.y) > 0.0f)
                    {
                        break;
                    }

                    k--;
                }

                hulls[k++] = mapped[i];
            }

            // finally we can build our mesh, generate all the variables
            // and fill them up
            int vertCount = k - 1;
            int triCount  = (vertCount - 2) * 3;

            // this should not happen, but here just in case
            if (vertCount < 3)
            {
                tri = null;
                return(false);
            }

            // ensure List does not dynamically grow, performing copy ops each time!
            tri = new List <Triangle>(triCount / 3);

            float width  = maxDivX - minDivX;
            float height = maxDivY - minDivY;

            int indexCount = 1;

            // generate both the vertices and uv's in this loop
            for (int i = 0; i < triCount; i += 3)
            {
                // the Vertices in our triangle
                Mapped2D posA = hulls[0];
                Mapped2D posB = hulls[indexCount];
                Mapped2D posC = hulls[indexCount + 1];

                // generate UV Maps
                Vector2 uvA = posA.mappedValue;
                Vector2 uvB = posB.mappedValue;
                Vector2 uvC = posC.mappedValue;

                uvA.x = (uvA.x - minDivX) / width;
                uvA.y = (uvA.y - minDivY) / height;

                uvB.x = (uvB.x - minDivX) / width;
                uvB.y = (uvB.y - minDivY) / height;

                uvC.x = (uvC.x - minDivX) / width;
                uvC.y = (uvC.y - minDivY) / height;

                Triangle newTriangle = new Triangle(posA.originalValue, posB.originalValue, posC.originalValue);

                // ensure our UV coordinates are mapped into the requested TextureRegion
                newTriangle.SetUV(texRegion.Map(uvA), texRegion.Map(uvB), texRegion.Map(uvC));

                // the normals is the same for all vertices since the final mesh is completly flat
                newTriangle.SetNormal(normal, normal, normal);
                newTriangle.ComputeTangents();

                tri.Add(newTriangle);

                indexCount++;
            }

            return(true);
        }
コード例 #3
0
        /**
         * Perform an intersection between Plane and Triangle. This is a comprehensive function
         * which alwo builds a HULL Hirearchy useful for decimation projects. This obviously
         * comes at the cost of more complex code and runtime checks, but the returned results
         * are much more flexible.
         * Results will be filled into the IntersectionResult reference. Check result.isValid()
         * for the final results.
         */
        public static void Intersect(Plane pl, Triangle tri, ref IntersectionResult result)
        {
            // clear the previous results from the IntersectionResult
            result.Clear();

            // grab local variables for easier access
            Vector3 a = tri.positionA;
            Vector3 b = tri.positionB;
            Vector3 c = tri.positionC;

            // check to see which side of the plane the points all
            // lay in. SideOf operation is a simple dot product and some comparison
            // operations, so these are a very quick checks
            SideOfPlane sa = pl.SideOf(a);
            SideOfPlane sb = pl.SideOf(b);
            SideOfPlane sc = pl.SideOf(c);

            // we cannot intersect if the triangle points all fall on the same side
            // of the plane. This is an easy early out test as no intersections are possible.
            if (sa == sb && sb == sc)
            {
                return;
            }

            // detect cases where two points lay straight on the plane, meaning
            // that the plane is actually parralel with one of the edges of the triangle
            else if ((sa == SideOfPlane.ON && sa == sb) ||
                     (sa == SideOfPlane.ON && sa == sc) ||
                     (sb == SideOfPlane.ON && sb == sc))
            {
                return;
            }

            // keep in mind that intersection points are shared by both
            // the upper HULL and lower HULL hence they lie perfectly
            // on the plane that cut them
            Vector3 qa;
            Vector3 qb;

            // check the cases where the points of the triangle actually lie on the plane itself
            // in these cases, there is only going to be 2 triangles, one for the upper HULL and
            // the other on the lower HULL
            // we just need to figure out which points to accept into the upper or lower hulls.
            if (sa == SideOfPlane.ON)
            {
                // if the point a is on the plane, test line b-c
                if (Intersector.Intersect(pl, b, c, out qa))
                {
                    // line b-c intersected, construct out triangles and return approprietly
                    result.AddIntersectionPoint(qa);
                    result.AddIntersectionPoint(a);

                    // our two generated triangles, we need to figure out which
                    // triangle goes into the UPPER hull and which goes into the LOWER hull
                    Triangle ta = new Triangle(a, b, qa);
                    Triangle tb = new Triangle(a, qa, c);

                    // generate UV coordinates if there is any
                    if (tri.hasUV)
                    {
                        // the computed UV coordinate if the intersection point
                        Vector2 pq = tri.GenerateUV(qa);
                        Vector2 pa = tri.uvA;
                        Vector2 pb = tri.uvB;
                        Vector2 pc = tri.uvC;

                        ta.SetUV(pa, pb, pq);
                        tb.SetUV(pa, pq, pc);
                    }

                    // generate Normal coordinates if there is any
                    if (tri.hasNormal)
                    {
                        // the computed Normal coordinate if the intersection point
                        Vector3 pq = tri.GenerateNormal(qa);
                        Vector3 pa = tri.normalA;
                        Vector3 pb = tri.normalB;
                        Vector3 pc = tri.normalC;

                        ta.SetNormal(pa, pb, pq);
                        tb.SetNormal(pa, pq, pc);
                    }

                    // generate Tangent coordinates if there is any
                    if (tri.hasTangent)
                    {
                        // the computed Tangent coordinate if the intersection point
                        Vector4 pq = tri.GenerateTangent(qa);
                        Vector4 pa = tri.tangentA;
                        Vector4 pb = tri.tangentB;
                        Vector4 pc = tri.tangentC;

                        ta.SetTangent(pa, pb, pq);
                        tb.SetTangent(pa, pq, pc);
                    }

                    // b point lies on the upside of the plane
                    if (sb == SideOfPlane.UP)
                    {
                        result.AddUpperHull(ta).AddLowerHull(tb);
                    }

                    // b point lies on the downside of the plane
                    else if (sb == SideOfPlane.DOWN)
                    {
                        result.AddUpperHull(tb).AddLowerHull(ta);
                    }
                }
            }

            // test the case where the b point lies on the plane itself
            else if (sb == SideOfPlane.ON)
            {
                // if the point b is on the plane, test line a-c
                if (Intersector.Intersect(pl, a, c, out qa))
                {
                    // line a-c intersected, construct out triangles and return approprietly
                    result.AddIntersectionPoint(qa);
                    result.AddIntersectionPoint(b);

                    // our two generated triangles, we need to figure out which
                    // triangle goes into the UPPER hull and which goes into the LOWER hull
                    Triangle ta = new Triangle(a, b, qa);
                    Triangle tb = new Triangle(qa, b, c);

                    // generate UV coordinates if there is any
                    if (tri.hasUV)
                    {
                        // the computed UV coordinate if the intersection point
                        Vector2 pq = tri.GenerateUV(qa);
                        Vector2 pa = tri.uvA;
                        Vector2 pb = tri.uvB;
                        Vector2 pc = tri.uvC;

                        ta.SetUV(pa, pb, pq);
                        tb.SetUV(pq, pb, pc);
                    }

                    // generate Normal coordinates if there is any
                    if (tri.hasNormal)
                    {
                        // the computed Normal coordinate if the intersection point
                        Vector3 pq = tri.GenerateNormal(qa);
                        Vector3 pa = tri.normalA;
                        Vector3 pb = tri.normalB;
                        Vector3 pc = tri.normalC;

                        ta.SetNormal(pa, pb, pq);
                        tb.SetNormal(pq, pb, pc);
                    }

                    // generate Tangent coordinates if there is any
                    if (tri.hasTangent)
                    {
                        // the computed Tangent coordinate if the intersection point
                        Vector4 pq = tri.GenerateTangent(qa);
                        Vector4 pa = tri.tangentA;
                        Vector4 pb = tri.tangentB;
                        Vector4 pc = tri.tangentC;

                        ta.SetTangent(pa, pb, pq);
                        tb.SetTangent(pq, pb, pc);
                    }

                    // a point lies on the upside of the plane
                    if (sa == SideOfPlane.UP)
                    {
                        result.AddUpperHull(ta).AddLowerHull(tb);
                    }

                    // a point lies on the downside of the plane
                    else if (sa == SideOfPlane.DOWN)
                    {
                        result.AddUpperHull(tb).AddLowerHull(ta);
                    }
                }
            }

            // test the case where the c point lies on the plane itself
            else if (sc == SideOfPlane.ON)
            {
                // if the point c is on the plane, test line a-b
                if (Intersector.Intersect(pl, a, b, out qa))
                {
                    // line a-c intersected, construct out triangles and return approprietly
                    result.AddIntersectionPoint(qa);
                    result.AddIntersectionPoint(c);

                    // our two generated triangles, we need to figure out which
                    // triangle goes into the UPPER hull and which goes into the LOWER hull
                    Triangle ta = new Triangle(a, qa, c);
                    Triangle tb = new Triangle(qa, b, c);

                    // generate UV coordinates if there is any
                    if (tri.hasUV)
                    {
                        // the computed UV coordinate if the intersection point
                        Vector2 pq = tri.GenerateUV(qa);
                        Vector2 pa = tri.uvA;
                        Vector2 pb = tri.uvB;
                        Vector2 pc = tri.uvC;

                        ta.SetUV(pa, pq, pc);
                        tb.SetUV(pq, pb, pc);
                    }

                    // generate Normal coordinates if there is any
                    if (tri.hasNormal)
                    {
                        // the computed Normal coordinate if the intersection point
                        Vector3 pq = tri.GenerateNormal(qa);
                        Vector3 pa = tri.normalA;
                        Vector3 pb = tri.normalB;
                        Vector3 pc = tri.normalC;

                        ta.SetNormal(pa, pq, pc);
                        tb.SetNormal(pq, pb, pc);
                    }

                    // generate Tangent coordinates if there is any
                    if (tri.hasTangent)
                    {
                        // the computed Tangent coordinate if the intersection point
                        Vector4 pq = tri.GenerateTangent(qa);
                        Vector4 pa = tri.tangentA;
                        Vector4 pb = tri.tangentB;
                        Vector4 pc = tri.tangentC;

                        ta.SetTangent(pa, pq, pc);
                        tb.SetTangent(pq, pb, pc);
                    }

                    // a point lies on the upside of the plane
                    if (sa == SideOfPlane.UP)
                    {
                        result.AddUpperHull(ta).AddLowerHull(tb);
                    }

                    // a point lies on the downside of the plane
                    else if (sa == SideOfPlane.DOWN)
                    {
                        result.AddUpperHull(tb).AddLowerHull(ta);
                    }
                }
            }

            // at this point, all edge cases have been tested and failed, we need to perform
            // full intersection tests against the lines. From this point onwards we will generate
            // 3 triangles
            else if (sa != sb && Intersector.Intersect(pl, a, b, out qa))
            {
                // intersection found against a - b
                result.AddIntersectionPoint(qa);

                // since intersection was found against a - b, we need to check which other
                // lines to check (we only need to check one more line) for intersection.
                // the line we check against will be the line against the point which lies on
                // the other side of the plane.
                if (sa == sc)
                {
                    // we likely have an intersection against line b-c which will complete this loop
                    if (Intersector.Intersect(pl, b, c, out qb))
                    {
                        result.AddIntersectionPoint(qb);

                        // our three generated triangles. Two of these triangles will end
                        // up on either the UPPER or LOWER hulls.
                        Triangle ta = new Triangle(qa, b, qb);
                        Triangle tb = new Triangle(a, qa, qb);
                        Triangle tc = new Triangle(a, qb, c);

                        // generate UV coordinates if there is any
                        if (tri.hasUV)
                        {
                            // the computed UV coordinate if the intersection point
                            Vector2 pqa = tri.GenerateUV(qa);
                            Vector2 pqb = tri.GenerateUV(qb);
                            Vector2 pa  = tri.uvA;
                            Vector2 pb  = tri.uvB;
                            Vector2 pc  = tri.uvC;

                            ta.SetUV(pqa, pb, pqb);
                            tb.SetUV(pa, pqa, pqb);
                            tc.SetUV(pa, pqb, pc);
                        }

                        // generate Normal coordinates if there is any
                        if (tri.hasNormal)
                        {
                            // the computed Normal coordinate if the intersection point
                            Vector3 pqa = tri.GenerateNormal(qa);
                            Vector3 pqb = tri.GenerateNormal(qb);
                            Vector3 pa  = tri.normalA;
                            Vector3 pb  = tri.normalB;
                            Vector3 pc  = tri.normalC;

                            ta.SetNormal(pqa, pb, pqb);
                            tb.SetNormal(pa, pqa, pqb);
                            tc.SetNormal(pa, pqb, pc);
                        }

                        // generate Tangent coordinates if there is any
                        if (tri.hasTangent)
                        {
                            // the computed Tangent coordinate if the intersection point
                            Vector4 pqa = tri.GenerateTangent(qa);
                            Vector4 pqb = tri.GenerateTangent(qb);
                            Vector4 pa  = tri.tangentA;
                            Vector4 pb  = tri.tangentB;
                            Vector4 pc  = tri.tangentC;

                            ta.SetTangent(pqa, pb, pqb);
                            tb.SetTangent(pa, pqa, pqb);
                            tc.SetTangent(pa, pqb, pc);
                        }

                        if (sa == SideOfPlane.UP)
                        {
                            result.AddUpperHull(tb).AddUpperHull(tc).AddLowerHull(ta);
                        }
                        else
                        {
                            result.AddLowerHull(tb).AddLowerHull(tc).AddUpperHull(ta);
                        }
                    }
                }
                else
                {
                    // in this scenario, the point a is a "lone" point which lies in either upper
                    // or lower HULL. We need to perform another intersection to find the last point
                    if (Intersector.Intersect(pl, a, c, out qb))
                    {
                        result.AddIntersectionPoint(qb);

                        // our three generated triangles. Two of these triangles will end
                        // up on either the UPPER or LOWER hulls.
                        Triangle ta = new Triangle(a, qa, qb);
                        Triangle tb = new Triangle(qa, b, c);
                        Triangle tc = new Triangle(qb, qa, c);

                        // generate UV coordinates if there is any
                        if (tri.hasUV)
                        {
                            // the computed UV coordinate if the intersection point
                            Vector2 pqa = tri.GenerateUV(qa);
                            Vector2 pqb = tri.GenerateUV(qb);
                            Vector2 pa  = tri.uvA;
                            Vector2 pb  = tri.uvB;
                            Vector2 pc  = tri.uvC;

                            ta.SetUV(pa, pqa, pqb);
                            tb.SetUV(pqa, pb, pc);
                            tc.SetUV(pqb, pqa, pc);
                        }

                        // generate Normal coordinates if there is any
                        if (tri.hasNormal)
                        {
                            // the computed Normal coordinate if the intersection point
                            Vector3 pqa = tri.GenerateNormal(qa);
                            Vector3 pqb = tri.GenerateNormal(qb);
                            Vector3 pa  = tri.normalA;
                            Vector3 pb  = tri.normalB;
                            Vector3 pc  = tri.normalC;

                            ta.SetNormal(pa, pqa, pqb);
                            tb.SetNormal(pqa, pb, pc);
                            tc.SetNormal(pqb, pqa, pc);
                        }

                        // generate Tangent coordinates if there is any
                        if (tri.hasTangent)
                        {
                            // the computed Tangent coordinate if the intersection point
                            Vector4 pqa = tri.GenerateTangent(qa);
                            Vector4 pqb = tri.GenerateTangent(qb);
                            Vector4 pa  = tri.tangentA;
                            Vector4 pb  = tri.tangentB;
                            Vector4 pc  = tri.tangentC;

                            ta.SetTangent(pa, pqa, pqb);
                            tb.SetTangent(pqa, pb, pc);
                            tc.SetTangent(pqb, pqa, pc);
                        }

                        if (sa == SideOfPlane.UP)
                        {
                            result.AddUpperHull(ta).AddLowerHull(tb).AddLowerHull(tc);
                        }
                        else
                        {
                            result.AddLowerHull(ta).AddUpperHull(tb).AddUpperHull(tc);
                        }
                    }
                }
            }

            // if line a-b did not intersect (or the lie on the same side of the plane)
            // this simplifies the problem a fair bit. This means we have an intersection
            // in line a-c and b-c, which we can use to build a new UPPER and LOWER hulls
            // we are expecting both of these intersection tests to pass, otherwise something
            // went wrong (float errors? missed a checked case?)
            else if (Intersector.Intersect(pl, c, a, out qa) && Intersector.Intersect(pl, c, b, out qb))
            {
                // in here we know that line a-b actually lie on the same side of the plane, this will
                // simplify the rest of the logic. We also have our intersection points
                // the computed UV coordinate of the intersection point

                result.AddIntersectionPoint(qa);
                result.AddIntersectionPoint(qb);

                // our three generated triangles. Two of these triangles will end
                // up on either the UPPER or LOWER hulls.
                Triangle ta = new Triangle(qa, qb, c);
                Triangle tb = new Triangle(a, qb, qa);
                Triangle tc = new Triangle(a, b, qb);

                // generate UV coordinates if there is any
                if (tri.hasUV)
                {
                    // the computed UV coordinate if the intersection point
                    Vector2 pqa = tri.GenerateUV(qa);
                    Vector2 pqb = tri.GenerateUV(qb);
                    Vector2 pa  = tri.uvA;
                    Vector2 pb  = tri.uvB;
                    Vector2 pc  = tri.uvC;

                    ta.SetUV(pqa, pqb, pc);
                    tb.SetUV(pa, pqb, pqa);
                    tc.SetUV(pa, pb, pqb);
                }

                // generate Normal coordinates if there is any
                if (tri.hasNormal)
                {
                    // the computed Normal coordinate if the intersection point
                    Vector3 pqa = tri.GenerateNormal(qa);
                    Vector3 pqb = tri.GenerateNormal(qb);
                    Vector3 pa  = tri.normalA;
                    Vector3 pb  = tri.normalB;
                    Vector3 pc  = tri.normalC;

                    ta.SetNormal(pqa, pqb, pc);
                    tb.SetNormal(pa, pqb, pqa);
                    tc.SetNormal(pa, pb, pqb);
                }

                // generate Tangent coordinates if there is any
                if (tri.hasTangent)
                {
                    // the computed Tangent coordinate if the intersection point
                    Vector4 pqa = tri.GenerateTangent(qa);
                    Vector4 pqb = tri.GenerateTangent(qb);
                    Vector4 pa  = tri.tangentA;
                    Vector4 pb  = tri.tangentB;
                    Vector4 pc  = tri.tangentC;

                    ta.SetTangent(pqa, pqb, pc);
                    tb.SetTangent(pa, pqb, pqa);
                    tc.SetTangent(pa, pb, pqb);
                }

                if (sa == SideOfPlane.UP)
                {
                    result.AddUpperHull(tb).AddUpperHull(tc).AddLowerHull(ta);
                }
                else
                {
                    result.AddLowerHull(tb).AddLowerHull(tc).AddUpperHull(ta);
                }
            }
        }
コード例 #4
0
 /**
  * Perform an intersection between Plane and Line, storing intersection point
  * in reference q. Function returns true if intersection has been found or
  * false otherwise.
  */
 public static bool Intersect(Plane pl, Line ln, out Vector3 q)
 {
     return(Intersector.Intersect(pl, ln.positionA, ln.positionB, out q));
 }
コード例 #5
0
        /**
         * Helper function to split this triangle by the provided plane and store
         * the results inside the IntersectionResult structure.
         * Returns true on success or false otherwise
         */
        public bool Split(Plane pl, IntersectionResult result)
        {
            Intersector.Intersect(pl, this, ref result);

            return(result.isValid);
        }
コード例 #6
0
        /**
         * O(n log n) Convex Hull Algorithm.
         * Accepts a list of vertices as Vector3 and triangulates them according to a projection
         * plane defined as planeNormal. Algorithm will output vertices, indices and UV coordinates
         * as arrays
         */
        public static bool MonotoneChain(List <Vector3> vertices, Vector3 normal, out Vector3[] verts, out int[] indices, out Vector2[] uv)
        {
            int count = vertices.Count;

            // we cannot triangulate less than 3 points. Use minimum of 3 points
            if (count < 3)
            {
                verts   = null;
                indices = null;
                uv      = null;

                return(false);
            }

            // first, we map from 3D points into a 2D plane represented by the provided normal
            Vector3 r = Mathf.Abs(normal.x) > Mathf.Abs(normal.y) ? new Vector3(0, 1, 0) : new Vector3(1, 0, 0);

            Vector3 v = Vector3.Normalize(Vector3.Cross(r, normal));
            Vector3 u = Vector3.Cross(normal, v);

            // generate an array of mapped values
            Mapped2D[] mapped = new Mapped2D[count];

            // these values will be used to generate new UV coordinates later on
            float maxDivX = 0.0f;
            float maxDivY = 0.0f;

            // map the 3D vertices into the 2D mapped values
            for (int i = 0; i < count; i++)
            {
                Vector3 vertToAdd = vertices[i];

                Mapped2D newMappedValue = new Mapped2D(vertToAdd, u, v);
                Vector2  mapVal         = newMappedValue.mappedValue;

                // grab our maximal values so we can map UV's in a proper range
                maxDivX = Mathf.Max(maxDivX, mapVal.x);
                maxDivY = Mathf.Max(maxDivY, mapVal.y);

                mapped[i] = newMappedValue;
            }

            // sort our newly generated array values
            Array.Sort <Mapped2D>(mapped, (a, b) =>
            {
                Vector2 x = a.mappedValue;
                Vector2 p = b.mappedValue;

                return((x.x < p.x || (x.x == p.x && x.y < p.y)) ? -1 : 1);
            });

            // our final hull mappings will end up in here
            Mapped2D[] hulls = new Mapped2D[count + 1];

            int k = 0;

            // build the lower hull of the chain
            for (int i = 0; i < count; i++)
            {
                while (k >= 2)
                {
                    Vector2 mA = hulls[k - 2].mappedValue;
                    Vector2 mB = hulls[k - 1].mappedValue;
                    Vector2 mC = mapped[i].mappedValue;

                    if (Intersector.TriArea2D(mA.x, mA.y, mB.x, mB.y, mC.x, mC.y) > 0.0f)
                    {
                        break;
                    }

                    k--;
                }

                hulls[k++] = mapped[i];
            }

            // build the upper hull of the chain
            for (int i = count - 2, t = k + 1; i >= 0; i--)
            {
                while (k >= t)
                {
                    Vector2 mA = hulls[k - 2].mappedValue;
                    Vector2 mB = hulls[k - 1].mappedValue;
                    Vector2 mC = mapped[i].mappedValue;

                    if (Intersector.TriArea2D(mA.x, mA.y, mB.x, mB.y, mC.x, mC.y) > 0.0f)
                    {
                        break;
                    }

                    k--;
                }

                hulls[k++] = mapped[i];
            }

            // finally we can build our mesh, generate all the variables
            // and fill them up
            int vertCount = k - 1;

            // this should not happen, but here just in case
            if (vertCount < 3)
            {
                verts   = null;
                indices = null;
                uv      = null;

                return(false);
            }

            int triCount = (vertCount - 2) * 3;

            verts   = new Vector3[vertCount];
            indices = new int[triCount];
            uv      = new Vector2[vertCount];

            // generate both the vertices and uv's in this loop
            for (int i = 0; i < vertCount; i++)
            {
                Mapped2D val = hulls[i];

                // place the vertex
                verts[i] = val.originalValue;

                // generate and place the UV
                Vector2 mappedValue = val.mappedValue;
                mappedValue.x = (mappedValue.x / maxDivX) * 0.5f;
                mappedValue.y = (mappedValue.y / maxDivY) * 0.5f;

                uv[i] = mappedValue;
            }

            int indexCount = 1;

            // generate the triangles/indices
            for (int i = 0; i < triCount; i += 3)
            {
                indices[i + 0] = 0;
                indices[i + 1] = indexCount;
                indices[i + 2] = indexCount + 1;

                indexCount++;
            }

            return(true);
        }