Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/CompoundShapeVisitors.h
9917 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#pragma once56#include <Jolt/Physics/Collision/Shape/CompoundShape.h>7#include <Jolt/Physics/Collision/Shape/SubShapeID.h>8#include <Jolt/Physics/Collision/RayCast.h>9#include <Jolt/Physics/Collision/CastResult.h>10#include <Jolt/Physics/Collision/ShapeCast.h>11#include <Jolt/Physics/Collision/TransformedShape.h>12#include <Jolt/Physics/Collision/CollisionDispatch.h>13#include <Jolt/Geometry/RayAABox.h>14#include <Jolt/Geometry/AABox4.h>15#include <Jolt/Geometry/OrientedBox.h>1617JPH_NAMESPACE_BEGIN1819struct CompoundShape::CastRayVisitor20{21JPH_INLINE CastRayVisitor(const RayCast &inRay, const CompoundShape *inShape, const SubShapeIDCreator &inSubShapeIDCreator, RayCastResult &ioHit) :22mRay(inRay),23mHit(ioHit),24mSubShapeIDCreator(inSubShapeIDCreator),25mSubShapeBits(inShape->GetSubShapeIDBits())26{27// Determine ray properties of cast28mInvDirection.Set(inRay.mDirection);29}3031/// Returns true when collision detection should abort because it's not possible to find a better hit32JPH_INLINE bool ShouldAbort() const33{34return mHit.mFraction <= 0.0f;35}3637/// Test ray against 4 bounding boxes and returns the distance where the ray enters the bounding box38JPH_INLINE Vec4 TestBounds(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const39{40return RayAABox4(mRay.mOrigin, mInvDirection, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);41}4243/// Test the ray against a single subshape44JPH_INLINE void VisitShape(const SubShape &inSubShape, uint32 inSubShapeIndex)45{46// Create ID for sub shape47SubShapeIDCreator shape2_sub_shape_id = mSubShapeIDCreator.PushID(inSubShapeIndex, mSubShapeBits);4849// Transform the ray50Mat44 transform = Mat44::sInverseRotationTranslation(inSubShape.GetRotation(), inSubShape.GetPositionCOM());51RayCast ray = mRay.Transformed(transform);52if (inSubShape.mShape->CastRay(ray, shape2_sub_shape_id, mHit))53mReturnValue = true;54}5556RayInvDirection mInvDirection;57const RayCast & mRay;58RayCastResult & mHit;59SubShapeIDCreator mSubShapeIDCreator;60uint mSubShapeBits;61bool mReturnValue = false;62};6364struct CompoundShape::CastRayVisitorCollector65{66JPH_INLINE CastRayVisitorCollector(const RayCast &inRay, const RayCastSettings &inRayCastSettings, const CompoundShape *inShape, const SubShapeIDCreator &inSubShapeIDCreator, CastRayCollector &ioCollector, const ShapeFilter &inShapeFilter) :67mRay(inRay),68mCollector(ioCollector),69mSubShapeIDCreator(inSubShapeIDCreator),70mSubShapeBits(inShape->GetSubShapeIDBits()),71mRayCastSettings(inRayCastSettings),72mShapeFilter(inShapeFilter)73{74// Determine ray properties of cast75mInvDirection.Set(inRay.mDirection);76}7778/// Returns true when collision detection should abort because it's not possible to find a better hit79JPH_INLINE bool ShouldAbort() const80{81return mCollector.ShouldEarlyOut();82}8384/// Test ray against 4 bounding boxes and returns the distance where the ray enters the bounding box85JPH_INLINE Vec4 TestBounds(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const86{87return RayAABox4(mRay.mOrigin, mInvDirection, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);88}8990/// Test the ray against a single subshape91JPH_INLINE void VisitShape(const SubShape &inSubShape, uint32 inSubShapeIndex)92{93// Create ID for sub shape94SubShapeIDCreator shape2_sub_shape_id = mSubShapeIDCreator.PushID(inSubShapeIndex, mSubShapeBits);9596// Transform the ray97Mat44 transform = Mat44::sInverseRotationTranslation(inSubShape.GetRotation(), inSubShape.GetPositionCOM());98RayCast ray = mRay.Transformed(transform);99inSubShape.mShape->CastRay(ray, mRayCastSettings, shape2_sub_shape_id, mCollector, mShapeFilter);100}101102RayInvDirection mInvDirection;103const RayCast & mRay;104CastRayCollector & mCollector;105SubShapeIDCreator mSubShapeIDCreator;106uint mSubShapeBits;107RayCastSettings mRayCastSettings;108const ShapeFilter & mShapeFilter;109};110111struct CompoundShape::CollidePointVisitor112{113JPH_INLINE CollidePointVisitor(Vec3Arg inPoint, const CompoundShape *inShape, const SubShapeIDCreator &inSubShapeIDCreator, CollidePointCollector &ioCollector, const ShapeFilter &inShapeFilter) :114mPoint(inPoint),115mSubShapeIDCreator(inSubShapeIDCreator),116mCollector(ioCollector),117mSubShapeBits(inShape->GetSubShapeIDBits()),118mShapeFilter(inShapeFilter)119{120}121122/// Returns true when collision detection should abort because it's not possible to find a better hit123JPH_INLINE bool ShouldAbort() const124{125return mCollector.ShouldEarlyOut();126}127128/// Test if point overlaps with 4 boxes, returns true for the ones that do129JPH_INLINE UVec4 TestBounds(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const130{131return AABox4VsPoint(mPoint, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);132}133134/// Test the point against a single subshape135JPH_INLINE void VisitShape(const SubShape &inSubShape, uint32 inSubShapeIndex)136{137// Create ID for sub shape138SubShapeIDCreator shape2_sub_shape_id = mSubShapeIDCreator.PushID(inSubShapeIndex, mSubShapeBits);139140// Transform the point141Mat44 transform = Mat44::sInverseRotationTranslation(inSubShape.GetRotation(), inSubShape.GetPositionCOM());142inSubShape.mShape->CollidePoint(transform * mPoint, shape2_sub_shape_id, mCollector, mShapeFilter);143}144145Vec3 mPoint;146SubShapeIDCreator mSubShapeIDCreator;147CollidePointCollector & mCollector;148uint mSubShapeBits;149const ShapeFilter & mShapeFilter;150};151152struct CompoundShape::CastShapeVisitor153{154JPH_INLINE CastShapeVisitor(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, const CompoundShape *inShape, Vec3Arg inScale, const ShapeFilter &inShapeFilter, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, CastShapeCollector &ioCollector) :155mBoxCenter(inShapeCast.mShapeWorldBounds.GetCenter()),156mBoxExtent(inShapeCast.mShapeWorldBounds.GetExtent()),157mScale(inScale),158mShapeCast(inShapeCast),159mShapeCastSettings(inShapeCastSettings),160mShapeFilter(inShapeFilter),161mCollector(ioCollector),162mCenterOfMassTransform2(inCenterOfMassTransform2),163mSubShapeIDCreator1(inSubShapeIDCreator1),164mSubShapeIDCreator2(inSubShapeIDCreator2),165mSubShapeBits(inShape->GetSubShapeIDBits())166{167// Determine ray properties of cast168mInvDirection.Set(inShapeCast.mDirection);169}170171/// Returns true when collision detection should abort because it's not possible to find a better hit172JPH_INLINE bool ShouldAbort() const173{174return mCollector.ShouldEarlyOut();175}176177/// Tests the shape cast against 4 bounding boxes, returns the distance along the shape cast where the shape first enters the bounding box178JPH_INLINE Vec4 TestBounds(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const179{180// Scale the bounding boxes181Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;182AABox4Scale(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);183184// Enlarge them by the casted shape's box extents185AABox4EnlargeWithExtent(mBoxExtent, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);186187// Test ray against the bounding boxes188return RayAABox4(mBoxCenter, mInvDirection, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);189}190191/// Test the cast shape against a single subshape192JPH_INLINE void VisitShape(const SubShape &inSubShape, uint32 inSubShapeIndex)193{194JPH_ASSERT(inSubShape.IsValidScale(mScale));195196// Create ID for sub shape197SubShapeIDCreator shape2_sub_shape_id = mSubShapeIDCreator2.PushID(inSubShapeIndex, mSubShapeBits);198199// Calculate the local transform for this sub shape200Mat44 local_transform = Mat44::sRotationTranslation(inSubShape.GetRotation(), mScale * inSubShape.GetPositionCOM());201202// Transform the center of mass of 2203Mat44 center_of_mass_transform2 = mCenterOfMassTransform2 * local_transform;204205// Transform the shape cast206ShapeCast shape_cast = mShapeCast.PostTransformed(local_transform.InversedRotationTranslation());207208CollisionDispatch::sCastShapeVsShapeLocalSpace(shape_cast, mShapeCastSettings, inSubShape.mShape, inSubShape.TransformScale(mScale), mShapeFilter, center_of_mass_transform2, mSubShapeIDCreator1, shape2_sub_shape_id, mCollector);209}210211RayInvDirection mInvDirection;212Vec3 mBoxCenter;213Vec3 mBoxExtent;214Vec3 mScale;215const ShapeCast & mShapeCast;216const ShapeCastSettings & mShapeCastSettings;217const ShapeFilter & mShapeFilter;218CastShapeCollector & mCollector;219Mat44 mCenterOfMassTransform2;220SubShapeIDCreator mSubShapeIDCreator1;221SubShapeIDCreator mSubShapeIDCreator2;222uint mSubShapeBits;223};224225struct CompoundShape::CollectTransformedShapesVisitor226{227JPH_INLINE CollectTransformedShapesVisitor(const AABox &inBox, const CompoundShape *inShape, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale, const SubShapeIDCreator &inSubShapeIDCreator, TransformedShapeCollector &ioCollector, const ShapeFilter &inShapeFilter) :228mBox(inBox),229mLocalBox(Mat44::sInverseRotationTranslation(inRotation, inPositionCOM), inBox),230mPositionCOM(inPositionCOM),231mRotation(inRotation),232mScale(inScale),233mSubShapeIDCreator(inSubShapeIDCreator),234mCollector(ioCollector),235mSubShapeBits(inShape->GetSubShapeIDBits()),236mShapeFilter(inShapeFilter)237{238}239240/// Returns true when collision detection should abort because it's not possible to find a better hit241JPH_INLINE bool ShouldAbort() const242{243return mCollector.ShouldEarlyOut();244}245246/// Tests 4 bounding boxes against the query box, returns true for the ones that collide247JPH_INLINE UVec4 TestBounds(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const248{249// Scale the bounding boxes of this node250Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;251AABox4Scale(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);252253// Test which nodes collide254return AABox4VsBox(mLocalBox, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);255}256257/// Collect the transformed sub shapes for a single subshape258JPH_INLINE void VisitShape(const SubShape &inSubShape, uint32 inSubShapeIndex)259{260JPH_ASSERT(inSubShape.IsValidScale(mScale));261262// Create ID for sub shape263SubShapeIDCreator sub_shape_id = mSubShapeIDCreator.PushID(inSubShapeIndex, mSubShapeBits);264265// Calculate world transform for sub shape266Vec3 position = mPositionCOM + mRotation * (mScale * inSubShape.GetPositionCOM());267Quat rotation = mRotation * inSubShape.GetRotation();268269// Recurse to sub shape270inSubShape.mShape->CollectTransformedShapes(mBox, position, rotation, inSubShape.TransformScale(mScale), sub_shape_id, mCollector, mShapeFilter);271}272273AABox mBox;274OrientedBox mLocalBox;275Vec3 mPositionCOM;276Quat mRotation;277Vec3 mScale;278SubShapeIDCreator mSubShapeIDCreator;279TransformedShapeCollector & mCollector;280uint mSubShapeBits;281const ShapeFilter & mShapeFilter;282};283284struct CompoundShape::CollideCompoundVsShapeVisitor285{286JPH_INLINE CollideCompoundVsShapeVisitor(const CompoundShape *inShape1, const Shape *inShape2, Vec3Arg inScale1, Vec3Arg inScale2, Mat44Arg inCenterOfMassTransform1, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, const CollideShapeSettings &inCollideShapeSettings, CollideShapeCollector &ioCollector, const ShapeFilter &inShapeFilter) :287mCollideShapeSettings(inCollideShapeSettings),288mCollector(ioCollector),289mShape2(inShape2),290mScale1(inScale1),291mScale2(inScale2),292mTransform1(inCenterOfMassTransform1),293mTransform2(inCenterOfMassTransform2),294mSubShapeIDCreator1(inSubShapeIDCreator1),295mSubShapeIDCreator2(inSubShapeIDCreator2),296mSubShapeBits(inShape1->GetSubShapeIDBits()),297mShapeFilter(inShapeFilter)298{299// Get transform from shape 2 to shape 1300Mat44 transform2_to_1 = inCenterOfMassTransform1.InversedRotationTranslation() * inCenterOfMassTransform2;301302// Convert bounding box of 2 into space of 1303mBoundsOf2InSpaceOf1 = inShape2->GetLocalBounds().Scaled(inScale2).Transformed(transform2_to_1);304}305306/// Returns true when collision detection should abort because it's not possible to find a better hit307JPH_INLINE bool ShouldAbort() const308{309return mCollector.ShouldEarlyOut();310}311312/// Tests the bounds of shape 2 vs 4 bounding boxes, returns true for the ones that intersect313JPH_INLINE UVec4 TestBounds(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const314{315// Scale the bounding boxes316Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;317AABox4Scale(mScale1, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);318319// Test which boxes collide320return AABox4VsBox(mBoundsOf2InSpaceOf1, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);321}322323/// Test the shape against a single subshape324JPH_INLINE void VisitShape(const SubShape &inSubShape, uint32 inSubShapeIndex)325{326// Get world transform of 1327Mat44 transform1 = mTransform1 * inSubShape.GetLocalTransformNoScale(mScale1);328329// Create ID for sub shape330SubShapeIDCreator shape1_sub_shape_id = mSubShapeIDCreator1.PushID(inSubShapeIndex, mSubShapeBits);331332CollisionDispatch::sCollideShapeVsShape(inSubShape.mShape, mShape2, inSubShape.TransformScale(mScale1), mScale2, transform1, mTransform2, shape1_sub_shape_id, mSubShapeIDCreator2, mCollideShapeSettings, mCollector, mShapeFilter);333}334335const CollideShapeSettings & mCollideShapeSettings;336CollideShapeCollector & mCollector;337const Shape * mShape2;338Vec3 mScale1;339Vec3 mScale2;340Mat44 mTransform1;341Mat44 mTransform2;342AABox mBoundsOf2InSpaceOf1;343SubShapeIDCreator mSubShapeIDCreator1;344SubShapeIDCreator mSubShapeIDCreator2;345uint mSubShapeBits;346const ShapeFilter & mShapeFilter;347};348349struct CompoundShape::CollideShapeVsCompoundVisitor350{351JPH_INLINE CollideShapeVsCompoundVisitor(const Shape *inShape1, const CompoundShape *inShape2, Vec3Arg inScale1, Vec3Arg inScale2, Mat44Arg inCenterOfMassTransform1, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, const CollideShapeSettings &inCollideShapeSettings, CollideShapeCollector &ioCollector, const ShapeFilter &inShapeFilter) :352mCollideShapeSettings(inCollideShapeSettings),353mCollector(ioCollector),354mShape1(inShape1),355mScale1(inScale1),356mScale2(inScale2),357mTransform1(inCenterOfMassTransform1),358mTransform2(inCenterOfMassTransform2),359mSubShapeIDCreator1(inSubShapeIDCreator1),360mSubShapeIDCreator2(inSubShapeIDCreator2),361mSubShapeBits(inShape2->GetSubShapeIDBits()),362mShapeFilter(inShapeFilter)363{364// Get transform from shape 1 to shape 2365Mat44 transform1_to_2 = inCenterOfMassTransform2.InversedRotationTranslation() * inCenterOfMassTransform1;366367// Convert bounding box of 1 into space of 2368mBoundsOf1InSpaceOf2 = inShape1->GetLocalBounds().Scaled(inScale1).Transformed(transform1_to_2);369mBoundsOf1InSpaceOf2.ExpandBy(Vec3::sReplicate(inCollideShapeSettings.mMaxSeparationDistance));370}371372/// Returns true when collision detection should abort because it's not possible to find a better hit373JPH_INLINE bool ShouldAbort() const374{375return mCollector.ShouldEarlyOut();376}377378/// Tests the bounds of shape 1 vs 4 bounding boxes, returns true for the ones that intersect379JPH_INLINE UVec4 TestBounds(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const380{381// Scale the bounding boxes382Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;383AABox4Scale(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);384385// Test which bounding boxes collide386return AABox4VsBox(mBoundsOf1InSpaceOf2, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);387}388389/// Test the shape against a single subshape390JPH_INLINE void VisitShape(const SubShape &inSubShape, uint32 inSubShapeIndex)391{392// Create ID for sub shape393SubShapeIDCreator shape2_sub_shape_id = mSubShapeIDCreator2.PushID(inSubShapeIndex, mSubShapeBits);394395// Get world transform of 2396Mat44 transform2 = mTransform2 * inSubShape.GetLocalTransformNoScale(mScale2);397398CollisionDispatch::sCollideShapeVsShape(mShape1, inSubShape.mShape, mScale1, inSubShape.TransformScale(mScale2), mTransform1, transform2, mSubShapeIDCreator1, shape2_sub_shape_id, mCollideShapeSettings, mCollector, mShapeFilter);399}400401const CollideShapeSettings & mCollideShapeSettings;402CollideShapeCollector & mCollector;403const Shape * mShape1;404Vec3 mScale1;405Vec3 mScale2;406Mat44 mTransform1;407Mat44 mTransform2;408AABox mBoundsOf1InSpaceOf2;409SubShapeIDCreator mSubShapeIDCreator1;410SubShapeIDCreator mSubShapeIDCreator2;411uint mSubShapeBits;412const ShapeFilter & mShapeFilter;413};414415template <class BoxType>416struct CompoundShape::GetIntersectingSubShapesVisitor417{418JPH_INLINE GetIntersectingSubShapesVisitor(const BoxType &inBox, uint *outSubShapeIndices, int inMaxSubShapeIndices) :419mBox(inBox),420mSubShapeIndices(outSubShapeIndices),421mMaxSubShapeIndices(inMaxSubShapeIndices)422{423}424425/// Returns true when collision detection should abort because the buffer is full426JPH_INLINE bool ShouldAbort() const427{428return mNumResults >= mMaxSubShapeIndices;429}430431/// Tests the box vs 4 bounding boxes, returns true for the ones that intersect432JPH_INLINE UVec4 TestBounds(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const433{434// Test which bounding boxes collide435return AABox4VsBox(mBox, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);436}437438/// Records a hit439JPH_INLINE void VisitShape([[maybe_unused]] const SubShape &inSubShape, uint32 inSubShapeIndex)440{441JPH_ASSERT(mNumResults < mMaxSubShapeIndices);442*mSubShapeIndices++ = inSubShapeIndex;443mNumResults++;444}445446/// Get the number of indices that were found447JPH_INLINE int GetNumResults() const448{449return mNumResults;450}451452private:453BoxType mBox;454uint * mSubShapeIndices;455int mMaxSubShapeIndices;456int mNumResults = 0;457};458459JPH_NAMESPACE_END460461462