void TesselateGeometry(List <UIVertex> verts)
        {
            Vector2 tessellatedSize = mySettings.GetTesslationSize();

            //find if we are aligned with canvas main axis
            TransformMisaligned = !(savedUp.AlmostEqual(Vector3.up.normalized));

            // Convert the list from triangles to quads to be used by the tesselation
            TrisToQuads(verts);


            //do not tesselate text verts. Text usually is small and has plenty of verts already.
#if CURVEDUI_TMP || TMP_PRESENT
            if (myText == null && myTMP == null && !DoNotTesselate)
            {
#else
            if (myText == null && !DoNotTesselate)
            {
#endif
                // Tesselate quads and apply transformation
                int startingVertexCount = verts.Count;
                for (int i = 0; i < startingVertexCount; i += 4)
                {
                    ModifyQuad(verts, i, tessellatedSize);
                }

                // Remove old quads
                verts.RemoveRange(0, startingVertexCount);
            }
        }

        void ModifyQuad(List <UIVertex> verts, int vertexIndex, Vector2 requiredSize)
        {
            // Read the existing quad vertices
            UIVertex[] quad = new UIVertex[4];
            for (int i = 0; i < 4; i++)
            {
                quad[i] = verts[vertexIndex + i];
            }

            // horizotal and vertical directions of a quad. We're going to tesselate parallel to these.
            Vector3 horizontalDir = quad[2].position - quad[1].position;
            Vector3 verticalDir   = quad[1].position - quad[0].position;

            //To make sure filled image is properly tesselated, were going to find the bigger side of the quad.
            if (myImage != null && myImage.type == Image.Type.Filled)
            {
                horizontalDir = (horizontalDir).x > (quad[3].position - quad[0].position).x ? horizontalDir : quad[3].position - quad[0].position;
                verticalDir   = (verticalDir).y > (quad[2].position - quad[3].position).y ? verticalDir : quad[2].position - quad[3].position;
            }

            // Find how many quads we need to create
            int horizontalQuads = 1;
            int verticalQuads   = 1;

            // Tesselate vertically only if the recttransform (or parent) is rotated
            // This cuts down the time needed to tesselate by 90% in some cases.
            if (TransformMisaligned || mySettings.Shape == CurvedUISettings.CurvedUIShape.SPHERE || mySettings.Shape == CurvedUISettings.CurvedUIShape.CYLINDER_VERTICAL)
            {
                verticalQuads = Mathf.CeilToInt(verticalDir.magnitude * (1.0f / Mathf.Max(0.0001f, requiredSize.y)));
            }

            if (TransformMisaligned || mySettings.Shape != CurvedUISettings.CurvedUIShape.CYLINDER_VERTICAL)
            {
                horizontalQuads = Mathf.CeilToInt(horizontalDir.magnitude * (1.0f / Mathf.Max(0.0001f, requiredSize.x)));
            }
            //Debug.Log(this.transform.root.name + "'s panel: hori size:" + horizontalDir.magnitude + " req:" + requiredSize.x + " divs:"+horizontalQuads);

            bool oneVert = false;
            bool oneHori = false;

            // Create the quads!
            float yStart = 0.0f;

            for (int y = 0; y < verticalQuads || !oneVert; ++y)
            {
                oneVert = true;
                float yEnd   = (y + 1.0f) / verticalQuads;
                float xStart = 0.0f;

                for (int x = 0; x < horizontalQuads || !oneHori; ++x)
                {
                    oneHori = true;

                    float xEnd = (x + 1.0f) / horizontalQuads;

                    //Add new quads to list
                    verts.Add(TesselateQuad(quad, xStart, yStart));
                    verts.Add(TesselateQuad(quad, xStart, yEnd));
                    verts.Add(TesselateQuad(quad, xEnd, yEnd));
                    verts.Add(TesselateQuad(quad, xEnd, yStart));

                    //begin the next quad where we ened this one
                    xStart = xEnd;
                }
                //begin the next row where we ended this one
                yStart = yEnd;
            }
        }

        /// <summary>
        /// Converts a List of triangle mesh vertices to a list of quad mesh vertices
        /// </summary>
        void TrisToQuads(List <UIVertex> verts)
        {
            int addCount         = 0;
            int vertsInTrisCount = verts.Count;

            UIVertex[] vertsInQuads = new UIVertex[vertsInTrisCount / 6 * 4];

            for (int i = 0; i < vertsInTrisCount; i += 6)
            {
                // Get four corners from two triangles. Basic UI always comes in quads anyway.
                vertsInQuads[addCount++] = (verts[i + 0]);
                vertsInQuads[addCount++] = (verts[i + 1]);
                vertsInQuads[addCount++] = (verts[i + 2]);
                vertsInQuads[addCount++] = (verts[i + 4]);
            }
            //add quads to the list and remove the triangles
            verts.AddRange(vertsInQuads);
            verts.RemoveRange(0, vertsInTrisCount);
        }

        /// <summary>
        /// Subdivides a quad into 4 quads.
        /// </summary>
        /// <returns>The quad.</returns>
        /// <param name="quad">Quad.</param>
        /// <param name="x">The x coordinate.</param>
        /// <param name="y">The y coordinate.</param>
        UIVertex TesselateQuad(UIVertex[] quad, float x, float y)
        {
            UIVertex ret = new UIVertex();

            //1. calculate weighting factors
            float[] weights = new float[4] {
                (1 - x) * (1 - y),
                (1 - x) * y,
                x *y,
                x *(1 - y),
            };

            //2. interpolate all the vertex properties using weighting factors
            Vector2 uv0 = Vector2.zero, uv1 = Vector2.zero;
            Vector3 pos = Vector3.zero;

            for (int i = 0; i < 4; i++)
            {
                uv0 += quad[i].uv0 * weights[i];
                uv1 += quad[i].uv1 * weights[i];
                pos += quad[i].position * weights[i];
                //normal += quad[i].normal * weights[i]; // normals should be recalculated to take the curve into account;
                //tan += quad[i].tangent * weights[i]; // tangents should be recalculated to take the curve into account;
            }


            //4. return output
            ret.position = pos;
            //ret.color = Color32.Lerp(Color32.Lerp(quad[3].color, quad[1].color, y), Color32.Lerp(quad[0].color, quad[2].color, y), x);
            ret.color   = quad[0].color; //used instead to save performance. Color lerps are expensive.
            ret.uv0     = uv0;
            ret.uv1     = uv1;
            ret.normal  = quad[0].normal;
            ret.tangent = quad[0].tangent;

            return(ret);
        }
        void TesselateGeometry(List <UIVertex> verts)
        {
            Vector2 tessellatedSize = mySettings.GetTesslationSize();

            //find if we are aligned with canvas main axis
            TransformMisaligned = !(savedUp.AlmostEqual(Vector3.up.normalized));

            // Convert the list from triangles to quads to be used by the tesselation
            TrisToQuads(verts);


            //do not tesselate text verts. Text usually is small and has plenty of verts already.
#if CURVEDUI_TMP || TMP_PRESENT
            if (myText == null && myTMP == null && !DoNotTesselate)
            {
#else
            if (myText == null && !DoNotTesselate)
            {
#endif
                // Tesselate quads and apply transformation
                int startingVertexCount = verts.Count;
                for (int i = 0; i < startingVertexCount; i += 4)
                {
                    ModifyQuad(verts, i, tessellatedSize);
                }

                // Remove old quads
                verts.RemoveRange(0, startingVertexCount);
            }
        }

        void ModifyQuad(List <UIVertex> verts, int vertexIndex, Vector2 requiredSize)
        {
            // Read the existing quad vertices
            for (int i = 0; i < 4; i++)
            {
                m_quad[i] = verts[vertexIndex + i];
            }

            // horizotal and vertical directions of a quad. We're going to tesselate parallel to these.
            Vector3 horizontalDir = m_quad[2].position - m_quad[1].position;
            Vector3 verticalDir   = m_quad[1].position - m_quad[0].position;

            //To make sure filled image is properly tesselated, were going to find the bigger side of the quad.
            if (myGraphic != null && (myGraphic is Image) && (myGraphic as Image).type == Image.Type.Filled)
            {
                horizontalDir = (horizontalDir).x > (m_quad[3].position - m_quad[0].position).x ? horizontalDir : m_quad[3].position - m_quad[0].position;
                verticalDir   = (verticalDir).y > (m_quad[2].position - m_quad[3].position).y ? verticalDir : m_quad[2].position - m_quad[3].position;
            }

            // Find how many quads we need to create
            int horizontalQuads = 1;
            int verticalQuads   = 1;

            // Tesselate vertically only if the recttransform (or parent) is rotated
            // This cuts down the time needed to tesselate by 90% in some cases.
            if (TransformMisaligned || mySettings.Shape == CurvedUISettings.CurvedUIShape.SPHERE || mySettings.Shape == CurvedUISettings.CurvedUIShape.CYLINDER_VERTICAL)
            {
                verticalQuads = Mathf.CeilToInt(verticalDir.magnitude * (1.0f / Mathf.Max(0.0001f, requiredSize.y)));
            }

            if (TransformMisaligned || mySettings.Shape != CurvedUISettings.CurvedUIShape.CYLINDER_VERTICAL)
            {
                horizontalQuads = Mathf.CeilToInt(horizontalDir.magnitude * (1.0f / Mathf.Max(0.0001f, requiredSize.x)));
            }
            //Debug.Log(this.transform.root.name + "'s panel: hori size:" + horizontalDir.magnitude + " req:" + requiredSize.x + " divs:"+horizontalQuads);

            bool oneVert = false;
            bool oneHori = false;

            // Create the quads!
            float yStart = 0.0f;

            for (int y = 0; y < verticalQuads || !oneVert; ++y)
            {
                oneVert = true;
                float yEnd   = (y + 1.0f) / verticalQuads;
                float xStart = 0.0f;

                for (int x = 0; x < horizontalQuads || !oneHori; ++x)
                {
                    oneHori = true;

                    float xEnd = (x + 1.0f) / horizontalQuads;

                    //Add new quads to list
                    verts.Add(TesselateQuad(xStart, yStart));
                    verts.Add(TesselateQuad(xStart, yEnd));
                    verts.Add(TesselateQuad(xEnd, yEnd));
                    verts.Add(TesselateQuad(xEnd, yStart));

                    //begin the next quad where we ened this one
                    xStart = xEnd;
                }
                //begin the next row where we ended this one
                yStart = yEnd;
            }
        }

        /// <summary>
        /// Converts a List of triangle mesh vertices to a list of quad mesh vertices
        /// </summary>
        void TrisToQuads(List <UIVertex> verts)
        {
            int vertsInTrisCount = verts.Count;

            m_vertsInQuads.Clear();

            for (int i = 0; i < vertsInTrisCount; i += 6)
            {
                // Get four corners from two triangles. Basic UI always comes in quads anyway.
                m_vertsInQuads.Add(verts[i + 0]);
                m_vertsInQuads.Add(verts[i + 1]);
                m_vertsInQuads.Add(verts[i + 2]);
                m_vertsInQuads.Add(verts[i + 4]);
            }
            //add quads to the list and remove the triangles
            verts.AddRange(m_vertsInQuads);
            verts.RemoveRange(0, vertsInTrisCount);
        }
        Mesh CreateSphereColliderMesh()
        {
            Mesh meshie = new Mesh();

            Vector3[] Corners = new Vector3[4];
            (myCanvas.transform as RectTransform).GetWorldCorners(Corners);

            List <Vector3> verts = new List <Vector3>(Corners);

            for (int i = 0; i < verts.Count; i++)
            {
                verts[i] = mySettings.transform.worldToLocalMatrix.MultiplyPoint3x4(verts[i]);
            }

            if (mySettings.Angle != 0)
            {
                // Tesselate quads and apply transformation
                int startingVertexCount = verts.Count;
                for (int i = 0; i < startingVertexCount; i += 4)
                {
                    ModifyQuad(verts, i, mySettings.GetTesslationSize(true));
                }

                // Remove old quads
                verts.RemoveRange(0, startingVertexCount);

                //curve verts
                float   vangle         = mySettings.VerticalAngle;
                float   cylinder_angle = mySettings.Angle;
                Vector2 canvasSize     = (myCanvas.transform as RectTransform).rect.size;
                float   radius         = mySettings.GetCyllinderRadiusInCanvasSpace();

                //caluclate vertical angle for aspect - consistent mapping
                if (mySettings.PreserveAspect)
                {
                    vangle = mySettings.Angle * (canvasSize.y / canvasSize.x);
                }
                else  //if we're not going for constant aspect, set the width of the sphere to equal width of the original canvas
                {
                    radius = canvasSize.x / 2.0f;
                }

                //curve the vertices
                for (int i = 0; i < verts.Count; i++)
                {
                    float theta = (verts[i].x / canvasSize.x).Remap(-0.5f, 0.5f, (180 - cylinder_angle) / 2.0f - 90, 180 - (180 - cylinder_angle) / 2.0f - 90);
                    theta *= Mathf.Deg2Rad;
                    float gamma = (verts[i].y / canvasSize.y).Remap(-0.5f, 0.5f, (180 - vangle) / 2.0f, 180 - (180 - vangle) / 2.0f);
                    gamma *= Mathf.Deg2Rad;

                    verts[i] = new Vector3(Mathf.Sin(gamma) * Mathf.Sin(theta) * radius,
                                           -radius * Mathf.Cos(gamma),
                                           Mathf.Sin(gamma) * Mathf.Cos(theta) * radius + (mySettings.PreserveAspect ? -radius : 0));
                }
            }
            meshie.vertices = verts.ToArray();

            //create triangles from verts
            List <int> tris = new List <int>();

            for (int i = 0; i < verts.Count; i += 4)
            {
                tris.Add(i + 0);
                tris.Add(i + 1);
                tris.Add(i + 2);

                tris.Add(i + 3);
                tris.Add(i + 0);
                tris.Add(i + 2);
            }


            meshie.triangles = tris.ToArray();
            return(meshie);
        }
Beispiel #4
0
        void TesselateGeometry(List <UIVertex> verts)
        {
            Vector2 tessellatedSize = mySettings.GetTesslationSize();

            //find if we are aligned with canvas main axis
            TransformMisaligned = !(savedUp.AlmostEqual(Vector3.up));

#if !UNITY_5_1 /// Convert the list from triangles to quads to be used by the tesselation
            TrisToQuads(verts);
#endif

            //do not tesselate text verts. Text usually is small and has plenty of verts already.
#if CURVEDUI_TMP
            if (GetComponent <Text>() == null && GetComponent <TextMeshProUGUI>() == null)
            {
#else
            if (this.GetComponent <Text>() == null)
            {
#endif
                // Tesselate quads and apply transformation
                int startingVertexCount = verts.Count;
                for (int i = 0; i < startingVertexCount; i += 4)
                {
                    ModifyQuad(verts, i, tessellatedSize);
                }

                // Remove old quads
                verts.RemoveRange(0, startingVertexCount);
            }
        }

        void ModifyQuad(List <UIVertex> verts, int vertexIndex, Vector2 requiredSize)
        {
            // Read the existing quad vertices
            UIVertex[] quad = new UIVertex[4];
            for (int i = 0; i < 4; i++)
            {
                quad[i] = verts[vertexIndex + i];
            }

            // horizotal and vertical directions of a quad. We're going to tesselate parallel to these.
            Vector3 horizontalDir = quad[2].position - quad[1].position;
            Vector3 verticalDir   = quad[1].position - quad[0].position;

            // Find how many quads we need to create
            int horizontalQuads = 1;
            int verticalQuads   = 1;

            // Tesselate vertically only if the recttransform (or parent) is rotated
            // This cuts down the time needed to tesselate by 90% in some cases.
            if (TransformMisaligned || mySettings.Shape == CurvedUISettings.CurvedUIShape.SPHERE || mySettings.Shape == CurvedUISettings.CurvedUIShape.CYLINDER_VERTICAL)
            {
                verticalQuads = Mathf.CeilToInt(verticalDir.magnitude * (1.0f / Mathf.Max(1.0f, requiredSize.y)));
            }

            if (TransformMisaligned || mySettings.Shape != CurvedUISettings.CurvedUIShape.CYLINDER_VERTICAL)
            {
                horizontalQuads = Mathf.CeilToInt(horizontalDir.magnitude * (1.0f / Mathf.Max(1.0f, requiredSize.x)));
            }


            // Create the quads!
            float yStart = 0.0f;

            for (int y = 0; y < verticalQuads; ++y)
            {
                float yEnd   = (y + 1.0f) / verticalQuads;
                float xStart = 0.0f;

                for (int x = 0; x < horizontalQuads; ++x)
                {
                    float xEnd = (x + 1.0f) / horizontalQuads;

                    //Add new quads to list
                    verts.Add(TesselateQuad(quad, xStart, yStart));
                    verts.Add(TesselateQuad(quad, xStart, yEnd));
                    verts.Add(TesselateQuad(quad, xEnd, yEnd));
                    verts.Add(TesselateQuad(quad, xEnd, yStart));

                    //begin the next quad where we ened this one
                    xStart = xEnd;
                }
                //begin the next row where we ended this one
                yStart = yEnd;
            }
        }

        void TrisToQuads(List <UIVertex> verts)
        {
            int addCount         = 0;
            int vertsInTrisCount = verts.Count;

            UIVertex[] vertsInQuads = new UIVertex[vertsInTrisCount / 6 * 4];

            for (int i = 0; i < vertsInTrisCount; i += 6)
            {
                // Get four corners from two triangles. Basic UI always comes in quads anyway.
                vertsInQuads[addCount++] = (verts[i + 0]);
                vertsInQuads[addCount++] = (verts[i + 1]);
                vertsInQuads[addCount++] = (verts[i + 2]);
                vertsInQuads[addCount++] = (verts[i + 4]);
            }
            //add quads to the list and remove the triangles
            verts.AddRange(vertsInQuads);
            verts.RemoveRange(0, vertsInTrisCount);
        }

        UIVertex TesselateQuad(UIVertex[] quad, float x, float y)
        {
            UIVertex ret;

            //1. calculate weighting factors
            float[] weights = new float[4] {
                (1 - x) * (1 - y),
                (1 - x) * y,
                x *y,
                x *(1 - y),
            };

            //2. interpolate all the vertex properties using weighting factors
            Vector2 uv0 = Vector2.zero, uv1 = Vector2.zero;
            Vector3 pos = Vector3.zero;

            for (int i = 0; i < 4; i++)
            {
                uv0 += quad[i].uv0 * weights[i];
                uv1 += quad[i].uv1 * weights[i];
                pos += quad[i].position * weights[i];
                //normal += quad[i].normal * weights[i]; // normals should be recalculated to take the curve into account;
                //tan += quad[i].tangent * weights[i]; // tangents should be recalculated to take the curve into account;
            }

            //4. return output
            ret.position = pos;
            ret.color    = quad[0].color;
            ret.uv0      = uv0;
            ret.uv1      = uv1;
            ret.normal   = quad[0].normal;
            ret.tangent  = quad[0].tangent;

            return(ret);
        }