예제 #1
0
        // arc utils
        public static IEnumerable <PolylinePoint> GetArcPoints(PolylinePoint a, PolylinePoint b, Vector3 normA, Vector3 normB, Vector3 center, float radius, int count)
        {
            count = Mathf.Max(2, count);               // at least 2

            PolylinePoint DirToPt(Vector3 dir, float t)
            {
                PolylinePoint p = t <= 0 ? a : (t >= 1 ? b : PolylinePoint.Lerp(a, b, t));

                p.point = center + dir * radius;
                return(p);
            }

            yield return(DirToPt(normA, 0));

            for (int i = 1; i < count - 1; i++)
            {
                float t = i / (count - 1f);
                yield return(DirToPt(Vector3.Slerp(normA, normB, t), t));
            }

            yield return(DirToPt(normB, 1));
        }
예제 #2
0
 [MethodImpl(INLINE)] public static PolylinePoint WeightedSum(Vector4 w, PolylinePoint a, PolylinePoint b, PolylinePoint c, PolylinePoint d) => w.x * a + w.y * b + w.z * c + w.w * d;
예제 #3
0
 public static PolylinePoint CubicBezier(PolylinePoint a, PolylinePoint b, PolylinePoint c, PolylinePoint d, float t)
 {
     if (t <= 0f)
     {
         return(a);
     }
     if (t >= 1f)
     {
         return(d);
     }
     return(WeightedSum(GetCubicBezierWeights(t), a, b, c, d));
 }
예제 #4
0
        public static IEnumerable <PolylinePoint> CubicBezierPointsSkipFirstMatchStyle(PolylinePoint style, Vector3 a, Vector3 b, Vector3 c, Vector3 d, int count)
        {
            // skip first point
            for (int i = 1; i < count - 1; i++)
            {
                float         t  = i / (count - 1f);
                PolylinePoint pp = style;
                pp.point = CubicBezier(a, b, c, d, t);
                yield return(pp);
            }

            PolylinePoint ppEnd = style;

            ppEnd.point = d;
            yield return(ppEnd);
        }
예제 #5
0
        // bezier utils
        public static IEnumerable <PolylinePoint> CubicBezierPointsSkipFirst(PolylinePoint a, PolylinePoint b, PolylinePoint c, PolylinePoint d, int count)
        {
            // skip first point
            for (int i = 1; i < count - 1; i++)
            {
                float t = i / (count - 1f);
                yield return(CubicBezier(a, b, c, d, t));
            }

            yield return(d);
        }
