ShapeGeometryUtil.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "ShapeGeometryUtil.h"
  9. #include <AzCore/Math/IntersectPoint.h>
  10. #include <AzCore/Math/IntersectSegment.h>
  11. #include <AzCore/Math/Quaternion.h>
  12. #include <AzFramework/Entity/EntityDebugDisplayBus.h>
  13. #include <Shape/ShapeDisplay.h>
  14. namespace LmbrCentral
  15. {
  16. AZ::u32* WriteTriangle(AZ::u32 a, AZ::u32 b, AZ::u32 c, AZ::u32* indices)
  17. {
  18. indices[0] = a;
  19. indices[1] = b;
  20. indices[2] = c;
  21. return indices + 3;
  22. }
  23. AZ::Vector3* WriteVertex(const AZ::Vector3& vertex, AZ::Vector3* vertices)
  24. {
  25. *vertices = vertex;
  26. return vertices + 1;
  27. }
  28. void DrawShape(
  29. AzFramework::DebugDisplayRequests& debugDisplay,
  30. const ShapeDrawParams& shapeDrawParams,
  31. const ShapeMesh& shapeMesh,
  32. const AZ::Vector3& shapeOffset)
  33. {
  34. debugDisplay.PushMatrix(AZ::Transform::CreateTranslation(shapeOffset));
  35. if (shapeDrawParams.m_filled)
  36. {
  37. if (!shapeMesh.m_vertexBuffer.empty() && !shapeMesh.m_indexBuffer.empty())
  38. {
  39. debugDisplay.DrawTrianglesIndexed(shapeMesh.m_vertexBuffer, shapeMesh.m_indexBuffer, shapeDrawParams.m_shapeColor);
  40. }
  41. }
  42. if (!shapeMesh.m_lineBuffer.empty())
  43. {
  44. debugDisplay.DrawLines(shapeMesh.m_lineBuffer, shapeDrawParams.m_wireColor);
  45. }
  46. debugDisplay.PopMatrix();
  47. }
  48. /// Determine if a list of vertices constitute a simple polygon
  49. /// (none of the edges are self intersecting).
  50. /// https://en.wikipedia.org/wiki/Simple_polygon
  51. static bool SimplePolygon(const AZStd::vector<AZ::Vector2>& vertices)
  52. {
  53. const size_t vertexCount = vertices.size();
  54. if (vertexCount < 3)
  55. {
  56. return false;
  57. }
  58. if (vertexCount == 3)
  59. {
  60. return true;
  61. }
  62. for (size_t i = 0; i < vertexCount; ++i)
  63. {
  64. // make it easy to nicely wrap indices
  65. const size_t safeIndex = i + vertexCount;
  66. const size_t endIndex = (safeIndex - 1) % vertexCount;
  67. const size_t beginIndex = (safeIndex + 2) % vertexCount;
  68. for (size_t j = beginIndex; j != endIndex; j = (j + 1) % vertexCount)
  69. {
  70. float aa, bb;
  71. AZ::Vector3 a, b;
  72. AZ::Intersect::ClosestSegmentSegment(
  73. AZ::Vector3(vertices[i]),
  74. AZ::Vector3(vertices[(i + 1) % vertexCount]),
  75. AZ::Vector3(vertices[j]),
  76. AZ::Vector3(vertices[(j + 1) % vertexCount]),
  77. aa, bb, a, b);
  78. if ((a - b).GetLength() < 0.001f)
  79. {
  80. return false;
  81. }
  82. }
  83. }
  84. return true;
  85. }
  86. bool ClockwiseOrder(const AZStd::vector<AZ::Vector2>& vertices)
  87. {
  88. const size_t vertexCount = vertices.size();
  89. float total = 0.0f;
  90. for (size_t i = 0; i < vertexCount; ++i)
  91. {
  92. const AZ::Vector2 a = vertices[i];
  93. const AZ::Vector2 b = vertices[(i + 1) % vertexCount];
  94. total += (b.GetX() - a.GetX()) * (b.GetY() + a.GetY());
  95. }
  96. return total > 0.0f;
  97. }
  98. /// Calculate the Wedge Product of two vectors (the area of the parallelogram formed by them)
  99. static float Wedge(const AZ::Vector2& v1, const AZ::Vector2& v2)
  100. {
  101. return v1.GetX() * v2.GetY() - v1.GetY() * v2.GetX();
  102. }
  103. AZStd::vector<AZ::Vector3> GenerateTriangles(AZStd::vector<AZ::Vector2> vertices)
  104. {
  105. AZStd::vector<AZ::Vector3> triangles;
  106. // we only support simple polygons (ones with no self intersections)
  107. if (!SimplePolygon(vertices))
  108. {
  109. return triangles;
  110. }
  111. // vertices must be in anti-clockwise winding order
  112. if (ClockwiseOrder(vertices))
  113. {
  114. AZStd::reverse(vertices.begin(), vertices.end());
  115. }
  116. // while we still have vertices remaining
  117. for (;;)
  118. {
  119. for (size_t i = 0; i < vertices.size(); ++i)
  120. {
  121. // make it easy to nicely wrap indices
  122. const size_t safeIndex = i + vertices.size();
  123. const size_t prevIndex = (safeIndex - 1) % vertices.size();
  124. const size_t currIndex = safeIndex % vertices.size();
  125. const size_t nextIndex = (safeIndex + 1) % vertices.size();
  126. // vertices making up the triangle
  127. const AZ::Vector2 prev = vertices[prevIndex];
  128. const AZ::Vector2 curr = vertices[currIndex];
  129. const AZ::Vector2 next = vertices[nextIndex];
  130. const AZ::Vector2 edgeBefore = prev - curr;
  131. const AZ::Vector2 edgeAfter = next - curr;
  132. const float triangleArea = Wedge(edgeBefore, edgeAfter);
  133. const float tolerance = 0.001f;
  134. const bool interiorVertex = triangleArea <= 0.0f;
  135. // if triangle is not an 'ear' and we have other vertices, continue.
  136. if (!interiorVertex && vertices.size() > 3)
  137. {
  138. continue;
  139. }
  140. // check if this is a large enough triangle, that there are no other vertices
  141. // inside the triangle formed, otherwise, continue to next vertex.
  142. if (vertices.size() > 3 && !AZ::IsClose(triangleArea, 0.f, tolerance))
  143. {
  144. bool pointInside = false;
  145. for (size_t j = (nextIndex + 1) % vertices.size(); j != prevIndex; j = (j + 1) % vertices.size())
  146. {
  147. if (AZ::Intersect::TestPointTriangle(
  148. AZ::Vector3(vertices[j]),
  149. AZ::Vector3(prev),
  150. AZ::Vector3(curr),
  151. AZ::Vector3(next)))
  152. {
  153. pointInside = true;
  154. break;
  155. }
  156. }
  157. if (pointInside)
  158. {
  159. continue;
  160. }
  161. }
  162. // form new triangle from 'ear'
  163. triangles.push_back(AZ::Vector3(prev));
  164. triangles.push_back(AZ::Vector3(curr));
  165. triangles.push_back(AZ::Vector3(next));
  166. // if work is still do be done, remove vertex from list and iterate again
  167. if (vertices.size() > 3)
  168. {
  169. for (size_t k = i; k < vertices.size() - 1; ++k)
  170. {
  171. vertices[k] = vertices[k + 1];
  172. }
  173. vertices.pop_back();
  174. }
  175. else
  176. {
  177. return triangles;
  178. }
  179. }
  180. }
  181. }
  182. namespace CapsuleTubeUtil
  183. {
  184. AZ::Vector3 CalculatePositionOnSphere(
  185. const AZ::Vector3& localPosition, const AZ::Vector3& forwardAxis, const AZ::Vector3& sideAxis,
  186. const float radius, const float angle)
  187. {
  188. return localPosition +
  189. (forwardAxis * sinf(angle) * radius) +
  190. (sideAxis * cosf(angle) * radius);
  191. }
  192. AZ::Vector3* GenerateWireCap(
  193. const AZ::Vector3& localPosition, const AZ::Vector3& direction, const AZ::Vector3& side,
  194. const float radius, const AZ::u32 capSegments, AZ::Vector3* vertices)
  195. {
  196. const AZ::Vector3 up = side.Cross(direction);
  197. // number of cap segments is tesselation of end - total is double, as we need lines for first
  198. // 90 degrees, then the same tesselation completing the semi-cicle for the next 90 degrees
  199. const AZ::u32 totalCapSegments = capSegments * 2;
  200. const float deltaAngle = AZ::Constants::Pi / static_cast<float>(totalCapSegments);
  201. float angle = 0.0f;
  202. for (size_t i = 0; i < totalCapSegments; ++i)
  203. {
  204. const float nextAngle = angle + deltaAngle;
  205. // horizontal semi-circle arc
  206. vertices = WriteVertex(
  207. CalculatePositionOnSphere(localPosition, direction, side, radius, angle),
  208. vertices);
  209. vertices = WriteVertex(
  210. CalculatePositionOnSphere(localPosition, direction, side, radius, nextAngle),
  211. vertices);
  212. // vertical semi-circle arc
  213. vertices = WriteVertex(
  214. CalculatePositionOnSphere(localPosition, direction, up, radius, angle),
  215. vertices);
  216. vertices = WriteVertex(
  217. CalculatePositionOnSphere(localPosition, direction, up, radius, nextAngle),
  218. vertices);
  219. angle += deltaAngle;
  220. }
  221. return vertices;
  222. }
  223. AZ::Vector3* GenerateWireLoop(
  224. const AZ::Vector3& position, const AZ::Vector3& direction, const AZ::Vector3& side,
  225. const AZ::u32 sides, const float radius, AZ::Vector3* vertices)
  226. {
  227. const auto deltaRot = AZ::Quaternion::CreateFromAxisAngle(
  228. direction, AZ::Constants::TwoPi / static_cast<float>(sides));
  229. auto currentNormal = side;
  230. for (size_t i = 0; i < sides; ++i)
  231. {
  232. const auto nextNormal = deltaRot.TransformVector(currentNormal);
  233. const auto localPosition = position + currentNormal * radius;
  234. const auto nextlocalPosition = position + nextNormal * radius;
  235. vertices = WriteVertex(localPosition, vertices);
  236. vertices = WriteVertex(nextlocalPosition, vertices);
  237. currentNormal = deltaRot.TransformVector(currentNormal);
  238. }
  239. return vertices;
  240. }
  241. /// Generate verts to be used when drawing triangles for cap (top vertex is ommitted and is
  242. /// added in concrete Start/End cap because of ordering - StartCap must at top vertex first,
  243. /// EndCap must add bottom vertex last.
  244. static AZ::Vector3* GenerateSolidCap(
  245. const AZ::Vector3& localPosition, const AZ::Vector3& direction,
  246. const AZ::Vector3& side, const float radius, const AZ::u32 sides, const AZ::u32 capSegments,
  247. const float angleOffset, const float sign, AZ::Vector3* vertices)
  248. {
  249. const float angleDelta = AZ::Constants::HalfPi / static_cast<float>(capSegments);
  250. float angle = 0.0f;
  251. for (size_t i = 1; i <= capSegments; ++i)
  252. {
  253. const AZ::Vector3 capSegmentPosition = localPosition + direction * sign * cosf(angle - angleOffset) * radius;
  254. vertices = GenerateSegmentVertices(
  255. capSegmentPosition, direction, side, sinf(angle + angleOffset) * radius, sides, vertices);
  256. angle += angleDelta;
  257. }
  258. return vertices;
  259. }
  260. AZ::Vector3* GenerateSolidStartCap(
  261. const AZ::Vector3& localPosition, const AZ::Vector3& direction,
  262. const AZ::Vector3& side, const float radius, const AZ::u32 sides,
  263. const AZ::u32 capSegments, AZ::Vector3* vertices)
  264. {
  265. vertices = WriteVertex( // cap end vertex
  266. localPosition - direction * radius, vertices);
  267. return GenerateSolidCap( // circular segments of cap vertices
  268. localPosition, direction,
  269. side, radius, sides, capSegments, 0.0f, -1.0f, vertices);
  270. }
  271. AZ::Vector3* GenerateSolidEndCap(
  272. const AZ::Vector3& localPosition, const AZ::Vector3& direction,
  273. const AZ::Vector3& side, const float radius, const AZ::u32 sides,
  274. const AZ::u32 capSegments, AZ::Vector3* vertices)
  275. {
  276. vertices = GenerateSolidCap( // circular segments of cap vertices
  277. localPosition, direction,
  278. side, radius, sides, capSegments, AZ::Constants::HalfPi, 1.0f, vertices);
  279. return WriteVertex( // cap end vertex
  280. localPosition + direction * radius, vertices);
  281. }
  282. /// Generates a single segment of vertices - Extrudes the point using the normal * radius,
  283. /// then rotates it around the axis 'sides' times.
  284. AZ::Vector3* GenerateSegmentVertices(
  285. const AZ::Vector3& point,
  286. const AZ::Vector3& axis,
  287. const AZ::Vector3& normal,
  288. const float radius,
  289. const AZ::u32 sides,
  290. AZ::Vector3* vertices)
  291. {
  292. const auto deltaRot = AZ::Quaternion::CreateFromAxisAngle(
  293. axis, AZ::Constants::TwoPi / static_cast<float>(sides));
  294. auto currentNormal = normal;
  295. for (size_t i = 0; i < sides; ++i)
  296. {
  297. const auto localPosition = point + currentNormal * radius;
  298. vertices = WriteVertex(localPosition, vertices);
  299. currentNormal = deltaRot.TransformVector(currentNormal);
  300. }
  301. return vertices;
  302. }
  303. void GenerateSolidMeshIndices(
  304. const AZ::u32 sides, const AZ::u32 segments, const AZ::u32 capSegments,
  305. AZ::u32* indices)
  306. {
  307. const AZ::u32 capSegmentTipVerts = capSegments > 0 ? 1 : 0;
  308. const AZ::u32 totalSegments = segments + capSegments * 2;
  309. const AZ::u32 numVerts = sides * (totalSegments + 1) + 2 * capSegmentTipVerts;
  310. const AZ::u32 hasEnds = capSegments > 0;
  311. // Start Faces (start point of tube)
  312. // Each starting face shares the same vertex at the beginning of the vertex buffer
  313. // like a triangle fan
  314. // 1 triangle per face
  315. // 1 face per side
  316. if (hasEnds)
  317. {
  318. for (AZ::u32 i = 0; i < sides; ++i)
  319. {
  320. AZ::u32 a = i + 1;
  321. AZ::u32 b = a + 1;
  322. AZ::u32 start = 0; // First vertex
  323. if (i == sides - 1)
  324. {
  325. b -= sides;
  326. }
  327. indices = WriteTriangle(start, b, a, indices);
  328. }
  329. }
  330. // Middle Faces
  331. // 2 triangles per face.
  332. // 1 face per side.
  333. for (AZ::u32 i = 0; i < totalSegments; ++i)
  334. {
  335. for (AZ::u32 j = 0; j < sides; ++j)
  336. {
  337. // 4 corners for each face
  338. // a ------ d
  339. // | |
  340. // | |
  341. // b ------ c
  342. AZ::u32 a = (i + 0) * sides + (j + 0) + capSegmentTipVerts;
  343. AZ::u32 b = (i + 0) * sides + (j + 1) + capSegmentTipVerts;
  344. AZ::u32 c = (i + 1) * sides + (j + 1) + capSegmentTipVerts;
  345. AZ::u32 d = (i + 1) * sides + (j + 0) + capSegmentTipVerts;
  346. // Wraps back to beginning vertices
  347. if (j == sides - 1)
  348. {
  349. b -= sides;
  350. c -= sides;
  351. }
  352. indices = WriteTriangle(a, b, d, indices);
  353. indices = WriteTriangle(b, c, d, indices);
  354. }
  355. }
  356. // End Faces (end point of tube)
  357. // Each face shares the same vertex at the end of the vertex buffer
  358. // like a triangle fan
  359. // 1 triangle per face
  360. // 1 face per side
  361. if (hasEnds)
  362. {
  363. for (AZ::u32 i = 0; i < sides; ++i)
  364. {
  365. AZ::u32 a = totalSegments * sides + i + 1;
  366. AZ::u32 b = a + 1;
  367. AZ::u32 end = numVerts - 1; // Last vertex
  368. if (i == sides - 1)
  369. {
  370. b -= sides;
  371. }
  372. indices = WriteTriangle(a, b, end, indices);
  373. }
  374. }
  375. }
  376. }
  377. } // namespace LmbrCentral