HeightFieldShape.cpp 88 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395
  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. #include <Jolt/Physics/Collision/Shape/HeightFieldShape.h>
  6. #include <Jolt/Physics/Collision/Shape/ConvexShape.h>
  7. #include <Jolt/Physics/Collision/Shape/ScaleHelpers.h>
  8. #include <Jolt/Physics/Collision/Shape/SphereShape.h>
  9. #include <Jolt/Physics/Collision/RayCast.h>
  10. #include <Jolt/Physics/Collision/ShapeCast.h>
  11. #include <Jolt/Physics/Collision/CastResult.h>
  12. #include <Jolt/Physics/Collision/CollidePointResult.h>
  13. #include <Jolt/Physics/Collision/ShapeFilter.h>
  14. #include <Jolt/Physics/Collision/CastConvexVsTriangles.h>
  15. #include <Jolt/Physics/Collision/CastSphereVsTriangles.h>
  16. #include <Jolt/Physics/Collision/CollideConvexVsTriangles.h>
  17. #include <Jolt/Physics/Collision/CollideSphereVsTriangles.h>
  18. #include <Jolt/Physics/Collision/TransformedShape.h>
  19. #include <Jolt/Physics/Collision/ActiveEdges.h>
  20. #include <Jolt/Physics/Collision/CollisionDispatch.h>
  21. #include <Jolt/Physics/Collision/SortReverseAndStore.h>
  22. #include <Jolt/Core/Profiler.h>
  23. #include <Jolt/Core/StringTools.h>
  24. #include <Jolt/Core/StreamIn.h>
  25. #include <Jolt/Core/StreamOut.h>
  26. #include <Jolt/Core/TempAllocator.h>
  27. #include <Jolt/Geometry/AABox4.h>
  28. #include <Jolt/Geometry/RayTriangle.h>
  29. #include <Jolt/Geometry/RayAABox.h>
  30. #include <Jolt/Geometry/OrientedBox.h>
  31. #include <Jolt/ObjectStream/TypeDeclarations.h>
  32. //#define JPH_DEBUG_HEIGHT_FIELD
  33. JPH_NAMESPACE_BEGIN
  34. #ifdef JPH_DEBUG_RENDERER
  35. bool HeightFieldShape::sDrawTriangleOutlines = false;
  36. #endif // JPH_DEBUG_RENDERER
  37. using namespace HeightFieldShapeConstants;
  38. JPH_IMPLEMENT_SERIALIZABLE_VIRTUAL(HeightFieldShapeSettings)
  39. {
  40. JPH_ADD_BASE_CLASS(HeightFieldShapeSettings, ShapeSettings)
  41. JPH_ADD_ATTRIBUTE(HeightFieldShapeSettings, mHeightSamples)
  42. JPH_ADD_ATTRIBUTE(HeightFieldShapeSettings, mOffset)
  43. JPH_ADD_ATTRIBUTE(HeightFieldShapeSettings, mScale)
  44. JPH_ADD_ATTRIBUTE(HeightFieldShapeSettings, mMinHeightValue)
  45. JPH_ADD_ATTRIBUTE(HeightFieldShapeSettings, mMaxHeightValue)
  46. JPH_ADD_ATTRIBUTE(HeightFieldShapeSettings, mSampleCount)
  47. JPH_ADD_ATTRIBUTE(HeightFieldShapeSettings, mBlockSize)
  48. JPH_ADD_ATTRIBUTE(HeightFieldShapeSettings, mBitsPerSample)
  49. JPH_ADD_ATTRIBUTE(HeightFieldShapeSettings, mMaterialIndices)
  50. JPH_ADD_ATTRIBUTE(HeightFieldShapeSettings, mMaterials)
  51. JPH_ADD_ATTRIBUTE(HeightFieldShapeSettings, mActiveEdgeCosThresholdAngle)
  52. }
  53. const uint HeightFieldShape::sGridOffsets[] =
  54. {
  55. 0, // level: 0, max x/y: 0, offset: 0
  56. 1, // level: 1, max x/y: 1, offset: 1
  57. 5, // level: 2, max x/y: 3, offset: 1 + 4
  58. 21, // level: 3, max x/y: 7, offset: 1 + 4 + 16
  59. 85, // level: 4, max x/y: 15, offset: 1 + 4 + 16 + 64
  60. 341, // level: 5, max x/y: 31, offset: 1 + 4 + 16 + 64 + 256
  61. 1365, // level: 6, max x/y: 63, offset: 1 + 4 + 16 + 64 + 256 + 1024
  62. 5461, // level: 7, max x/y: 127, offset: 1 + 4 + 16 + 64 + 256 + 1024 + 4096
  63. 21845, // level: 8, max x/y: 255, offset: 1 + 4 + 16 + 64 + 256 + 1024 + 4096 + ...
  64. 87381, // level: 9, max x/y: 511, offset: 1 + 4 + 16 + 64 + 256 + 1024 + 4096 + ...
  65. 349525, // level: 10, max x/y: 1023, offset: 1 + 4 + 16 + 64 + 256 + 1024 + 4096 + ...
  66. 1398101, // level: 11, max x/y: 2047, offset: 1 + 4 + 16 + 64 + 256 + 1024 + 4096 + ...
  67. 5592405, // level: 12, max x/y: 4095, offset: 1 + 4 + 16 + 64 + 256 + 1024 + 4096 + ...
  68. 22369621, // level: 13, max x/y: 8191, offset: 1 + 4 + 16 + 64 + 256 + 1024 + 4096 + ...
  69. 89478485, // level: 14, max x/y: 16383, offset: 1 + 4 + 16 + 64 + 256 + 1024 + 4096 + ...
  70. };
  71. HeightFieldShapeSettings::HeightFieldShapeSettings(const float *inSamples, Vec3Arg inOffset, Vec3Arg inScale, uint32 inSampleCount, const uint8 *inMaterialIndices, const PhysicsMaterialList &inMaterialList) :
  72. mOffset(inOffset),
  73. mScale(inScale),
  74. mSampleCount(inSampleCount)
  75. {
  76. mHeightSamples.resize(inSampleCount * inSampleCount);
  77. memcpy(&mHeightSamples[0], inSamples, inSampleCount * inSampleCount * sizeof(float));
  78. if (!inMaterialList.empty() && inMaterialIndices != nullptr)
  79. {
  80. mMaterialIndices.resize(Square(inSampleCount - 1));
  81. memcpy(&mMaterialIndices[0], inMaterialIndices, Square(inSampleCount - 1) * sizeof(uint8));
  82. mMaterials = inMaterialList;
  83. }
  84. else
  85. {
  86. JPH_ASSERT(inMaterialList.empty());
  87. JPH_ASSERT(inMaterialIndices == nullptr);
  88. }
  89. }
  90. ShapeSettings::ShapeResult HeightFieldShapeSettings::Create() const
  91. {
  92. if (mCachedResult.IsEmpty())
  93. Ref<Shape> shape = new HeightFieldShape(*this, mCachedResult);
  94. return mCachedResult;
  95. }
  96. void HeightFieldShapeSettings::DetermineMinAndMaxSample(float &outMinValue, float &outMaxValue, float &outQuantizationScale) const
  97. {
  98. // Determine min and max value
  99. outMinValue = mMinHeightValue;
  100. outMaxValue = mMaxHeightValue;
  101. for (float h : mHeightSamples)
  102. if (h != cNoCollisionValue)
  103. {
  104. outMinValue = min(outMinValue, h);
  105. outMaxValue = max(outMaxValue, h);
  106. }
  107. // Prevent dividing by zero by setting a minimal height difference
  108. float height_diff = max(outMaxValue - outMinValue, 1.0e-6f);
  109. // Calculate the scale factor to quantize to 16 bits
  110. outQuantizationScale = float(cMaxHeightValue16) / height_diff;
  111. }
  112. uint32 HeightFieldShapeSettings::CalculateBitsPerSampleForError(float inMaxError) const
  113. {
  114. // Start with 1 bit per sample
  115. uint32 bits_per_sample = 1;
  116. // Determine total range
  117. float min_value, max_value, scale;
  118. DetermineMinAndMaxSample(min_value, max_value, scale);
  119. if (min_value < max_value)
  120. {
  121. // Loop over all blocks
  122. for (uint y = 0; y < mSampleCount; y += mBlockSize)
  123. for (uint x = 0; x < mSampleCount; x += mBlockSize)
  124. {
  125. // Determine min and max block value + take 1 sample border just like we do while building the hierarchical grids
  126. float block_min_value = FLT_MAX, block_max_value = -FLT_MAX;
  127. for (uint bx = x; bx < min(x + mBlockSize + 1, mSampleCount); ++bx)
  128. for (uint by = y; by < min(y + mBlockSize + 1, mSampleCount); ++by)
  129. {
  130. float h = mHeightSamples[by * mSampleCount + bx];
  131. if (h != cNoCollisionValue)
  132. {
  133. block_min_value = min(block_min_value, h);
  134. block_max_value = max(block_max_value, h);
  135. }
  136. }
  137. if (block_min_value < block_max_value)
  138. {
  139. // Quantize then dequantize block min/max value
  140. block_min_value = min_value + floor((block_min_value - min_value) * scale) / scale;
  141. block_max_value = min_value + ceil((block_max_value - min_value) * scale) / scale;
  142. float block_height = block_max_value - block_min_value;
  143. // Loop over the block again
  144. for (uint bx = x; bx < x + mBlockSize; ++bx)
  145. for (uint by = y; by < y + mBlockSize; ++by)
  146. {
  147. // Get the height
  148. float height = mHeightSamples[by * mSampleCount + bx];
  149. if (height != cNoCollisionValue)
  150. {
  151. for (;;)
  152. {
  153. // Determine bitmask for sample
  154. uint32 sample_mask = (1 << bits_per_sample) - 1;
  155. // Quantize
  156. float quantized_height = floor((height - block_min_value) * float(sample_mask) / block_height);
  157. quantized_height = Clamp(quantized_height, 0.0f, float(sample_mask - 1));
  158. // Dequantize and check error
  159. float dequantized_height = block_min_value + (quantized_height + 0.5f) * block_height / float(sample_mask);
  160. if (abs(dequantized_height - height) <= inMaxError)
  161. break;
  162. // Not accurate enough, increase bits per sample
  163. bits_per_sample++;
  164. // Don't go above 8 bits per sample
  165. if (bits_per_sample == 8)
  166. return bits_per_sample;
  167. }
  168. }
  169. }
  170. }
  171. }
  172. }
  173. return bits_per_sample;
  174. }
  175. void HeightFieldShape::CalculateActiveEdges(uint inX, uint inY, uint inSizeX, uint inSizeY, const float *inHeights, uint inHeightsStartX, uint inHeightsStartY, uint inHeightsStride, float inHeightsScale, float inActiveEdgeCosThresholdAngle, TempAllocator &inAllocator)
  176. {
  177. // Allocate temporary buffer for normals
  178. uint normals_size = 2 * inSizeX * inSizeY * sizeof(Vec3);
  179. Vec3 *normals = (Vec3 *)inAllocator.Allocate(normals_size);
  180. // Calculate triangle normals and make normals zero for triangles that are missing
  181. Vec3 *out_normal = normals;
  182. for (uint y = 0; y < inSizeY; ++y)
  183. for (uint x = 0; x < inSizeX; ++x)
  184. {
  185. // Get height on diagonal
  186. const float *height_samples = inHeights + (inY - inHeightsStartY + y) * inHeightsStride + (inX - inHeightsStartX + x);
  187. float x1y1_h = height_samples[0];
  188. float x2y2_h = height_samples[inHeightsStride + 1];
  189. if (x1y1_h != cNoCollisionValue && x2y2_h != cNoCollisionValue)
  190. {
  191. // Calculate normal for lower left triangle (e.g. T1A)
  192. float x1y2_h = height_samples[inHeightsStride];
  193. if (x1y2_h != cNoCollisionValue)
  194. {
  195. Vec3 x2y2_minus_x1y2(mScale.GetX(), inHeightsScale * (x2y2_h - x1y2_h), 0);
  196. Vec3 x1y1_minus_x1y2(0, inHeightsScale * (x1y1_h - x1y2_h), -mScale.GetZ());
  197. out_normal[0] = x2y2_minus_x1y2.Cross(x1y1_minus_x1y2).Normalized();
  198. }
  199. else
  200. out_normal[0] = Vec3::sZero();
  201. // Calculate normal for upper right triangle (e.g. T1B)
  202. float x2y1_h = height_samples[1];
  203. if (x2y1_h != cNoCollisionValue)
  204. {
  205. Vec3 x1y1_minus_x2y1(-mScale.GetX(), inHeightsScale * (x1y1_h - x2y1_h), 0);
  206. Vec3 x2y2_minus_x2y1(0, inHeightsScale * (x2y2_h - x2y1_h), mScale.GetZ());
  207. out_normal[1] = x1y1_minus_x2y1.Cross(x2y2_minus_x2y1).Normalized();
  208. }
  209. else
  210. out_normal[1] = Vec3::sZero();
  211. }
  212. else
  213. {
  214. out_normal[0] = Vec3::sZero();
  215. out_normal[1] = Vec3::sZero();
  216. }
  217. out_normal += 2;
  218. }
  219. // Calculate active edges
  220. const Vec3 *in_normal = normals;
  221. uint global_bit_pos = 3 * (inY * (mSampleCount - 1) + inX);
  222. for (uint y = 0; y < inSizeY; ++y)
  223. {
  224. for (uint x = 0; x < inSizeX; ++x)
  225. {
  226. // Get vertex heights
  227. const float *height_samples = inHeights + (inY - inHeightsStartY + y) * inHeightsStride + (inX - inHeightsStartX + x);
  228. float x1y1_h = height_samples[0];
  229. float x1y2_h = height_samples[inHeightsStride];
  230. float x2y2_h = height_samples[inHeightsStride + 1];
  231. bool x1y1_valid = x1y1_h != cNoCollisionValue;
  232. bool x1y2_valid = x1y2_h != cNoCollisionValue;
  233. bool x2y2_valid = x2y2_h != cNoCollisionValue;
  234. // Calculate the edge flags (3 bits)
  235. // See diagram in the next function for the edge numbering
  236. uint16 edge_mask = 0b111;
  237. uint16 edge_flags = 0;
  238. // Edge 0
  239. if (x == 0)
  240. edge_mask &= 0b110; // We need normal x - 1 which we didn't calculate, don't update this edge
  241. else if (x1y1_valid && x1y2_valid)
  242. {
  243. Vec3 edge0_direction(0, inHeightsScale * (x1y2_h - x1y1_h), mScale.GetZ());
  244. if (ActiveEdges::IsEdgeActive(in_normal[0], in_normal[-1], edge0_direction, inActiveEdgeCosThresholdAngle))
  245. edge_flags |= 0b001;
  246. }
  247. // Edge 1
  248. if (y == inSizeY - 1)
  249. edge_mask &= 0b101; // We need normal y + 1 which we didn't calculate, don't update this edge
  250. else if (x1y2_valid && x2y2_valid)
  251. {
  252. Vec3 edge1_direction(mScale.GetX(), inHeightsScale * (x2y2_h - x1y2_h), 0);
  253. if (ActiveEdges::IsEdgeActive(in_normal[0], in_normal[2 * inSizeX + 1], edge1_direction, inActiveEdgeCosThresholdAngle))
  254. edge_flags |= 0b010;
  255. }
  256. // Edge 2
  257. if (x1y1_valid && x2y2_valid)
  258. {
  259. Vec3 edge2_direction(-mScale.GetX(), inHeightsScale * (x1y1_h - x2y2_h), -mScale.GetZ());
  260. if (ActiveEdges::IsEdgeActive(in_normal[0], in_normal[1], edge2_direction, inActiveEdgeCosThresholdAngle))
  261. edge_flags |= 0b100;
  262. }
  263. // Store the edge flags in the array
  264. uint byte_pos = global_bit_pos >> 3;
  265. uint bit_pos = global_bit_pos & 0b111;
  266. uint8 *edge_flags_ptr = &mActiveEdges[byte_pos];
  267. uint16 combined_edge_flags = uint16(edge_flags_ptr[0]) | uint16(uint16(edge_flags_ptr[1]) << 8);
  268. combined_edge_flags &= ~(edge_mask << bit_pos);
  269. combined_edge_flags |= edge_flags << bit_pos;
  270. edge_flags_ptr[0] = uint8(combined_edge_flags);
  271. edge_flags_ptr[1] = uint8(combined_edge_flags >> 8);
  272. in_normal += 2;
  273. global_bit_pos += 3;
  274. }
  275. global_bit_pos += 3 * (mSampleCount - 1 - inSizeX);
  276. }
  277. // Free temporary buffer for normals
  278. inAllocator.Free(normals, normals_size);
  279. }
  280. void HeightFieldShape::CalculateActiveEdges(const HeightFieldShapeSettings &inSettings)
  281. {
  282. /*
  283. Store active edges. The triangles are organized like this:
  284. x --->
  285. y + +
  286. | \ T1B | \ T2B
  287. | e0 e2 | \
  288. | | T1A \ | T2A \
  289. V +--e1---+-------+
  290. | \ T3B | \ T4B
  291. | \ | \
  292. | T3A \ | T4A \
  293. +-------+-------+
  294. We store active edges e0 .. e2 as bits 0 .. 2.
  295. We store triangles horizontally then vertically (order T1A, T2A, T3A and T4A).
  296. The top edge and right edge of the heightfield are always active so we do not need to store them,
  297. therefore we only need to store (mSampleCount - 1)^2 * 3-bit
  298. The triangles T1B, T2B, T3B and T4B do not need to be stored, their active edges can be constructed from adjacent triangles.
  299. Add 1 byte padding so we can always read 1 uint16 to get the bits that cross an 8 bit boundary
  300. */
  301. mActiveEdges.resize((Square(mSampleCount - 1) * 3 + 7) / 8 + 1);
  302. // Make all edges active (if mSampleCount is bigger than inSettings.mSampleCount we need to fill up the padding,
  303. // also edges at x = 0 and y = inSettings.mSampleCount - 1 are not updated)
  304. memset(mActiveEdges.data(), 0xff, mActiveEdges.size());
  305. // Now clear the edges that are not active
  306. TempAllocatorMalloc allocator;
  307. CalculateActiveEdges(0, 0, inSettings.mSampleCount - 1, inSettings.mSampleCount - 1, inSettings.mHeightSamples.data(), 0, 0, inSettings.mSampleCount, inSettings.mScale.GetY(), inSettings.mActiveEdgeCosThresholdAngle, allocator);
  308. }
  309. void HeightFieldShape::StoreMaterialIndices(const HeightFieldShapeSettings &inSettings)
  310. {
  311. // We need to account for any rounding of the sample count to the nearest block size
  312. uint in_count_min_1 = inSettings.mSampleCount - 1;
  313. uint out_count_min_1 = mSampleCount - 1;
  314. mNumBitsPerMaterialIndex = 32 - CountLeadingZeros((uint32)mMaterials.size() - 1);
  315. mMaterialIndices.resize(((Square(out_count_min_1) * mNumBitsPerMaterialIndex + 7) >> 3) + 1); // Add 1 byte so we don't read out of bounds when reading an uint16
  316. for (uint y = 0; y < out_count_min_1; ++y)
  317. for (uint x = 0; x < out_count_min_1; ++x)
  318. {
  319. // Read material
  320. uint16 material_index = x < in_count_min_1 && y < in_count_min_1? uint16(inSettings.mMaterialIndices[x + y * in_count_min_1]) : 0;
  321. // Calculate byte and bit position where the material index needs to go
  322. uint sample_pos = x + y * out_count_min_1;
  323. uint bit_pos = sample_pos * mNumBitsPerMaterialIndex;
  324. uint byte_pos = bit_pos >> 3;
  325. bit_pos &= 0b111;
  326. // Write the material index
  327. material_index <<= bit_pos;
  328. JPH_ASSERT(byte_pos + 1 < mMaterialIndices.size());
  329. mMaterialIndices[byte_pos] |= uint8(material_index);
  330. mMaterialIndices[byte_pos + 1] |= uint8(material_index >> 8);
  331. }
  332. }
  333. void HeightFieldShape::CacheValues()
  334. {
  335. mSampleMask = uint8((uint32(1) << mBitsPerSample) - 1);
  336. }
  337. HeightFieldShape::HeightFieldShape(const HeightFieldShapeSettings &inSettings, ShapeResult &outResult) :
  338. Shape(EShapeType::HeightField, EShapeSubType::HeightField, inSettings, outResult),
  339. mOffset(inSettings.mOffset),
  340. mScale(inSettings.mScale),
  341. mSampleCount(((inSettings.mSampleCount + inSettings.mBlockSize - 1) / inSettings.mBlockSize) * inSettings.mBlockSize), // Round sample count to nearest block size
  342. mBlockSize(inSettings.mBlockSize),
  343. mBitsPerSample(uint8(inSettings.mBitsPerSample)),
  344. mMaterials(inSettings.mMaterials)
  345. {
  346. CacheValues();
  347. // Check block size
  348. if (mBlockSize < 2 || mBlockSize > 8)
  349. {
  350. outResult.SetError("HeightFieldShape: Block size must be in the range [2, 8]!");
  351. return;
  352. }
  353. // Check bits per sample
  354. if (inSettings.mBitsPerSample < 1 || inSettings.mBitsPerSample > 8)
  355. {
  356. outResult.SetError("HeightFieldShape: Bits per sample must be in the range [1, 8]!");
  357. return;
  358. }
  359. // We stop at mBlockSize x mBlockSize height sample blocks
  360. uint num_blocks = GetNumBlocks();
  361. // We want at least 1 grid layer
  362. if (num_blocks < 2)
  363. {
  364. outResult.SetError("HeightFieldShape: Sample count too low!");
  365. return;
  366. }
  367. // Check that we don't overflow our 32 bit 'properties'
  368. if (num_blocks > (1 << cNumBitsXY))
  369. {
  370. outResult.SetError("HeightFieldShape: Sample count too high!");
  371. return;
  372. }
  373. // Check if we're not exceeding the amount of sub shape id bits
  374. if (GetSubShapeIDBitsRecursive() > SubShapeID::MaxBits)
  375. {
  376. outResult.SetError("HeightFieldShape: Size exceeds the amount of available sub shape ID bits!");
  377. return;
  378. }
  379. if (!mMaterials.empty())
  380. {
  381. // Validate materials
  382. if (mMaterials.size() > 256)
  383. {
  384. outResult.SetError("Supporting max 256 materials per height field");
  385. return;
  386. }
  387. for (uint8 s : inSettings.mMaterialIndices)
  388. if (s >= mMaterials.size())
  389. {
  390. outResult.SetError(StringFormat("Material %u is beyond material list (size: %u)", s, (uint)mMaterials.size()));
  391. return;
  392. }
  393. }
  394. else
  395. {
  396. // No materials assigned, validate that no materials have been specified
  397. if (!inSettings.mMaterialIndices.empty())
  398. {
  399. outResult.SetError("No materials present, mMaterialIndices should be empty");
  400. return;
  401. }
  402. }
  403. // Determine range
  404. float min_value, max_value, scale;
  405. inSettings.DetermineMinAndMaxSample(min_value, max_value, scale);
  406. if (min_value > max_value)
  407. {
  408. // If there is no collision with this heightmap, leave everything empty
  409. mMaterials.clear();
  410. outResult.Set(this);
  411. return;
  412. }
  413. // Quantize to uint16
  414. Array<uint16> quantized_samples;
  415. quantized_samples.reserve(mSampleCount * mSampleCount);
  416. for (uint y = 0; y < inSettings.mSampleCount; ++y)
  417. {
  418. for (uint x = 0; x < inSettings.mSampleCount; ++x)
  419. {
  420. float h = inSettings.mHeightSamples[x + y * inSettings.mSampleCount];
  421. if (h == cNoCollisionValue)
  422. {
  423. quantized_samples.push_back(cNoCollisionValue16);
  424. }
  425. else
  426. {
  427. // Floor the quantized height to get a lower bound for the quantized value
  428. int quantized_height = (int)floor(scale * (h - min_value));
  429. // Ensure that the height says below the max height value so we can safely add 1 to get the upper bound for the quantized value
  430. quantized_height = Clamp(quantized_height, 0, int(cMaxHeightValue16 - 1));
  431. quantized_samples.push_back(uint16(quantized_height));
  432. }
  433. }
  434. // Pad remaining columns with no collision
  435. for (uint x = inSettings.mSampleCount; x < mSampleCount; ++x)
  436. quantized_samples.push_back(cNoCollisionValue16);
  437. }
  438. // Pad remaining rows with no collision
  439. for (uint y = inSettings.mSampleCount; y < mSampleCount; ++y)
  440. for (uint x = 0; x < mSampleCount; ++x)
  441. quantized_samples.push_back(cNoCollisionValue16);
  442. // Update offset and scale to account for the compression to uint16
  443. if (min_value <= max_value) // Only when there was collision
  444. {
  445. // In GetPosition we always add 0.5 to the quantized sample in order to reduce the average error.
  446. // We want to be able to exactly quantize min_value (this is important in case the heightfield is entirely flat) so we subtract that value from min_value.
  447. min_value -= 0.5f / (scale * mSampleMask);
  448. mOffset.SetY(mOffset.GetY() + mScale.GetY() * min_value);
  449. }
  450. mScale.SetY(mScale.GetY() / scale);
  451. // Calculate amount of grids
  452. uint max_level = sGetMaxLevel(num_blocks);
  453. // Temporary data structure used during creating of a hierarchy of grids
  454. struct Range
  455. {
  456. uint16 mMin;
  457. uint16 mMax;
  458. };
  459. // Reserve size for temporary range data + reserve 1 extra for a 1x1 grid that we won't store but use for calculating the bounding box
  460. Array<Array<Range>> ranges;
  461. ranges.resize(max_level + 1);
  462. // Calculate highest detail grid by combining mBlockSize x mBlockSize height samples
  463. Array<Range> *cur_range_vector = &ranges.back();
  464. uint num_blocks_pow2 = GetNextPowerOf2(num_blocks); // We calculate the range blocks as if the heightfield was a power of 2, when we save the range blocks we'll ignore the extra samples (this makes downsampling easier)
  465. cur_range_vector->resize(num_blocks_pow2 * num_blocks_pow2);
  466. Range *range_dst = &cur_range_vector->front();
  467. for (uint y = 0; y < num_blocks_pow2; ++y)
  468. for (uint x = 0; x < num_blocks_pow2; ++x)
  469. {
  470. range_dst->mMin = 0xffff;
  471. range_dst->mMax = 0;
  472. uint max_bx = x == num_blocks_pow2 - 1? mBlockSize : mBlockSize + 1; // for interior blocks take 1 more because the triangles connect to the next block so we must include their height too
  473. uint max_by = y == num_blocks_pow2 - 1? mBlockSize : mBlockSize + 1;
  474. for (uint by = 0; by < max_by; ++by)
  475. for (uint bx = 0; bx < max_bx; ++bx)
  476. {
  477. uint sx = x * mBlockSize + bx;
  478. uint sy = y * mBlockSize + by;
  479. if (sx < mSampleCount && sy < mSampleCount)
  480. {
  481. uint16 h = quantized_samples[sy * mSampleCount + sx];
  482. if (h != cNoCollisionValue16)
  483. {
  484. range_dst->mMin = min(range_dst->mMin, h);
  485. range_dst->mMax = max(range_dst->mMax, uint16(h + 1)); // Add 1 to the max so we know the real value is between mMin and mMax
  486. }
  487. }
  488. }
  489. ++range_dst;
  490. }
  491. // Calculate remaining grids
  492. for (uint n = num_blocks_pow2 >> 1; n >= 1; n >>= 1)
  493. {
  494. // Get source buffer
  495. const Range *range_src = &cur_range_vector->front();
  496. // Previous array element
  497. --cur_range_vector;
  498. // Make space for this grid
  499. cur_range_vector->resize(n * n);
  500. // Get target buffer
  501. range_dst = &cur_range_vector->front();
  502. // Combine the results of 2x2 ranges
  503. for (uint y = 0; y < n; ++y)
  504. for (uint x = 0; x < n; ++x)
  505. {
  506. range_dst->mMin = 0xffff;
  507. range_dst->mMax = 0;
  508. for (uint by = 0; by < 2; ++by)
  509. for (uint bx = 0; bx < 2; ++bx)
  510. {
  511. const Range &r = range_src[(y * 2 + by) * n * 2 + x * 2 + bx];
  512. range_dst->mMin = min(range_dst->mMin, r.mMin);
  513. range_dst->mMax = max(range_dst->mMax, r.mMax);
  514. }
  515. ++range_dst;
  516. }
  517. }
  518. JPH_ASSERT(cur_range_vector == &ranges.front());
  519. // Store global range for bounding box calculation
  520. mMinSample = ranges[0][0].mMin;
  521. mMaxSample = ranges[0][0].mMax;
  522. #ifdef JPH_ENABLE_ASSERTS
  523. // Validate that we did not lose range along the way
  524. uint16 minv = 0xffff, maxv = 0;
  525. for (uint16 v : quantized_samples)
  526. if (v != cNoCollisionValue16)
  527. {
  528. minv = min(minv, v);
  529. maxv = max(maxv, uint16(v + 1));
  530. }
  531. JPH_ASSERT(mMinSample == minv && mMaxSample == maxv);
  532. #endif
  533. // Now erase the first element, we need a 2x2 grid to start with
  534. ranges.erase(ranges.begin());
  535. // Create blocks
  536. uint max_stride = (num_blocks + 1) >> 1;
  537. mRangeBlocks.reserve(sGridOffsets[ranges.size()]);
  538. for (uint level = 0; level < ranges.size(); ++level)
  539. {
  540. JPH_ASSERT(mRangeBlocks.size() == sGridOffsets[level]);
  541. uint in_n = 1 << level;
  542. uint out_n = min(in_n, max_stride); // At the most detailed level we store a non-power of 2 number of blocks
  543. for (uint y = 0; y < out_n; ++y)
  544. for (uint x = 0; x < out_n; ++x)
  545. {
  546. // Convert from 2x2 Range structure to 1 RangeBlock structure
  547. RangeBlock rb;
  548. for (uint by = 0; by < 2; ++by)
  549. for (uint bx = 0; bx < 2; ++bx)
  550. {
  551. uint src_pos = (y * 2 + by) * 2 * in_n + (x * 2 + bx);
  552. uint dst_pos = by * 2 + bx;
  553. rb.mMin[dst_pos] = ranges[level][src_pos].mMin;
  554. rb.mMax[dst_pos] = ranges[level][src_pos].mMax;
  555. }
  556. // Add this block
  557. mRangeBlocks.push_back(rb);
  558. }
  559. }
  560. JPH_ASSERT(mRangeBlocks.size() == sGridOffsets[ranges.size() - 1] + Square(max_stride));
  561. // Quantize height samples
  562. mHeightSamples.resize((mSampleCount * mSampleCount * inSettings.mBitsPerSample + 7) / 8 + 1);
  563. int sample = 0;
  564. for (uint y = 0; y < mSampleCount; ++y)
  565. for (uint x = 0; x < mSampleCount; ++x)
  566. {
  567. uint32 output_value;
  568. float h = x < inSettings.mSampleCount && y < inSettings.mSampleCount? inSettings.mHeightSamples[x + y * inSettings.mSampleCount] : cNoCollisionValue;
  569. if (h == cNoCollisionValue)
  570. {
  571. // No collision
  572. output_value = mSampleMask;
  573. }
  574. else
  575. {
  576. // Get range of block so we know what range to compress to
  577. uint bx = x / mBlockSize;
  578. uint by = y / mBlockSize;
  579. const Range &range = ranges.back()[by * num_blocks_pow2 + bx];
  580. JPH_ASSERT(range.mMin < range.mMax);
  581. // Quantize to mBitsPerSample bits, note that mSampleMask is reserved for indicating that there's no collision.
  582. // We divide the range into mSampleMask segments and use the mid points of these segments as the quantized values.
  583. // This results in a lower error than if we had quantized our data using the lowest point of all these segments.
  584. float h_min = min_value + range.mMin / scale;
  585. float h_delta = float(range.mMax - range.mMin) / scale;
  586. float quantized_height = floor((h - h_min) * float(mSampleMask) / h_delta);
  587. output_value = uint32(Clamp((int)quantized_height, 0, int(mSampleMask) - 1)); // mSampleMask is reserved as 'no collision value'
  588. }
  589. // Store the sample
  590. uint byte_pos = sample >> 3;
  591. uint bit_pos = sample & 0b111;
  592. output_value <<= bit_pos;
  593. mHeightSamples[byte_pos] |= uint8(output_value);
  594. mHeightSamples[byte_pos + 1] |= uint8(output_value >> 8);
  595. sample += inSettings.mBitsPerSample;
  596. }
  597. // Calculate the active edges
  598. CalculateActiveEdges(inSettings);
  599. // Compress material indices
  600. if (mMaterials.size() > 1)
  601. StoreMaterialIndices(inSettings);
  602. outResult.Set(this);
  603. }
  604. inline void HeightFieldShape::sGetRangeBlockOffsetAndStride(uint inNumBlocks, uint inMaxLevel, uint &outRangeBlockOffset, uint &outRangeBlockStride)
  605. {
  606. outRangeBlockOffset = sGridOffsets[inMaxLevel - 1];
  607. outRangeBlockStride = (inNumBlocks + 1) >> 1;
  608. }
  609. inline void HeightFieldShape::GetRangeBlock(uint inBlockX, uint inBlockY, uint inRangeBlockOffset, uint inRangeBlockStride, RangeBlock *&outBlock, uint &outIndexInBlock)
  610. {
  611. JPH_ASSERT(inBlockX < GetNumBlocks() && inBlockY < GetNumBlocks());
  612. // Convert to location of range block
  613. uint rbx = inBlockX >> 1;
  614. uint rby = inBlockY >> 1;
  615. outIndexInBlock = ((inBlockY & 1) << 1) + (inBlockX & 1);
  616. outBlock = &mRangeBlocks[inRangeBlockOffset + rby * inRangeBlockStride + rbx];
  617. }
  618. inline void HeightFieldShape::GetBlockOffsetAndScale(uint inBlockX, uint inBlockY, uint inRangeBlockOffset, uint inRangeBlockStride, float &outBlockOffset, float &outBlockScale) const
  619. {
  620. JPH_ASSERT(inBlockX < GetNumBlocks() && inBlockY < GetNumBlocks());
  621. // Convert to location of range block
  622. uint rbx = inBlockX >> 1;
  623. uint rby = inBlockY >> 1;
  624. uint n = ((inBlockY & 1) << 1) + (inBlockX & 1);
  625. // Calculate offset and scale
  626. const RangeBlock &block = mRangeBlocks[inRangeBlockOffset + rby * inRangeBlockStride + rbx];
  627. outBlockOffset = float(block.mMin[n]);
  628. outBlockScale = float(block.mMax[n] - block.mMin[n]) / float(mSampleMask);
  629. }
  630. inline uint8 HeightFieldShape::GetHeightSample(uint inX, uint inY) const
  631. {
  632. JPH_ASSERT(inX < mSampleCount);
  633. JPH_ASSERT(inY < mSampleCount);
  634. // Determine bit position of sample
  635. uint sample = (inY * mSampleCount + inX) * uint(mBitsPerSample);
  636. uint byte_pos = sample >> 3;
  637. uint bit_pos = sample & 0b111;
  638. // Fetch the height sample value
  639. JPH_ASSERT(byte_pos + 1 < mHeightSamples.size());
  640. const uint8 *height_samples = mHeightSamples.data() + byte_pos;
  641. uint16 height_sample = uint16(height_samples[0]) | uint16(uint16(height_samples[1]) << 8);
  642. return uint8(height_sample >> bit_pos) & mSampleMask;
  643. }
  644. inline Vec3 HeightFieldShape::GetPosition(uint inX, uint inY, float inBlockOffset, float inBlockScale, bool &outNoCollision) const
  645. {
  646. // Get quantized value
  647. uint8 height_sample = GetHeightSample(inX, inY);
  648. outNoCollision = height_sample == mSampleMask;
  649. // Add 0.5 to the quantized value to minimize the error (see constructor)
  650. return mOffset + mScale * Vec3(float(inX), inBlockOffset + (0.5f + height_sample) * inBlockScale, float(inY));
  651. }
  652. Vec3 HeightFieldShape::GetPosition(uint inX, uint inY) const
  653. {
  654. // Test if there are any samples
  655. if (mHeightSamples.empty())
  656. return mOffset + mScale * Vec3(float(inX), 0.0f, float(inY));
  657. // Get block location
  658. uint bx = inX / mBlockSize;
  659. uint by = inY / mBlockSize;
  660. // Calculate offset and stride
  661. uint num_blocks = GetNumBlocks();
  662. uint range_block_offset, range_block_stride;
  663. sGetRangeBlockOffsetAndStride(num_blocks, sGetMaxLevel(num_blocks), range_block_offset, range_block_stride);
  664. float offset, scale;
  665. GetBlockOffsetAndScale(bx, by, range_block_offset, range_block_stride, offset, scale);
  666. bool no_collision;
  667. return GetPosition(inX, inY, offset, scale, no_collision);
  668. }
  669. bool HeightFieldShape::IsNoCollision(uint inX, uint inY) const
  670. {
  671. return mHeightSamples.empty() || GetHeightSample(inX, inY) == mSampleMask;
  672. }
  673. bool HeightFieldShape::ProjectOntoSurface(Vec3Arg inLocalPosition, Vec3 &outSurfacePosition, SubShapeID &outSubShapeID) const
  674. {
  675. // Check if we have collision
  676. if (mHeightSamples.empty())
  677. return false;
  678. // Convert coordinate to integer space
  679. Vec3 integer_space = (inLocalPosition - mOffset) / mScale;
  680. // Get x coordinate and fraction
  681. float x_frac = integer_space.GetX();
  682. if (x_frac < 0.0f || x_frac >= mSampleCount - 1)
  683. return false;
  684. uint x = (uint)floor(x_frac);
  685. x_frac -= x;
  686. // Get y coordinate and fraction
  687. float y_frac = integer_space.GetZ();
  688. if (y_frac < 0.0f || y_frac >= mSampleCount - 1)
  689. return false;
  690. uint y = (uint)floor(y_frac);
  691. y_frac -= y;
  692. // If one of the diagonal points doesn't have collision, we don't have a height at this location
  693. if (IsNoCollision(x, y) || IsNoCollision(x + 1, y + 1))
  694. return false;
  695. if (y_frac >= x_frac)
  696. {
  697. // Left bottom triangle, test the 3rd point
  698. if (IsNoCollision(x, y + 1))
  699. return false;
  700. // Interpolate height value
  701. Vec3 v1 = GetPosition(x, y);
  702. Vec3 v2 = GetPosition(x, y + 1);
  703. Vec3 v3 = GetPosition(x + 1, y + 1);
  704. outSurfacePosition = v1 + y_frac * (v2 - v1) + x_frac * (v3 - v2);
  705. SubShapeIDCreator creator;
  706. outSubShapeID = EncodeSubShapeID(creator, x, y, 0);
  707. return true;
  708. }
  709. else
  710. {
  711. // Right top triangle, test the third point
  712. if (IsNoCollision(x + 1, y))
  713. return false;
  714. // Interpolate height value
  715. Vec3 v1 = GetPosition(x, y);
  716. Vec3 v2 = GetPosition(x + 1, y + 1);
  717. Vec3 v3 = GetPosition(x + 1, y);
  718. outSurfacePosition = v1 + y_frac * (v2 - v3) + x_frac * (v3 - v1);
  719. SubShapeIDCreator creator;
  720. outSubShapeID = EncodeSubShapeID(creator, x, y, 1);
  721. return true;
  722. }
  723. }
  724. void HeightFieldShape::GetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY, float *outHeights, uint inHeightsStride) const
  725. {
  726. if (inSizeX == 0 || inSizeY == 0)
  727. return;
  728. JPH_ASSERT(inX % mBlockSize == 0 && inY % mBlockSize == 0);
  729. JPH_ASSERT(inX < mSampleCount && inY < mSampleCount);
  730. JPH_ASSERT(inX + inSizeX <= mSampleCount && inY + inSizeY <= mSampleCount);
  731. // Test if there are any samples
  732. if (mHeightSamples.empty())
  733. {
  734. // No samples, return the offset
  735. float offset = mOffset.GetY();
  736. for (uint y = 0; y < inSizeY; ++y, outHeights += inHeightsStride)
  737. for (uint x = 0; x < inSizeX; ++x)
  738. outHeights[x] = offset;
  739. }
  740. else
  741. {
  742. // Calculate offset and stride
  743. uint num_blocks = GetNumBlocks();
  744. uint range_block_offset, range_block_stride;
  745. sGetRangeBlockOffsetAndStride(num_blocks, sGetMaxLevel(num_blocks), range_block_offset, range_block_stride);
  746. // Loop over blocks
  747. uint block_start_x = inX / mBlockSize;
  748. uint block_start_y = inY / mBlockSize;
  749. uint num_blocks_x = inSizeX / mBlockSize;
  750. uint num_blocks_y = inSizeY / mBlockSize;
  751. for (uint block_y = 0; block_y < num_blocks_y; ++block_y)
  752. for (uint block_x = 0; block_x < num_blocks_x; ++block_x)
  753. {
  754. // Get offset and scale for block
  755. float offset, scale;
  756. GetBlockOffsetAndScale(block_start_x + block_x, block_start_y + block_y, range_block_offset, range_block_stride, offset, scale);
  757. // Adjust by global offset and scale
  758. // Note: This is the math applied in GetPosition() written out to reduce calculations in the inner loop
  759. scale *= mScale.GetY();
  760. offset = mOffset.GetY() + mScale.GetY() * offset + 0.5f * scale;
  761. // Loop over samples in block
  762. for (uint sample_y = 0; sample_y < mBlockSize; ++sample_y)
  763. for (uint sample_x = 0; sample_x < mBlockSize; ++sample_x)
  764. {
  765. // Calculate output coordinate
  766. uint output_x = block_x * mBlockSize + sample_x;
  767. uint output_y = block_y * mBlockSize + sample_y;
  768. // Get quantized value
  769. uint8 height_sample = GetHeightSample(inX + output_x, inY + output_y);
  770. // Dequantize
  771. float h = height_sample != mSampleMask? offset + height_sample * scale : cNoCollisionValue;
  772. outHeights[output_y * inHeightsStride + output_x] = h;
  773. }
  774. }
  775. }
  776. }
  777. void HeightFieldShape::SetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY, const float *inHeights, uint inHeightsStride, TempAllocator &inAllocator, float inActiveEdgeCosThresholdAngle)
  778. {
  779. if (inSizeX == 0 || inSizeY == 0)
  780. return;
  781. JPH_ASSERT(!mHeightSamples.empty());
  782. JPH_ASSERT(inX % mBlockSize == 0 && inY % mBlockSize == 0);
  783. JPH_ASSERT(inX < mSampleCount && inY < mSampleCount);
  784. JPH_ASSERT(inX + inSizeX <= mSampleCount && inY + inSizeY <= mSampleCount);
  785. // If we have a block in negative x/y direction, we will affect its range so we need to take it into account
  786. bool need_temp_heights = false;
  787. uint affected_x = inX;
  788. uint affected_y = inY;
  789. uint affected_size_x = inSizeX;
  790. uint affected_size_y = inSizeY;
  791. if (inX > 0) { affected_x -= mBlockSize; affected_size_x += mBlockSize; need_temp_heights = true; }
  792. if (inY > 0) { affected_y -= mBlockSize; affected_size_y += mBlockSize; need_temp_heights = true; }
  793. // If we have a block in positive x/y direction, our ranges are affected by it so we need to take it into account
  794. uint heights_size_x = affected_size_x;
  795. uint heights_size_y = affected_size_y;
  796. if (inX + inSizeX < mSampleCount) { heights_size_x += mBlockSize; need_temp_heights = true; }
  797. if (inY + inSizeY < mSampleCount) { heights_size_y += mBlockSize; need_temp_heights = true; }
  798. // Get heights for affected area
  799. const float *heights;
  800. float *temp_heights;
  801. if (need_temp_heights)
  802. {
  803. // Fetch the surrounding height data (note we're forced to recompress this data with a potentially different range so there will be some precision loss here)
  804. temp_heights = (float *)inAllocator.Allocate(heights_size_x * heights_size_y * sizeof(float));
  805. heights = temp_heights;
  806. // We need to fill in the following areas:
  807. //
  808. // +-----------------+
  809. // | 2 |
  810. // |---+---------+---|
  811. // | | | |
  812. // | 3 | 1 | 4 |
  813. // | | | |
  814. // |---+---------+---|
  815. // | 5 |
  816. // +-----------------+
  817. //
  818. // 1. The area that is affected by the new heights (we just copy these)
  819. // 2-5. These areas are either needed to calculate the range of the affected blocks or they need to be recompressed with a different range
  820. uint offset_x = inX - affected_x;
  821. uint offset_y = inY - affected_y;
  822. // Area 2
  823. GetHeights(affected_x, affected_y, heights_size_x, offset_y, temp_heights, heights_size_x);
  824. float *area3_start = temp_heights + offset_y * heights_size_x;
  825. // Area 3
  826. GetHeights(affected_x, inY, offset_x, inSizeY, area3_start, heights_size_x);
  827. // Area 1
  828. float *area1_start = area3_start + offset_x;
  829. for (uint y = 0; y < inSizeY; ++y, area1_start += heights_size_x, inHeights += inHeightsStride)
  830. memcpy(area1_start, inHeights, inSizeX * sizeof(float));
  831. // Area 4
  832. uint area4_x = inX + inSizeX;
  833. GetHeights(area4_x, inY, affected_x + heights_size_x - area4_x, inSizeY, area3_start + area4_x - affected_x, heights_size_x);
  834. // Area 5
  835. uint area5_y = inY + inSizeY;
  836. float *area5_start = temp_heights + (area5_y - affected_y) * heights_size_x;
  837. GetHeights(affected_x, area5_y, heights_size_x, affected_y + heights_size_y - area5_y, area5_start, heights_size_x);
  838. }
  839. else
  840. {
  841. // We can directly use the input buffer because there are no extra edges to take into account
  842. heights = inHeights;
  843. heights_size_x = inHeightsStride;
  844. temp_heights = nullptr;
  845. }
  846. // Calculate offset and stride
  847. uint num_blocks = GetNumBlocks();
  848. uint range_block_offset, range_block_stride;
  849. uint max_level = sGetMaxLevel(num_blocks);
  850. sGetRangeBlockOffsetAndStride(num_blocks, max_level, range_block_offset, range_block_stride);
  851. // Loop over blocks
  852. uint block_start_x = affected_x / mBlockSize;
  853. uint block_start_y = affected_y / mBlockSize;
  854. uint num_blocks_x = affected_size_x / mBlockSize;
  855. uint num_blocks_y = affected_size_y / mBlockSize;
  856. for (uint block_y = 0, sample_start_y = 0; block_y < num_blocks_y; ++block_y, sample_start_y += mBlockSize)
  857. for (uint block_x = 0, sample_start_x = 0; block_x < num_blocks_x; ++block_x, sample_start_x += mBlockSize)
  858. {
  859. // Determine quantized min and max value for block
  860. // Note that we need to include 1 extra row in the positive x/y direction to account for connecting triangles
  861. int min_value = 0xffff;
  862. int max_value = 0;
  863. uint sample_x_end = min(sample_start_x + mBlockSize + 1, mSampleCount - affected_x);
  864. uint sample_y_end = min(sample_start_y + mBlockSize + 1, mSampleCount - affected_y);
  865. for (uint sample_y = sample_start_y; sample_y < sample_y_end; ++sample_y)
  866. for (uint sample_x = sample_start_x; sample_x < sample_x_end; ++sample_x)
  867. {
  868. float h = heights[sample_y * heights_size_x + sample_x];
  869. if (h != cNoCollisionValue)
  870. {
  871. int quantized_height = Clamp((int)floor((h - mOffset.GetY()) / mScale.GetY()), 0, int(cMaxHeightValue16 - 1));
  872. min_value = min(min_value, quantized_height);
  873. max_value = max(max_value, quantized_height + 1);
  874. }
  875. }
  876. if (min_value > max_value)
  877. min_value = max_value = cNoCollisionValue16;
  878. // Update range for block
  879. RangeBlock *range_block;
  880. uint index_in_block;
  881. GetRangeBlock(block_start_x + block_x, block_start_y + block_y, range_block_offset, range_block_stride, range_block, index_in_block);
  882. range_block->mMin[index_in_block] = uint16(min_value);
  883. range_block->mMax[index_in_block] = uint16(max_value);
  884. // Get offset and scale for block
  885. float offset_block = float(min_value);
  886. float scale_block = float(max_value - min_value) / float(mSampleMask);
  887. // Calculate scale and offset using the formula used in GetPosition() solved for the quantized height (excluding 0.5 because we round down while quantizing)
  888. float scale = scale_block * mScale.GetY();
  889. float offset = mOffset.GetY() + offset_block * mScale.GetY();
  890. // Loop over samples in block
  891. sample_x_end = sample_start_x + mBlockSize;
  892. sample_y_end = sample_start_y + mBlockSize;
  893. for (uint sample_y = sample_start_y; sample_y < sample_y_end; ++sample_y)
  894. for (uint sample_x = sample_start_x; sample_x < sample_x_end; ++sample_x)
  895. {
  896. // Quantize height
  897. float h = heights[sample_y * heights_size_x + sample_x];
  898. uint8 quantized_height = h != cNoCollisionValue? uint8(Clamp((int)floor((h - offset) / scale), 0, int(mSampleMask) - 1)) : mSampleMask;
  899. // Determine bit position of sample
  900. uint sample = ((affected_y + sample_y) * mSampleCount + affected_x + sample_x) * uint(mBitsPerSample);
  901. uint byte_pos = sample >> 3;
  902. uint bit_pos = sample & 0b111;
  903. // Update the height value sample
  904. JPH_ASSERT(byte_pos + 1 < mHeightSamples.size());
  905. uint8 *height_samples = mHeightSamples.data() + byte_pos;
  906. uint16 height_sample = uint16(height_samples[0]) | uint16(uint16(height_samples[1]) << 8);
  907. height_sample &= ~(uint16(mSampleMask) << bit_pos);
  908. height_sample |= uint16(quantized_height) << bit_pos;
  909. height_samples[0] = uint8(height_sample);
  910. height_samples[1] = uint8(height_sample >> 8);
  911. }
  912. }
  913. // Update active edges
  914. // Note that we must take an extra row on all sides to account for connecting triangles
  915. uint ae_x = inX > 1? inX - 2 : 0;
  916. uint ae_y = inY > 1? inY - 2 : 0;
  917. uint ae_sx = min(inX + inSizeX + 1, mSampleCount - 1) - ae_x;
  918. uint ae_sy = min(inY + inSizeY + 1, mSampleCount - 1) - ae_y;
  919. CalculateActiveEdges(ae_x, ae_y, ae_sx, ae_sy, heights, affected_x, affected_y, heights_size_x, 1.0f, inActiveEdgeCosThresholdAngle, inAllocator);
  920. // Free temporary buffer
  921. if (temp_heights != nullptr)
  922. inAllocator.Free(temp_heights, heights_size_x * heights_size_y * sizeof(float));
  923. // Update hierarchy of range blocks
  924. while (max_level > 1)
  925. {
  926. // Get offset and stride for destination blocks
  927. uint dst_range_block_offset, dst_range_block_stride;
  928. sGetRangeBlockOffsetAndStride(num_blocks >> 1, max_level - 1, dst_range_block_offset, dst_range_block_stride);
  929. // If we're starting halfway through a 2x2 block, we need to process one extra block since we take steps of 2 blocks below
  930. uint block_x_end = (block_start_x & 1) && block_start_x + num_blocks_x < num_blocks? num_blocks_x + 1 : num_blocks_x;
  931. uint block_y_end = (block_start_y & 1) && block_start_y + num_blocks_y < num_blocks? num_blocks_y + 1 : num_blocks_y;
  932. // Loop over all affected blocks
  933. for (uint block_y = 0; block_y < block_y_end; block_y += 2)
  934. for (uint block_x = 0; block_x < block_x_end; block_x += 2)
  935. {
  936. // Get source range block
  937. RangeBlock *src_range_block;
  938. uint index_in_src_block;
  939. GetRangeBlock(block_start_x + block_x, block_start_y + block_y, range_block_offset, range_block_stride, src_range_block, index_in_src_block);
  940. // Determine quantized min and max value for the entire 2x2 block
  941. uint16 min_value = 0xffff;
  942. uint16 max_value = 0;
  943. for (uint i = 0; i < 4; ++i)
  944. if (src_range_block->mMin[i] != cNoCollisionValue16)
  945. {
  946. min_value = min(min_value, src_range_block->mMin[i]);
  947. max_value = max(max_value, src_range_block->mMax[i]);
  948. }
  949. // Write to destination block
  950. RangeBlock *dst_range_block;
  951. uint index_in_dst_block;
  952. GetRangeBlock((block_start_x + block_x) >> 1, (block_start_y + block_y) >> 1, dst_range_block_offset, dst_range_block_stride, dst_range_block, index_in_dst_block);
  953. dst_range_block->mMin[index_in_dst_block] = uint16(min_value);
  954. dst_range_block->mMax[index_in_dst_block] = uint16(max_value);
  955. }
  956. // Go up one level
  957. --max_level;
  958. num_blocks >>= 1;
  959. block_start_x >>= 1;
  960. block_start_y >>= 1;
  961. num_blocks_x = min((num_blocks_x + 1) >> 1, num_blocks);
  962. num_blocks_y = min((num_blocks_y + 1) >> 1, num_blocks);
  963. // Update stride and offset for source to old destination
  964. range_block_offset = dst_range_block_offset;
  965. range_block_stride = dst_range_block_stride;
  966. }
  967. // Calculate new min and max sample for the entire height field
  968. mMinSample = 0xffff;
  969. mMaxSample = 0;
  970. for (uint i = 0; i < 4; ++i)
  971. if (mRangeBlocks[0].mMin[i] != cNoCollisionValue16)
  972. {
  973. mMinSample = min(mMinSample, mRangeBlocks[0].mMin[i]);
  974. mMaxSample = max(mMaxSample, mRangeBlocks[0].mMax[i]);
  975. }
  976. #ifdef JPH_DEBUG_RENDERER
  977. // Invalidate temporary rendering data
  978. mGeometry.clear();
  979. #endif
  980. }
  981. MassProperties HeightFieldShape::GetMassProperties() const
  982. {
  983. // Object should always be static, return default mass properties
  984. return MassProperties();
  985. }
  986. const PhysicsMaterial *HeightFieldShape::GetMaterial(uint inX, uint inY) const
  987. {
  988. if (mMaterials.empty())
  989. return PhysicsMaterial::sDefault;
  990. if (mMaterials.size() == 1)
  991. return mMaterials[0];
  992. uint count_min_1 = mSampleCount - 1;
  993. JPH_ASSERT(inX < count_min_1);
  994. JPH_ASSERT(inY < count_min_1);
  995. // Calculate at which bit the material index starts
  996. uint bit_pos = (inX + inY * count_min_1) * mNumBitsPerMaterialIndex;
  997. uint byte_pos = bit_pos >> 3;
  998. bit_pos &= 0b111;
  999. // Read the material index
  1000. JPH_ASSERT(byte_pos + 1 < mMaterialIndices.size());
  1001. const uint8 *material_indices = mMaterialIndices.data() + byte_pos;
  1002. uint16 material_index = uint16(material_indices[0]) + uint16(uint16(material_indices[1]) << 8);
  1003. material_index >>= bit_pos;
  1004. material_index &= (1 << mNumBitsPerMaterialIndex) - 1;
  1005. // Return the material
  1006. return mMaterials[material_index];
  1007. }
  1008. uint HeightFieldShape::GetSubShapeIDBits() const
  1009. {
  1010. // Need to store X, Y and 1 extra bit to specify the triangle number in the quad
  1011. return 2 * (32 - CountLeadingZeros(mSampleCount - 1)) + 1;
  1012. }
  1013. SubShapeID HeightFieldShape::EncodeSubShapeID(const SubShapeIDCreator &inCreator, uint inX, uint inY, uint inTriangle) const
  1014. {
  1015. return inCreator.PushID((inX + inY * mSampleCount) * 2 + inTriangle, GetSubShapeIDBits()).GetID();
  1016. }
  1017. void HeightFieldShape::DecodeSubShapeID(const SubShapeID &inSubShapeID, uint &outX, uint &outY, uint &outTriangle) const
  1018. {
  1019. // Decode sub shape id
  1020. SubShapeID remainder;
  1021. uint32 id = inSubShapeID.PopID(GetSubShapeIDBits(), remainder);
  1022. JPH_ASSERT(remainder.IsEmpty(), "Invalid subshape ID");
  1023. // Get triangle index
  1024. outTriangle = id & 1;
  1025. id >>= 1;
  1026. // Fetch the x and y coordinate
  1027. outX = id % mSampleCount;
  1028. outY = id / mSampleCount;
  1029. }
  1030. const PhysicsMaterial *HeightFieldShape::GetMaterial(const SubShapeID &inSubShapeID) const
  1031. {
  1032. // Decode ID
  1033. uint x, y, triangle;
  1034. DecodeSubShapeID(inSubShapeID, x, y, triangle);
  1035. // Fetch the material
  1036. return GetMaterial(x, y);
  1037. }
  1038. Vec3 HeightFieldShape::GetSurfaceNormal(const SubShapeID &inSubShapeID, Vec3Arg inLocalSurfacePosition) const
  1039. {
  1040. // Decode ID
  1041. uint x, y, triangle;
  1042. DecodeSubShapeID(inSubShapeID, x, y, triangle);
  1043. // Fetch vertices that both triangles share
  1044. Vec3 x1y1 = GetPosition(x, y);
  1045. Vec3 x2y2 = GetPosition(x + 1, y + 1);
  1046. // Get normal depending on which triangle was selected
  1047. Vec3 normal;
  1048. if (triangle == 0)
  1049. {
  1050. Vec3 x1y2 = GetPosition(x, y + 1);
  1051. normal = (x2y2 - x1y2).Cross(x1y1 - x1y2);
  1052. }
  1053. else
  1054. {
  1055. Vec3 x2y1 = GetPosition(x + 1, y);
  1056. normal = (x1y1 - x2y1).Cross(x2y2 - x2y1);
  1057. }
  1058. return normal.Normalized();
  1059. }
  1060. void HeightFieldShape::GetSupportingFace(const SubShapeID &inSubShapeID, Vec3Arg inDirection, Vec3Arg inScale, Mat44Arg inCenterOfMassTransform, SupportingFace &outVertices) const
  1061. {
  1062. // Decode ID
  1063. uint x, y, triangle;
  1064. DecodeSubShapeID(inSubShapeID, x, y, triangle);
  1065. // Fetch the triangle
  1066. outVertices.resize(3);
  1067. outVertices[0] = GetPosition(x, y);
  1068. Vec3 v2 = GetPosition(x + 1, y + 1);
  1069. if (triangle == 0)
  1070. {
  1071. outVertices[1] = GetPosition(x, y + 1);
  1072. outVertices[2] = v2;
  1073. }
  1074. else
  1075. {
  1076. outVertices[1] = v2;
  1077. outVertices[2] = GetPosition(x + 1, y);
  1078. }
  1079. // Flip triangle if scaled inside out
  1080. if (ScaleHelpers::IsInsideOut(inScale))
  1081. swap(outVertices[1], outVertices[2]);
  1082. // Transform to world space
  1083. Mat44 transform = inCenterOfMassTransform.PreScaled(inScale);
  1084. for (Vec3 &v : outVertices)
  1085. v = transform * v;
  1086. }
  1087. inline uint8 HeightFieldShape::GetEdgeFlags(uint inX, uint inY, uint inTriangle) const
  1088. {
  1089. JPH_ASSERT(inX < mSampleCount - 1 && inY < mSampleCount - 1);
  1090. if (inTriangle == 0)
  1091. {
  1092. // The edge flags for this triangle are directly stored, find the right 3 bits
  1093. uint bit_pos = 3 * (inX + inY * (mSampleCount - 1));
  1094. uint byte_pos = bit_pos >> 3;
  1095. bit_pos &= 0b111;
  1096. JPH_ASSERT(byte_pos + 1 < mActiveEdges.size());
  1097. const uint8 *active_edges = mActiveEdges.data() + byte_pos;
  1098. uint16 edge_flags = uint16(active_edges[0]) + uint16(uint16(active_edges[1]) << 8);
  1099. return uint8(edge_flags >> bit_pos) & 0b111;
  1100. }
  1101. else
  1102. {
  1103. // We don't store this triangle directly, we need to look at our three neighbours to construct the edge flags
  1104. uint8 edge0 = (GetEdgeFlags(inX, inY, 0) & 0b100) != 0? 0b001 : 0; // Diagonal edge
  1105. uint8 edge1 = inX == mSampleCount - 2 || (GetEdgeFlags(inX + 1, inY, 0) & 0b001) != 0? 0b010 : 0; // Vertical edge
  1106. uint8 edge2 = inY == 0 || (GetEdgeFlags(inX, inY - 1, 0) & 0b010) != 0? 0b100 : 0; // Horizontal edge
  1107. return edge0 | edge1 | edge2;
  1108. }
  1109. }
  1110. AABox HeightFieldShape::GetLocalBounds() const
  1111. {
  1112. if (mMinSample == cNoCollisionValue16)
  1113. {
  1114. // This whole height field shape doesn't have any collision, return the center point
  1115. Vec3 center = mOffset + 0.5f * mScale * Vec3(float(mSampleCount - 1), 0.0f, float(mSampleCount - 1));
  1116. return AABox(center, center);
  1117. }
  1118. else
  1119. {
  1120. // Bounding box based on min and max sample height
  1121. Vec3 bmin = mOffset + mScale * Vec3(0.0f, float(mMinSample), 0.0f);
  1122. Vec3 bmax = mOffset + mScale * Vec3(float(mSampleCount - 1), float(mMaxSample), float(mSampleCount - 1));
  1123. return AABox(bmin, bmax);
  1124. }
  1125. }
  1126. #ifdef JPH_DEBUG_RENDERER
  1127. void HeightFieldShape::Draw(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, Vec3Arg inScale, ColorArg inColor, bool inUseMaterialColors, bool inDrawWireframe) const
  1128. {
  1129. // Don't draw anything if we don't have any collision
  1130. if (mHeightSamples.empty())
  1131. return;
  1132. // Reset the batch if we switch coloring mode
  1133. if (mCachedUseMaterialColors != inUseMaterialColors)
  1134. {
  1135. mGeometry.clear();
  1136. mCachedUseMaterialColors = inUseMaterialColors;
  1137. }
  1138. if (mGeometry.empty())
  1139. {
  1140. // Divide terrain in triangle batches of max 64x64x2 triangles to allow better culling of the terrain
  1141. uint32 block_size = min<uint32>(mSampleCount, 64);
  1142. for (uint32 by = 0; by < mSampleCount; by += block_size)
  1143. for (uint32 bx = 0; bx < mSampleCount; bx += block_size)
  1144. {
  1145. // Create vertices for a block
  1146. Array<DebugRenderer::Triangle> triangles;
  1147. triangles.resize(block_size * block_size * 2);
  1148. DebugRenderer::Triangle *out_tri = &triangles[0];
  1149. for (uint32 y = by, max_y = min(by + block_size, mSampleCount - 1); y < max_y; ++y)
  1150. for (uint32 x = bx, max_x = min(bx + block_size, mSampleCount - 1); x < max_x; ++x)
  1151. if (!IsNoCollision(x, y) && !IsNoCollision(x + 1, y + 1))
  1152. {
  1153. Vec3 x1y1 = GetPosition(x, y);
  1154. Vec3 x2y2 = GetPosition(x + 1, y + 1);
  1155. Color color = inUseMaterialColors? GetMaterial(x, y)->GetDebugColor() : Color::sWhite;
  1156. if (!IsNoCollision(x, y + 1))
  1157. {
  1158. Vec3 x1y2 = GetPosition(x, y + 1);
  1159. x1y1.StoreFloat3(&out_tri->mV[0].mPosition);
  1160. x1y2.StoreFloat3(&out_tri->mV[1].mPosition);
  1161. x2y2.StoreFloat3(&out_tri->mV[2].mPosition);
  1162. Vec3 normal = (x2y2 - x1y2).Cross(x1y1 - x1y2).Normalized();
  1163. for (DebugRenderer::Vertex &v : out_tri->mV)
  1164. {
  1165. v.mColor = color;
  1166. v.mUV = Float2(0, 0);
  1167. normal.StoreFloat3(&v.mNormal);
  1168. }
  1169. ++out_tri;
  1170. }
  1171. if (!IsNoCollision(x + 1, y))
  1172. {
  1173. Vec3 x2y1 = GetPosition(x + 1, y);
  1174. x1y1.StoreFloat3(&out_tri->mV[0].mPosition);
  1175. x2y2.StoreFloat3(&out_tri->mV[1].mPosition);
  1176. x2y1.StoreFloat3(&out_tri->mV[2].mPosition);
  1177. Vec3 normal = (x1y1 - x2y1).Cross(x2y2 - x2y1).Normalized();
  1178. for (DebugRenderer::Vertex &v : out_tri->mV)
  1179. {
  1180. v.mColor = color;
  1181. v.mUV = Float2(0, 0);
  1182. normal.StoreFloat3(&v.mNormal);
  1183. }
  1184. ++out_tri;
  1185. }
  1186. }
  1187. // Resize triangles array to actual amount of triangles written
  1188. size_t num_triangles = out_tri - &triangles[0];
  1189. triangles.resize(num_triangles);
  1190. // Create batch
  1191. if (num_triangles > 0)
  1192. mGeometry.push_back(new DebugRenderer::Geometry(inRenderer->CreateTriangleBatch(triangles), DebugRenderer::sCalculateBounds(&triangles[0].mV[0], int(3 * num_triangles))));
  1193. }
  1194. }
  1195. // Get transform including scale
  1196. RMat44 transform = inCenterOfMassTransform.PreScaled(inScale);
  1197. // Test if the shape is scaled inside out
  1198. DebugRenderer::ECullMode cull_mode = ScaleHelpers::IsInsideOut(inScale)? DebugRenderer::ECullMode::CullFrontFace : DebugRenderer::ECullMode::CullBackFace;
  1199. // Determine the draw mode
  1200. DebugRenderer::EDrawMode draw_mode = inDrawWireframe? DebugRenderer::EDrawMode::Wireframe : DebugRenderer::EDrawMode::Solid;
  1201. // Draw the geometry
  1202. for (const DebugRenderer::GeometryRef &b : mGeometry)
  1203. inRenderer->DrawGeometry(transform, inColor, b, cull_mode, DebugRenderer::ECastShadow::On, draw_mode);
  1204. if (sDrawTriangleOutlines)
  1205. {
  1206. struct Visitor
  1207. {
  1208. JPH_INLINE explicit Visitor(const HeightFieldShape *inShape, DebugRenderer *inRenderer, RMat44Arg inTransform) :
  1209. mShape(inShape),
  1210. mRenderer(inRenderer),
  1211. mTransform(inTransform)
  1212. {
  1213. }
  1214. JPH_INLINE bool ShouldAbort() const
  1215. {
  1216. return false;
  1217. }
  1218. JPH_INLINE bool ShouldVisitRangeBlock([[maybe_unused]] int inStackTop) const
  1219. {
  1220. return true;
  1221. }
  1222. JPH_INLINE int VisitRangeBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, [[maybe_unused]] int inStackTop) const
  1223. {
  1224. UVec4 valid = Vec4::sLessOrEqual(inBoundsMinY, inBoundsMaxY);
  1225. return CountAndSortTrues(valid, ioProperties);
  1226. }
  1227. JPH_INLINE void VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2) const
  1228. {
  1229. // Determine active edges
  1230. uint8 active_edges = mShape->GetEdgeFlags(inX, inY, inTriangle);
  1231. // Loop through edges
  1232. Vec3 v[] = { inV0, inV1, inV2 };
  1233. for (uint edge_idx = 0; edge_idx < 3; ++edge_idx)
  1234. {
  1235. RVec3 v1 = mTransform * v[edge_idx];
  1236. RVec3 v2 = mTransform * v[(edge_idx + 1) % 3];
  1237. // Draw active edge as a green arrow, other edges as grey
  1238. if (active_edges & (1 << edge_idx))
  1239. mRenderer->DrawArrow(v1, v2, Color::sGreen, 0.01f);
  1240. else
  1241. mRenderer->DrawLine(v1, v2, Color::sGrey);
  1242. }
  1243. }
  1244. const HeightFieldShape *mShape;
  1245. DebugRenderer * mRenderer;
  1246. RMat44 mTransform;
  1247. };
  1248. Visitor visitor(this, inRenderer, inCenterOfMassTransform.PreScaled(inScale));
  1249. WalkHeightField(visitor);
  1250. }
  1251. }
  1252. #endif // JPH_DEBUG_RENDERER
  1253. class HeightFieldShape::DecodingContext
  1254. {
  1255. public:
  1256. JPH_INLINE explicit DecodingContext(const HeightFieldShape *inShape) :
  1257. mShape(inShape)
  1258. {
  1259. static_assert(sizeof(sGridOffsets) / sizeof(uint) == cNumBitsXY + 1, "Offsets array is not long enough");
  1260. // Construct root stack entry
  1261. mPropertiesStack[0] = 0; // level: 0, x: 0, y: 0
  1262. }
  1263. template <class Visitor>
  1264. JPH_INLINE void WalkHeightField(Visitor &ioVisitor)
  1265. {
  1266. // Early out if there's no collision
  1267. if (mShape->mHeightSamples.empty())
  1268. return;
  1269. // Precalculate values relating to sample count
  1270. uint32 sample_count = mShape->mSampleCount;
  1271. UVec4 sample_count_min_1 = UVec4::sReplicate(sample_count - 1);
  1272. // Precalculate values relating to block size
  1273. uint32 block_size = mShape->mBlockSize;
  1274. uint32 block_size_plus_1 = block_size + 1;
  1275. uint num_blocks = mShape->GetNumBlocks();
  1276. uint num_blocks_min_1 = num_blocks - 1;
  1277. uint max_level = HeightFieldShape::sGetMaxLevel(num_blocks);
  1278. uint32 max_stride = (num_blocks + 1) >> 1;
  1279. // Precalculate range block offset and stride for GetBlockOffsetAndScale
  1280. uint range_block_offset, range_block_stride;
  1281. sGetRangeBlockOffsetAndStride(num_blocks, max_level, range_block_offset, range_block_stride);
  1282. // Allocate space for vertices and 'no collision' flags
  1283. int array_size = Square(block_size_plus_1);
  1284. Vec3 *vertices = reinterpret_cast<Vec3 *>(JPH_STACK_ALLOC(array_size * sizeof(Vec3)));
  1285. bool *no_collision = reinterpret_cast<bool *>(JPH_STACK_ALLOC(array_size * sizeof(bool)));
  1286. // Splat offsets
  1287. Vec4 ox = mShape->mOffset.SplatX();
  1288. Vec4 oy = mShape->mOffset.SplatY();
  1289. Vec4 oz = mShape->mOffset.SplatZ();
  1290. // Splat scales
  1291. Vec4 sx = mShape->mScale.SplatX();
  1292. Vec4 sy = mShape->mScale.SplatY();
  1293. Vec4 sz = mShape->mScale.SplatZ();
  1294. do
  1295. {
  1296. // Decode properties
  1297. uint32 properties_top = mPropertiesStack[mTop];
  1298. uint32 x = properties_top & cMaskBitsXY;
  1299. uint32 y = (properties_top >> cNumBitsXY) & cMaskBitsXY;
  1300. uint32 level = properties_top >> cLevelShift;
  1301. if (level >= max_level)
  1302. {
  1303. // Determine actual range of samples (minus one because we eventually want to iterate over the triangles, not the samples)
  1304. uint32 min_x = x * block_size;
  1305. uint32 max_x = min_x + block_size;
  1306. uint32 min_y = y * block_size;
  1307. uint32 max_y = min_y + block_size;
  1308. // Decompress vertices of block at (x, y)
  1309. Vec3 *dst_vertex = vertices;
  1310. bool *dst_no_collision = no_collision;
  1311. float block_offset, block_scale;
  1312. mShape->GetBlockOffsetAndScale(x, y, range_block_offset, range_block_stride, block_offset, block_scale);
  1313. for (uint32 v_y = min_y; v_y < max_y; ++v_y)
  1314. {
  1315. for (uint32 v_x = min_x; v_x < max_x; ++v_x)
  1316. {
  1317. *dst_vertex = mShape->GetPosition(v_x, v_y, block_offset, block_scale, *dst_no_collision);
  1318. ++dst_vertex;
  1319. ++dst_no_collision;
  1320. }
  1321. // Skip last column, these values come from a different block
  1322. ++dst_vertex;
  1323. ++dst_no_collision;
  1324. }
  1325. // Decompress block (x + 1, y)
  1326. uint32 max_x_decrement = 0;
  1327. if (x < num_blocks_min_1)
  1328. {
  1329. dst_vertex = vertices + block_size;
  1330. dst_no_collision = no_collision + block_size;
  1331. mShape->GetBlockOffsetAndScale(x + 1, y, range_block_offset, range_block_stride, block_offset, block_scale);
  1332. for (uint32 v_y = min_y; v_y < max_y; ++v_y)
  1333. {
  1334. *dst_vertex = mShape->GetPosition(max_x, v_y, block_offset, block_scale, *dst_no_collision);
  1335. dst_vertex += block_size_plus_1;
  1336. dst_no_collision += block_size_plus_1;
  1337. }
  1338. }
  1339. else
  1340. max_x_decrement = 1; // We don't have a next block, one less triangle to test
  1341. // Decompress block (x, y + 1)
  1342. if (y < num_blocks_min_1)
  1343. {
  1344. uint start = block_size * block_size_plus_1;
  1345. dst_vertex = vertices + start;
  1346. dst_no_collision = no_collision + start;
  1347. mShape->GetBlockOffsetAndScale(x, y + 1, range_block_offset, range_block_stride, block_offset, block_scale);
  1348. for (uint32 v_x = min_x; v_x < max_x; ++v_x)
  1349. {
  1350. *dst_vertex = mShape->GetPosition(v_x, max_y, block_offset, block_scale, *dst_no_collision);
  1351. ++dst_vertex;
  1352. ++dst_no_collision;
  1353. }
  1354. // Decompress single sample of block at (x + 1, y + 1)
  1355. if (x < num_blocks_min_1)
  1356. {
  1357. mShape->GetBlockOffsetAndScale(x + 1, y + 1, range_block_offset, range_block_stride, block_offset, block_scale);
  1358. *dst_vertex = mShape->GetPosition(max_x, max_y, block_offset, block_scale, *dst_no_collision);
  1359. }
  1360. }
  1361. else
  1362. --max_y; // We don't have a next block, one less triangle to test
  1363. // Update max_x (we've been using it so we couldn't update it earlier)
  1364. max_x -= max_x_decrement;
  1365. // We're going to divide the vertices in 4 blocks to do one more runtime sub-division, calculate the ranges of those blocks
  1366. struct Range
  1367. {
  1368. uint32 mMinX, mMinY, mNumTrianglesX, mNumTrianglesY;
  1369. };
  1370. uint32 half_block_size = block_size >> 1;
  1371. uint32 block_size_x = max_x - min_x - half_block_size;
  1372. uint32 block_size_y = max_y - min_y - half_block_size;
  1373. Range ranges[] =
  1374. {
  1375. { 0, 0, half_block_size, half_block_size },
  1376. { half_block_size, 0, block_size_x, half_block_size },
  1377. { 0, half_block_size, half_block_size, block_size_y },
  1378. { half_block_size, half_block_size, block_size_x, block_size_y },
  1379. };
  1380. // Calculate the min and max of each of the blocks
  1381. Mat44 block_min, block_max;
  1382. for (int block = 0; block < 4; ++block)
  1383. {
  1384. // Get the range for this block
  1385. const Range &range = ranges[block];
  1386. uint32 start = range.mMinX + range.mMinY * block_size_plus_1;
  1387. uint32 size_x_plus_1 = range.mNumTrianglesX + 1;
  1388. uint32 size_y_plus_1 = range.mNumTrianglesY + 1;
  1389. // Calculate where to start reading
  1390. const Vec3 *src_vertex = vertices + start;
  1391. const bool *src_no_collision = no_collision + start;
  1392. uint32 stride = block_size_plus_1 - size_x_plus_1;
  1393. // Start range with a very large inside-out box
  1394. Vec3 value_min = Vec3::sReplicate(1.0e30f);
  1395. Vec3 value_max = Vec3::sReplicate(-1.0e30f);
  1396. // Loop over the samples to determine the min and max of this block
  1397. for (uint32 block_y = 0; block_y < size_y_plus_1; ++block_y)
  1398. {
  1399. for (uint32 block_x = 0; block_x < size_x_plus_1; ++block_x)
  1400. {
  1401. if (!*src_no_collision)
  1402. {
  1403. value_min = Vec3::sMin(value_min, *src_vertex);
  1404. value_max = Vec3::sMax(value_max, *src_vertex);
  1405. }
  1406. ++src_vertex;
  1407. ++src_no_collision;
  1408. }
  1409. src_vertex += stride;
  1410. src_no_collision += stride;
  1411. }
  1412. block_min.SetColumn4(block, Vec4(value_min));
  1413. block_max.SetColumn4(block, Vec4(value_max));
  1414. }
  1415. #ifdef JPH_DEBUG_HEIGHT_FIELD
  1416. // Draw the bounding boxes of the sub-nodes
  1417. for (int block = 0; block < 4; ++block)
  1418. {
  1419. AABox bounds(block_min.GetColumn3(block), block_max.GetColumn3(block));
  1420. if (bounds.IsValid())
  1421. DebugRenderer::sInstance->DrawWireBox(bounds, Color::sYellow);
  1422. }
  1423. #endif // JPH_DEBUG_HEIGHT_FIELD
  1424. // Transpose so we have the mins and maxes of each of the blocks in rows instead of columns
  1425. Mat44 transposed_min = block_min.Transposed();
  1426. Mat44 transposed_max = block_max.Transposed();
  1427. // Check which blocks collide
  1428. // Note: At this point we don't use our own stack but we do allow the visitor to use its own stack
  1429. // to store collision distances so that we can still early out when no closer hits have been found.
  1430. UVec4 colliding_blocks(0, 1, 2, 3);
  1431. int num_results = ioVisitor.VisitRangeBlock(transposed_min.GetColumn4(0), transposed_min.GetColumn4(1), transposed_min.GetColumn4(2), transposed_max.GetColumn4(0), transposed_max.GetColumn4(1), transposed_max.GetColumn4(2), colliding_blocks, mTop);
  1432. // Loop through the results backwards (closest first)
  1433. int result = num_results - 1;
  1434. while (result >= 0)
  1435. {
  1436. // Calculate the min and max of this block
  1437. uint32 block = colliding_blocks[result];
  1438. const Range &range = ranges[block];
  1439. uint32 block_min_x = min_x + range.mMinX;
  1440. uint32 block_max_x = block_min_x + range.mNumTrianglesX;
  1441. uint32 block_min_y = min_y + range.mMinY;
  1442. uint32 block_max_y = block_min_y + range.mNumTrianglesY;
  1443. // Loop triangles
  1444. for (uint32 v_y = block_min_y; v_y < block_max_y; ++v_y)
  1445. for (uint32 v_x = block_min_x; v_x < block_max_x; ++v_x)
  1446. {
  1447. // Get first vertex
  1448. const int offset = (v_y - min_y) * block_size_plus_1 + (v_x - min_x);
  1449. const Vec3 *start_vertex = vertices + offset;
  1450. const bool *start_no_collision = no_collision + offset;
  1451. // Check if vertices shared by both triangles have collision
  1452. if (!start_no_collision[0] && !start_no_collision[block_size_plus_1 + 1])
  1453. {
  1454. // Loop 2 triangles
  1455. for (uint t = 0; t < 2; ++t)
  1456. {
  1457. // Determine triangle vertices
  1458. Vec3 v0, v1, v2;
  1459. if (t == 0)
  1460. {
  1461. // Check third vertex
  1462. if (start_no_collision[block_size_plus_1])
  1463. continue;
  1464. // Get vertices for triangle
  1465. v0 = start_vertex[0];
  1466. v1 = start_vertex[block_size_plus_1];
  1467. v2 = start_vertex[block_size_plus_1 + 1];
  1468. }
  1469. else
  1470. {
  1471. // Check third vertex
  1472. if (start_no_collision[1])
  1473. continue;
  1474. // Get vertices for triangle
  1475. v0 = start_vertex[0];
  1476. v1 = start_vertex[block_size_plus_1 + 1];
  1477. v2 = start_vertex[1];
  1478. }
  1479. #ifdef JPH_DEBUG_HEIGHT_FIELD
  1480. DebugRenderer::sInstance->DrawWireTriangle(RVec3(v0), RVec3(v1), RVec3(v2), Color::sWhite);
  1481. #endif
  1482. // Call visitor
  1483. ioVisitor.VisitTriangle(v_x, v_y, t, v0, v1, v2);
  1484. // Check if we're done
  1485. if (ioVisitor.ShouldAbort())
  1486. return;
  1487. }
  1488. }
  1489. }
  1490. // Fetch next block until we find one that the visitor wants to see
  1491. do
  1492. --result;
  1493. while (result >= 0 && !ioVisitor.ShouldVisitRangeBlock(mTop + result));
  1494. }
  1495. }
  1496. else
  1497. {
  1498. // Visit child grid
  1499. uint32 stride = min(1U << level, max_stride); // At the most detailed level we store a non-power of 2 number of blocks
  1500. uint32 offset = sGridOffsets[level] + stride * y + x;
  1501. // Decode min/max height
  1502. UVec4 block = UVec4::sLoadInt4Aligned(reinterpret_cast<const uint32 *>(&mShape->mRangeBlocks[offset]));
  1503. Vec4 bounds_miny = oy + sy * block.Expand4Uint16Lo().ToFloat();
  1504. Vec4 bounds_maxy = oy + sy * block.Expand4Uint16Hi().ToFloat();
  1505. // Calculate size of one cell at this grid level
  1506. UVec4 internal_cell_size = UVec4::sReplicate(block_size << (max_level - level - 1)); // subtract 1 from level because we have an internal grid of 2x2
  1507. // Calculate min/max x and z
  1508. UVec4 two_x = UVec4::sReplicate(2 * x); // multiply by two because we have an internal grid of 2x2
  1509. Vec4 bounds_minx = ox + sx * (internal_cell_size * (two_x + UVec4(0, 1, 0, 1))).ToFloat();
  1510. Vec4 bounds_maxx = ox + sx * UVec4::sMin(internal_cell_size * (two_x + UVec4(1, 2, 1, 2)), sample_count_min_1).ToFloat();
  1511. UVec4 two_y = UVec4::sReplicate(2 * y);
  1512. Vec4 bounds_minz = oz + sz * (internal_cell_size * (two_y + UVec4(0, 0, 1, 1))).ToFloat();
  1513. Vec4 bounds_maxz = oz + sz * UVec4::sMin(internal_cell_size * (two_y + UVec4(1, 1, 2, 2)), sample_count_min_1).ToFloat();
  1514. // Calculate properties of child blocks
  1515. UVec4 properties = UVec4::sReplicate(((level + 1) << cLevelShift) + (y << (cNumBitsXY + 1)) + (x << 1)) + UVec4(0, 1, 1 << cNumBitsXY, (1 << cNumBitsXY) + 1);
  1516. #ifdef JPH_DEBUG_HEIGHT_FIELD
  1517. // Draw boxes
  1518. for (int i = 0; i < 4; ++i)
  1519. {
  1520. AABox b(Vec3(bounds_minx[i], bounds_miny[i], bounds_minz[i]), Vec3(bounds_maxx[i], bounds_maxy[i], bounds_maxz[i]));
  1521. if (b.IsValid())
  1522. DebugRenderer::sInstance->DrawWireBox(b, Color::sGreen);
  1523. }
  1524. #endif
  1525. // Check which sub nodes to visit
  1526. int num_results = ioVisitor.VisitRangeBlock(bounds_minx, bounds_miny, bounds_minz, bounds_maxx, bounds_maxy, bounds_maxz, properties, mTop);
  1527. // Push them onto the stack
  1528. JPH_ASSERT(mTop + 4 < cStackSize);
  1529. properties.StoreInt4(&mPropertiesStack[mTop]);
  1530. mTop += num_results;
  1531. }
  1532. // Check if we're done
  1533. if (ioVisitor.ShouldAbort())
  1534. return;
  1535. // Fetch next node until we find one that the visitor wants to see
  1536. do
  1537. --mTop;
  1538. while (mTop >= 0 && !ioVisitor.ShouldVisitRangeBlock(mTop));
  1539. }
  1540. while (mTop >= 0);
  1541. }
  1542. // This can be used to have the visitor early out (ioVisitor.ShouldAbort() returns true) and later continue again (call WalkHeightField() again)
  1543. JPH_INLINE bool IsDoneWalking() const
  1544. {
  1545. return mTop < 0;
  1546. }
  1547. private:
  1548. const HeightFieldShape * mShape;
  1549. int mTop = 0;
  1550. uint32 mPropertiesStack[cStackSize];
  1551. };
  1552. template <class Visitor>
  1553. JPH_INLINE void HeightFieldShape::WalkHeightField(Visitor &ioVisitor) const
  1554. {
  1555. DecodingContext ctx(this);
  1556. ctx.WalkHeightField(ioVisitor);
  1557. }
  1558. bool HeightFieldShape::CastRay(const RayCast &inRay, const SubShapeIDCreator &inSubShapeIDCreator, RayCastResult &ioHit) const
  1559. {
  1560. JPH_PROFILE_FUNCTION();
  1561. struct Visitor
  1562. {
  1563. JPH_INLINE explicit Visitor(const HeightFieldShape *inShape, const RayCast &inRay, const SubShapeIDCreator &inSubShapeIDCreator, RayCastResult &ioHit) :
  1564. mHit(ioHit),
  1565. mRayOrigin(inRay.mOrigin),
  1566. mRayDirection(inRay.mDirection),
  1567. mRayInvDirection(inRay.mDirection),
  1568. mShape(inShape),
  1569. mSubShapeIDCreator(inSubShapeIDCreator)
  1570. {
  1571. }
  1572. JPH_INLINE bool ShouldAbort() const
  1573. {
  1574. return mHit.mFraction <= 0.0f;
  1575. }
  1576. JPH_INLINE bool ShouldVisitRangeBlock(int inStackTop) const
  1577. {
  1578. return mDistanceStack[inStackTop] < mHit.mFraction;
  1579. }
  1580. JPH_INLINE int VisitRangeBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop)
  1581. {
  1582. // Test bounds of 4 children
  1583. Vec4 distance = RayAABox4(mRayOrigin, mRayInvDirection, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  1584. // Sort so that highest values are first (we want to first process closer hits and we process stack top to bottom)
  1585. return SortReverseAndStore(distance, mHit.mFraction, ioProperties, &mDistanceStack[inStackTop]);
  1586. }
  1587. JPH_INLINE void VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2)
  1588. {
  1589. float fraction = RayTriangle(mRayOrigin, mRayDirection, inV0, inV1, inV2);
  1590. if (fraction < mHit.mFraction)
  1591. {
  1592. // It's a closer hit
  1593. mHit.mFraction = fraction;
  1594. mHit.mSubShapeID2 = mShape->EncodeSubShapeID(mSubShapeIDCreator, inX, inY, inTriangle);
  1595. mReturnValue = true;
  1596. }
  1597. }
  1598. RayCastResult & mHit;
  1599. Vec3 mRayOrigin;
  1600. Vec3 mRayDirection;
  1601. RayInvDirection mRayInvDirection;
  1602. const HeightFieldShape *mShape;
  1603. SubShapeIDCreator mSubShapeIDCreator;
  1604. bool mReturnValue = false;
  1605. float mDistanceStack[cStackSize];
  1606. };
  1607. Visitor visitor(this, inRay, inSubShapeIDCreator, ioHit);
  1608. WalkHeightField(visitor);
  1609. return visitor.mReturnValue;
  1610. }
  1611. void HeightFieldShape::CastRay(const RayCast &inRay, const RayCastSettings &inRayCastSettings, const SubShapeIDCreator &inSubShapeIDCreator, CastRayCollector &ioCollector, const ShapeFilter &inShapeFilter) const
  1612. {
  1613. JPH_PROFILE_FUNCTION();
  1614. // Test shape filter
  1615. if (!inShapeFilter.ShouldCollide(this, inSubShapeIDCreator.GetID()))
  1616. return;
  1617. struct Visitor
  1618. {
  1619. JPH_INLINE explicit Visitor(const HeightFieldShape *inShape, const RayCast &inRay, const RayCastSettings &inRayCastSettings, const SubShapeIDCreator &inSubShapeIDCreator, CastRayCollector &ioCollector) :
  1620. mCollector(ioCollector),
  1621. mRayOrigin(inRay.mOrigin),
  1622. mRayDirection(inRay.mDirection),
  1623. mRayInvDirection(inRay.mDirection),
  1624. mBackFaceMode(inRayCastSettings.mBackFaceMode),
  1625. mShape(inShape),
  1626. mSubShapeIDCreator(inSubShapeIDCreator)
  1627. {
  1628. }
  1629. JPH_INLINE bool ShouldAbort() const
  1630. {
  1631. return mCollector.ShouldEarlyOut();
  1632. }
  1633. JPH_INLINE bool ShouldVisitRangeBlock(int inStackTop) const
  1634. {
  1635. return mDistanceStack[inStackTop] < mCollector.GetEarlyOutFraction();
  1636. }
  1637. JPH_INLINE int VisitRangeBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop)
  1638. {
  1639. // Test bounds of 4 children
  1640. Vec4 distance = RayAABox4(mRayOrigin, mRayInvDirection, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  1641. // Sort so that highest values are first (we want to first process closer hits and we process stack top to bottom)
  1642. return SortReverseAndStore(distance, mCollector.GetEarlyOutFraction(), ioProperties, &mDistanceStack[inStackTop]);
  1643. }
  1644. JPH_INLINE void VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2) const
  1645. {
  1646. // Back facing check
  1647. if (mBackFaceMode == EBackFaceMode::IgnoreBackFaces && (inV2 - inV0).Cross(inV1 - inV0).Dot(mRayDirection) < 0)
  1648. return;
  1649. // Check the triangle
  1650. float fraction = RayTriangle(mRayOrigin, mRayDirection, inV0, inV1, inV2);
  1651. if (fraction < mCollector.GetEarlyOutFraction())
  1652. {
  1653. RayCastResult hit;
  1654. hit.mBodyID = TransformedShape::sGetBodyID(mCollector.GetContext());
  1655. hit.mFraction = fraction;
  1656. hit.mSubShapeID2 = mShape->EncodeSubShapeID(mSubShapeIDCreator, inX, inY, inTriangle);
  1657. mCollector.AddHit(hit);
  1658. }
  1659. }
  1660. CastRayCollector & mCollector;
  1661. Vec3 mRayOrigin;
  1662. Vec3 mRayDirection;
  1663. RayInvDirection mRayInvDirection;
  1664. EBackFaceMode mBackFaceMode;
  1665. const HeightFieldShape *mShape;
  1666. SubShapeIDCreator mSubShapeIDCreator;
  1667. float mDistanceStack[cStackSize];
  1668. };
  1669. Visitor visitor(this, inRay, inRayCastSettings, inSubShapeIDCreator, ioCollector);
  1670. WalkHeightField(visitor);
  1671. }
  1672. void HeightFieldShape::CollidePoint(Vec3Arg inPoint, const SubShapeIDCreator &inSubShapeIDCreator, CollidePointCollector &ioCollector, const ShapeFilter &inShapeFilter) const
  1673. {
  1674. // A height field doesn't have volume, so we can't test insideness
  1675. }
  1676. void HeightFieldShape::CollideSoftBodyVertices(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, SoftBodyVertex *ioVertices, uint inNumVertices, float inDeltaTime, Vec3Arg inDisplacementDueToGravity, int inCollidingShapeIndex) const
  1677. {
  1678. sCollideSoftBodyVerticesUsingRayCast(*this, inCenterOfMassTransform, inScale, ioVertices, inNumVertices, inDeltaTime, inDisplacementDueToGravity, inCollidingShapeIndex);
  1679. }
  1680. void HeightFieldShape::sCastConvexVsHeightField(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, const Shape *inShape, Vec3Arg inScale, [[maybe_unused]] const ShapeFilter &inShapeFilter, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, CastShapeCollector &ioCollector)
  1681. {
  1682. JPH_PROFILE_FUNCTION();
  1683. struct Visitor : public CastConvexVsTriangles
  1684. {
  1685. using CastConvexVsTriangles::CastConvexVsTriangles;
  1686. JPH_INLINE bool ShouldAbort() const
  1687. {
  1688. return mCollector.ShouldEarlyOut();
  1689. }
  1690. JPH_INLINE bool ShouldVisitRangeBlock(int inStackTop) const
  1691. {
  1692. return mDistanceStack[inStackTop] < mCollector.GetPositiveEarlyOutFraction();
  1693. }
  1694. JPH_INLINE int VisitRangeBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop)
  1695. {
  1696. // Scale the bounding boxes of this node
  1697. Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;
  1698. AABox4Scale(mScale, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  1699. // Enlarge them by the casted shape's box extents
  1700. AABox4EnlargeWithExtent(mBoxExtent, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  1701. // Test bounds of 4 children
  1702. Vec4 distance = RayAABox4(mBoxCenter, mInvDirection, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  1703. // Clear distance for invalid bounds
  1704. distance = Vec4::sSelect(Vec4::sReplicate(FLT_MAX), distance, Vec4::sLessOrEqual(inBoundsMinY, inBoundsMaxY));
  1705. // Sort so that highest values are first (we want to first process closer hits and we process stack top to bottom)
  1706. return SortReverseAndStore(distance, mCollector.GetPositiveEarlyOutFraction(), ioProperties, &mDistanceStack[inStackTop]);
  1707. }
  1708. JPH_INLINE void VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2)
  1709. {
  1710. // Create sub shape id for this part
  1711. SubShapeID triangle_sub_shape_id = mShape2->EncodeSubShapeID(mSubShapeIDCreator2, inX, inY, inTriangle);
  1712. // Determine active edges
  1713. uint8 active_edges = mShape2->GetEdgeFlags(inX, inY, inTriangle);
  1714. Cast(inV0, inV1, inV2, active_edges, triangle_sub_shape_id);
  1715. }
  1716. const HeightFieldShape * mShape2;
  1717. RayInvDirection mInvDirection;
  1718. Vec3 mBoxCenter;
  1719. Vec3 mBoxExtent;
  1720. SubShapeIDCreator mSubShapeIDCreator2;
  1721. float mDistanceStack[cStackSize];
  1722. };
  1723. JPH_ASSERT(inShape->GetSubType() == EShapeSubType::HeightField);
  1724. const HeightFieldShape *shape = static_cast<const HeightFieldShape *>(inShape);
  1725. Visitor visitor(inShapeCast, inShapeCastSettings, inScale, inCenterOfMassTransform2, inSubShapeIDCreator1, ioCollector);
  1726. visitor.mShape2 = shape;
  1727. visitor.mInvDirection.Set(inShapeCast.mDirection);
  1728. visitor.mBoxCenter = inShapeCast.mShapeWorldBounds.GetCenter();
  1729. visitor.mBoxExtent = inShapeCast.mShapeWorldBounds.GetExtent();
  1730. visitor.mSubShapeIDCreator2 = inSubShapeIDCreator2;
  1731. shape->WalkHeightField(visitor);
  1732. }
  1733. void HeightFieldShape::sCastSphereVsHeightField(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, const Shape *inShape, Vec3Arg inScale, [[maybe_unused]] const ShapeFilter &inShapeFilter, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, CastShapeCollector &ioCollector)
  1734. {
  1735. JPH_PROFILE_FUNCTION();
  1736. struct Visitor : public CastSphereVsTriangles
  1737. {
  1738. using CastSphereVsTriangles::CastSphereVsTriangles;
  1739. JPH_INLINE bool ShouldAbort() const
  1740. {
  1741. return mCollector.ShouldEarlyOut();
  1742. }
  1743. JPH_INLINE bool ShouldVisitRangeBlock(int inStackTop) const
  1744. {
  1745. return mDistanceStack[inStackTop] < mCollector.GetPositiveEarlyOutFraction();
  1746. }
  1747. JPH_INLINE int VisitRangeBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop)
  1748. {
  1749. // Scale the bounding boxes of this node
  1750. Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;
  1751. AABox4Scale(mScale, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  1752. // Enlarge them by the radius of the sphere
  1753. AABox4EnlargeWithExtent(Vec3::sReplicate(mRadius), bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  1754. // Test bounds of 4 children
  1755. Vec4 distance = RayAABox4(mStart, mInvDirection, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  1756. // Clear distance for invalid bounds
  1757. distance = Vec4::sSelect(Vec4::sReplicate(FLT_MAX), distance, Vec4::sLessOrEqual(inBoundsMinY, inBoundsMaxY));
  1758. // Sort so that highest values are first (we want to first process closer hits and we process stack top to bottom)
  1759. return SortReverseAndStore(distance, mCollector.GetPositiveEarlyOutFraction(), ioProperties, &mDistanceStack[inStackTop]);
  1760. }
  1761. JPH_INLINE void VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2)
  1762. {
  1763. // Create sub shape id for this part
  1764. SubShapeID triangle_sub_shape_id = mShape2->EncodeSubShapeID(mSubShapeIDCreator2, inX, inY, inTriangle);
  1765. // Determine active edges
  1766. uint8 active_edges = mShape2->GetEdgeFlags(inX, inY, inTriangle);
  1767. Cast(inV0, inV1, inV2, active_edges, triangle_sub_shape_id);
  1768. }
  1769. const HeightFieldShape * mShape2;
  1770. RayInvDirection mInvDirection;
  1771. SubShapeIDCreator mSubShapeIDCreator2;
  1772. float mDistanceStack[cStackSize];
  1773. };
  1774. JPH_ASSERT(inShape->GetSubType() == EShapeSubType::HeightField);
  1775. const HeightFieldShape *shape = static_cast<const HeightFieldShape *>(inShape);
  1776. Visitor visitor(inShapeCast, inShapeCastSettings, inScale, inCenterOfMassTransform2, inSubShapeIDCreator1, ioCollector);
  1777. visitor.mShape2 = shape;
  1778. visitor.mInvDirection.Set(inShapeCast.mDirection);
  1779. visitor.mSubShapeIDCreator2 = inSubShapeIDCreator2;
  1780. shape->WalkHeightField(visitor);
  1781. }
  1782. struct HeightFieldShape::HSGetTrianglesContext
  1783. {
  1784. HSGetTrianglesContext(const HeightFieldShape *inShape, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) :
  1785. mDecodeCtx(inShape),
  1786. mShape(inShape),
  1787. mLocalBox(Mat44::sInverseRotationTranslation(inRotation, inPositionCOM), inBox),
  1788. mHeightFieldScale(inScale),
  1789. mLocalToWorld(Mat44::sRotationTranslation(inRotation, inPositionCOM) * Mat44::sScale(inScale)),
  1790. mIsInsideOut(ScaleHelpers::IsInsideOut(inScale))
  1791. {
  1792. }
  1793. bool ShouldAbort() const
  1794. {
  1795. return mShouldAbort;
  1796. }
  1797. bool ShouldVisitRangeBlock([[maybe_unused]] int inStackTop) const
  1798. {
  1799. return true;
  1800. }
  1801. int VisitRangeBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, [[maybe_unused]] int inStackTop) const
  1802. {
  1803. // Scale the bounding boxes of this node
  1804. Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;
  1805. AABox4Scale(mHeightFieldScale, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  1806. // Test which nodes collide
  1807. UVec4 collides = AABox4VsBox(mLocalBox, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  1808. // Filter out invalid bounding boxes
  1809. collides = UVec4::sAnd(collides, Vec4::sLessOrEqual(inBoundsMinY, inBoundsMaxY));
  1810. return CountAndSortTrues(collides, ioProperties);
  1811. }
  1812. void VisitTriangle(uint inX, uint inY, [[maybe_unused]] uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2)
  1813. {
  1814. // When the buffer is full and we cannot process the triangles, abort the height field walk. The next time GetTrianglesNext is called we will continue here.
  1815. if (mNumTrianglesFound + 1 > mMaxTrianglesRequested)
  1816. {
  1817. mShouldAbort = true;
  1818. return;
  1819. }
  1820. // Store vertices as Float3
  1821. if (mIsInsideOut)
  1822. {
  1823. // Reverse vertices
  1824. (mLocalToWorld * inV0).StoreFloat3(mTriangleVertices++);
  1825. (mLocalToWorld * inV2).StoreFloat3(mTriangleVertices++);
  1826. (mLocalToWorld * inV1).StoreFloat3(mTriangleVertices++);
  1827. }
  1828. else
  1829. {
  1830. // Normal scale
  1831. (mLocalToWorld * inV0).StoreFloat3(mTriangleVertices++);
  1832. (mLocalToWorld * inV1).StoreFloat3(mTriangleVertices++);
  1833. (mLocalToWorld * inV2).StoreFloat3(mTriangleVertices++);
  1834. }
  1835. // Decode material
  1836. if (mMaterials != nullptr)
  1837. *mMaterials++ = mShape->GetMaterial(inX, inY);
  1838. // Accumulate triangles found
  1839. mNumTrianglesFound++;
  1840. }
  1841. DecodingContext mDecodeCtx;
  1842. const HeightFieldShape * mShape;
  1843. OrientedBox mLocalBox;
  1844. Vec3 mHeightFieldScale;
  1845. Mat44 mLocalToWorld;
  1846. int mMaxTrianglesRequested;
  1847. Float3 * mTriangleVertices;
  1848. int mNumTrianglesFound;
  1849. const PhysicsMaterial ** mMaterials;
  1850. bool mShouldAbort;
  1851. bool mIsInsideOut;
  1852. };
  1853. void HeightFieldShape::GetTrianglesStart(GetTrianglesContext &ioContext, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) const
  1854. {
  1855. static_assert(sizeof(HSGetTrianglesContext) <= sizeof(GetTrianglesContext), "GetTrianglesContext too small");
  1856. JPH_ASSERT(IsAligned(&ioContext, alignof(HSGetTrianglesContext)));
  1857. new (&ioContext) HSGetTrianglesContext(this, inBox, inPositionCOM, inRotation, inScale);
  1858. }
  1859. int HeightFieldShape::GetTrianglesNext(GetTrianglesContext &ioContext, int inMaxTrianglesRequested, Float3 *outTriangleVertices, const PhysicsMaterial **outMaterials) const
  1860. {
  1861. static_assert(cGetTrianglesMinTrianglesRequested >= 1, "cGetTrianglesMinTrianglesRequested is too small");
  1862. JPH_ASSERT(inMaxTrianglesRequested >= cGetTrianglesMinTrianglesRequested);
  1863. // Check if we're done
  1864. HSGetTrianglesContext &context = (HSGetTrianglesContext &)ioContext;
  1865. if (context.mDecodeCtx.IsDoneWalking())
  1866. return 0;
  1867. // Store parameters on context
  1868. context.mMaxTrianglesRequested = inMaxTrianglesRequested;
  1869. context.mTriangleVertices = outTriangleVertices;
  1870. context.mMaterials = outMaterials;
  1871. context.mShouldAbort = false; // Reset the abort flag
  1872. context.mNumTrianglesFound = 0;
  1873. // Continue (or start) walking the height field
  1874. context.mDecodeCtx.WalkHeightField(context);
  1875. return context.mNumTrianglesFound;
  1876. }
  1877. void HeightFieldShape::sCollideConvexVsHeightField(const Shape *inShape1, const Shape *inShape2, Vec3Arg inScale1, Vec3Arg inScale2, Mat44Arg inCenterOfMassTransform1, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, const CollideShapeSettings &inCollideShapeSettings, CollideShapeCollector &ioCollector, [[maybe_unused]] const ShapeFilter &inShapeFilter)
  1878. {
  1879. JPH_PROFILE_FUNCTION();
  1880. // Get the shapes
  1881. JPH_ASSERT(inShape1->GetType() == EShapeType::Convex);
  1882. JPH_ASSERT(inShape2->GetType() == EShapeType::HeightField);
  1883. const ConvexShape *shape1 = static_cast<const ConvexShape *>(inShape1);
  1884. const HeightFieldShape *shape2 = static_cast<const HeightFieldShape *>(inShape2);
  1885. struct Visitor : public CollideConvexVsTriangles
  1886. {
  1887. using CollideConvexVsTriangles::CollideConvexVsTriangles;
  1888. JPH_INLINE bool ShouldAbort() const
  1889. {
  1890. return mCollector.ShouldEarlyOut();
  1891. }
  1892. JPH_INLINE bool ShouldVisitRangeBlock([[maybe_unused]] int inStackTop) const
  1893. {
  1894. return true;
  1895. }
  1896. JPH_INLINE int VisitRangeBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, [[maybe_unused]] int inStackTop) const
  1897. {
  1898. // Scale the bounding boxes of this node
  1899. Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;
  1900. AABox4Scale(mScale2, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  1901. // Test which nodes collide
  1902. UVec4 collides = AABox4VsBox(mBoundsOf1InSpaceOf2, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  1903. // Filter out invalid bounding boxes
  1904. collides = UVec4::sAnd(collides, Vec4::sLessOrEqual(inBoundsMinY, inBoundsMaxY));
  1905. return CountAndSortTrues(collides, ioProperties);
  1906. }
  1907. JPH_INLINE void VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2)
  1908. {
  1909. // Create ID for triangle
  1910. SubShapeID triangle_sub_shape_id = mShape2->EncodeSubShapeID(mSubShapeIDCreator2, inX, inY, inTriangle);
  1911. // Determine active edges
  1912. uint8 active_edges = mShape2->GetEdgeFlags(inX, inY, inTriangle);
  1913. Collide(inV0, inV1, inV2, active_edges, triangle_sub_shape_id);
  1914. }
  1915. const HeightFieldShape * mShape2;
  1916. SubShapeIDCreator mSubShapeIDCreator2;
  1917. };
  1918. Visitor visitor(shape1, inScale1, inScale2, inCenterOfMassTransform1, inCenterOfMassTransform2, inSubShapeIDCreator1.GetID(), inCollideShapeSettings, ioCollector);
  1919. visitor.mShape2 = shape2;
  1920. visitor.mSubShapeIDCreator2 = inSubShapeIDCreator2;
  1921. shape2->WalkHeightField(visitor);
  1922. }
  1923. void HeightFieldShape::sCollideSphereVsHeightField(const Shape *inShape1, const Shape *inShape2, Vec3Arg inScale1, Vec3Arg inScale2, Mat44Arg inCenterOfMassTransform1, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, const CollideShapeSettings &inCollideShapeSettings, CollideShapeCollector &ioCollector, [[maybe_unused]] const ShapeFilter &inShapeFilter)
  1924. {
  1925. JPH_PROFILE_FUNCTION();
  1926. // Get the shapes
  1927. JPH_ASSERT(inShape1->GetSubType() == EShapeSubType::Sphere);
  1928. JPH_ASSERT(inShape2->GetType() == EShapeType::HeightField);
  1929. const SphereShape *shape1 = static_cast<const SphereShape *>(inShape1);
  1930. const HeightFieldShape *shape2 = static_cast<const HeightFieldShape *>(inShape2);
  1931. struct Visitor : public CollideSphereVsTriangles
  1932. {
  1933. using CollideSphereVsTriangles::CollideSphereVsTriangles;
  1934. JPH_INLINE bool ShouldAbort() const
  1935. {
  1936. return mCollector.ShouldEarlyOut();
  1937. }
  1938. JPH_INLINE bool ShouldVisitRangeBlock([[maybe_unused]] int inStackTop) const
  1939. {
  1940. return true;
  1941. }
  1942. JPH_INLINE int VisitRangeBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, [[maybe_unused]] int inStackTop) const
  1943. {
  1944. // Scale the bounding boxes of this node
  1945. Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;
  1946. AABox4Scale(mScale2, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  1947. // Test which nodes collide
  1948. UVec4 collides = AABox4VsSphere(mSphereCenterIn2, mRadiusPlusMaxSeparationSq, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);
  1949. // Filter out invalid bounding boxes
  1950. collides = UVec4::sAnd(collides, Vec4::sLessOrEqual(inBoundsMinY, inBoundsMaxY));
  1951. return CountAndSortTrues(collides, ioProperties);
  1952. }
  1953. JPH_INLINE void VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2)
  1954. {
  1955. // Create ID for triangle
  1956. SubShapeID triangle_sub_shape_id = mShape2->EncodeSubShapeID(mSubShapeIDCreator2, inX, inY, inTriangle);
  1957. // Determine active edges
  1958. uint8 active_edges = mShape2->GetEdgeFlags(inX, inY, inTriangle);
  1959. Collide(inV0, inV1, inV2, active_edges, triangle_sub_shape_id);
  1960. }
  1961. const HeightFieldShape * mShape2;
  1962. SubShapeIDCreator mSubShapeIDCreator2;
  1963. };
  1964. Visitor visitor(shape1, inScale1, inScale2, inCenterOfMassTransform1, inCenterOfMassTransform2, inSubShapeIDCreator1.GetID(), inCollideShapeSettings, ioCollector);
  1965. visitor.mShape2 = shape2;
  1966. visitor.mSubShapeIDCreator2 = inSubShapeIDCreator2;
  1967. shape2->WalkHeightField(visitor);
  1968. }
  1969. void HeightFieldShape::SaveBinaryState(StreamOut &inStream) const
  1970. {
  1971. Shape::SaveBinaryState(inStream);
  1972. inStream.Write(mOffset);
  1973. inStream.Write(mScale);
  1974. inStream.Write(mSampleCount);
  1975. inStream.Write(mBlockSize);
  1976. inStream.Write(mBitsPerSample);
  1977. inStream.Write(mMinSample);
  1978. inStream.Write(mMaxSample);
  1979. inStream.Write(mRangeBlocks);
  1980. inStream.Write(mHeightSamples);
  1981. inStream.Write(mActiveEdges);
  1982. inStream.Write(mMaterialIndices);
  1983. inStream.Write(mNumBitsPerMaterialIndex);
  1984. }
  1985. void HeightFieldShape::RestoreBinaryState(StreamIn &inStream)
  1986. {
  1987. Shape::RestoreBinaryState(inStream);
  1988. inStream.Read(mOffset);
  1989. inStream.Read(mScale);
  1990. inStream.Read(mSampleCount);
  1991. inStream.Read(mBlockSize);
  1992. inStream.Read(mBitsPerSample);
  1993. inStream.Read(mMinSample);
  1994. inStream.Read(mMaxSample);
  1995. inStream.Read(mRangeBlocks);
  1996. inStream.Read(mHeightSamples);
  1997. inStream.Read(mActiveEdges);
  1998. inStream.Read(mMaterialIndices);
  1999. inStream.Read(mNumBitsPerMaterialIndex);
  2000. CacheValues();
  2001. }
  2002. void HeightFieldShape::SaveMaterialState(PhysicsMaterialList &outMaterials) const
  2003. {
  2004. outMaterials = mMaterials;
  2005. }
  2006. void HeightFieldShape::RestoreMaterialState(const PhysicsMaterialRefC *inMaterials, uint inNumMaterials)
  2007. {
  2008. mMaterials.assign(inMaterials, inMaterials + inNumMaterials);
  2009. }
  2010. Shape::Stats HeightFieldShape::GetStats() const
  2011. {
  2012. return Stats(
  2013. sizeof(*this)
  2014. + mMaterials.size() * sizeof(Ref<PhysicsMaterial>)
  2015. + mRangeBlocks.size() * sizeof(RangeBlock)
  2016. + mHeightSamples.size() * sizeof(uint8)
  2017. + mActiveEdges.size() * sizeof(uint8)
  2018. + mMaterialIndices.size() * sizeof(uint8),
  2019. mHeightSamples.empty()? 0 : Square(mSampleCount - 1) * 2);
  2020. }
  2021. void HeightFieldShape::sRegister()
  2022. {
  2023. ShapeFunctions &f = ShapeFunctions::sGet(EShapeSubType::HeightField);
  2024. f.mConstruct = []() -> Shape * { return new HeightFieldShape; };
  2025. f.mColor = Color::sPurple;
  2026. for (EShapeSubType s : sConvexSubShapeTypes)
  2027. {
  2028. CollisionDispatch::sRegisterCollideShape(s, EShapeSubType::HeightField, sCollideConvexVsHeightField);
  2029. CollisionDispatch::sRegisterCastShape(s, EShapeSubType::HeightField, sCastConvexVsHeightField);
  2030. CollisionDispatch::sRegisterCastShape(EShapeSubType::HeightField, s, CollisionDispatch::sReversedCastShape);
  2031. CollisionDispatch::sRegisterCollideShape(EShapeSubType::HeightField, s, CollisionDispatch::sReversedCollideShape);
  2032. }
  2033. // Specialized collision functions
  2034. CollisionDispatch::sRegisterCollideShape(EShapeSubType::Sphere, EShapeSubType::HeightField, sCollideSphereVsHeightField);
  2035. CollisionDispatch::sRegisterCastShape(EShapeSubType::Sphere, EShapeSubType::HeightField, sCastSphereVsHeightField);
  2036. }
  2037. JPH_NAMESPACE_END