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); }
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); }