//------------------------------// // ProceduralCapsule.cs // // Written by Jay Kay // // 2016/05/27 // //------------------------------// using UnityEngine; using System.Collections; [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))] public class ProceduralCapsule : MonoBehaviour { #if UNITY_EDITOR [ContextMenu("Generate Procedural Capsule")] public void GenerateProceduralCapsule() { // GenerateMesh(); } #endif public float height = 2f; public float radius = 0.5f; public int segments = 24; // void GenerateMesh() void Start() { } public void CreateMesh() { // make segments an even number if (segments % 2 != 0) segments++; // extra vertex on the seam int points = segments + 1; // calculate points around a circle float[] pX = new float[points]; float[] pZ = new float[points]; float[] pY = new float[points]; float[] pR = new float[points]; float calcH = 0f; float calcV = 0f; for (int i = 0; i < points; i++) { pX[i] = Mathf.Sin(calcH * Mathf.Deg2Rad); pZ[i] = Mathf.Cos(calcH * Mathf.Deg2Rad); pY[i] = Mathf.Cos(calcV * Mathf.Deg2Rad); pR[i] = Mathf.Sin(calcV * Mathf.Deg2Rad); calcH += 360f / (float) segments; calcV += 180f / (float) segments; } // - Vertices and UVs - Vector3[] vertices = new Vector3[points * (points + 1)]; Vector2[] uvs = new Vector2[vertices.Length]; int ind = 0; // Y-offset is half the height minus the diameter // float yOff = ( height - ( radius * 2f ) ) * 0.5f; float yOff = (height - (radius)) * 0.5f; if (yOff < 0) yOff = 0; // uv calculations float stepX = 1f / ((float) (points - 1)); float uvX, uvY; // Top Hemisphere int top = Mathf.CeilToInt((float) points * 0.5f); for (int y = 0; y < top; y++) { for (int x = 0; x < points; x++) { vertices[ind] = new Vector3(pX[x] * pR[y], pY[y], pZ[x] * pR[y]) * radius; vertices[ind].y = yOff + vertices[ind].y; uvX = 1f - (stepX * (float) x); uvY = (vertices[ind].y + (height * 0.5f)) / height; uvs[ind] = new Vector2(uvX, uvY); ind++; } } // Bottom Hemisphere int btm = Mathf.FloorToInt((float) points * 0.5f); for (int y = btm; y < points; y++) { for (int x = 0; x < points; x++) { vertices[ind] = new Vector3(pX[x] * pR[y], pY[y], pZ[x] * pR[y]) * radius; vertices[ind].y = -yOff + vertices[ind].y; uvX = 1f - (stepX * (float) x); uvY = (vertices[ind].y + (height * 0.5f)) / height; uvs[ind] = new Vector2(uvX, uvY); ind++; } } // - Triangles - int[] triangles = new int[(segments * (segments + 1) * 2 * 3)]; for (int y = 0, t = 0; y < segments + 1; y++) { for (int x = 0; x < segments; x++, t += 6) { triangles[t + 0] = ((y + 0) * (segments + 1)) + x + 0; triangles[t + 1] = ((y + 1) * (segments + 1)) + x + 0; triangles[t + 2] = ((y + 1) * (segments + 1)) + x + 1; triangles[t + 3] = ((y + 0) * (segments + 1)) + x + 1; triangles[t + 4] = ((y + 0) * (segments + 1)) + x + 0; triangles[t + 5] = ((y + 1) * (segments + 1)) + x + 1; } } // - Assign Mesh - MeshFilter mf = gameObject.GetComponent(); Mesh mesh = mf.sharedMesh; if (!mesh) { mesh = new Mesh(); mf.sharedMesh = mesh; } mesh.Clear(); mesh.name = "ProceduralCapsule"; mesh.vertices = vertices; mesh.uv = uvs; mesh.triangles = triangles; mesh.RecalculateBounds(); mesh.RecalculateNormals(); } }