public static Bounds GenerateParametricMesh(Mesh mesh, float radius, float falloffDistance, float angle, int sides)
        {
            var angleOffset = Mathf.PI / 2.0f + Mathf.Deg2Rad * angle;

            if (sides < 3)
            {
                radius = 0.70710678118654752440084436210485f * radius;
                sides  = 4;
            }

            if (sides == 4)
            {
                angleOffset = Mathf.PI / 4.0f + Mathf.Deg2Rad * angle;
            }

            var vertexCount = 1 + 2 * sides;
            var indexCount  = 3 * 3 * sides;
            var vertices    = new NativeArray <ParametricLightMeshVertex>(vertexCount, Allocator.Temp);
            var triangles   = new NativeArray <ushort>(indexCount, Allocator.Temp);
            var centerIndex = (ushort)(2 * sides);

            // Color will contain r,g = x,y extrusion direction, a = alpha. b is unused at the moment. The inner shape should not be extruded
            var color = new Color(0, 0, 0, 1);

            vertices[centerIndex] = new ParametricLightMeshVertex
            {
                position = float3.zero,
                color    = color
            };

            var radiansPerSide = 2 * Mathf.PI / sides;
            var min            = new float3(float.MaxValue, float.MaxValue, 0);
            var max            = new float3(float.MinValue, float.MinValue, 0);

            for (var i = 0; i < sides; i++)
            {
                var endAngle   = (i + 1) * radiansPerSide;
                var extrudeDir = new float3(math.cos(endAngle + angleOffset), math.sin(endAngle + angleOffset), 0);
                var endPoint   = radius * extrudeDir;

                var vertexIndex = (2 * i + 2) % (2 * sides);
                vertices[vertexIndex] = new ParametricLightMeshVertex
                {
                    position = endPoint,
                    color    = new Color(extrudeDir.x, extrudeDir.y, 0, 0)
                };
                vertices[vertexIndex + 1] = new ParametricLightMeshVertex
                {
                    position = endPoint,
                    color    = color
                };

                // Triangle 1 (Tip)
                var triangleIndex = 9 * i;
                triangles[triangleIndex]     = (ushort)(vertexIndex + 1);
                triangles[triangleIndex + 1] = (ushort)(2 * i + 1);
                triangles[triangleIndex + 2] = centerIndex;

                // Triangle 2 (Upper Top Left)
                triangles[triangleIndex + 3] = (ushort)(vertexIndex);
                triangles[triangleIndex + 4] = (ushort)(2 * i);
                triangles[triangleIndex + 5] = (ushort)(2 * i + 1);

                // Triangle 2 (Bottom Top Left)
                triangles[triangleIndex + 6] = (ushort)(vertexIndex + 1);
                triangles[triangleIndex + 7] = (ushort)(vertexIndex);
                triangles[triangleIndex + 8] = (ushort)(2 * i + 1);

                min = math.min(min, endPoint + extrudeDir * falloffDistance);
                max = math.max(max, endPoint + extrudeDir * falloffDistance);
            }

            mesh.SetVertexBufferParams(vertexCount, ParametricLightMeshVertex.VertexLayout);
            mesh.SetVertexBufferData(vertices, 0, 0, vertexCount);
            mesh.SetIndices(triangles, MeshTopology.Triangles, 0, false);

            return(new Bounds
            {
                min = min,
                max = max
            });
        }
        public static Bounds GenerateShapeMesh(Mesh mesh, Vector3[] shapePath, float falloffDistance)
        {
            var meshInteriorColor = new Color(0, 0, 0, 1);
            var min = new float3(float.MaxValue, float.MaxValue, 0);
            var max = new float3(float.MinValue, float.MinValue, 0);

            // Create interior geometry
            var pointCount = shapePath.Length;
            var inputs     = new ContourVertex[pointCount];

            for (var i = 0; i < pointCount; ++i)
            {
                inputs[i] = new ContourVertex()
                {
                    Position = new Vec3()
                    {
                        X = shapePath[i].x, Y = shapePath[i].y
                    }
                }
            }
            ;

            var tessI = new Tess();

            tessI.AddContour(inputs, ContourOrientation.Original);
            tessI.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3);

            var indicesI  = tessI.Elements.Select(i => i);
            var verticesI = tessI.Vertices.Select(v => new float3(v.Position.X, v.Position.Y, 0));

            var finalVertices = new NativeArray <ParametricLightMeshVertex>(verticesI.Count() + 2 * shapePath.Length, Allocator.Temp);
            var finalIndices  = new NativeArray <ushort>(indicesI.Count() + 6 * shapePath.Length, Allocator.Temp);

            var vertexOffset = 0;

            foreach (var v in verticesI)
            {
                finalVertices[vertexOffset++] = new ParametricLightMeshVertex
                {
                    position = v,
                    color    = meshInteriorColor
                };
            }

            var indexOffset = 0;

            foreach (var v in indicesI)
            {
                finalIndices[indexOffset++] = (ushort)v;
            }

            // Create falloff geometry
            var extrusionDirs     = GetFalloffShape(shapePath);
            var falloffPointCount = 2 * shapePath.Length;

            for (var i = 0; i < shapePath.Length; i++)
            {
                // Making triangles ABD and DCA
                var triangleIndex = 2 * i;
                var aIndex        = vertexOffset + triangleIndex;
                var bIndex        = vertexOffset + triangleIndex + 1;
                var cIndex        = vertexOffset + (triangleIndex + 2) % falloffPointCount;
                var dIndex        = vertexOffset + (triangleIndex + 3) % falloffPointCount;

                // We are making degenerate triangles which will be extruded by the shader
                var point = new ParametricLightMeshVertex
                {
                    position = shapePath[i],
                    color    = new Color(0, 0, 0, 1)
                };
                finalVertices[vertexOffset + i * 2] = point;

                point.color = new Color(extrusionDirs[i].x, extrusionDirs[i].y, 0, 0);
                finalVertices[vertexOffset + i * 2 + 1] = point;

                finalIndices[indexOffset + i * 6 + 0] = (ushort)aIndex;
                finalIndices[indexOffset + i * 6 + 1] = (ushort)bIndex;
                finalIndices[indexOffset + i * 6 + 2] = (ushort)dIndex;

                finalIndices[indexOffset + i * 6 + 3] = (ushort)dIndex;
                finalIndices[indexOffset + i * 6 + 4] = (ushort)cIndex;
                finalIndices[indexOffset + i * 6 + 5] = (ushort)aIndex;

                var extrudeDir = new float3(extrusionDirs[i].x, extrusionDirs[i].y, 0);
                min = math.min(min, point.position + extrudeDir * falloffDistance);
                max = math.max(max, point.position + extrudeDir * falloffDistance);
            }

            mesh.SetVertexBufferParams(finalVertices.Length, ParametricLightMeshVertex.VertexLayout);
            mesh.SetVertexBufferData(finalVertices, 0, 0, finalVertices.Length);
            mesh.SetIndices(finalIndices, MeshTopology.Triangles, 0, false);

            return(new Bounds
            {
                min = min,
                max = max
            });
        }