DebugRenderer.cpp 39 KB

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