VehicleCollisionTester.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt.h>
  4. #include <Physics/Vehicle/VehicleCollisionTester.h>
  5. #include <Physics/Collision/RayCast.h>
  6. #include <Physics/Collision/ShapeCast.h>
  7. #include <Physics/Collision/CastResult.h>
  8. #include <Physics/Collision/Shape/SphereShape.h>
  9. #include <Physics/Collision/CollisionCollectorImpl.h>
  10. #include <Physics/PhysicsSystem.h>
  11. namespace JPH {
  12. bool VehicleCollisionTesterRay::Collide(PhysicsSystem &inPhysicsSystem, uint inWheelIndex, Vec3Arg inOrigin, Vec3Arg inDirection, float inSuspensionMaxLength, const BodyID &inVehicleBodyID, Body *&outBody, SubShapeID &outSubShapeID, Vec3 &outContactPosition, Vec3 &outContactNormal, float &outSuspensionLength) const
  13. {
  14. DefaultBroadPhaseLayerFilter broadphase_layer_filter = inPhysicsSystem.GetDefaultBroadPhaseLayerFilter(mObjectLayer);
  15. DefaultObjectLayerFilter object_layer_filter = inPhysicsSystem.GetDefaultLayerFilter(mObjectLayer);
  16. IgnoreSingleBodyFilter body_filter(inVehicleBodyID);
  17. RayCast ray { inOrigin, inSuspensionMaxLength * inDirection };
  18. class MyCollector : public CastRayCollector
  19. {
  20. public:
  21. MyCollector(PhysicsSystem &inPhysicsSystem, const RayCast &inRay, Vec3Arg inUpDirection, float inCosMaxSlopeAngle) :
  22. mPhysicsSystem(inPhysicsSystem),
  23. mRay(inRay),
  24. mUpDirection(inUpDirection),
  25. mCosMaxSlopeAngle(inCosMaxSlopeAngle)
  26. {
  27. }
  28. virtual void AddHit(const RayCastResult &inResult) override
  29. {
  30. // Test if this collision is closer than the previous one
  31. if (inResult.mFraction < GetEarlyOutFraction())
  32. {
  33. // Lock the body
  34. BodyLockRead lock(mPhysicsSystem.GetBodyLockInterfaceNoLock(), inResult.mBodyID);
  35. JPH_ASSERT(lock.Succeeded()); // When this runs all bodies are locked so this should not fail
  36. const Body *body = &lock.GetBody();
  37. // Test that we're not hitting a vertical wall
  38. Vec3 contact_pos = mRay.mOrigin + inResult.mFraction * mRay.mDirection;
  39. Vec3 normal = body->GetWorldSpaceSurfaceNormal(inResult.mSubShapeID2, contact_pos);
  40. if (normal.Dot(mUpDirection) > mCosMaxSlopeAngle)
  41. {
  42. // Update early out fraction to this hit
  43. UpdateEarlyOutFraction(inResult.mFraction);
  44. // Get the contact properties
  45. mBody = body;
  46. mSubShapeID2 = inResult.mSubShapeID2;
  47. mContactPosition = contact_pos;
  48. mContactNormal = normal;
  49. }
  50. }
  51. }
  52. // Configuration
  53. PhysicsSystem & mPhysicsSystem;
  54. RayCast mRay;
  55. Vec3 mUpDirection;
  56. float mCosMaxSlopeAngle;
  57. // Resulting closest collision
  58. const Body * mBody = nullptr;
  59. SubShapeID mSubShapeID2;
  60. Vec3 mContactPosition;
  61. Vec3 mContactNormal;
  62. };
  63. RayCastSettings settings;
  64. MyCollector collector(inPhysicsSystem, ray, mUp, mCosMaxSlopeAngle);
  65. inPhysicsSystem.GetNarrowPhaseQueryNoLock().CastRay(ray, settings, collector, broadphase_layer_filter, object_layer_filter, body_filter);
  66. if (collector.mBody == nullptr)
  67. return false;
  68. outBody = const_cast<Body *>(collector.mBody);
  69. outSubShapeID = collector.mSubShapeID2;
  70. outContactPosition = collector.mContactPosition;
  71. outContactNormal = collector.mContactNormal;
  72. outSuspensionLength = inSuspensionMaxLength * collector.GetEarlyOutFraction();
  73. return true;
  74. }
  75. bool VehicleCollisionTesterCastSphere::Collide(PhysicsSystem &inPhysicsSystem, uint inWheelIndex, Vec3Arg inOrigin, Vec3Arg inDirection, float inSuspensionMaxLength, const BodyID &inVehicleBodyID, Body *&outBody, SubShapeID &outSubShapeID, Vec3 &outContactPosition, Vec3 &outContactNormal, float &outSuspensionLength) const
  76. {
  77. DefaultBroadPhaseLayerFilter broadphase_layer_filter = inPhysicsSystem.GetDefaultBroadPhaseLayerFilter(mObjectLayer);
  78. DefaultObjectLayerFilter object_layer_filter = inPhysicsSystem.GetDefaultLayerFilter(mObjectLayer);
  79. IgnoreSingleBodyFilter body_filter(inVehicleBodyID);
  80. SphereShape sphere(mRadius);
  81. sphere.SetEmbedded();
  82. float cast_length = max(0.0f, inSuspensionMaxLength - mRadius);
  83. ShapeCast shape_cast(&sphere, Vec3::sReplicate(1.0f), Mat44::sTranslation(inOrigin), inDirection * cast_length);
  84. ShapeCastSettings settings;
  85. settings.mUseShrunkenShapeAndConvexRadius = true;
  86. settings.mReturnDeepestPoint = true;
  87. class MyCollector : public CastShapeCollector
  88. {
  89. public:
  90. MyCollector(PhysicsSystem &inPhysicsSystem, const ShapeCast &inShapeCast, Vec3Arg inUpDirection, float inCosMaxSlopeAngle) :
  91. mPhysicsSystem(inPhysicsSystem),
  92. mShapeCast(inShapeCast),
  93. mUpDirection(inUpDirection),
  94. mCosMaxSlopeAngle(inCosMaxSlopeAngle)
  95. {
  96. }
  97. virtual void AddHit(const ShapeCastResult &inResult) override
  98. {
  99. // Test if this collision is closer than the previous one
  100. if (inResult.mFraction < GetEarlyOutFraction())
  101. {
  102. // Lock the body
  103. BodyLockRead lock(mPhysicsSystem.GetBodyLockInterfaceNoLock(), inResult.mBodyID2);
  104. JPH_ASSERT(lock.Succeeded()); // When this runs all bodies are locked so this should not fail
  105. const Body *body = &lock.GetBody();
  106. // Test that we're not hitting a vertical wall
  107. Vec3 normal = -inResult.mPenetrationAxis.Normalized();
  108. if (normal.Dot(mUpDirection) > mCosMaxSlopeAngle)
  109. {
  110. // Update early out fraction to this hit
  111. UpdateEarlyOutFraction(inResult.mFraction);
  112. // Get the contact properties
  113. mBody = body;
  114. mSubShapeID2 = inResult.mSubShapeID2;
  115. mContactPosition = inResult.mContactPointOn2;
  116. mContactNormal = normal;
  117. }
  118. }
  119. }
  120. // Configuration
  121. PhysicsSystem & mPhysicsSystem;
  122. const ShapeCast & mShapeCast;
  123. Vec3 mUpDirection;
  124. float mCosMaxSlopeAngle;
  125. // Resulting closest collision
  126. const Body * mBody = nullptr;
  127. SubShapeID mSubShapeID2;
  128. Vec3 mContactPosition;
  129. Vec3 mContactNormal;
  130. };
  131. MyCollector collector(inPhysicsSystem, shape_cast, mUp, mCosMaxSlopeAngle);
  132. inPhysicsSystem.GetNarrowPhaseQueryNoLock().CastShape(shape_cast, settings, collector, broadphase_layer_filter, object_layer_filter, body_filter);
  133. if (collector.mBody == nullptr)
  134. return false;
  135. outBody = const_cast<Body *>(collector.mBody);
  136. outSubShapeID = collector.mSubShapeID2;
  137. outContactPosition = collector.mContactPosition;
  138. outContactNormal = collector.mContactNormal;
  139. outSuspensionLength = min(inSuspensionMaxLength, cast_length * collector.GetEarlyOutFraction() + mRadius);
  140. return true;
  141. }
  142. } // JPH