| | 1 | | // Copyright (c) 2020-2023 dotBunny Inc. |
| | 2 | | // dotBunny licenses this file to you under the BSL-1.0 license. |
| | 3 | | // See the LICENSE file in the project root for more information. |
| | 4 | |
|
| | 5 | | using UnityEngine; |
| | 6 | | using Unity.Mathematics; |
| | 7 | |
|
| | 8 | | namespace GDX.Experimental |
| | 9 | | { |
| | 10 | | public static class DebugDrawShapes |
| | 11 | | { |
| | 12 | | const float PI = 3.1415927f; |
| | 13 | | const float Deg2Rad = 0.017453292f; |
| | 14 | | const int DefaultCircleVertexCount = 32; |
| | 15 | |
|
| | 16 | | /// <summary> |
| | 17 | | /// The ordered segment index pairs used to describe a cube. |
| | 18 | | /// </summary> |
| | 19 | | /// <remarks> |
| | 20 | | /// This effectively wraps the left side, then the right, then connects the two sides. |
| | 21 | | /// </remarks> |
| 0 | 22 | | public static int[] CubeSegmentIndices = |
| | 23 | | { |
| | 24 | | 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 |
| | 25 | | }; |
| | 26 | |
|
| | 27 | |
|
| | 28 | | static void GetCircleVertices(ref Vector3[] vertices, int startIndex, Vector3 center, Quaternion rotation, float |
| 0 | 29 | | { |
| 0 | 30 | | float radiansInterval = PI * 2f / circleVertexCount; |
| | 31 | |
|
| | 32 | | // Loop through and figure out the points |
| 0 | 33 | | for (int i = 0; i < circleVertexCount; i++) |
| 0 | 34 | | { |
| 0 | 35 | | float angle = i * radiansInterval; |
| | 36 | |
|
| | 37 | | // Create base point |
| 0 | 38 | | vertices[i+startIndex] = (rotation * new Vector3(0, math.sin(angle) * radius, math.cos(angle) * radius)) |
| 0 | 39 | | } |
| 0 | 40 | | } |
| | 41 | |
|
| | 42 | | static int[] GetCubeSegmentOffset(int offset) |
| 0 | 43 | | { |
| 0 | 44 | | int[] newIndices = new int[24] |
| | 45 | | { |
| | 46 | | CubeSegmentIndices[0] + offset, CubeSegmentIndices[1] + offset, CubeSegmentIndices[2] + offset, |
| | 47 | | CubeSegmentIndices[3] + offset, CubeSegmentIndices[4] + offset, CubeSegmentIndices[5] + offset, |
| | 48 | | CubeSegmentIndices[6] + offset, CubeSegmentIndices[7] + offset, CubeSegmentIndices[8] + offset, |
| | 49 | | CubeSegmentIndices[9] + offset, CubeSegmentIndices[10] + offset, CubeSegmentIndices[11] + offset, |
| | 50 | | CubeSegmentIndices[12] + offset, CubeSegmentIndices[13] + offset, CubeSegmentIndices[14] + offset, |
| | 51 | | CubeSegmentIndices[15] + offset, CubeSegmentIndices[16] + offset, CubeSegmentIndices[17] + offset, |
| | 52 | | CubeSegmentIndices[18] + offset, CubeSegmentIndices[19] + offset, CubeSegmentIndices[20] + offset, |
| | 53 | | CubeSegmentIndices[21] + offset, CubeSegmentIndices[22] + offset, CubeSegmentIndices[23] + offset |
| | 54 | | }; |
| 0 | 55 | | return newIndices; |
| 0 | 56 | | } |
| | 57 | |
|
| | 58 | | static void GetCubeSegmentOffsetNonAlloc(int[] indices, int startIndex, int offset) |
| 0 | 59 | | { |
| 0 | 60 | | indices[startIndex] = CubeSegmentIndices[0] + offset; |
| 0 | 61 | | indices[startIndex+1] = CubeSegmentIndices[1] + offset; |
| 0 | 62 | | indices[startIndex+2] = CubeSegmentIndices[2] + offset; |
| 0 | 63 | | indices[startIndex+3] = CubeSegmentIndices[3] + offset; |
| 0 | 64 | | indices[startIndex+4] = CubeSegmentIndices[4] + offset; |
| 0 | 65 | | indices[startIndex+5] = CubeSegmentIndices[5] + offset; |
| 0 | 66 | | indices[startIndex+6] = CubeSegmentIndices[6] + offset; |
| 0 | 67 | | indices[startIndex+7] = CubeSegmentIndices[7] + offset; |
| 0 | 68 | | indices[startIndex+8] = CubeSegmentIndices[8] + offset; |
| 0 | 69 | | indices[startIndex+9] = CubeSegmentIndices[9] + offset; |
| 0 | 70 | | indices[startIndex+10] = CubeSegmentIndices[10] + offset; |
| 0 | 71 | | indices[startIndex+11] = CubeSegmentIndices[11] + offset; |
| 0 | 72 | | indices[startIndex+12] = CubeSegmentIndices[12] + offset; |
| 0 | 73 | | indices[startIndex+13] = CubeSegmentIndices[13] + offset; |
| 0 | 74 | | indices[startIndex+14] = CubeSegmentIndices[14] + offset; |
| 0 | 75 | | indices[startIndex+15] = CubeSegmentIndices[15] + offset; |
| 0 | 76 | | indices[startIndex+16] = CubeSegmentIndices[16] + offset; |
| 0 | 77 | | indices[startIndex+17] = CubeSegmentIndices[17] + offset; |
| 0 | 78 | | indices[startIndex+18] = CubeSegmentIndices[18] + offset; |
| 0 | 79 | | indices[startIndex+19] = CubeSegmentIndices[19] + offset; |
| 0 | 80 | | indices[startIndex+20] = CubeSegmentIndices[20] + offset; |
| 0 | 81 | | indices[startIndex+21] = CubeSegmentIndices[21] + offset; |
| 0 | 82 | | indices[startIndex+22] = CubeSegmentIndices[22] + offset; |
| 0 | 83 | | indices[startIndex+23] = CubeSegmentIndices[23] + offset; |
| 0 | 84 | | } |
| | 85 | |
|
| | 86 | | /// <summary> |
| | 87 | | /// Get the vertices that make up a cube. |
| | 88 | | /// </summary> |
| | 89 | | /// <remarks> |
| | 90 | | /// Ordered based on <see cref="CubeSegmentIndices"/>. |
| | 91 | | /// </remarks> |
| | 92 | | /// <param name="center">The world space center location of the cube.</param> |
| | 93 | | /// <param name="size">The size of the cube.</param> |
| | 94 | | /// <returns>An array of ordered vertices.</returns> |
| | 95 | | static Vector3[] GetCubeVertices(Vector3 center, Quaternion rotation, Vector3 size) |
| 0 | 96 | | { |
| 0 | 97 | | Vector3 half = size / 2f; |
| | 98 | |
|
| 0 | 99 | | float centerMinusHalfX = center.x - half.x; |
| 0 | 100 | | float centerMinusHalfY = center.y - half.y; |
| 0 | 101 | | float centerMinusHalfZ = center.z - half.z; |
| 0 | 102 | | float centerPlusHalfX = center.x + half.x; |
| 0 | 103 | | float centerPlusHalfY = center.y + half.y; |
| 0 | 104 | | float centerPlusHalfZ = center.z + half.z; |
| | 105 | |
|
| 0 | 106 | | Vector3[] points = |
| | 107 | | { |
| | 108 | | rotation * new Vector3(centerMinusHalfX, centerMinusHalfY, centerMinusHalfZ), // Front Bottom Left (0) |
| | 109 | | rotation * new Vector3(centerMinusHalfX, centerMinusHalfY, centerPlusHalfZ), // Back Bottom Left (1) |
| | 110 | | rotation * new Vector3(centerMinusHalfX, centerPlusHalfY, centerPlusHalfZ), // Back Top Left (2) |
| | 111 | | rotation * new Vector3(centerMinusHalfX, centerPlusHalfY, centerMinusHalfZ), // Front Top Left (3) |
| | 112 | | rotation * new Vector3(centerPlusHalfX, centerMinusHalfY, centerMinusHalfZ), // Front Bottom Right (4) |
| | 113 | | rotation * new Vector3(centerPlusHalfX, centerMinusHalfY, centerPlusHalfZ), // Back Bottom Right (5) |
| | 114 | | rotation * new Vector3(centerPlusHalfX, centerPlusHalfY, centerPlusHalfZ), // Back Top Right (6) |
| | 115 | | rotation * new Vector3(centerPlusHalfX, centerPlusHalfY, centerMinusHalfZ), // Front Top Right (7) |
| | 116 | | }; |
| | 117 | |
|
| 0 | 118 | | return points; |
| 0 | 119 | | } |
| | 120 | |
|
| | 121 | | static void GetCubeVerticesNonAlloc(ref Vector3[] points, int startIndex, Vector3 center, Quaternion rotation, V |
| 0 | 122 | | { |
| 0 | 123 | | Vector3 half = size / 2f; |
| | 124 | |
|
| 0 | 125 | | float centerMinusHalfX = center.x - half.x; |
| 0 | 126 | | float centerMinusHalfY = center.y - half.y; |
| 0 | 127 | | float centerMinusHalfZ = center.z - half.z; |
| 0 | 128 | | float centerPlusHalfX = center.x + half.x; |
| 0 | 129 | | float centerPlusHalfY = center.y + half.y; |
| 0 | 130 | | float centerPlusHalfZ = center.z + half.z; |
| | 131 | |
|
| 0 | 132 | | points[startIndex] = rotation * new Vector3(centerMinusHalfX, centerMinusHalfY, centerMinusHalfZ); // Front |
| 0 | 133 | | points[startIndex + 1] = rotation * new Vector3(centerMinusHalfX, centerMinusHalfY, centerPlusHalfZ); // Bac |
| 0 | 134 | | points[startIndex + 2] = rotation * new Vector3(centerMinusHalfX, centerPlusHalfY, centerPlusHalfZ); // Back |
| 0 | 135 | | points[startIndex + 3] = rotation * new Vector3(centerMinusHalfX, centerPlusHalfY, centerMinusHalfZ); // Fro |
| 0 | 136 | | points[startIndex + 4] = rotation * new Vector3(centerPlusHalfX, centerMinusHalfY, centerMinusHalfZ); // Fro |
| 0 | 137 | | points[startIndex + 5] = rotation * new Vector3(centerPlusHalfX, centerMinusHalfY, centerPlusHalfZ); // Back |
| 0 | 138 | | points[startIndex + 6] = rotation * new Vector3(centerPlusHalfX, centerPlusHalfY, centerPlusHalfZ); // Back |
| 0 | 139 | | points[startIndex + 7] = rotation * new Vector3(centerPlusHalfX, centerPlusHalfY, centerMinusHalfZ); // Fron |
| 0 | 140 | | } |
| | 141 | |
|
| | 142 | | /// <summary> |
| | 143 | | /// Draw a dotted line cube of a specific color to the buffer. |
| | 144 | | /// </summary> |
| | 145 | | /// <param name="color">The color which to draw the dotted line cube with.</param> |
| | 146 | | /// <param name="center">The center world position of the cube.</param> |
| | 147 | | /// <param name="size">The unit size of the cube</param> |
| | 148 | | /// <returns>The created cube's invalidation token.</returns> |
| | 149 | | public static int DrawDottedCube(this DebugDrawBuffer buffer, Color color, Vector3 center, Quaternion rotation, |
| 0 | 150 | | { |
| 0 | 151 | | Vector3[] vertices = GetCubeVertices(center, rotation, size); |
| 0 | 152 | | return buffer.DrawDottedLines(color, ref vertices, ref CubeSegmentIndices); |
| 0 | 153 | | } |
| | 154 | |
|
| 0 | 155 | | static readonly Quaternion k_RotationPrimaryTopLoop = Quaternion.Euler(0, 90, 0); |
| 0 | 156 | | static readonly Quaternion k_RotationPrimaryBottomLoop = Quaternion.Euler(0, -90, 180); |
| | 157 | |
|
| 0 | 158 | | static readonly Quaternion k_RotationSecondaryTopLoop = Quaternion.Euler(0, 180, 0); |
| 0 | 159 | | static readonly Quaternion k_RotationSecondaryBottomLoop = Quaternion.Euler(0, 0, 180); |
| | 160 | |
|
| | 161 | |
|
| | 162 | | public static int DrawWireCapsule(this DebugDrawBuffer buffer, Color color, Vector3 bottomSpherePosition, Vector |
| 0 | 163 | | { |
| | 164 | | // Calculate total vertices |
| 0 | 165 | | int totalVertices = arcVertexCount * 4; |
| | 166 | |
|
| | 167 | | // TODO: add circles? |
| 0 | 168 | | Vector3[] vertices = new Vector3[totalVertices]; |
| 0 | 169 | | float baseAngle = 0f; |
| 0 | 170 | | float arcLength = 180f; |
| 0 | 171 | | int lineCount = arcVertexCount - 1; |
| | 172 | |
|
| 0 | 173 | | int bottomPrimaryStartIndex = arcVertexCount; |
| 0 | 174 | | int topSecondaryStartIndex = bottomPrimaryStartIndex * 2; |
| 0 | 175 | | int bottomSecondaryStartIndex = bottomPrimaryStartIndex * 3; |
| | 176 | |
|
| 0 | 177 | | Quaternion primaryTopRotation = rotation * k_RotationPrimaryTopLoop; |
| 0 | 178 | | Quaternion primaryBottomRotation = rotation * k_RotationPrimaryBottomLoop; |
| 0 | 179 | | Quaternion secondaryTopRotation = rotation * k_RotationSecondaryTopLoop; |
| 0 | 180 | | Quaternion secondaryBottomRotation = rotation * k_RotationSecondaryBottomLoop; |
| | 181 | |
|
| 0 | 182 | | for (int i = 0; i < arcVertexCount; i++) |
| 0 | 183 | | { |
| 0 | 184 | | float currentAngle = Deg2Rad * baseAngle; |
| | 185 | |
|
| 0 | 186 | | Vector3 basePosition = new Vector3(0, Mathf.Sin(currentAngle) * radius, Mathf.Cos(currentAngle) * radius |
| | 187 | |
|
| 0 | 188 | | vertices[i] = primaryTopRotation * basePosition + topSpherePosition; |
| 0 | 189 | | vertices[i+bottomPrimaryStartIndex] = primaryBottomRotation * basePosition + bottomSpherePosition; |
| | 190 | |
|
| 0 | 191 | | vertices[i+topSecondaryStartIndex] = secondaryTopRotation * basePosition + topSpherePosition; |
| 0 | 192 | | vertices[i+bottomSecondaryStartIndex] = secondaryBottomRotation * basePosition + bottomSpherePosition; |
| | 193 | |
|
| 0 | 194 | | baseAngle += arcLength / lineCount; |
| 0 | 195 | | } |
| | 196 | |
|
| | 197 | |
|
| | 198 | | // Create segment connections |
| 0 | 199 | | int blockSize = (lineCount * 2) + 2; |
| 0 | 200 | | int[] segments = new int[blockSize * 4]; |
| | 201 | |
|
| 0 | 202 | | int primaryTopBottomConnectionIndex = blockSize - 2; |
| 0 | 203 | | int primaryBottomTopConnectionIndex = (blockSize * 2) - 2; |
| 0 | 204 | | int secondaryTopBottomConnectionIndex = (blockSize * 3) - 2; |
| 0 | 205 | | int secondaryBottomTopConnectionIndex = (blockSize * 4) - 2; |
| | 206 | |
|
| 0 | 207 | | int segmentCount = segments.Length; |
| 0 | 208 | | int baseCount = 0; |
| | 209 | |
|
| 0 | 210 | | for (int i = 0; i < segmentCount; i+=2) |
| 0 | 211 | | { |
| 0 | 212 | | if (i == primaryTopBottomConnectionIndex || i == primaryBottomTopConnectionIndex || i == secondaryTopBot |
| 0 | 213 | | { |
| 0 | 214 | | baseCount++; |
| 0 | 215 | | continue; |
| | 216 | | } |
| | 217 | |
|
| 0 | 218 | | segments[i] = baseCount; |
| 0 | 219 | | baseCount++; |
| 0 | 220 | | segments[i + 1] = baseCount; |
| 0 | 221 | | } |
| | 222 | |
|
| 0 | 223 | | segments[primaryTopBottomConnectionIndex] = segments[primaryTopBottomConnectionIndex - 1]; |
| 0 | 224 | | segments[primaryTopBottomConnectionIndex+1] = segments[primaryTopBottomConnectionIndex + 2]; |
| | 225 | |
|
| 0 | 226 | | segments[primaryBottomTopConnectionIndex] = segments[primaryBottomTopConnectionIndex - 1]; |
| 0 | 227 | | segments[primaryBottomTopConnectionIndex+1] = segments[0]; |
| | 228 | |
|
| 0 | 229 | | segments[secondaryTopBottomConnectionIndex] = segments[secondaryTopBottomConnectionIndex - 1]; |
| 0 | 230 | | segments[secondaryTopBottomConnectionIndex+1] = segments[secondaryTopBottomConnectionIndex + 2]; |
| | 231 | |
|
| 0 | 232 | | segments[secondaryBottomTopConnectionIndex] = segments[secondaryBottomTopConnectionIndex - 1]; |
| 0 | 233 | | segments[secondaryBottomTopConnectionIndex+1] = segments[primaryBottomTopConnectionIndex + 2]; |
| | 234 | |
|
| | 235 | | // Link top to bottom |
| 0 | 236 | | return buffer.DrawLines(color, ref vertices, ref segments); |
| 0 | 237 | | } |
| | 238 | |
|
| | 239 | | public static int DrawWireArc(this DebugDrawBuffer buffer, Color color, Vector3 center, Quaternion rotation, flo |
| 0 | 240 | | { |
| | 241 | | // We do the plus one to complete the full arc segment, otherwise it would not be every peice |
| 0 | 242 | | Vector3[] vertices = new Vector3[arcVertexCount]; |
| 0 | 243 | | float baseAngle = startAngle; |
| 0 | 244 | | float arcLength = endAngle - startAngle; |
| 0 | 245 | | int lineCount = arcVertexCount - 1; |
| 0 | 246 | | for (int i = 0; i < arcVertexCount; i++) |
| 0 | 247 | | { |
| 0 | 248 | | float currentAngle = Deg2Rad * baseAngle; |
| 0 | 249 | | vertices[i] = (rotation * new Vector3(0, Mathf.Sin(currentAngle) * radius,Mathf.Cos(currentAngle) * radi |
| 0 | 250 | | baseAngle += (arcLength / lineCount); |
| 0 | 251 | | } |
| | 252 | |
|
| | 253 | | // Create segment connections |
| 0 | 254 | | int[] segments = new int[lineCount * 2]; |
| 0 | 255 | | int segmentCount = segments.Length; |
| 0 | 256 | | int baseCount = 0; |
| 0 | 257 | | for (int i = 0; i < segmentCount; i+=2) |
| 0 | 258 | | { |
| 0 | 259 | | segments[i] = baseCount; |
| 0 | 260 | | baseCount++; |
| 0 | 261 | | segments[i + 1] = baseCount; |
| 0 | 262 | | } |
| 0 | 263 | | return buffer.DrawLines(color, ref vertices, ref segments); |
| 0 | 264 | | } |
| | 265 | |
|
| | 266 | | public static int DrawWireCircle(this DebugDrawBuffer buffer, Color color, Vector3 center, Quaternion rotation, |
| 0 | 267 | | { |
| 0 | 268 | | Vector3[] vertices = new Vector3[circleVertexCount]; |
| 0 | 269 | | float radiansInterval = PI * 2f / circleVertexCount; |
| | 270 | |
|
| | 271 | | // Loop through and figure out the points |
| 0 | 272 | | for (int i = 0; i < circleVertexCount; i++) |
| 0 | 273 | | { |
| 0 | 274 | | float angle = i * radiansInterval; |
| | 275 | |
|
| | 276 | | // Create base point |
| 0 | 277 | | vertices[i] = (rotation * new Vector3(0, math.sin(angle) * radius, math.cos(angle) * radius)) + center; |
| 0 | 278 | | } |
| | 279 | |
|
| 0 | 280 | | int[] segments = new int[circleVertexCount * 2]; |
| 0 | 281 | | int segmentCount = segments.Length; |
| 0 | 282 | | int baseCount = 0; |
| | 283 | |
|
| 0 | 284 | | for (int i = 0; i < segmentCount; i+=2) |
| 0 | 285 | | { |
| 0 | 286 | | segments[i] = baseCount; |
| 0 | 287 | | baseCount++; |
| 0 | 288 | | segments[i + 1] = baseCount; |
| 0 | 289 | | } |
| 0 | 290 | | segments[segmentCount - 1] = 0; |
| | 291 | |
|
| 0 | 292 | | return buffer.DrawLines(color, ref vertices, ref segments); |
| 0 | 293 | | } |
| | 294 | |
|
| | 295 | | /// <summary> |
| | 296 | | /// Draw a wireframe cube of a specific color to the buffer. |
| | 297 | | /// </summary> |
| | 298 | | /// <param name="color">The color which to draw the wire cube with.</param> |
| | 299 | | /// <param name="center">The center world position of the cube.</param> |
| | 300 | | /// <param name="size">The unit size of the cube</param> |
| | 301 | | /// <returns>The created cube's invalidation token.</returns> |
| | 302 | | public static int DrawWireCube(this DebugDrawBuffer buffer, Color color, Vector3 center, Quaternion rotation, Ve |
| 0 | 303 | | { |
| 0 | 304 | | Vector3[] vertices = GetCubeVertices(center, rotation, size); |
| 0 | 305 | | return buffer.DrawLines(color, ref vertices, ref CubeSegmentIndices); |
| 0 | 306 | | } |
| | 307 | |
|
| | 308 | | public static int DrawWireSphere(this DebugDrawBuffer buffer, Color color, Vector3 center, Quaternion rotation, |
| 0 | 309 | | { |
| 0 | 310 | | int pointCount = circleVertexCount * 2; |
| 0 | 311 | | Vector3[] vertices = new Vector3[pointCount]; |
| | 312 | |
|
| 0 | 313 | | float radiansInterval = PI * 2f / circleVertexCount; |
| 0 | 314 | | Quaternion xRotation = Space.Axis.X.ToRotation() * rotation; |
| 0 | 315 | | Quaternion yRotation = Space.Axis.Y.ToRotation() * rotation; |
| | 316 | |
|
| | 317 | | // Loop through and figure out the points |
| 0 | 318 | | for (int i = 0; i < circleVertexCount; i++) |
| 0 | 319 | | { |
| 0 | 320 | | float angle = i * radiansInterval; |
| | 321 | |
|
| | 322 | | // Create base points |
| 0 | 323 | | vertices[i] = (xRotation * new Vector3(0, math.sin(angle) * radius, math.cos(angle) * radius)) + center; |
| 0 | 324 | | vertices[i+circleVertexCount] = (yRotation * new Vector3(0, math.sin(angle) * radius, math.cos(angle) * |
| 0 | 325 | | } |
| | 326 | |
|
| | 327 | | // Create segment connections |
| 0 | 328 | | int[] segments = new int[pointCount * 2]; |
| 0 | 329 | | int segmentCount = segments.Length; |
| 0 | 330 | | int baseCount = 0; |
| 0 | 331 | | for (int i = 0; i < segmentCount; i+=2) |
| 0 | 332 | | { |
| 0 | 333 | | segments[i] = baseCount; |
| 0 | 334 | | baseCount++; |
| 0 | 335 | | segments[i + 1] = baseCount; |
| 0 | 336 | | } |
| 0 | 337 | | segments[pointCount - 1] = 0; |
| 0 | 338 | | segments[segmentCount - 1] = circleVertexCount; |
| | 339 | |
|
| 0 | 340 | | return buffer.DrawLines(color, ref vertices, ref segments); |
| 0 | 341 | | } |
| | 342 | | } |
| | 343 | | } |