예제 #6
0
        public static void GenPolylineMesh(Mesh mesh, IList <PolylinePoint> path, bool closed, PolylineJoins joins, bool useColors)
        {
            mesh.Clear();             // todo maybe not always do this you know?

            int pointCount = path.Count;

            if (pointCount < 2)
            {
                return;
            }
            if (pointCount == 2 && closed)
            {
                closed = false;
            }

            PolylinePoint firstPoint = path[0];
            PolylinePoint lastPoint  = path[path.Count - 1];

            // if the last point is at the same place as the first and it's closed, ignore the last point
            if ((closed || pointCount == 2) && SamePosition(firstPoint.point, lastPoint.point))
            {
                pointCount--;                 // ignore last point
                if (pointCount < 2)           // check point count again
                {
                    return;
                }
                lastPoint = path[path.Count - 2];                 // second last point technically
            }

            // only mitered joints can be in the same submesh at the moment
            bool separateJoinMesh    = joins.HasJoinMesh();
            bool isSimpleJoin        = joins.HasSimpleJoin();      // only used when join meshes exist
            int  vertsPerPathPoint   = separateJoinMesh ? 5 : 2;
            int  trianglesPerSegment = separateJoinMesh ? 4 : 2;
            int  vertexCount         = pointCount * vertsPerPathPoint;
            int  vertexCountTotal    = vertexCount;
            int  segmentCount        = closed ? pointCount : pointCount - 1;
            int  triangleCount       = segmentCount * trianglesPerSegment;
            int  triangleIndexCount  = triangleCount * 3;

            // Joins mesh data
            int[] meshJoinsTriangles = default;
            int   joinVertsPerJoin   = default;

            if (separateJoinMesh)
            {
                joinVertsPerJoin = isSimpleJoin ? 3 : 5;
                int joinCount              = closed ? pointCount : pointCount - 2;
                int joinTrianglesPerJoin   = isSimpleJoin ? 1 : 3;
                int joinTriangleIndexCount = joinCount * joinTrianglesPerJoin * 3;
                int vertexCountJoins       = joinCount * joinVertsPerJoin;
                vertexCountTotal  += vertexCountJoins;
                meshJoinsTriangles = new int[joinTriangleIndexCount];
            }


            Color[]   meshColors   = useColors ? new Color[vertexCountTotal] : null;
            Vector3[] meshVertices = new Vector3[vertexCountTotal];

                        #if UNITY_2019_3_OR_NEWER
            Vector4[] meshUv0      = new Vector4[vertexCountTotal];        // UVs for masking. z contains endpoint status, w is thickness
            Vector3[] meshUv1Prevs = new Vector3[vertexCountTotal];
            Vector3[] meshUv2Nexts = new Vector3[vertexCountTotal];
                        #else
            // List<> is the only supported vec3 UV assignment method prior to Unity 2019.3
            List <Vector4> meshUv0      = new List <Vector4>(new Vector4[vertexCountTotal]);
            List <Vector3> meshUv1Prevs = new List <Vector3>(new Vector3[vertexCountTotal]);
            List <Vector3> meshUv2Nexts = new List <Vector3>(new Vector3[vertexCountTotal]);
                        #endif


            int[] meshTriangles = new int[triangleIndexCount];


            // indices used per triangle
            int iv0, iv1, iv2 = 0, iv3 = 0, iv4 = 0;
            int ivj0 = 0, ivj1 = 0, ivj2 = 0, ivj3 = 0, ivj4 = 0;
            int triId     = 0;
            int triIdJoin = 0;
            for (int i = 0; i < pointCount; i++)
            {
                bool  isLast          = i == pointCount - 1;
                bool  isFirst         = i == 0;
                bool  makeJoin        = closed || (!isLast && !isFirst);
                bool  isEndpoint      = closed == false && (isFirst || isLast);
                float uvEndpointValue = isEndpoint ? (isFirst ? -1 : 1) : 0;
                void SetUv0(int id, float x, float y) => meshUv0[id] = new Vector4(x, y, uvEndpointValue, path[i].thickness);


                // Indices & verts
                Vector3 vert  = path[i].point;
                Color   color = useColors ? path[i].color : default;
                iv0 = i * vertsPerPathPoint;
                if (separateJoinMesh)
                {
                    iv1 = iv0 + 1;                     // "prev" outer
                    iv2 = iv0 + 2;                     // "next" outer
                    iv3 = iv0 + 3;                     // "prev" inner
                    iv4 = iv0 + 4;                     // "next" inner
                    meshVertices[iv0] = vert;
                    meshVertices[iv1] = vert;
                    meshVertices[iv2] = vert;
                    meshVertices[iv3] = vert;
                    meshVertices[iv4] = vert;
                    if (useColors)
                    {
                        meshColors[iv0] = color;
                        meshColors[iv1] = color;
                        meshColors[iv2] = color;
                        meshColors[iv3] = color;
                        meshColors[iv4] = color;
                    }


                    // joins mesh
                    if (makeJoin)
                    {
                        int joinIndex = (closed ? i : i - 1);                           // Skip first if open
                        ivj0 = joinIndex * joinVertsPerJoin + vertexCount;
                        ivj1 = ivj0 + 1;
                        ivj2 = ivj0 + 2;
                        ivj3 = ivj0 + 3;
                        ivj4 = ivj0 + 4;
                        meshVertices[ivj0] = vert;
                        meshVertices[ivj1] = vert;
                        meshVertices[ivj2] = vert;
                        if (useColors)
                        {
                            meshColors[ivj0] = color;
                            meshColors[ivj1] = color;
                            meshColors[ivj2] = color;
                        }

                        if (isSimpleJoin == false)
                        {
                            meshVertices[ivj3] = vert;
                            meshVertices[ivj4] = vert;
                            if (useColors)
                            {
                                meshColors[ivj3] = color;
                                meshColors[ivj4] = color;
                            }
                        }
                    }
                }
                else
                {
                    iv1 = iv0 + 1;                     // Inner vert
                    meshVertices[iv0] = vert;
                    meshVertices[iv1] = vert;
                    if (useColors)
                    {
                        meshColors[iv0] = color;
                        meshColors[iv1] = color;
                    }
                }


                // Setting up next/previous positions
                Vector3 prevPos;
                Vector3 nextPos;
                if (i == 0)
                {
                    prevPos = closed ? lastPoint.point : (firstPoint.point * 2 - path[1].point);                       // Mirror second point
                    nextPos = path[i + 1].point;
                }
                else if (i == pointCount - 1)
                {
                    prevPos = path[i - 1].point;
                    nextPos = closed ? firstPoint.point : (path[pointCount - 1].point * 2 - path[pointCount - 2].point);                       // Mirror second last point
                }
                else
                {
                    prevPos = path[i - 1].point;
                    nextPos = path[i + 1].point;
                }

                void SetPrevNext(int atIndex)
                {
                    meshUv1Prevs[atIndex] = prevPos;
                    meshUv2Nexts[atIndex] = nextPos;
                }

                SetPrevNext(iv0);
                SetPrevNext(iv1);
                if (separateJoinMesh)
                {
                    SetPrevNext(iv2);
                    SetPrevNext(iv3);
                    SetPrevNext(iv4);
                    if (makeJoin)
                    {
                        SetPrevNext(ivj0);
                        SetPrevNext(ivj1);
                        SetPrevNext(ivj2);
                        if (isSimpleJoin == false)
                        {
                            SetPrevNext(ivj3);
                            SetPrevNext(ivj4);
                        }
                    }
                }

                if (separateJoinMesh)
                {
                    SetUv0(iv0, 0, 0);
                    SetUv0(iv1, -1, -1);
                    SetUv0(iv2, -1, 1);
                    SetUv0(iv3, 1, -1);
                    SetUv0(iv4, 1, 1);
                    if (makeJoin)
                    {
                        SetUv0(ivj0, 0, 0);
                        if (isSimpleJoin)
                        {
                            SetUv0(ivj1, 1, -1);
                            SetUv0(ivj2, 1, 1);
                        }
                        else
                        {
                            SetUv0(ivj1, 1, -1);
                            SetUv0(ivj2, -1, -1);
                            SetUv0(ivj3, -1, 1);
                            SetUv0(ivj4, 1, 1);
                        }
                    }
                }
                else
                {
                    SetUv0(iv0, -1, i);
                    SetUv0(iv1, 1, i);
                }


                if (isLast == false || closed)
                {
                    // clockwise order
                    void AddQuad(int a, int b, int c, int d)
                    {
                        meshTriangles[triId++] = a;
                        meshTriangles[triId++] = b;
                        meshTriangles[triId++] = c;
                        meshTriangles[triId++] = c;
                        meshTriangles[triId++] = d;
                        meshTriangles[triId++] = a;
                    }

                    if (separateJoinMesh)
                    {
                        int rootCenter = iv0;
                        int rootOuter  = iv2;
                        int rootInner  = iv4;
                        int nextCenter = isLast ? 0 : rootCenter + vertsPerPathPoint;
                        int nextOuter  = nextCenter + 1;
                        int nextInner  = nextCenter + 3;
                        AddQuad(rootCenter, rootOuter, nextOuter, nextCenter);
                        AddQuad(nextCenter, nextInner, rootInner, rootCenter);

                        if (makeJoin)
                        {
                            meshJoinsTriangles[triIdJoin++] = ivj0;
                            meshJoinsTriangles[triIdJoin++] = ivj1;
                            meshJoinsTriangles[triIdJoin++] = ivj2;

                            if (isSimpleJoin == false)
                            {
                                meshJoinsTriangles[triIdJoin++] = ivj2;
                                meshJoinsTriangles[triIdJoin++] = ivj3;
                                meshJoinsTriangles[triIdJoin++] = ivj0;

                                meshJoinsTriangles[triIdJoin++] = ivj0;
                                meshJoinsTriangles[triIdJoin++] = ivj3;
                                meshJoinsTriangles[triIdJoin++] = ivj4;
                            }
                        }
                    }
                    else
                    {
                        int rootOuter = iv0;
                        int rootInner = iv1;
                        int nextOuter = isLast ? 0 : rootOuter + vertsPerPathPoint;
                        int nextInner = nextOuter + 1;
                        AddQuad(rootInner, rootOuter, nextOuter, nextInner);
                    }
                }
            }

            // assign to segments mesh
            mesh.vertices     = meshVertices;
            mesh.subMeshCount = 2;
            mesh.SetTriangles(meshTriangles, 0);
            mesh.SetTriangles(meshJoinsTriangles, 1);
            mesh.SetUVs(0, meshUv0);
            mesh.SetUVs(1, meshUv1Prevs);
            mesh.SetUVs(2, meshUv2Nexts);
            if (useColors)
            {
                mesh.colors = meshColors;
            }
        }