CastConvexVsTriangles.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt.h>
  4. #include <Physics/Collision/CastConvexVsTriangles.h>
  5. #include <Physics/Collision/TransformedShape.h>
  6. #include <Physics/Collision/Shape/ScaleHelpers.h>
  7. #include <Physics/Collision/ActiveEdges.h>
  8. #include <Geometry/EPAPenetrationDepth.h>
  9. namespace JPH {
  10. CastConvexVsTriangles::CastConvexVsTriangles(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, const Vec3 &inScale, const ShapeFilter &inShapeFilter, const Mat44 &inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, CastShapeCollector &ioCollector) :
  11. mShapeCast(inShapeCast),
  12. mShapeCastSettings(inShapeCastSettings),
  13. mShapeFilter(inShapeFilter),
  14. mCenterOfMassTransform2(inCenterOfMassTransform2),
  15. mScale(inScale),
  16. mSubShapeIDCreator1(inSubShapeIDCreator1),
  17. mCollector(ioCollector)
  18. {
  19. JPH_ASSERT(inShapeCast.mShape->GetType() == EShapeType::Convex);
  20. // Determine if shape is inside out or not
  21. mScaleSign = ScaleHelpers::IsInsideOut(inScale)? -1.0f : 1.0f;
  22. }
  23. void CastConvexVsTriangles::Cast(Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2, uint8 inActiveEdges, const SubShapeID &inSubShapeID2)
  24. {
  25. JPH_PROFILE_FUNCTION();
  26. // Scale triangle
  27. Vec3 v0 = mScale * inV0;
  28. Vec3 v1 = mScale * inV1;
  29. Vec3 v2 = mScale * inV2;
  30. // Calculate triangle normal
  31. Vec3 triangle_normal = mScaleSign * (v1 - v0).Cross(v2 - v0);
  32. // Backface check
  33. bool back_facing = triangle_normal.Dot(mShapeCast.mDirection) > 0.0f;
  34. if (mShapeCastSettings.mBackFaceModeTriangles == EBackFaceMode::IgnoreBackFaces && back_facing)
  35. return;
  36. // Test the shape filter if this shape should collide
  37. if (!mShapeFilter.ShouldCollide(mSubShapeIDCreator1.GetID(), inSubShapeID2))
  38. return;
  39. // Create triangle support function
  40. TriangleConvexSupport triangle { v0, v1, v2 };
  41. // Check if we already created the cast shape support function
  42. if (mSupport == nullptr)
  43. {
  44. // Determine if we want to use the actual shape or a shrunken shape with convex radius
  45. ConvexShape::ESupportMode support_mode = mShapeCastSettings.mUseShrunkenShapeAndConvexRadius? ConvexShape::ESupportMode::ExcludeConvexRadius : ConvexShape::ESupportMode::IncludeConvexRadius;
  46. // Create support function
  47. mSupport = static_cast<const ConvexShape *>(mShapeCast.mShape.GetPtr())->GetSupportFunction(support_mode, mSupportBuffer, mShapeCast.mScale);
  48. }
  49. EPAPenetrationDepth epa;
  50. float fraction = mCollector.GetEarlyOutFraction();
  51. Vec3 contact_point_a, contact_point_b, contact_normal;
  52. if (epa.CastShape(mShapeCast.mCenterOfMassStart, mShapeCast.mDirection, mShapeCastSettings.mCollisionTolerance, mShapeCastSettings.mPenetrationTolerance, *mSupport, triangle, mSupport->GetConvexRadius(), 0.0f, mShapeCastSettings.mReturnDeepestPoint, fraction, contact_point_a, contact_point_b, contact_normal))
  53. {
  54. // Check if we have enabled active edge detection
  55. if (mShapeCastSettings.mActiveEdgeMode == EActiveEdgeMode::CollideOnlyWithActive)
  56. {
  57. // Convert the active edge velocity hint to local space
  58. Vec3 active_edge_movement_direction = mCenterOfMassTransform2.Multiply3x3Transposed(mShapeCastSettings.mActiveEdgeMovementDirection);
  59. // Update the contact normal to account for active edges
  60. // Note that we flip the triangle normal as the penetration axis is pointing towards the triangle instead of away
  61. contact_normal = ActiveEdges::FixNormal(v0, v1, v2, back_facing? triangle_normal : -triangle_normal, inActiveEdges, contact_point_b, contact_normal, active_edge_movement_direction);
  62. }
  63. // Convert to world space
  64. contact_point_a = mCenterOfMassTransform2 * contact_point_a;
  65. contact_point_b = mCenterOfMassTransform2 * contact_point_b;
  66. Vec3 contact_normal_world = mCenterOfMassTransform2.Multiply3x3(contact_normal);
  67. // Its a hit, store the sub shape id's
  68. ShapeCastResult result(fraction, contact_point_a, contact_point_b, contact_normal_world, back_facing, mSubShapeIDCreator1.GetID(), inSubShapeID2, TransformedShape::sGetBodyID(mCollector.GetContext()));
  69. // Gather faces
  70. if (mShapeCastSettings.mCollectFacesMode == ECollectFacesMode::CollectFaces)
  71. {
  72. // Get supporting face of shape 1
  73. Mat44 transform_1_to_2 = mShapeCast.mCenterOfMassStart;
  74. transform_1_to_2.SetTranslation(transform_1_to_2.GetTranslation() + fraction * mShapeCast.mDirection);
  75. static_cast<const ConvexShape *>(mShapeCast.mShape.GetPtr())->GetSupportingFace(transform_1_to_2.Multiply3x3Transposed(-contact_normal), mShapeCast.mScale, result.mShape1Face);
  76. // Convert to world space
  77. Mat44 transform_1_to_world = mCenterOfMassTransform2 * transform_1_to_2;
  78. for (Vec3 &p : result.mShape1Face)
  79. p = transform_1_to_world * p;
  80. // Get face of the triangle
  81. triangle.GetSupportingFace(contact_normal, result.mShape2Face);
  82. // Convert to world space
  83. for (Vec3 &p : result.mShape2Face)
  84. p = mCenterOfMassTransform2 * p;
  85. }
  86. mCollector.AddHit(result);
  87. }
  88. }
  89. } // JPH