HeightFieldShape.cpp 97 KB

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