Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/CompoundShapeVisitors.h
21694 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);304mBoundsOf2InSpaceOf1.ExpandBy(Vec3::sReplicate(inCollideShapeSettings.mMaxSeparationDistance));305}306307/// Returns true when collision detection should abort because it's not possible to find a better hit308JPH_INLINE bool ShouldAbort() const309{310return mCollector.ShouldEarlyOut();311}312313/// Tests the bounds of shape 2 vs 4 bounding boxes, returns true for the ones that intersect314JPH_INLINE UVec4 TestBounds(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const315{316// Scale the bounding boxes317Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;318AABox4Scale(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);319320// Test which boxes collide321return AABox4VsBox(mBoundsOf2InSpaceOf1, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);322}323324/// Test the shape against a single subshape325JPH_INLINE void VisitShape(const SubShape &inSubShape, uint32 inSubShapeIndex)326{327// Get world transform of 1328Mat44 transform1 = mTransform1 * inSubShape.GetLocalTransformNoScale(mScale1);329330// Create ID for sub shape331SubShapeIDCreator shape1_sub_shape_id = mSubShapeIDCreator1.PushID(inSubShapeIndex, mSubShapeBits);332333CollisionDispatch::sCollideShapeVsShape(inSubShape.mShape, mShape2, inSubShape.TransformScale(mScale1), mScale2, transform1, mTransform2, shape1_sub_shape_id, mSubShapeIDCreator2, mCollideShapeSettings, mCollector, mShapeFilter);334}335336const CollideShapeSettings & mCollideShapeSettings;337CollideShapeCollector & mCollector;338const Shape * mShape2;339Vec3 mScale1;340Vec3 mScale2;341Mat44 mTransform1;342Mat44 mTransform2;343AABox mBoundsOf2InSpaceOf1;344SubShapeIDCreator mSubShapeIDCreator1;345SubShapeIDCreator mSubShapeIDCreator2;346uint mSubShapeBits;347const ShapeFilter & mShapeFilter;348};349350struct CompoundShape::CollideShapeVsCompoundVisitor351{352JPH_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) :353mCollideShapeSettings(inCollideShapeSettings),354mCollector(ioCollector),355mShape1(inShape1),356mScale1(inScale1),357mScale2(inScale2),358mTransform1(inCenterOfMassTransform1),359mTransform2(inCenterOfMassTransform2),360mSubShapeIDCreator1(inSubShapeIDCreator1),361mSubShapeIDCreator2(inSubShapeIDCreator2),362mSubShapeBits(inShape2->GetSubShapeIDBits()),363mShapeFilter(inShapeFilter)364{365// Get transform from shape 1 to shape 2366Mat44 transform1_to_2 = inCenterOfMassTransform2.InversedRotationTranslation() * inCenterOfMassTransform1;367368// Convert bounding box of 1 into space of 2369mBoundsOf1InSpaceOf2 = inShape1->GetLocalBounds().Scaled(inScale1).Transformed(transform1_to_2);370mBoundsOf1InSpaceOf2.ExpandBy(Vec3::sReplicate(inCollideShapeSettings.mMaxSeparationDistance));371}372373/// Returns true when collision detection should abort because it's not possible to find a better hit374JPH_INLINE bool ShouldAbort() const375{376return mCollector.ShouldEarlyOut();377}378379/// Tests the bounds of shape 1 vs 4 bounding boxes, returns true for the ones that intersect380JPH_INLINE UVec4 TestBounds(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const381{382// Scale the bounding boxes383Vec4 bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z;384AABox4Scale(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);385386// Test which bounding boxes collide387return AABox4VsBox(mBoundsOf1InSpaceOf2, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);388}389390/// Test the shape against a single subshape391JPH_INLINE void VisitShape(const SubShape &inSubShape, uint32 inSubShapeIndex)392{393// Create ID for sub shape394SubShapeIDCreator shape2_sub_shape_id = mSubShapeIDCreator2.PushID(inSubShapeIndex, mSubShapeBits);395396// Get world transform of 2397Mat44 transform2 = mTransform2 * inSubShape.GetLocalTransformNoScale(mScale2);398399CollisionDispatch::sCollideShapeVsShape(mShape1, inSubShape.mShape, mScale1, inSubShape.TransformScale(mScale2), mTransform1, transform2, mSubShapeIDCreator1, shape2_sub_shape_id, mCollideShapeSettings, mCollector, mShapeFilter);400}401402const CollideShapeSettings & mCollideShapeSettings;403CollideShapeCollector & mCollector;404const Shape * mShape1;405Vec3 mScale1;406Vec3 mScale2;407Mat44 mTransform1;408Mat44 mTransform2;409AABox mBoundsOf1InSpaceOf2;410SubShapeIDCreator mSubShapeIDCreator1;411SubShapeIDCreator mSubShapeIDCreator2;412uint mSubShapeBits;413const ShapeFilter & mShapeFilter;414};415416template <class BoxType>417struct CompoundShape::GetIntersectingSubShapesVisitor418{419JPH_INLINE GetIntersectingSubShapesVisitor(const BoxType &inBox, uint *outSubShapeIndices, int inMaxSubShapeIndices) :420mBox(inBox),421mSubShapeIndices(outSubShapeIndices),422mMaxSubShapeIndices(inMaxSubShapeIndices)423{424}425426/// Returns true when collision detection should abort because the buffer is full427JPH_INLINE bool ShouldAbort() const428{429return mNumResults >= mMaxSubShapeIndices;430}431432/// Tests the box vs 4 bounding boxes, returns true for the ones that intersect433JPH_INLINE UVec4 TestBounds(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const434{435// Test which bounding boxes collide436return AABox4VsBox(mBox, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);437}438439/// Records a hit440JPH_INLINE void VisitShape([[maybe_unused]] const SubShape &inSubShape, uint32 inSubShapeIndex)441{442JPH_ASSERT(mNumResults < mMaxSubShapeIndices);443*mSubShapeIndices++ = inSubShapeIndex;444mNumResults++;445}446447/// Get the number of indices that were found448JPH_INLINE int GetNumResults() const449{450return mNumResults;451}452453private:454BoxType mBox;455uint * mSubShapeIndices;456int mMaxSubShapeIndices;457int mNumResults = 0;458};459460JPH_NAMESPACE_END461462463