VehicleCollisionTester.cpp 6.3 KB

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