private void DrawCapsule(CapsuleCache c0, Pen p) { var n = c0.normal; var r = c0.capsule.radius; var twor = 2 * r; var x = r * n; var p0 = c0.capsule.p0; var p1 = c0.capsule.p1; DrawLine(p, p0 + x, p1 + x); DrawLine(p, p0 - x, p1 - x); float angle = Mathf.RAD_TO_DEG * (float)Math.Atan2(n.y, n.x); _graphics.DrawArc(p, p0.x - r, p0.y - r, twor, twor, angle, 180); _graphics.DrawArc(p, p1.x - r, p1.y - r, twor, twor, angle + 180, 180); }
RasterizationMesh RasterizeCapsuleCollider(float radius, float height, Bounds bounds, Matrix4x4 localToWorldMatrix) { // Calculate the number of rows to use // grows as sqrt(x) to the radius of the sphere/capsule which I have found works quite well int rows = Mathf.Max(4, Mathf.RoundToInt(colliderRasterizeDetail * Mathf.Sqrt(localToWorldMatrix.MultiplyVector(Vector3.one).magnitude))); if (rows > 100) { Debug.LogWarning("Very large detail for some collider meshes. Consider decreasing Collider Rasterize Detail (RecastGraph)"); } int cols = rows; Vector3[] verts; int[] trisArr; // Check if we have already calculated a similar capsule CapsuleCache cached = null; for (int i = 0; i < capsuleCache.Count; i++) { CapsuleCache c = capsuleCache[i]; if (c.rows == rows && Mathf.Approximately(c.height, height)) { cached = c; } } if (cached == null) { // Generate a sphere/capsule mesh verts = new Vector3[(rows) * cols + 2]; var tris = new List <int>(); verts[verts.Length - 1] = Vector3.up; for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { verts[c + r * cols] = new Vector3(Mathf.Cos(c * Mathf.PI * 2 / cols) * Mathf.Sin((r * Mathf.PI / (rows - 1))), Mathf.Cos((r * Mathf.PI / (rows - 1))) + (r < rows / 2 ? height : -height), Mathf.Sin(c * Mathf.PI * 2 / cols) * Mathf.Sin((r * Mathf.PI / (rows - 1)))); } } verts[verts.Length - 2] = Vector3.down; for (int i = 0, j = cols - 1; i < cols; j = i++) { tris.Add(verts.Length - 1); tris.Add(0 * cols + j); tris.Add(0 * cols + i); } for (int r = 1; r < rows; r++) { for (int i = 0, j = cols - 1; i < cols; j = i++) { tris.Add(r * cols + i); tris.Add(r * cols + j); tris.Add((r - 1) * cols + i); tris.Add((r - 1) * cols + j); tris.Add((r - 1) * cols + i); tris.Add(r * cols + j); } } for (int i = 0, j = cols - 1; i < cols; j = i++) { tris.Add(verts.Length - 2); tris.Add((rows - 1) * cols + j); tris.Add((rows - 1) * cols + i); } // Add calculated mesh to the cache cached = new CapsuleCache(); cached.rows = rows; cached.height = height; cached.verts = verts; cached.tris = tris.ToArray(); capsuleCache.Add(cached); } // Read from cache verts = cached.verts; trisArr = cached.tris; return(new RasterizationMesh(verts, trisArr, bounds, localToWorldMatrix)); }
/** Rasterizes a collider to a mesh assuming it's vertices should be multiplied with the matrix. * Note that the bounds of the returned ExtraMesh is based on collider.bounds. So you might want to * call myExtraMesh.RecalculateBounds on the returned mesh to recalculate it if the collider.bounds would * not give the correct value. * */ ExtraMesh RasterizeCollider (Collider col, Matrix4x4 localToWorldMatrix) { if (col is BoxCollider) { BoxCollider collider = col as BoxCollider; Matrix4x4 matrix = Matrix4x4.TRS (collider.center, Quaternion.identity, collider.size*0.5f); matrix = localToWorldMatrix * matrix; Bounds b = collider.bounds; ExtraMesh m = new ExtraMesh(BoxColliderVerts,BoxColliderTris, b, matrix); #if ASTARDEBUG Vector3[] verts = BoxColliderVerts; int[] tris = BoxColliderTris; for (int i=0;i<tris.Length;i+=3) { Debug.DrawLine (matrix.MultiplyPoint3x4(verts[tris[i]]),matrix.MultiplyPoint3x4(verts[tris[i+1]]), Color.yellow); Debug.DrawLine (matrix.MultiplyPoint3x4(verts[tris[i+2]]),matrix.MultiplyPoint3x4(verts[tris[i+1]]), Color.yellow); Debug.DrawLine (matrix.MultiplyPoint3x4(verts[tris[i]]),matrix.MultiplyPoint3x4(verts[tris[i+2]]), Color.yellow); //Normal debug /*Vector3 va = matrix.MultiplyPoint3x4(verts[tris[i]]); Vector3 vb = matrix.MultiplyPoint3x4(verts[tris[i+1]]); Vector3 vc = matrix.MultiplyPoint3x4(verts[tris[i+2]]); Debug.DrawRay ((va+vb+vc)/3, Vector3.Cross(vb-va,vc-va).normalized,Color.blue);*/ } #endif return m; } else if (col is SphereCollider || col is CapsuleCollider) { SphereCollider scollider = col as SphereCollider; CapsuleCollider ccollider = col as CapsuleCollider; float radius = (scollider != null ? scollider.radius : ccollider.radius); float height = scollider != null ? 0 : (ccollider.height*0.5f/radius) - 1; Matrix4x4 matrix = Matrix4x4.TRS (scollider != null ? scollider.center : ccollider.center, Quaternion.identity, Vector3.one*radius); matrix = localToWorldMatrix * matrix; //Calculate the number of rows to use //grows as sqrt(x) to the radius of the sphere/capsule which I have found works quite good int rows = Mathf.Max (4,Mathf.RoundToInt(colliderRasterizeDetail*Mathf.Sqrt(matrix.MultiplyVector(Vector3.one).magnitude))); if (rows > 100) { Debug.LogWarning ("Very large detail for some collider meshes. Consider decreasing Collider Rasterize Detail (RecastGraph)"); } int cols = rows; Vector3[] verts; int[] trisArr; //Check if we have already calculated a similar capsule CapsuleCache cached = null; for (int i=0;i<capsuleCache.Count;i++) { CapsuleCache c = capsuleCache[i]; if (c.rows == rows && Mathf.Approximately (c.height, height)) { cached = c; } } if (cached == null) { //Generate a sphere/capsule mesh verts = new Vector3[(rows)*cols + 2]; List<int> tris = new List<int>(); verts[verts.Length-1] = Vector3.up; for (int r=0;r<rows;r++) { for (int c=0;c<cols;c++) { verts[c + r*cols] = new Vector3 (Mathf.Cos (c*Mathf.PI*2/cols)*Mathf.Sin ((r*Mathf.PI/(rows-1))), Mathf.Cos ((r*Mathf.PI/(rows-1))) + (r < rows/2 ? height : -height) , Mathf.Sin (c*Mathf.PI*2/cols)*Mathf.Sin ((r*Mathf.PI/(rows-1)))); } } verts[verts.Length-2] = Vector3.down; for (int i=0, j = cols-1;i<cols; j = i++) { tris.Add (verts.Length-1); tris.Add (0*cols + j); tris.Add (0*cols + i); } for (int r=1;r<rows;r++) { for (int i=0, j = cols-1;i<cols; j = i++) { tris.Add (r*cols + i); tris.Add (r*cols + j); tris.Add ((r-1)*cols + i); tris.Add ((r-1)*cols + j); tris.Add ((r-1)*cols + i); tris.Add (r*cols + j); } } for (int i=0, j = cols-1;i<cols; j = i++) { tris.Add (verts.Length-2); tris.Add ((rows-1)*cols + j); tris.Add ((rows-1)*cols + i); } //Add calculated mesh to the cache cached = new CapsuleCache (); cached.rows = rows; cached.height = height; cached.verts = verts; cached.tris = tris.ToArray(); capsuleCache.Add (cached); } //Read from cache verts = cached.verts; trisArr = cached.tris; Bounds b = col.bounds; ExtraMesh m = new ExtraMesh(verts,trisArr, b, matrix); #if ASTARDEBUG for (int i=0;i<trisArr.Length;i+=3) { Debug.DrawLine (matrix.MultiplyPoint3x4(verts[trisArr[i]]),matrix.MultiplyPoint3x4(verts[trisArr[i+1]]), Color.yellow); Debug.DrawLine (matrix.MultiplyPoint3x4(verts[trisArr[i+2]]),matrix.MultiplyPoint3x4(verts[trisArr[i+1]]), Color.yellow); Debug.DrawLine (matrix.MultiplyPoint3x4(verts[trisArr[i]]),matrix.MultiplyPoint3x4(verts[trisArr[i+2]]), Color.yellow); //Normal debug /*Vector3 va = matrix.MultiplyPoint3x4(verts[trisArr[i]]); Vector3 vb = matrix.MultiplyPoint3x4(verts[trisArr[i+1]]); Vector3 vc = matrix.MultiplyPoint3x4(verts[trisArr[i+2]]); Debug.DrawRay ((va+vb+vc)/3, Vector3.Cross(vb-va,vc-va).normalized,Color.blue);*/ } #endif return m; } else if (col is MeshCollider) { MeshCollider collider = col as MeshCollider; if ( collider.sharedMesh != null ) { ExtraMesh m = new ExtraMesh(collider.sharedMesh.vertices, collider.sharedMesh.triangles, collider.bounds, localToWorldMatrix); return m; } } return new ExtraMesh(); }
private RasterizationMesh RasterizeCapsuleCollider(float radius, float height, Bounds bounds, Matrix4x4 localToWorldMatrix) { Vector3[] verts; int num = Mathf.Max(4, Mathf.RoundToInt(this.colliderRasterizeDetail * Mathf.Sqrt(localToWorldMatrix.MultiplyVector(Vector3.one).magnitude))); if (num > 100) { Debug.LogWarning("Very large detail for some collider meshes. Consider decreasing Collider Rasterize Detail (RecastGraph)"); } int num2 = num; CapsuleCache item = null; for (int i = 0; i < this.capsuleCache.Count; i++) { CapsuleCache cache2 = this.capsuleCache[i]; if ((cache2.rows == num) && Mathf.Approximately(cache2.height, height)) { item = cache2; } } if (item == null) { verts = new Vector3[(num * num2) + 2]; List <int> list = new List <int>(); verts[verts.Length - 1] = Vector3.up; for (int j = 0; j < num; j++) { for (int num5 = 0; num5 < num2; num5++) { verts[num5 + (j * num2)] = new Vector3(Mathf.Cos(((num5 * 3.141593f) * 2f) / ((float)num2)) * Mathf.Sin((j * 3.141593f) / ((float)(num - 1))), Mathf.Cos((j * 3.141593f) / ((float)(num - 1))) + ((j >= (num / 2)) ? -height : height), Mathf.Sin(((num5 * 3.141593f) * 2f) / ((float)num2)) * Mathf.Sin((j * 3.141593f) / ((float)(num - 1)))); } } verts[verts.Length - 2] = Vector3.down; int num6 = 0; for (int k = num2 - 1; num6 < num2; k = num6++) { list.Add(verts.Length - 1); list.Add((0 * num2) + k); list.Add((0 * num2) + num6); } for (int m = 1; m < num; m++) { int num9 = 0; for (int num10 = num2 - 1; num9 < num2; num10 = num9++) { list.Add((m * num2) + num9); list.Add((m * num2) + num10); list.Add(((m - 1) * num2) + num9); list.Add(((m - 1) * num2) + num10); list.Add(((m - 1) * num2) + num9); list.Add((m * num2) + num10); } } int num11 = 0; for (int n = num2 - 1; num11 < num2; n = num11++) { list.Add(verts.Length - 2); list.Add(((num - 1) * num2) + n); list.Add(((num - 1) * num2) + num11); } item = new CapsuleCache(); item.rows = num; item.height = height; item.verts = verts; item.tris = list.ToArray(); this.capsuleCache.Add(item); } verts = item.verts; return(new RasterizationMesh(verts, item.tris, bounds, localToWorldMatrix)); }