RecastFilledVolumeRasterization.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. /*
  2. recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
  3. DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. using System;
  19. using DotRecast.Core;
  20. using static DotRecast.Core.RcMath;
  21. using static DotRecast.Recast.RcConstants;
  22. namespace DotRecast.Recast
  23. {
  24. public static class RecastFilledVolumeRasterization
  25. {
  26. private const float EPSILON = 0.00001f;
  27. private static readonly int[] BOX_EDGES = new[] { 0, 1, 0, 2, 0, 4, 1, 3, 1, 5, 2, 3, 2, 6, 3, 7, 4, 5, 4, 6, 5, 7, 6, 7 };
  28. public static void RasterizeSphere(RcHeightfield hf, RcVec3f center, float radius, int area, int flagMergeThr, RcTelemetry ctx)
  29. {
  30. using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_SPHERE);
  31. float[] bounds =
  32. {
  33. center.x - radius, center.y - radius, center.z - radius, center.x + radius, center.y + radius,
  34. center.z + radius
  35. };
  36. RasterizationFilledShape(hf, bounds, area, flagMergeThr,
  37. rectangle => IntersectSphere(rectangle, center, radius * radius));
  38. }
  39. public static void RasterizeCapsule(RcHeightfield hf, RcVec3f start, RcVec3f end, float radius, int area, int flagMergeThr, RcTelemetry ctx)
  40. {
  41. using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CAPSULE);
  42. float[] bounds =
  43. {
  44. Math.Min(start.x, end.x) - radius, Math.Min(start.y, end.y) - radius,
  45. Math.Min(start.z, end.z) - radius, Math.Max(start.x, end.x) + radius, Math.Max(start.y, end.y) + radius,
  46. Math.Max(start.z, end.z) + radius
  47. };
  48. RcVec3f axis = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
  49. RasterizationFilledShape(hf, bounds, area, flagMergeThr,
  50. rectangle => IntersectCapsule(rectangle, start, end, axis, radius * radius));
  51. }
  52. public static void RasterizeCylinder(RcHeightfield hf, RcVec3f start, RcVec3f end, float radius, int area, int flagMergeThr,
  53. RcTelemetry ctx)
  54. {
  55. using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CYLINDER);
  56. float[] bounds =
  57. {
  58. Math.Min(start.x, end.x) - radius, Math.Min(start.y, end.y) - radius,
  59. Math.Min(start.z, end.z) - radius, Math.Max(start.x, end.x) + radius, Math.Max(start.y, end.y) + radius,
  60. Math.Max(start.z, end.z) + radius
  61. };
  62. RcVec3f axis = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
  63. RasterizationFilledShape(hf, bounds, area, flagMergeThr,
  64. rectangle => IntersectCylinder(rectangle, start, end, axis, radius * radius));
  65. }
  66. public static void RasterizeBox(RcHeightfield hf, RcVec3f center, RcVec3f[] halfEdges, int area, int flagMergeThr,
  67. RcTelemetry ctx)
  68. {
  69. using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_BOX);
  70. RcVec3f[] normals =
  71. {
  72. RcVec3f.Of(halfEdges[0].x, halfEdges[0].y, halfEdges[0].z),
  73. RcVec3f.Of(halfEdges[1].x, halfEdges[1].y, halfEdges[1].z),
  74. RcVec3f.Of(halfEdges[2].x, halfEdges[2].y, halfEdges[2].z),
  75. };
  76. RcVec3f.Normalize(ref normals[0]);
  77. RcVec3f.Normalize(ref normals[1]);
  78. RcVec3f.Normalize(ref normals[2]);
  79. float[] vertices = new float[8 * 3];
  80. float[] bounds = new float[]
  81. {
  82. float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity,
  83. float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity
  84. };
  85. for (int i = 0; i < 8; ++i)
  86. {
  87. float s0 = (i & 1) != 0 ? 1f : -1f;
  88. float s1 = (i & 2) != 0 ? 1f : -1f;
  89. float s2 = (i & 4) != 0 ? 1f : -1f;
  90. vertices[i * 3 + 0] = center.x + s0 * halfEdges[0].x + s1 * halfEdges[1].x + s2 * halfEdges[2].x;
  91. vertices[i * 3 + 1] = center.y + s0 * halfEdges[0].y + s1 * halfEdges[1].y + s2 * halfEdges[2].y;
  92. vertices[i * 3 + 2] = center.z + s0 * halfEdges[0].z + s1 * halfEdges[1].z + s2 * halfEdges[2].z;
  93. bounds[0] = Math.Min(bounds[0], vertices[i * 3 + 0]);
  94. bounds[1] = Math.Min(bounds[1], vertices[i * 3 + 1]);
  95. bounds[2] = Math.Min(bounds[2], vertices[i * 3 + 2]);
  96. bounds[3] = Math.Max(bounds[3], vertices[i * 3 + 0]);
  97. bounds[4] = Math.Max(bounds[4], vertices[i * 3 + 1]);
  98. bounds[5] = Math.Max(bounds[5], vertices[i * 3 + 2]);
  99. }
  100. float[][] planes = RcArrayUtils.Of<float>(6, 4);
  101. for (int i = 0; i < 6; i++)
  102. {
  103. float m = i < 3 ? -1 : 1;
  104. int vi = i < 3 ? 0 : 7;
  105. planes[i][0] = m * normals[i % 3].x;
  106. planes[i][1] = m * normals[i % 3].y;
  107. planes[i][2] = m * normals[i % 3].z;
  108. planes[i][3] = vertices[vi * 3] * planes[i][0] + vertices[vi * 3 + 1] * planes[i][1]
  109. + vertices[vi * 3 + 2] * planes[i][2];
  110. }
  111. RasterizationFilledShape(hf, bounds, area, flagMergeThr, rectangle => IntersectBox(rectangle, vertices, planes));
  112. }
  113. public static void RasterizeConvex(RcHeightfield hf, float[] vertices, int[] triangles, int area, int flagMergeThr,
  114. RcTelemetry ctx)
  115. {
  116. using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CONVEX);
  117. float[] bounds = new float[] { vertices[0], vertices[1], vertices[2], vertices[0], vertices[1], vertices[2] };
  118. for (int i = 0; i < vertices.Length; i += 3)
  119. {
  120. bounds[0] = Math.Min(bounds[0], vertices[i + 0]);
  121. bounds[1] = Math.Min(bounds[1], vertices[i + 1]);
  122. bounds[2] = Math.Min(bounds[2], vertices[i + 2]);
  123. bounds[3] = Math.Max(bounds[3], vertices[i + 0]);
  124. bounds[4] = Math.Max(bounds[4], vertices[i + 1]);
  125. bounds[5] = Math.Max(bounds[5], vertices[i + 2]);
  126. }
  127. float[][] planes = RcArrayUtils.Of<float>(triangles.Length, 4);
  128. float[][] triBounds = RcArrayUtils.Of<float>(triangles.Length / 3, 4);
  129. for (int i = 0, j = 0; i < triangles.Length; i += 3, j++)
  130. {
  131. int a = triangles[i] * 3;
  132. int b = triangles[i + 1] * 3;
  133. int c = triangles[i + 2] * 3;
  134. float[] ab = { vertices[b] - vertices[a], vertices[b + 1] - vertices[a + 1], vertices[b + 2] - vertices[a + 2] };
  135. float[] ac = { vertices[c] - vertices[a], vertices[c + 1] - vertices[a + 1], vertices[c + 2] - vertices[a + 2] };
  136. float[] bc = { vertices[c] - vertices[b], vertices[c + 1] - vertices[b + 1], vertices[c + 2] - vertices[b + 2] };
  137. float[] ca = { vertices[a] - vertices[c], vertices[a + 1] - vertices[c + 1], vertices[a + 2] - vertices[c + 2] };
  138. Plane(planes, i, ab, ac, vertices, a);
  139. Plane(planes, i + 1, planes[i], bc, vertices, b);
  140. Plane(planes, i + 2, planes[i], ca, vertices, c);
  141. float s = 1.0f / (vertices[a] * planes[i + 1][0] + vertices[a + 1] * planes[i + 1][1]
  142. + vertices[a + 2] * planes[i + 1][2] - planes[i + 1][3]);
  143. planes[i + 1][0] *= s;
  144. planes[i + 1][1] *= s;
  145. planes[i + 1][2] *= s;
  146. planes[i + 1][3] *= s;
  147. s = 1.0f / (vertices[b] * planes[i + 2][0] + vertices[b + 1] * planes[i + 2][1] + vertices[b + 2] * planes[i + 2][2]
  148. - planes[i + 2][3]);
  149. planes[i + 2][0] *= s;
  150. planes[i + 2][1] *= s;
  151. planes[i + 2][2] *= s;
  152. planes[i + 2][3] *= s;
  153. triBounds[j][0] = Math.Min(Math.Min(vertices[a], vertices[b]), vertices[c]);
  154. triBounds[j][1] = Math.Min(Math.Min(vertices[a + 2], vertices[b + 2]), vertices[c + 2]);
  155. triBounds[j][2] = Math.Max(Math.Max(vertices[a], vertices[b]), vertices[c]);
  156. triBounds[j][3] = Math.Max(Math.Max(vertices[a + 2], vertices[b + 2]), vertices[c + 2]);
  157. }
  158. RasterizationFilledShape(hf, bounds, area, flagMergeThr,
  159. rectangle => IntersectConvex(rectangle, triangles, vertices, planes, triBounds));
  160. }
  161. private static void Plane(float[][] planes, int p, float[] v1, float[] v2, float[] vertices, int vert)
  162. {
  163. RcVec3f.Cross(planes[p], v1, v2);
  164. planes[p][3] = planes[p][0] * vertices[vert] + planes[p][1] * vertices[vert + 1] + planes[p][2] * vertices[vert + 2];
  165. }
  166. private static void RasterizationFilledShape(RcHeightfield hf, float[] bounds, int area, int flagMergeThr,
  167. Func<float[], float[]> intersection)
  168. {
  169. if (!OverlapBounds(hf.bmin, hf.bmax, bounds))
  170. {
  171. return;
  172. }
  173. bounds[3] = Math.Min(bounds[3], hf.bmax.x);
  174. bounds[5] = Math.Min(bounds[5], hf.bmax.z);
  175. bounds[0] = Math.Max(bounds[0], hf.bmin.x);
  176. bounds[2] = Math.Max(bounds[2], hf.bmin.z);
  177. if (bounds[3] <= bounds[0] || bounds[4] <= bounds[1] || bounds[5] <= bounds[2])
  178. {
  179. return;
  180. }
  181. float ics = 1.0f / hf.cs;
  182. float ich = 1.0f / hf.ch;
  183. int xMin = (int)((bounds[0] - hf.bmin.x) * ics);
  184. int zMin = (int)((bounds[2] - hf.bmin.z) * ics);
  185. int xMax = Math.Min(hf.width - 1, (int)((bounds[3] - hf.bmin.x) * ics));
  186. int zMax = Math.Min(hf.height - 1, (int)((bounds[5] - hf.bmin.z) * ics));
  187. float[] rectangle = new float[5];
  188. rectangle[4] = hf.bmin.y;
  189. for (int x = xMin; x <= xMax; x++)
  190. {
  191. for (int z = zMin; z <= zMax; z++)
  192. {
  193. rectangle[0] = x * hf.cs + hf.bmin.x;
  194. rectangle[1] = z * hf.cs + hf.bmin.z;
  195. rectangle[2] = rectangle[0] + hf.cs;
  196. rectangle[3] = rectangle[1] + hf.cs;
  197. float[] h = intersection.Invoke(rectangle);
  198. if (h != null)
  199. {
  200. int smin = (int)Math.Floor((h[0] - hf.bmin.y) * ich);
  201. int smax = (int)Math.Ceiling((h[1] - hf.bmin.y) * ich);
  202. if (smin != smax)
  203. {
  204. int ismin = Clamp(smin, 0, SPAN_MAX_HEIGHT);
  205. int ismax = Clamp(smax, ismin + 1, SPAN_MAX_HEIGHT);
  206. RecastRasterization.AddSpan(hf, x, z, ismin, ismax, area, flagMergeThr);
  207. }
  208. }
  209. }
  210. }
  211. }
  212. private static float[] IntersectSphere(float[] rectangle, RcVec3f center, float radiusSqr)
  213. {
  214. float x = Math.Max(rectangle[0], Math.Min(center.x, rectangle[2]));
  215. float y = rectangle[4];
  216. float z = Math.Max(rectangle[1], Math.Min(center.z, rectangle[3]));
  217. float mx = x - center.x;
  218. float my = y - center.y;
  219. float mz = z - center.z;
  220. float b = my; // Dot(m, d) d = (0, 1, 0)
  221. float c = LenSqr(mx, my, mz) - radiusSqr;
  222. if (c > 0.0f && b > 0.0f)
  223. {
  224. return null;
  225. }
  226. float discr = b * b - c;
  227. if (discr < 0.0f)
  228. {
  229. return null;
  230. }
  231. float discrSqrt = (float)Math.Sqrt(discr);
  232. float tmin = -b - discrSqrt;
  233. float tmax = -b + discrSqrt;
  234. if (tmin < 0.0f)
  235. {
  236. tmin = 0.0f;
  237. }
  238. return new float[] { y + tmin, y + tmax };
  239. }
  240. private static float[] IntersectCapsule(float[] rectangle, RcVec3f start, RcVec3f end, RcVec3f axis, float radiusSqr)
  241. {
  242. float[] s = MergeIntersections(IntersectSphere(rectangle, start, radiusSqr), IntersectSphere(rectangle, end, radiusSqr));
  243. float axisLen2dSqr = axis.x * axis.x + axis.z * axis.z;
  244. if (axisLen2dSqr > EPSILON)
  245. {
  246. s = SlabsCylinderIntersection(rectangle, start, end, axis, radiusSqr, s);
  247. }
  248. return s;
  249. }
  250. private static float[] IntersectCylinder(float[] rectangle, RcVec3f start, RcVec3f end, RcVec3f axis, float radiusSqr)
  251. {
  252. float[] s = MergeIntersections(
  253. RayCylinderIntersection(RcVec3f.Of(
  254. Clamp(start.x, rectangle[0], rectangle[2]), rectangle[4],
  255. Clamp(start.z, rectangle[1], rectangle[3])
  256. ), start, axis, radiusSqr),
  257. RayCylinderIntersection(RcVec3f.Of(
  258. Clamp(end.x, rectangle[0], rectangle[2]), rectangle[4],
  259. Clamp(end.z, rectangle[1], rectangle[3])
  260. ), start, axis, radiusSqr));
  261. float axisLen2dSqr = axis.x * axis.x + axis.z * axis.z;
  262. if (axisLen2dSqr > EPSILON)
  263. {
  264. s = SlabsCylinderIntersection(rectangle, start, end, axis, radiusSqr, s);
  265. }
  266. if (axis.y * axis.y > EPSILON)
  267. {
  268. RcVec3f[] rectangleOnStartPlane = new RcVec3f[4];
  269. RcVec3f[] rectangleOnEndPlane = new RcVec3f[4];
  270. float ds = RcVec3f.Dot(axis, start);
  271. float de = RcVec3f.Dot(axis, end);
  272. for (int i = 0; i < 4; i++)
  273. {
  274. float x = rectangle[(i + 1) & 2];
  275. float z = rectangle[(i & 2) + 1];
  276. RcVec3f a = RcVec3f.Of(x, rectangle[4], z);
  277. float dotAxisA = RcVec3f.Dot(axis, a);
  278. float t = (ds - dotAxisA) / axis.y;
  279. rectangleOnStartPlane[i].x = x;
  280. rectangleOnStartPlane[i].y = rectangle[4] + t;
  281. rectangleOnStartPlane[i].z = z;
  282. t = (de - dotAxisA) / axis.y;
  283. rectangleOnEndPlane[i].x = x;
  284. rectangleOnEndPlane[i].y = rectangle[4] + t;
  285. rectangleOnEndPlane[i].z = z;
  286. }
  287. for (int i = 0; i < 4; i++)
  288. {
  289. s = CylinderCapIntersection(start, radiusSqr, s, i, rectangleOnStartPlane);
  290. s = CylinderCapIntersection(end, radiusSqr, s, i, rectangleOnEndPlane);
  291. }
  292. }
  293. return s;
  294. }
  295. private static float[] CylinderCapIntersection(RcVec3f start, float radiusSqr, float[] s, int i, RcVec3f[] rectangleOnPlane)
  296. {
  297. int j = (i + 1) % 4;
  298. // Ray against sphere intersection
  299. var m = RcVec3f.Of(
  300. rectangleOnPlane[i].x - start.x,
  301. rectangleOnPlane[i].y - start.y,
  302. rectangleOnPlane[i].z - start.z
  303. );
  304. var d = RcVec3f.Of(
  305. rectangleOnPlane[j].x - rectangleOnPlane[i].x,
  306. rectangleOnPlane[j].y - rectangleOnPlane[i].y,
  307. rectangleOnPlane[j].z - rectangleOnPlane[i].z
  308. );
  309. float dl = RcVec3f.Dot(d, d);
  310. float b = RcVec3f.Dot(m, d) / dl;
  311. float c = (RcVec3f.Dot(m, m) - radiusSqr) / dl;
  312. float discr = b * b - c;
  313. if (discr > EPSILON)
  314. {
  315. float discrSqrt = (float)Math.Sqrt(discr);
  316. float t1 = -b - discrSqrt;
  317. float t2 = -b + discrSqrt;
  318. if (t1 <= 1 && t2 >= 0)
  319. {
  320. t1 = Math.Max(0, t1);
  321. t2 = Math.Min(1, t2);
  322. float y1 = rectangleOnPlane[i].y + t1 * d.y;
  323. float y2 = rectangleOnPlane[i].y + t2 * d.y;
  324. float[] y = { Math.Min(y1, y2), Math.Max(y1, y2) };
  325. s = MergeIntersections(s, y);
  326. }
  327. }
  328. return s;
  329. }
  330. private static float[] SlabsCylinderIntersection(float[] rectangle, RcVec3f start, RcVec3f end, RcVec3f axis, float radiusSqr, float[] s)
  331. {
  332. if (Math.Min(start.x, end.x) < rectangle[0])
  333. {
  334. s = MergeIntersections(s, XSlabCylinderIntersection(rectangle, start, axis, radiusSqr, rectangle[0]));
  335. }
  336. if (Math.Max(start.x, end.x) > rectangle[2])
  337. {
  338. s = MergeIntersections(s, XSlabCylinderIntersection(rectangle, start, axis, radiusSqr, rectangle[2]));
  339. }
  340. if (Math.Min(start.z, end.z) < rectangle[1])
  341. {
  342. s = MergeIntersections(s, ZSlabCylinderIntersection(rectangle, start, axis, radiusSqr, rectangle[1]));
  343. }
  344. if (Math.Max(start.z, end.z) > rectangle[3])
  345. {
  346. s = MergeIntersections(s, ZSlabCylinderIntersection(rectangle, start, axis, radiusSqr, rectangle[3]));
  347. }
  348. return s;
  349. }
  350. private static float[] XSlabCylinderIntersection(float[] rectangle, RcVec3f start, RcVec3f axis, float radiusSqr, float x)
  351. {
  352. return RayCylinderIntersection(XSlabRayIntersection(rectangle, start, axis, x), start, axis, radiusSqr);
  353. }
  354. private static RcVec3f XSlabRayIntersection(float[] rectangle, RcVec3f start, RcVec3f direction, float x)
  355. {
  356. // 2d intersection of plane and segment
  357. float t = (x - start.x) / direction.x;
  358. float z = Clamp(start.z + t * direction.z, rectangle[1], rectangle[3]);
  359. return RcVec3f.Of(x, rectangle[4], z);
  360. }
  361. private static float[] ZSlabCylinderIntersection(float[] rectangle, RcVec3f start, RcVec3f axis, float radiusSqr, float z)
  362. {
  363. return RayCylinderIntersection(ZSlabRayIntersection(rectangle, start, axis, z), start, axis, radiusSqr);
  364. }
  365. private static RcVec3f ZSlabRayIntersection(float[] rectangle, RcVec3f start, RcVec3f direction, float z)
  366. {
  367. // 2d intersection of plane and segment
  368. float t = (z - start.z) / direction.z;
  369. float x = Clamp(start.x + t * direction.x, rectangle[0], rectangle[2]);
  370. return RcVec3f.Of(x, rectangle[4], z);
  371. }
  372. // Based on Christer Ericsons's "Real-Time Collision Detection"
  373. private static float[] RayCylinderIntersection(RcVec3f point, RcVec3f start, RcVec3f axis, float radiusSqr)
  374. {
  375. RcVec3f d = axis;
  376. RcVec3f m = RcVec3f.Of(point.x - start.x, point.y - start.y, point.z - start.z);
  377. // float[] n = { 0, 1, 0 };
  378. float md = RcVec3f.Dot(m, d);
  379. // float nd = Dot(n, d);
  380. float nd = axis.y;
  381. float dd = RcVec3f.Dot(d, d);
  382. // float nn = Dot(n, n);
  383. float nn = 1;
  384. // float mn = Dot(m, n);
  385. float mn = m.y;
  386. // float a = dd * nn - nd * nd;
  387. float a = dd - nd * nd;
  388. float k = RcVec3f.Dot(m, m) - radiusSqr;
  389. float c = dd * k - md * md;
  390. if (Math.Abs(a) < EPSILON)
  391. {
  392. // Segment runs parallel to cylinder axis
  393. if (c > 0.0f)
  394. {
  395. return null; // ’a’ and thus the segment lie outside cylinder
  396. }
  397. // Now known that segment intersects cylinder; figure out how it intersects
  398. float tt1 = -mn / nn; // Intersect segment against ’p’ endcap
  399. float tt2 = (nd - mn) / nn; // Intersect segment against ’q’ endcap
  400. return new float[] { point.y + Math.Min(tt1, tt2), point.y + Math.Max(tt1, tt2) };
  401. }
  402. float b = dd * mn - nd * md;
  403. float discr = b * b - a * c;
  404. if (discr < 0.0f)
  405. {
  406. return null; // No real roots; no intersection
  407. }
  408. float discSqrt = (float)Math.Sqrt(discr);
  409. float t1 = (-b - discSqrt) / a;
  410. float t2 = (-b + discSqrt) / a;
  411. if (md + t1 * nd < 0.0f)
  412. {
  413. // Intersection outside cylinder on ’p’ side
  414. t1 = -md / nd;
  415. if (k + t1 * (2 * mn + t1 * nn) > 0.0f)
  416. {
  417. return null;
  418. }
  419. }
  420. else if (md + t1 * nd > dd)
  421. {
  422. // Intersection outside cylinder on ’q’ side
  423. t1 = (dd - md) / nd;
  424. if (k + dd - 2 * md + t1 * (2 * (mn - nd) + t1 * nn) > 0.0f)
  425. {
  426. return null;
  427. }
  428. }
  429. if (md + t2 * nd < 0.0f)
  430. {
  431. // Intersection outside cylinder on ’p’ side
  432. t2 = -md / nd;
  433. if (k + t2 * (2 * mn + t2 * nn) > 0.0f)
  434. {
  435. return null;
  436. }
  437. }
  438. else if (md + t2 * nd > dd)
  439. {
  440. // Intersection outside cylinder on ’q’ side
  441. t2 = (dd - md) / nd;
  442. if (k + dd - 2 * md + t2 * (2 * (mn - nd) + t2 * nn) > 0.0f)
  443. {
  444. return null;
  445. }
  446. }
  447. return new float[] { point.y + Math.Min(t1, t2), point.y + Math.Max(t1, t2) };
  448. }
  449. private static float[] IntersectBox(float[] rectangle, float[] vertices, float[][] planes)
  450. {
  451. float yMin = float.PositiveInfinity;
  452. float yMax = float.NegativeInfinity;
  453. // check intersection with rays starting in box vertices first
  454. for (int i = 0; i < 8; i++)
  455. {
  456. int vi = i * 3;
  457. if (vertices[vi] >= rectangle[0] && vertices[vi] < rectangle[2] && vertices[vi + 2] >= rectangle[1]
  458. && vertices[vi + 2] < rectangle[3])
  459. {
  460. yMin = Math.Min(yMin, vertices[vi + 1]);
  461. yMax = Math.Max(yMax, vertices[vi + 1]);
  462. }
  463. }
  464. // check intersection with rays starting in rectangle vertices
  465. var point = RcVec3f.Of(0, rectangle[1], 0);
  466. for (int i = 0; i < 4; i++)
  467. {
  468. point.x = ((i & 1) == 0) ? rectangle[0] : rectangle[2];
  469. point.z = ((i & 2) == 0) ? rectangle[1] : rectangle[3];
  470. for (int j = 0; j < 6; j++)
  471. {
  472. if (Math.Abs(planes[j][1]) > EPSILON)
  473. {
  474. float dotNormalPoint = RcVec3f.Dot(planes[j], point);
  475. float t = (planes[j][3] - dotNormalPoint) / planes[j][1];
  476. float y = point.y + t;
  477. bool valid = true;
  478. for (int k = 0; k < 6; k++)
  479. {
  480. if (k != j)
  481. {
  482. if (point.x * planes[k][0] + y * planes[k][1] + point.z * planes[k][2] > planes[k][3])
  483. {
  484. valid = false;
  485. break;
  486. }
  487. }
  488. }
  489. if (valid)
  490. {
  491. yMin = Math.Min(yMin, y);
  492. yMax = Math.Max(yMax, y);
  493. }
  494. }
  495. }
  496. }
  497. // check intersection with box edges
  498. for (int i = 0; i < BOX_EDGES.Length; i += 2)
  499. {
  500. int vi = BOX_EDGES[i] * 3;
  501. int vj = BOX_EDGES[i + 1] * 3;
  502. float x = vertices[vi];
  503. float z = vertices[vi + 2];
  504. // edge slab intersection
  505. float y = vertices[vi + 1];
  506. float dx = vertices[vj] - x;
  507. float dy = vertices[vj + 1] - y;
  508. float dz = vertices[vj + 2] - z;
  509. if (Math.Abs(dx) > EPSILON)
  510. {
  511. if (XSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[0], out var iy))
  512. {
  513. yMin = Math.Min(yMin, iy);
  514. yMax = Math.Max(yMax, iy);
  515. }
  516. if (XSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[2], out iy))
  517. {
  518. yMin = Math.Min(yMin, iy);
  519. yMax = Math.Max(yMax, iy);
  520. }
  521. }
  522. if (Math.Abs(dz) > EPSILON)
  523. {
  524. if (ZSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[1], out var iy))
  525. {
  526. yMin = Math.Min(yMin, iy);
  527. yMax = Math.Max(yMax, iy);
  528. }
  529. if (ZSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[3], out iy))
  530. {
  531. yMin = Math.Min(yMin, iy);
  532. yMax = Math.Max(yMax, iy);
  533. }
  534. }
  535. }
  536. if (yMin <= yMax)
  537. {
  538. return new float[] { yMin, yMax };
  539. }
  540. return null;
  541. }
  542. private static float[] IntersectConvex(float[] rectangle, int[] triangles, float[] verts, float[][] planes,
  543. float[][] triBounds)
  544. {
  545. float imin = float.PositiveInfinity;
  546. float imax = float.NegativeInfinity;
  547. for (int tr = 0, tri = 0; tri < triangles.Length; tr++, tri += 3)
  548. {
  549. if (triBounds[tr][0] > rectangle[2] || triBounds[tr][2] < rectangle[0] || triBounds[tr][1] > rectangle[3]
  550. || triBounds[tr][3] < rectangle[1])
  551. {
  552. continue;
  553. }
  554. if (Math.Abs(planes[tri][1]) < EPSILON)
  555. {
  556. continue;
  557. }
  558. for (int i = 0; i < 3; i++)
  559. {
  560. int vi = triangles[tri + i] * 3;
  561. int vj = triangles[tri + (i + 1) % 3] * 3;
  562. float x = verts[vi];
  563. float z = verts[vi + 2];
  564. // triangle vertex
  565. if (x >= rectangle[0] && x <= rectangle[2] && z >= rectangle[1] && z <= rectangle[3])
  566. {
  567. imin = Math.Min(imin, verts[vi + 1]);
  568. imax = Math.Max(imax, verts[vi + 1]);
  569. }
  570. // triangle slab intersection
  571. float y = verts[vi + 1];
  572. float dx = verts[vj] - x;
  573. float dy = verts[vj + 1] - y;
  574. float dz = verts[vj + 2] - z;
  575. if (Math.Abs(dx) > EPSILON)
  576. {
  577. if (XSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[0], out var iy))
  578. {
  579. imin = Math.Min(imin, iy);
  580. imax = Math.Max(imax, iy);
  581. }
  582. if (XSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[2], out iy))
  583. {
  584. imin = Math.Min(imin, iy);
  585. imax = Math.Max(imax, iy);
  586. }
  587. }
  588. if (Math.Abs(dz) > EPSILON)
  589. {
  590. if (ZSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[1], out var iy))
  591. {
  592. imin = Math.Min(imin, iy);
  593. imax = Math.Max(imax, iy);
  594. }
  595. if (ZSlabSegmentIntersection(rectangle, x, y, z, dx, dy, dz, rectangle[3], out iy))
  596. {
  597. imin = Math.Min(imin, iy);
  598. imax = Math.Max(imax, iy);
  599. }
  600. }
  601. }
  602. // rectangle vertex
  603. var point = RcVec3f.Of(0, rectangle[1], 0);
  604. for (int i = 0; i < 4; i++)
  605. {
  606. point.x = ((i & 1) == 0) ? rectangle[0] : rectangle[2];
  607. point.z = ((i & 2) == 0) ? rectangle[1] : rectangle[3];
  608. if (RayTriangleIntersection(point, tri, planes, out var y))
  609. {
  610. imin = Math.Min(imin, y);
  611. imax = Math.Max(imax, y);
  612. }
  613. }
  614. }
  615. if (imin < imax)
  616. {
  617. return new float[] { imin, imax };
  618. }
  619. return null;
  620. }
  621. private static bool XSlabSegmentIntersection(float[] rectangle, float x, float y, float z, float dx, float dy, float dz, float slabX, out float iy)
  622. {
  623. float x2 = x + dx;
  624. if ((x < slabX && x2 > slabX) || (x > slabX && x2 < slabX))
  625. {
  626. float t = (slabX - x) / dx;
  627. float iz = z + dz * t;
  628. if (iz >= rectangle[1] && iz <= rectangle[3])
  629. {
  630. iy = y + dy * t;
  631. return true;
  632. }
  633. }
  634. iy = 0.0f;
  635. return false;
  636. }
  637. private static bool ZSlabSegmentIntersection(float[] rectangle, float x, float y, float z, float dx, float dy, float dz, float slabZ, out float iy)
  638. {
  639. float z2 = z + dz;
  640. if ((z < slabZ && z2 > slabZ) || (z > slabZ && z2 < slabZ))
  641. {
  642. float t = (slabZ - z) / dz;
  643. float ix = x + dx * t;
  644. if (ix >= rectangle[0] && ix <= rectangle[2])
  645. {
  646. iy = y + dy * t;
  647. return true;
  648. }
  649. }
  650. iy = 0.0f;
  651. return false;
  652. }
  653. private static bool RayTriangleIntersection(RcVec3f point, int plane, float[][] planes, out float y)
  654. {
  655. y = 0.0f;
  656. float t = (planes[plane][3] - RcVec3f.Dot(planes[plane], point)) / planes[plane][1];
  657. float[] s = { point.x, point.y + t, point.z };
  658. float u = RcVec3f.Dot(s, planes[plane + 1]) - planes[plane + 1][3];
  659. if (u < 0.0f || u > 1.0f)
  660. {
  661. return false;
  662. }
  663. float v = RcVec3f.Dot(s, planes[plane + 2]) - planes[plane + 2][3];
  664. if (v < 0.0f)
  665. {
  666. return false;
  667. }
  668. float w = 1f - u - v;
  669. if (w < 0.0f)
  670. {
  671. return false;
  672. }
  673. y = s[1];
  674. return true;
  675. }
  676. private static float[] MergeIntersections(float[] s1, float[] s2)
  677. {
  678. if (s1 == null)
  679. {
  680. return s2;
  681. }
  682. if (s2 == null)
  683. {
  684. return s1;
  685. }
  686. return new float[] { Math.Min(s1[0], s2[0]), Math.Max(s1[1], s2[1]) };
  687. }
  688. private static float LenSqr(float dx, float dy, float dz)
  689. {
  690. return dx * dx + dy * dy + dz * dz;
  691. }
  692. private static bool OverlapBounds(RcVec3f amin, RcVec3f amax, float[] bounds)
  693. {
  694. bool overlap = true;
  695. overlap = (amin.x > bounds[3] || amax.x < bounds[0]) ? false : overlap;
  696. overlap = (amin.y > bounds[4]) ? false : overlap;
  697. overlap = (amin.z > bounds[5] || amax.z < bounds[2]) ? false : overlap;
  698. return overlap;
  699. }
  700. }
  701. }