DebugRenderer.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt.h>
  4. #ifdef JPH_DEBUG_RENDERER
  5. #include <Renderer/DebugRenderer.h>
  6. #include <Core/Profiler.h>
  7. #include <Geometry/OrientedBox.h>
  8. namespace JPH {
  9. DebugRenderer *DebugRenderer::sInstance = nullptr;
  10. // Number of LOD levels to create
  11. static const int sMaxLevel = 4;
  12. // Distance for each LOD level, these are tweaked for an object of approx. size 1. Use the lod scale to scale these distances.
  13. static const float sLODDistanceForLevel[] = { 5.0f, 10.0f, 40.0f, FLT_MAX };
  14. DebugRenderer::Triangle::Triangle(Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, ColorArg inColor)
  15. {
  16. // Set position
  17. inV1.StoreFloat3(&mV[0].mPosition);
  18. inV2.StoreFloat3(&mV[1].mPosition);
  19. inV3.StoreFloat3(&mV[2].mPosition);
  20. // Set color
  21. mV[0].mColor = mV[1].mColor = mV[2].mColor = inColor;
  22. // Calculate normal
  23. Vec3 normal = (inV2 - inV1).Cross(inV3 - inV1);
  24. float normal_len = normal.Length();
  25. if (normal_len > 0.0f)
  26. normal /= normal_len;
  27. Float3 normal3;
  28. normal.StoreFloat3(&normal3);
  29. mV[0].mNormal = mV[1].mNormal = mV[2].mNormal = normal3;
  30. // Reset UV's
  31. mV[0].mUV = mV[1].mUV = mV[2].mUV = { 0, 0 };
  32. }
  33. DebugRenderer::Triangle::Triangle(Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, ColorArg inColor, Vec3Arg inUVOrigin, Vec3Arg inUVDirection)
  34. {
  35. // Set position
  36. inV1.StoreFloat3(&mV[0].mPosition);
  37. inV2.StoreFloat3(&mV[1].mPosition);
  38. inV3.StoreFloat3(&mV[2].mPosition);
  39. // Set color
  40. mV[0].mColor = mV[1].mColor = mV[2].mColor = inColor;
  41. // Calculate normal
  42. Vec3 normal = (inV2 - inV1).Cross(inV3 - inV1).Normalized();
  43. Float3 normal3;
  44. normal.StoreFloat3(&normal3);
  45. mV[0].mNormal = mV[1].mNormal = mV[2].mNormal = normal3;
  46. // Set UV's
  47. Vec3 uv1 = inV1 - inUVOrigin;
  48. Vec3 uv2 = inV2 - inUVOrigin;
  49. Vec3 uv3 = inV3 - inUVOrigin;
  50. Vec3 axis2 = normal.Cross(inUVDirection);
  51. mV[0].mUV = { inUVDirection.Dot(uv1), axis2.Dot(uv1) };
  52. mV[1].mUV = { inUVDirection.Dot(uv2), axis2.Dot(uv2) };
  53. mV[2].mUV = { inUVDirection.Dot(uv3), axis2.Dot(uv3) };
  54. }
  55. DebugRenderer::DebugRenderer()
  56. {
  57. // Store singleton
  58. JPH_ASSERT(sInstance == nullptr);
  59. sInstance = this;
  60. }
  61. DebugRenderer::~DebugRenderer()
  62. {
  63. JPH_ASSERT(sInstance == this);
  64. sInstance = nullptr;
  65. }
  66. void DebugRenderer::DrawWireBox(const AABox &inBox, ColorArg inColor)
  67. {
  68. JPH_PROFILE_FUNCTION();
  69. // 8 vertices
  70. Float3 v1(inBox.mMin.GetX(), inBox.mMin.GetY(), inBox.mMin.GetZ());
  71. Float3 v2(inBox.mMin.GetX(), inBox.mMin.GetY(), inBox.mMax.GetZ());
  72. Float3 v3(inBox.mMin.GetX(), inBox.mMax.GetY(), inBox.mMin.GetZ());
  73. Float3 v4(inBox.mMin.GetX(), inBox.mMax.GetY(), inBox.mMax.GetZ());
  74. Float3 v5(inBox.mMax.GetX(), inBox.mMin.GetY(), inBox.mMin.GetZ());
  75. Float3 v6(inBox.mMax.GetX(), inBox.mMin.GetY(), inBox.mMax.GetZ());
  76. Float3 v7(inBox.mMax.GetX(), inBox.mMax.GetY(), inBox.mMin.GetZ());
  77. Float3 v8(inBox.mMax.GetX(), inBox.mMax.GetY(), inBox.mMax.GetZ());
  78. // 12 edges
  79. DrawLine(v1, v2, inColor);
  80. DrawLine(v1, v3, inColor);
  81. DrawLine(v1, v5, inColor);
  82. DrawLine(v2, v4, inColor);
  83. DrawLine(v2, v6, inColor);
  84. DrawLine(v3, v4, inColor);
  85. DrawLine(v3, v7, inColor);
  86. DrawLine(v4, v8, inColor);
  87. DrawLine(v5, v6, inColor);
  88. DrawLine(v5, v7, inColor);
  89. DrawLine(v6, v8, inColor);
  90. DrawLine(v7, v8, inColor);
  91. }
  92. void DebugRenderer::DrawWireBox(const OrientedBox &inBox, ColorArg inColor)
  93. {
  94. JPH_PROFILE_FUNCTION();
  95. // 8 vertices
  96. Vec3 v1 = inBox.mOrientation * Vec3(-inBox.mHalfExtents.GetX(), -inBox.mHalfExtents.GetY(), -inBox.mHalfExtents.GetZ());
  97. Vec3 v2 = inBox.mOrientation * Vec3(-inBox.mHalfExtents.GetX(), -inBox.mHalfExtents.GetY(), inBox.mHalfExtents.GetZ());
  98. Vec3 v3 = inBox.mOrientation * Vec3(-inBox.mHalfExtents.GetX(), inBox.mHalfExtents.GetY(), -inBox.mHalfExtents.GetZ());
  99. Vec3 v4 = inBox.mOrientation * Vec3(-inBox.mHalfExtents.GetX(), inBox.mHalfExtents.GetY(), inBox.mHalfExtents.GetZ());
  100. Vec3 v5 = inBox.mOrientation * Vec3(inBox.mHalfExtents.GetX(), -inBox.mHalfExtents.GetY(), -inBox.mHalfExtents.GetZ());
  101. Vec3 v6 = inBox.mOrientation * Vec3(inBox.mHalfExtents.GetX(), -inBox.mHalfExtents.GetY(), inBox.mHalfExtents.GetZ());
  102. Vec3 v7 = inBox.mOrientation * Vec3(inBox.mHalfExtents.GetX(), inBox.mHalfExtents.GetY(), -inBox.mHalfExtents.GetZ());
  103. Vec3 v8 = inBox.mOrientation * Vec3(inBox.mHalfExtents.GetX(), inBox.mHalfExtents.GetY(), inBox.mHalfExtents.GetZ());
  104. // 12 edges
  105. DrawLine(v1, v2, inColor);
  106. DrawLine(v1, v3, inColor);
  107. DrawLine(v1, v5, inColor);
  108. DrawLine(v2, v4, inColor);
  109. DrawLine(v2, v6, inColor);
  110. DrawLine(v3, v4, inColor);
  111. DrawLine(v3, v7, inColor);
  112. DrawLine(v4, v8, inColor);
  113. DrawLine(v5, v6, inColor);
  114. DrawLine(v5, v7, inColor);
  115. DrawLine(v6, v8, inColor);
  116. DrawLine(v7, v8, inColor);
  117. }
  118. void DebugRenderer::DrawWireBox(Mat44Arg inMatrix, const AABox &inBox, ColorArg inColor)
  119. {
  120. JPH_PROFILE_FUNCTION();
  121. // 8 vertices
  122. Vec3 v1 = inMatrix * Vec3(inBox.mMin.GetX(), inBox.mMin.GetY(), inBox.mMin.GetZ());
  123. Vec3 v2 = inMatrix * Vec3(inBox.mMin.GetX(), inBox.mMin.GetY(), inBox.mMax.GetZ());
  124. Vec3 v3 = inMatrix * Vec3(inBox.mMin.GetX(), inBox.mMax.GetY(), inBox.mMin.GetZ());
  125. Vec3 v4 = inMatrix * Vec3(inBox.mMin.GetX(), inBox.mMax.GetY(), inBox.mMax.GetZ());
  126. Vec3 v5 = inMatrix * Vec3(inBox.mMax.GetX(), inBox.mMin.GetY(), inBox.mMin.GetZ());
  127. Vec3 v6 = inMatrix * Vec3(inBox.mMax.GetX(), inBox.mMin.GetY(), inBox.mMax.GetZ());
  128. Vec3 v7 = inMatrix * Vec3(inBox.mMax.GetX(), inBox.mMax.GetY(), inBox.mMin.GetZ());
  129. Vec3 v8 = inMatrix * Vec3(inBox.mMax.GetX(), inBox.mMax.GetY(), inBox.mMax.GetZ());
  130. // 12 edges
  131. DrawLine(v1, v2, inColor);
  132. DrawLine(v1, v3, inColor);
  133. DrawLine(v1, v5, inColor);
  134. DrawLine(v2, v4, inColor);
  135. DrawLine(v2, v6, inColor);
  136. DrawLine(v3, v4, inColor);
  137. DrawLine(v3, v7, inColor);
  138. DrawLine(v4, v8, inColor);
  139. DrawLine(v5, v6, inColor);
  140. DrawLine(v5, v7, inColor);
  141. DrawLine(v6, v8, inColor);
  142. DrawLine(v7, v8, inColor);
  143. }
  144. void DebugRenderer::DrawMarker(Vec3Arg inPosition, ColorArg inColor, float inSize)
  145. {
  146. JPH_PROFILE_FUNCTION();
  147. Vec3 dx(inSize, 0, 0);
  148. Vec3 dy(0, inSize, 0);
  149. Vec3 dz(0, 0, inSize);
  150. DrawLine(inPosition - dy, inPosition + dy, inColor);
  151. DrawLine(inPosition - dx, inPosition + dx, inColor);
  152. DrawLine(inPosition - dz, inPosition + dz, inColor);
  153. }
  154. void DebugRenderer::DrawArrow(Vec3Arg inFrom, Vec3Arg inTo, ColorArg inColor, float inSize)
  155. {
  156. JPH_PROFILE_FUNCTION();
  157. // Draw base line
  158. DrawLine(inFrom, inTo, inColor);
  159. if (inSize > 0.0f)
  160. {
  161. // Draw arrow head
  162. Vec3 dir = inTo - inFrom;
  163. float len = dir.Length();
  164. if (len != 0.0f)
  165. dir = dir * (inSize / len);
  166. else
  167. dir = Vec3(inSize, 0, 0);
  168. Vec3 perp = inSize * dir.GetNormalizedPerpendicular();
  169. DrawLine(inTo - dir + perp, inTo, inColor);
  170. DrawLine(inTo - dir - perp, inTo, inColor);
  171. }
  172. }
  173. void DebugRenderer::DrawCoordinateSystem(Mat44Arg inTransform, float inSize)
  174. {
  175. JPH_PROFILE_FUNCTION();
  176. DrawArrow(inTransform.GetTranslation(), inTransform * Vec3(inSize, 0, 0), Color::sRed, 0.1f * inSize);
  177. DrawArrow(inTransform.GetTranslation(), inTransform * Vec3(0, inSize, 0), Color::sGreen, 0.1f * inSize);
  178. DrawArrow(inTransform.GetTranslation(), inTransform * Vec3(0, 0, inSize), Color::sBlue, 0.1f * inSize);
  179. }
  180. void DebugRenderer::DrawWireTriangle(Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, ColorArg inColor)
  181. {
  182. JPH_PROFILE_FUNCTION();
  183. DrawLine(inV1, inV2, inColor);
  184. DrawLine(inV2, inV3, inColor);
  185. DrawLine(inV3, inV1, inColor);
  186. }
  187. void DebugRenderer::DrawWireSphere(Vec3Arg inCenter, float inRadius, ColorArg inColor, int inLevel)
  188. {
  189. Mat44 matrix = Mat44::sTranslation(inCenter) * Mat44::sScale(inRadius);
  190. DrawWireUnitSphere(matrix, inColor, inLevel);
  191. }
  192. void DebugRenderer::DrawWireUnitSphere(Mat44Arg inMatrix, ColorArg inColor, int inLevel)
  193. {
  194. JPH_PROFILE_FUNCTION();
  195. DrawWireUnitSphereRecursive(inMatrix, inColor, Vec3::sAxisX(), Vec3::sAxisY(), Vec3::sAxisZ(), inLevel);
  196. DrawWireUnitSphereRecursive(inMatrix, inColor, -Vec3::sAxisX(), Vec3::sAxisY(), Vec3::sAxisZ(), inLevel);
  197. DrawWireUnitSphereRecursive(inMatrix, inColor, Vec3::sAxisX(), -Vec3::sAxisY(), Vec3::sAxisZ(), inLevel);
  198. DrawWireUnitSphereRecursive(inMatrix, inColor, -Vec3::sAxisX(), -Vec3::sAxisY(), Vec3::sAxisZ(), inLevel);
  199. DrawWireUnitSphereRecursive(inMatrix, inColor, Vec3::sAxisX(), Vec3::sAxisY(), -Vec3::sAxisZ(), inLevel);
  200. DrawWireUnitSphereRecursive(inMatrix, inColor, -Vec3::sAxisX(), Vec3::sAxisY(), -Vec3::sAxisZ(), inLevel);
  201. DrawWireUnitSphereRecursive(inMatrix, inColor, Vec3::sAxisX(), -Vec3::sAxisY(), -Vec3::sAxisZ(), inLevel);
  202. DrawWireUnitSphereRecursive(inMatrix, inColor, -Vec3::sAxisX(), -Vec3::sAxisY(), -Vec3::sAxisZ(), inLevel);
  203. }
  204. void DebugRenderer::DrawWireUnitSphereRecursive(Mat44Arg inMatrix, ColorArg inColor, Vec3Arg inDir1, Vec3Arg inDir2, Vec3Arg inDir3, int inLevel)
  205. {
  206. if (inLevel == 0)
  207. {
  208. Vec3 d1 = inMatrix * inDir1;
  209. Vec3 d2 = inMatrix * inDir2;
  210. Vec3 d3 = inMatrix * inDir3;
  211. DrawLine(d1, d2, inColor);
  212. DrawLine(d2, d3, inColor);
  213. DrawLine(d3, d1, inColor);
  214. }
  215. else
  216. {
  217. Vec3 center1 = (inDir1 + inDir2).Normalized();
  218. Vec3 center2 = (inDir2 + inDir3).Normalized();
  219. Vec3 center3 = (inDir3 + inDir1).Normalized();
  220. DrawWireUnitSphereRecursive(inMatrix, inColor, inDir1, center1, center3, inLevel - 1);
  221. DrawWireUnitSphereRecursive(inMatrix, inColor, center1, center2, center3, inLevel - 1);
  222. DrawWireUnitSphereRecursive(inMatrix, inColor, center1, inDir2, center2, inLevel - 1);
  223. DrawWireUnitSphereRecursive(inMatrix, inColor, center3, center2, inDir3, inLevel - 1);
  224. }
  225. }
  226. void DebugRenderer::Create8thSphereRecursive(vector<uint32> &ioIndices, vector<Vertex> &ioVertices, Vec3Arg inDir1, uint32 &ioIdx1, Vec3Arg inDir2, uint32 &ioIdx2, Vec3Arg inDir3, uint32 &ioIdx3, const Float2 &inUV, SupportFunction inGetSupport, int inLevel)
  227. {
  228. if (inLevel == 0)
  229. {
  230. if (ioIdx1 == 0xffffffff)
  231. {
  232. ioIdx1 = (uint32)ioVertices.size();
  233. Float3 position, normal;
  234. inGetSupport(inDir1).StoreFloat3(&position);
  235. inDir1.StoreFloat3(&normal);
  236. ioVertices.push_back({ position, normal, inUV, Color::sWhite });
  237. }
  238. if (ioIdx2 == 0xffffffff)
  239. {
  240. ioIdx2 = (uint32)ioVertices.size();
  241. Float3 position, normal;
  242. inGetSupport(inDir2).StoreFloat3(&position);
  243. inDir2.StoreFloat3(&normal);
  244. ioVertices.push_back({ position, normal, inUV, Color::sWhite });
  245. }
  246. if (ioIdx3 == 0xffffffff)
  247. {
  248. ioIdx3 = (uint32)ioVertices.size();
  249. Float3 position, normal;
  250. inGetSupport(inDir3).StoreFloat3(&position);
  251. inDir3.StoreFloat3(&normal);
  252. ioVertices.push_back({ position, normal, inUV, Color::sWhite });
  253. }
  254. ioIndices.push_back(ioIdx1);
  255. ioIndices.push_back(ioIdx2);
  256. ioIndices.push_back(ioIdx3);
  257. }
  258. else
  259. {
  260. Vec3 center1 = (inDir1 + inDir2).Normalized();
  261. Vec3 center2 = (inDir2 + inDir3).Normalized();
  262. Vec3 center3 = (inDir3 + inDir1).Normalized();
  263. uint32 idx1 = 0xffffffff;
  264. uint32 idx2 = 0xffffffff;
  265. uint32 idx3 = 0xffffffff;
  266. Create8thSphereRecursive(ioIndices, ioVertices, inDir1, ioIdx1, center1, idx1, center3, idx3, inUV, inGetSupport, inLevel - 1);
  267. Create8thSphereRecursive(ioIndices, ioVertices, center1, idx1, center2, idx2, center3, idx3, inUV, inGetSupport, inLevel - 1);
  268. Create8thSphereRecursive(ioIndices, ioVertices, center1, idx1, inDir2, ioIdx2, center2, idx2, inUV, inGetSupport, inLevel - 1);
  269. Create8thSphereRecursive(ioIndices, ioVertices, center3, idx3, center2, idx2, inDir3, ioIdx3, inUV, inGetSupport, inLevel - 1);
  270. }
  271. }
  272. void DebugRenderer::Create8thSphere(vector<uint32> &ioIndices, vector<Vertex> &ioVertices, Vec3Arg inDir1, Vec3Arg inDir2, Vec3Arg inDir3, const Float2 &inUV, SupportFunction inGetSupport, int inLevel)
  273. {
  274. uint32 idx1 = 0xffffffff;
  275. uint32 idx2 = 0xffffffff;
  276. uint32 idx3 = 0xffffffff;
  277. Create8thSphereRecursive(ioIndices, ioVertices, inDir1, idx1, inDir2, idx2, inDir3, idx3, inUV, inGetSupport, inLevel);
  278. }
  279. void DebugRenderer::CreateQuad(vector<uint32> &ioIndices, vector<Vertex> &ioVertices, Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, Vec3Arg inV4)
  280. {
  281. // Make room
  282. uint32 start_idx = uint32(ioVertices.size());
  283. ioVertices.resize(start_idx + 4);
  284. Vertex *vertices = &ioVertices[start_idx];
  285. // Set position
  286. inV1.StoreFloat3(&vertices[0].mPosition);
  287. inV2.StoreFloat3(&vertices[1].mPosition);
  288. inV3.StoreFloat3(&vertices[2].mPosition);
  289. inV4.StoreFloat3(&vertices[3].mPosition);
  290. // Set color
  291. vertices[0].mColor = vertices[1].mColor = vertices[2].mColor = vertices[3].mColor = Color::sWhite;
  292. // Calculate normal
  293. Vec3 normal = (inV2 - inV1).Cross(inV3 - inV1).Normalized();
  294. Float3 normal3;
  295. normal.StoreFloat3(&normal3);
  296. vertices[0].mNormal = vertices[1].mNormal = vertices[2].mNormal = vertices[3].mNormal = normal3;
  297. // Set UV's
  298. vertices[0].mUV = { 0, 0 };
  299. vertices[1].mUV = { 2, 0 };
  300. vertices[2].mUV = { 2, 2 };
  301. vertices[3].mUV = { 0, 2 };
  302. // Set indices
  303. ioIndices.push_back(start_idx);
  304. ioIndices.push_back(start_idx + 1);
  305. ioIndices.push_back(start_idx + 2);
  306. ioIndices.push_back(start_idx);
  307. ioIndices.push_back(start_idx + 2);
  308. ioIndices.push_back(start_idx + 3);
  309. }
  310. void DebugRenderer::Initialize()
  311. {
  312. // Box
  313. {
  314. vector<Vertex> box_vertices;
  315. vector<uint32> box_indices;
  316. // Get corner points
  317. Vec3 v0 = Vec3(-1, 1, -1);
  318. Vec3 v1 = Vec3( 1, 1, -1);
  319. Vec3 v2 = Vec3( 1, 1, 1);
  320. Vec3 v3 = Vec3(-1, 1, 1);
  321. Vec3 v4 = Vec3(-1, -1, -1);
  322. Vec3 v5 = Vec3( 1, -1, -1);
  323. Vec3 v6 = Vec3( 1, -1, 1);
  324. Vec3 v7 = Vec3(-1, -1, 1);
  325. // Top
  326. CreateQuad(box_indices, box_vertices, v0, v3, v2, v1);
  327. // Bottom
  328. CreateQuad(box_indices, box_vertices, v4, v5, v6, v7);
  329. // Left
  330. CreateQuad(box_indices, box_vertices, v0, v4, v7, v3);
  331. // Right
  332. CreateQuad(box_indices, box_vertices, v2, v6, v5, v1);
  333. // Front
  334. CreateQuad(box_indices, box_vertices, v3, v7, v6, v2);
  335. // Back
  336. CreateQuad(box_indices, box_vertices, v0, v1, v5, v4);
  337. mBox = new Geometry(CreateTriangleBatch(box_vertices, box_indices), AABox(Vec3(-1, -1, -1), Vec3(1, 1, 1)));
  338. }
  339. // Support function that returns a unit sphere
  340. auto sphere_support = [](Vec3Arg inDirection) { return inDirection; };
  341. // Construct geometries
  342. mSphere = new Geometry(AABox(Vec3(-1, -1, -1), Vec3(1, 1, 1)));
  343. mCapsuleBottom = new Geometry(AABox(Vec3(-1, -1, -1), Vec3(1, 0, 1)));
  344. mCapsuleTop = new Geometry(AABox(Vec3(-1, 0, -1), Vec3(1, 1, 1)));
  345. mCapsuleMid = new Geometry(AABox(Vec3(-1, -1, -1), Vec3(1, 1, 1)));
  346. mOpenCone = new Geometry(AABox(Vec3(-1, 0, -1), Vec3(1, 1, 1)));
  347. mCylinder = new Geometry(AABox(Vec3(-1, -1, -1), Vec3(1, 1, 1)));
  348. // Iterate over levels
  349. for (int level = sMaxLevel; level >= 1; --level)
  350. {
  351. // Determine at which distance this level should be active
  352. float distance = sLODDistanceForLevel[sMaxLevel - level];
  353. // Sphere
  354. mSphere->mLODs.push_back({ CreateTriangleBatchForConvex(sphere_support, level), distance });
  355. // Capsule bottom half sphere
  356. {
  357. vector<Vertex> capsule_bottom_vertices;
  358. vector<uint32> capsule_bottom_indices;
  359. Create8thSphere(capsule_bottom_indices, capsule_bottom_vertices, -Vec3::sAxisX(), -Vec3::sAxisY(), Vec3::sAxisZ(), Float2(0.25f, 0.25f), sphere_support, level);
  360. Create8thSphere(capsule_bottom_indices, capsule_bottom_vertices, -Vec3::sAxisY(), Vec3::sAxisX(), Vec3::sAxisZ(), Float2(0.25f, 0.75f), sphere_support, level);
  361. Create8thSphere(capsule_bottom_indices, capsule_bottom_vertices, Vec3::sAxisX(), -Vec3::sAxisY(), -Vec3::sAxisZ(), Float2(0.25f, 0.25f), sphere_support, level);
  362. Create8thSphere(capsule_bottom_indices, capsule_bottom_vertices, -Vec3::sAxisY(), -Vec3::sAxisX(), -Vec3::sAxisZ(), Float2(0.25f, 0.75f), sphere_support, level);
  363. mCapsuleBottom->mLODs.push_back({ CreateTriangleBatch(capsule_bottom_vertices, capsule_bottom_indices), distance });
  364. }
  365. // Capsule top half sphere
  366. {
  367. vector<Vertex> capsule_top_vertices;
  368. vector<uint32> capsule_top_indices;
  369. Create8thSphere(capsule_top_indices, capsule_top_vertices, Vec3::sAxisX(), Vec3::sAxisY(), Vec3::sAxisZ(), Float2(0.25f, 0.75f), sphere_support, level);
  370. Create8thSphere(capsule_top_indices, capsule_top_vertices, Vec3::sAxisY(), -Vec3::sAxisX(), Vec3::sAxisZ(), Float2(0.25f, 0.25f), sphere_support, level);
  371. Create8thSphere(capsule_top_indices, capsule_top_vertices, Vec3::sAxisY(), Vec3::sAxisX(), -Vec3::sAxisZ(), Float2(0.25f, 0.25f), sphere_support, level);
  372. Create8thSphere(capsule_top_indices, capsule_top_vertices, -Vec3::sAxisX(), Vec3::sAxisY(), -Vec3::sAxisZ(), Float2(0.25f, 0.75f), sphere_support, level);
  373. mCapsuleTop->mLODs.push_back({ CreateTriangleBatch(capsule_top_vertices, capsule_top_indices), distance });
  374. }
  375. // Capsule middle part
  376. {
  377. vector<Vertex> capsule_mid_vertices;
  378. vector<uint32> capsule_mid_indices;
  379. for (int q = 0; q < 4; ++q)
  380. {
  381. Float2 uv = (q & 1) == 0? Float2(0.25f, 0.25f) : Float2(0.25f, 0.75f);
  382. uint32 start_idx = (uint32)capsule_mid_vertices.size();
  383. int num_parts = 1 << level;
  384. for (int i = 0; i <= num_parts; ++i)
  385. {
  386. float angle = 0.5f * JPH_PI * (float(q) + float(i) / num_parts);
  387. float s = sin(angle);
  388. float c = cos(angle);
  389. Float3 vt(s, 1.0f, c);
  390. Float3 vb(s, -1.0f, c);
  391. Float3 n(s, 0, c);
  392. capsule_mid_vertices.push_back({ vt, n, uv, Color::sWhite });
  393. capsule_mid_vertices.push_back({ vb, n, uv, Color::sWhite });
  394. }
  395. for (int i = 0; i < num_parts; ++i)
  396. {
  397. uint32 start = start_idx + 2 * i;
  398. capsule_mid_indices.push_back(start);
  399. capsule_mid_indices.push_back(start + 1);
  400. capsule_mid_indices.push_back(start + 3);
  401. capsule_mid_indices.push_back(start);
  402. capsule_mid_indices.push_back(start + 3);
  403. capsule_mid_indices.push_back(start + 2);
  404. }
  405. }
  406. mCapsuleMid->mLODs.push_back({ CreateTriangleBatch(capsule_mid_vertices, capsule_mid_indices), distance });
  407. }
  408. // Open cone
  409. {
  410. vector<Vertex> open_cone_vertices;
  411. vector<uint32> open_cone_indices;
  412. for (int q = 0; q < 4; ++q)
  413. {
  414. Float2 uv = (q & 1) == 0? Float2(0.25f, 0.25f) : Float2(0.25f, 0.75f);
  415. uint32 start_idx = (uint32)open_cone_vertices.size();
  416. int num_parts = 2 << level;
  417. Float3 vt(0, 0, 0);
  418. for (int i = 0; i <= num_parts; ++i)
  419. {
  420. // Calculate bottom vertex
  421. float angle = 0.5f * JPH_PI * (float(q) + float(i) / num_parts);
  422. float s = sin(angle);
  423. float c = cos(angle);
  424. Float3 vb(s, 1.0f, c);
  425. // Calculate normal
  426. // perpendicular = Y cross vb (perpendicular to the plane in which 0, y and vb exists)
  427. // normal = perpendicular cross vb (normal to the edge 0 vb)
  428. Vec3 normal = Vec3(s, -Square(s) - Square(c), c).Normalized();
  429. Float3 n; normal.StoreFloat3(&n);
  430. open_cone_vertices.push_back({ vt, n, uv, Color::sWhite });
  431. open_cone_vertices.push_back({ vb, n, uv, Color::sWhite });
  432. }
  433. for (int i = 0; i < num_parts; ++i)
  434. {
  435. uint32 start = start_idx + 2 * i;
  436. open_cone_indices.push_back(start);
  437. open_cone_indices.push_back(start + 1);
  438. open_cone_indices.push_back(start + 3);
  439. }
  440. }
  441. mOpenCone->mLODs.push_back({ CreateTriangleBatch(open_cone_vertices, open_cone_indices), distance });
  442. }
  443. // Cylinder
  444. {
  445. vector<Vertex> cylinder_vertices;
  446. vector<uint32> cylinder_indices;
  447. for (int q = 0; q < 4; ++q)
  448. {
  449. Float2 uv = (q & 1) == 0? Float2(0.25f, 0.75f) : Float2(0.25f, 0.25f);
  450. uint32 center_start_idx = (uint32)cylinder_vertices.size();
  451. Float3 nt(0.0f, 1.0f, 0.0f);
  452. Float3 nb(0.0f, -1.0f, 0.0f);
  453. cylinder_vertices.push_back({ Float3(0.0f, 1.0f, 0.0f), nt, uv, Color::sWhite });
  454. cylinder_vertices.push_back({ Float3(0.0f, -1.0f, 0.0f), nb, uv, Color::sWhite });
  455. uint32 vtx_start_idx = (uint32)cylinder_vertices.size();
  456. int num_parts = 1 << level;
  457. for (int i = 0; i <= num_parts; ++i)
  458. {
  459. float angle = 0.5f * JPH_PI * (float(q) + float(i) / num_parts);
  460. float s = sin(angle);
  461. float c = cos(angle);
  462. Float3 vt(s, 1.0f, c);
  463. Float3 vb(s, -1.0f, c);
  464. Float3 n(s, 0, c);
  465. cylinder_vertices.push_back({ vt, nt, uv, Color::sWhite });
  466. cylinder_vertices.push_back({ vb, nb, uv, Color::sWhite });
  467. cylinder_vertices.push_back({ vt, n, uv, Color::sWhite });
  468. cylinder_vertices.push_back({ vb, n, uv, Color::sWhite });
  469. }
  470. for (int i = 0; i < num_parts; ++i)
  471. {
  472. uint32 start = vtx_start_idx + 4 * i;
  473. // Top
  474. cylinder_indices.push_back(center_start_idx);
  475. cylinder_indices.push_back(start);
  476. cylinder_indices.push_back(start + 4);
  477. // Bottom
  478. cylinder_indices.push_back(center_start_idx + 1);
  479. cylinder_indices.push_back(start + 5);
  480. cylinder_indices.push_back(start + 1);
  481. // Side
  482. cylinder_indices.push_back(start + 2);
  483. cylinder_indices.push_back(start + 3);
  484. cylinder_indices.push_back(start + 7);
  485. cylinder_indices.push_back(start + 2);
  486. cylinder_indices.push_back(start + 7);
  487. cylinder_indices.push_back(start + 6);
  488. }
  489. }
  490. mCylinder->mLODs.push_back({ CreateTriangleBatch(cylinder_vertices, cylinder_indices), distance });
  491. }
  492. }
  493. }
  494. AABox DebugRenderer::sCalculateBounds(const Vertex *inVertices, int inVertexCount)
  495. {
  496. AABox bounds;
  497. for (const Vertex *v = inVertices, *v_end = inVertices + inVertexCount; v < v_end; ++v)
  498. bounds.Encapsulate(Vec3(v->mPosition));
  499. return bounds;
  500. }
  501. DebugRenderer::Batch DebugRenderer::CreateTriangleBatch(const VertexList &inVertices, const IndexedTriangleNoMaterialList &inTriangles)
  502. {
  503. JPH_PROFILE_FUNCTION();
  504. vector<Vertex> vertices;
  505. // Create render vertices
  506. vertices.resize(inVertices.size());
  507. for (size_t v = 0; v < inVertices.size(); ++v)
  508. {
  509. vertices[v].mPosition = inVertices[v];
  510. vertices[v].mNormal = Float3(0, 0, 0);
  511. vertices[v].mUV = Float2(0, 0);
  512. vertices[v].mColor = Color::sWhite;
  513. }
  514. // Calculate normals
  515. for (size_t i = 0; i < inTriangles.size(); ++i)
  516. {
  517. const IndexedTriangleNoMaterial &tri = inTriangles[i];
  518. // Calculate normal of face
  519. Vec3 vtx[3];
  520. for (int j = 0; j < 3; ++j)
  521. vtx[j] = Vec3::sLoadFloat3Unsafe(vertices[tri.mIdx[j]].mPosition);
  522. Vec3 normal = ((vtx[1] - vtx[0]).Cross(vtx[2] - vtx[0])).Normalized();
  523. // Add normal to all vertices in face
  524. for (int j = 0; j < 3; ++j)
  525. (Vec3::sLoadFloat3Unsafe(vertices[tri.mIdx[j]].mNormal) + normal).StoreFloat3(&vertices[tri.mIdx[j]].mNormal);
  526. }
  527. // Renormalize vertex normals
  528. for (size_t i = 0; i < vertices.size(); ++i)
  529. Vec3::sLoadFloat3Unsafe(vertices[i].mNormal).Normalized().StoreFloat3(&vertices[i].mNormal);
  530. return CreateTriangleBatch(&vertices[0], (int)vertices.size(), &inTriangles[0].mIdx[0], (int)(3 * inTriangles.size()));
  531. }
  532. DebugRenderer::Batch DebugRenderer::CreateTriangleBatchForConvex(SupportFunction inGetSupport, int inLevel, AABox *outBounds)
  533. {
  534. JPH_PROFILE_FUNCTION();
  535. vector<Vertex> vertices;
  536. vector<uint32> indices;
  537. Create8thSphere(indices, vertices, Vec3::sAxisX(), Vec3::sAxisY(), Vec3::sAxisZ(), Float2(0.25f, 0.25f), inGetSupport, inLevel);
  538. Create8thSphere(indices, vertices, Vec3::sAxisY(), -Vec3::sAxisX(), Vec3::sAxisZ(), Float2(0.25f, 0.75f), inGetSupport, inLevel);
  539. Create8thSphere(indices, vertices, -Vec3::sAxisY(), Vec3::sAxisX(), Vec3::sAxisZ(), Float2(0.25f, 0.75f), inGetSupport, inLevel);
  540. Create8thSphere(indices, vertices, -Vec3::sAxisX(), -Vec3::sAxisY(), Vec3::sAxisZ(), Float2(0.25f, 0.25f), inGetSupport, inLevel);
  541. Create8thSphere(indices, vertices, Vec3::sAxisY(), Vec3::sAxisX(), -Vec3::sAxisZ(), Float2(0.25f, 0.75f), inGetSupport, inLevel);
  542. Create8thSphere(indices, vertices, -Vec3::sAxisX(), Vec3::sAxisY(), -Vec3::sAxisZ(), Float2(0.25f, 0.25f), inGetSupport, inLevel);
  543. Create8thSphere(indices, vertices, Vec3::sAxisX(), -Vec3::sAxisY(), -Vec3::sAxisZ(), Float2(0.25f, 0.25f), inGetSupport, inLevel);
  544. Create8thSphere(indices, vertices, -Vec3::sAxisY(), -Vec3::sAxisX(), -Vec3::sAxisZ(), Float2(0.25f, 0.75f), inGetSupport, inLevel);
  545. if (outBounds != nullptr)
  546. *outBounds = sCalculateBounds(&vertices[0], (int)vertices.size());
  547. return CreateTriangleBatch(vertices, indices);
  548. }
  549. DebugRenderer::GeometryRef DebugRenderer::CreateTriangleGeometryForConvex(SupportFunction inGetSupport)
  550. {
  551. GeometryRef geometry;
  552. // Iterate over levels
  553. for (int level = sMaxLevel; level >= 1; --level)
  554. {
  555. // Determine at which distance this level should be active
  556. float distance = sLODDistanceForLevel[sMaxLevel - level];
  557. // Create triangle batch and only calculate bounds for highest LOD level
  558. AABox bounds;
  559. Batch batch = CreateTriangleBatchForConvex(inGetSupport, level, geometry == nullptr? &bounds : nullptr);
  560. // Construct geometry in the first iteration
  561. if (geometry == nullptr)
  562. geometry = new Geometry(bounds);
  563. // Add the LOD
  564. geometry->mLODs.push_back({ batch, distance });
  565. }
  566. return geometry;
  567. }
  568. void DebugRenderer::DrawBox(const AABox &inBox, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)
  569. {
  570. JPH_PROFILE_FUNCTION();
  571. Mat44 m = Mat44::sScale(inBox.GetExtent());
  572. m.SetTranslation(inBox.GetCenter());
  573. DrawGeometry(m, inColor, mBox, ECullMode::CullBackFace, inCastShadow, inDrawMode);
  574. }
  575. void DebugRenderer::DrawBox(Mat44Arg inMatrix, const AABox &inBox, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)
  576. {
  577. JPH_PROFILE_FUNCTION();
  578. Mat44 m = Mat44::sScale(inBox.GetExtent());
  579. m.SetTranslation(inBox.GetCenter());
  580. DrawGeometry(inMatrix * m, inColor, mBox, ECullMode::CullBackFace, inCastShadow, inDrawMode);
  581. }
  582. void DebugRenderer::DrawSphere(Vec3Arg inCenter, float inRadius, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)
  583. {
  584. JPH_PROFILE_FUNCTION();
  585. Mat44 matrix = Mat44::sTranslation(inCenter) * Mat44::sScale(inRadius);
  586. DrawUnitSphere(matrix, inColor, inCastShadow, inDrawMode);
  587. }
  588. void DebugRenderer::DrawUnitSphere(Mat44Arg inMatrix, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)
  589. {
  590. JPH_PROFILE_FUNCTION();
  591. DrawGeometry(inMatrix, inColor, mSphere, ECullMode::CullBackFace, inCastShadow, inDrawMode);
  592. }
  593. void DebugRenderer::DrawCapsule(Mat44Arg inMatrix, float inHalfHeightOfCylinder, float inRadius, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)
  594. {
  595. JPH_PROFILE_FUNCTION();
  596. Mat44 scale_matrix = Mat44::sScale(inRadius);
  597. // Calculate world space bounding box
  598. AABox local_bounds(Vec3(-inRadius, -inHalfHeightOfCylinder - inRadius, -inRadius), Vec3(inRadius, inHalfHeightOfCylinder + inRadius, inRadius));
  599. AABox world_bounds = local_bounds.Transformed(inMatrix);
  600. float radius_sq = Square(inRadius);
  601. // Draw bottom half sphere
  602. Mat44 bottom_matrix = inMatrix * Mat44::sTranslation(Vec3(0, -inHalfHeightOfCylinder, 0)) * scale_matrix;
  603. DrawGeometry(bottom_matrix, world_bounds, radius_sq, inColor, mCapsuleBottom, ECullMode::CullBackFace, inCastShadow, inDrawMode);
  604. // Draw top half sphere
  605. Mat44 top_matrix = inMatrix * Mat44::sTranslation(Vec3(0, inHalfHeightOfCylinder, 0)) * scale_matrix;
  606. DrawGeometry(top_matrix, world_bounds, radius_sq, inColor, mCapsuleTop, ECullMode::CullBackFace, inCastShadow, inDrawMode);
  607. // Draw middle part
  608. DrawGeometry(inMatrix * Mat44::sScale(Vec3(inRadius, inHalfHeightOfCylinder, inRadius)), world_bounds, radius_sq, inColor, mCapsuleMid, ECullMode::CullBackFace, inCastShadow, inDrawMode);
  609. }
  610. void DebugRenderer::DrawCylinder(Mat44Arg inMatrix, float inHalfHeight, float inRadius, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)
  611. {
  612. JPH_PROFILE_FUNCTION();
  613. Mat44 local_transform(Vec4(inRadius, 0, 0, 0), Vec4(0, inHalfHeight, 0, 0), Vec4(0, 0, inRadius, 0), Vec4(0, 0, 0, 1));
  614. Mat44 transform = inMatrix * local_transform;
  615. DrawGeometry(transform, mCylinder->mBounds.Transformed(transform), Square(inRadius), inColor, mCylinder, ECullMode::CullBackFace, inCastShadow, inDrawMode);
  616. }
  617. void DebugRenderer::DrawOpenCone(Vec3Arg inTop, Vec3Arg inAxis, Vec3Arg inPerpendicular, float inHalfAngle, float inLength, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)
  618. {
  619. JPH_PROFILE_FUNCTION();
  620. JPH_ASSERT(inAxis.IsNormalized(1.0e-4f));
  621. JPH_ASSERT(inPerpendicular.IsNormalized(1.0e-4f));
  622. JPH_ASSERT(abs(inPerpendicular.Dot(inAxis)) < 1.0e-4f);
  623. Vec3 axis = Sign(inHalfAngle) * inLength * inAxis;
  624. float scale = inLength * tan(abs(inHalfAngle));
  625. if (scale != 0.0f)
  626. {
  627. Vec3 perp1 = scale * inPerpendicular;
  628. Vec3 perp2 = scale * inAxis.Cross(inPerpendicular);
  629. Mat44 transform(Vec4(perp1, 0), Vec4(axis, 0), Vec4(perp2, 0), Vec4(inTop, 1));
  630. DrawGeometry(transform, inColor, mOpenCone, ECullMode::Off, inCastShadow, inDrawMode);
  631. }
  632. }
  633. void DebugRenderer::DrawSwingLimits(Mat44Arg inMatrix, float inSwingYHalfAngle, float inSwingZHalfAngle, float inEdgeLength, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)
  634. {
  635. JPH_PROFILE_FUNCTION();
  636. // Assert sane input
  637. JPH_ASSERT(inSwingYHalfAngle >= 0.0f && inSwingYHalfAngle <= JPH_PI);
  638. JPH_ASSERT(inSwingZHalfAngle >= 0.0f && inSwingZHalfAngle <= JPH_PI);
  639. JPH_ASSERT(inEdgeLength > 0.0f);
  640. // Check cache
  641. SwingLimits limits { inSwingYHalfAngle, inSwingZHalfAngle };
  642. GeometryRef &geometry = mSwingLimits[limits];
  643. if (geometry == nullptr)
  644. {
  645. // Number of segments to draw the cone with
  646. const int num_segments = 64;
  647. int half_num_segments = num_segments / 2;
  648. // The y and z values of the quaternion are limited to an ellipse, e1 and e2 are the radii of this ellipse
  649. float e1 = sin(0.5f * inSwingZHalfAngle);
  650. float e2 = sin(0.5f * inSwingYHalfAngle);
  651. // Check if the limits will draw something
  652. if ((e1 <= 0.0f && e2 <= 0.0f) || (e2 >= 1.0f && e1 >= 1.0f))
  653. return;
  654. // Calculate squared values
  655. float e1_sq = Square(e1);
  656. float e2_sq = Square(e2);
  657. // Allocate space for vertices
  658. int num_vertices = 2 * num_segments;
  659. Vertex *vertices_start = (Vertex *)JPH_STACK_ALLOC(num_vertices * sizeof(Vertex));
  660. Vertex *vertices = vertices_start;
  661. // Calculate local space vertices for shape
  662. Vec3 ls_vertices[num_segments];
  663. int tgt_vertex = 0;
  664. for (int side_iter = 0; side_iter < 2; ++side_iter)
  665. for (int segment_iter = 0; segment_iter < half_num_segments; ++segment_iter)
  666. {
  667. float y, z;
  668. if (e2_sq > e1_sq)
  669. {
  670. // Trace the y value of the quaternion
  671. y = e2 - 2.0f * segment_iter * e2 / half_num_segments;
  672. // Calculate the corresponding z value of the quaternion
  673. float z_sq = e1_sq - e1_sq / e2_sq * Square(y);
  674. z = z_sq <= 0.0f? 0.0f : sqrt(z_sq);
  675. }
  676. else
  677. {
  678. // Trace the z value of the quaternion
  679. z = -e1 + 2.0f * segment_iter * e1 / half_num_segments;
  680. // Calculate the corresponding y value of the quaternion
  681. float y_sq = e2_sq - e2_sq / e1_sq * Square(z);
  682. y = y_sq <= 0.0f? 0.0f : sqrt(y_sq);
  683. }
  684. // If we're tracing the opposite side, flip the values
  685. if (side_iter == 1)
  686. {
  687. z = -z;
  688. y = -y;
  689. }
  690. // Create quaternion
  691. Vec3 q_xyz(0, y, z);
  692. float w = sqrt(1.0f - q_xyz.LengthSq());
  693. Quat q(Vec4(q_xyz, w));
  694. // Store vertex
  695. ls_vertices[tgt_vertex++] = q.RotateAxisX();
  696. }
  697. for (int i = 0; i < num_segments; ++i)
  698. {
  699. // Get output vertices
  700. Vertex &top = *(vertices++);
  701. Vertex &bottom = *(vertices++);
  702. // Get local position
  703. Vec3 &pos = ls_vertices[i];
  704. // Get local normal
  705. Vec3 &prev_pos = ls_vertices[(i + num_segments - 1) % num_segments];
  706. Vec3 &next_pos = ls_vertices[(i + 1) % num_segments];
  707. Vec3 normal = 0.5f * (next_pos.Cross(pos).Normalized() + pos.Cross(prev_pos).Normalized());
  708. // Store top vertex
  709. top.mPosition = { 0, 0, 0 };
  710. normal.StoreFloat3(&top.mNormal);
  711. top.mColor = Color::sWhite;
  712. top.mUV = { 0, 0 };
  713. // Store bottom vertex
  714. pos.StoreFloat3(&bottom.mPosition);
  715. normal.StoreFloat3(&bottom.mNormal);
  716. bottom.mColor = Color::sWhite;
  717. bottom.mUV = { 0, 0 };
  718. }
  719. // Allocate space for indices
  720. int num_indices = 3 * num_segments;
  721. uint32 *indices_start = (uint32 *)JPH_STACK_ALLOC(num_indices * sizeof(uint32));
  722. uint32 *indices = indices_start;
  723. // Calculate indices
  724. for (int i = 0; i < num_segments; ++i)
  725. {
  726. int first = 2 * i;
  727. int second = (first + 3) % num_vertices;
  728. int third = first + 1;
  729. // Triangle
  730. *indices++ = first;
  731. *indices++ = second;
  732. *indices++ = third;
  733. }
  734. // Convert to triangle batch
  735. geometry = new Geometry(CreateTriangleBatch(vertices_start, num_vertices, indices_start, num_indices), sCalculateBounds(vertices_start, num_vertices));
  736. }
  737. DrawGeometry(inMatrix * Mat44::sScale(inEdgeLength), inColor, geometry, ECullMode::Off, inCastShadow, inDrawMode);
  738. }
  739. void DebugRenderer::DrawPie(Vec3Arg inCenter, float inRadius, Vec3Arg inNormal, Vec3Arg inAxis, float inMinAngle, float inMaxAngle, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)
  740. {
  741. if (inMinAngle >= inMaxAngle)
  742. return;
  743. JPH_PROFILE_FUNCTION();
  744. JPH_ASSERT(inAxis.IsNormalized(1.0e-4f));
  745. JPH_ASSERT(inNormal.IsNormalized(1.0e-4f));
  746. JPH_ASSERT(abs(inNormal.Dot(inAxis)) < 1.0e-4f);
  747. // Pies have a unique batch based on the difference between min and max angle
  748. float delta_angle = inMaxAngle - inMinAngle;
  749. GeometryRef &geometry = mPieLimits[delta_angle];
  750. if (geometry == nullptr)
  751. {
  752. int num_parts = (int)ceil(64.0f * delta_angle / (2.0f * JPH_PI));
  753. Float3 normal = { 0, 1, 0 };
  754. Float3 center = { 0, 0, 0 };
  755. // Allocate space for vertices
  756. int num_vertices = num_parts + 2;
  757. Vertex *vertices_start = (Vertex *)JPH_STACK_ALLOC(num_vertices * sizeof(Vertex));
  758. Vertex *vertices = vertices_start;
  759. // Center of circle
  760. *vertices++ = { center, normal, { 0, 0 }, Color::sWhite };
  761. // Outer edge of pie
  762. for (int i = 0; i <= num_parts; ++i)
  763. {
  764. float angle = float(i) / float(num_parts) * delta_angle;
  765. Float3 pos = { cos(angle), 0, sin(angle) };
  766. *vertices++ = { pos, normal, { 0, 0 }, Color::sWhite };
  767. }
  768. // Allocate space for indices
  769. int num_indices = num_parts * 3;
  770. uint32 *indices_start = (uint32 *)JPH_STACK_ALLOC(num_indices * sizeof(uint32));
  771. uint32 *indices = indices_start;
  772. for (int i = 0; i < num_parts; ++i)
  773. {
  774. *indices++ = 0;
  775. *indices++ = i + 1;
  776. *indices++ = i + 2;
  777. }
  778. // Convert to triangle batch
  779. geometry = new Geometry(CreateTriangleBatch(vertices_start, num_vertices, indices_start, num_indices), sCalculateBounds(vertices_start, num_vertices));
  780. }
  781. // Construct matrix that transforms pie into world space
  782. Mat44 matrix = Mat44(Vec4(inRadius * inAxis, 0), Vec4(inRadius * inNormal, 0), Vec4(inRadius * inNormal.Cross(inAxis), 0), Vec4(inCenter, 1)) * Mat44::sRotationY(-inMinAngle);
  783. DrawGeometry(matrix, inColor, geometry, ECullMode::Off, inCastShadow, inDrawMode);
  784. }
  785. } // JPH
  786. #endif // JPH_DEBUG_RENDERER