Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Collision/ShapeCast.h
9912 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#pragma once56#include <Jolt/Geometry/AABox.h>7#include <Jolt/Physics/Collision/CollideShape.h>8#include <Jolt/Physics/Collision/Shape/Shape.h>910JPH_NAMESPACE_BEGIN1112/// Structure that holds a single shape cast (a shape moving along a linear path in 3d space with no rotation)13template <class Vec, class Mat, class ShapeCastType>14struct ShapeCastT15{16JPH_OVERRIDE_NEW_DELETE1718/// Constructor19ShapeCastT(const Shape *inShape, Vec3Arg inScale, typename Mat::ArgType inCenterOfMassStart, Vec3Arg inDirection, const AABox &inWorldSpaceBounds) :20mShape(inShape),21mScale(inScale),22mCenterOfMassStart(inCenterOfMassStart),23mDirection(inDirection),24mShapeWorldBounds(inWorldSpaceBounds)25{26}2728/// Constructor29ShapeCastT(const Shape *inShape, Vec3Arg inScale, typename Mat::ArgType inCenterOfMassStart, Vec3Arg inDirection) :30ShapeCastT<Vec, Mat, ShapeCastType>(inShape, inScale, inCenterOfMassStart, inDirection, inShape->GetWorldSpaceBounds(inCenterOfMassStart, inScale))31{32}3334/// Construct a shape cast using a world transform for a shape instead of a center of mass transform35static inline ShapeCastType sFromWorldTransform(const Shape *inShape, Vec3Arg inScale, typename Mat::ArgType inWorldTransform, Vec3Arg inDirection)36{37return ShapeCastType(inShape, inScale, inWorldTransform.PreTranslated(inShape->GetCenterOfMass()), inDirection);38}3940/// Transform this shape cast using inTransform. Multiply transform on the left left hand side.41ShapeCastType PostTransformed(typename Mat::ArgType inTransform) const42{43Mat44 start = inTransform * mCenterOfMassStart;44Vec3 direction = inTransform.Multiply3x3(mDirection);45return { mShape, mScale, start, direction };46}4748/// Translate this shape cast by inTranslation.49ShapeCastType PostTranslated(typename Vec::ArgType inTranslation) const50{51return { mShape, mScale, mCenterOfMassStart.PostTranslated(inTranslation), mDirection };52}5354/// Get point with fraction inFraction on ray from mCenterOfMassStart to mCenterOfMassStart + mDirection (0 = start of ray, 1 = end of ray)55inline Vec GetPointOnRay(float inFraction) const56{57return mCenterOfMassStart.GetTranslation() + inFraction * mDirection;58}5960const Shape * mShape; ///< Shape that's being cast (cannot be mesh shape). Note that this structure does not assume ownership over the shape for performance reasons.61const Vec3 mScale; ///< Scale in local space of the shape being cast (scales relative to its center of mass)62const Mat mCenterOfMassStart; ///< Start position and orientation of the center of mass of the shape (construct using sFromWorldTransform if you have a world transform for your shape)63const Vec3 mDirection; ///< Direction and length of the cast (anything beyond this length will not be reported as a hit)64const AABox mShapeWorldBounds; ///< Cached shape's world bounds, calculated in constructor65};6667struct ShapeCast : public ShapeCastT<Vec3, Mat44, ShapeCast>68{69using ShapeCastT<Vec3, Mat44, ShapeCast>::ShapeCastT;70};7172struct RShapeCast : public ShapeCastT<RVec3, RMat44, RShapeCast>73{74using ShapeCastT<RVec3, RMat44, RShapeCast>::ShapeCastT;7576/// Convert from ShapeCast, converts single to double precision77explicit RShapeCast(const ShapeCast &inCast) :78RShapeCast(inCast.mShape, inCast.mScale, RMat44(inCast.mCenterOfMassStart), inCast.mDirection, inCast.mShapeWorldBounds)79{80}8182/// Convert to ShapeCast, which implies casting from double precision to single precision83explicit operator ShapeCast() const84{85return ShapeCast(mShape, mScale, mCenterOfMassStart.ToMat44(), mDirection, mShapeWorldBounds);86}87};8889/// Settings to be passed with a shape cast90class ShapeCastSettings : public CollideSettingsBase91{92public:93JPH_OVERRIDE_NEW_DELETE9495/// Set the backfacing mode for all shapes96void SetBackFaceMode(EBackFaceMode inMode) { mBackFaceModeTriangles = mBackFaceModeConvex = inMode; }9798/// How backfacing triangles should be treated (should we report moving from back to front for triangle based shapes, e.g. for MeshShape/HeightFieldShape?)99EBackFaceMode mBackFaceModeTriangles = EBackFaceMode::IgnoreBackFaces;100101/// How backfacing convex objects should be treated (should we report starting inside an object and moving out?)102EBackFaceMode mBackFaceModeConvex = EBackFaceMode::IgnoreBackFaces;103104/// Indicates if we want to shrink the shape by the convex radius and then expand it again. This speeds up collision detection and gives a more accurate normal at the cost of a more 'rounded' shape.105bool mUseShrunkenShapeAndConvexRadius = false;106107/// When true, and the shape is intersecting at the beginning of the cast (fraction = 0) then this will calculate the deepest penetration point (costing additional CPU time)108bool mReturnDeepestPoint = false;109};110111/// Result of a shape cast test112class ShapeCastResult : public CollideShapeResult113{114public:115JPH_OVERRIDE_NEW_DELETE116117/// Default constructor118ShapeCastResult() = default;119120/// Constructor121/// @param inFraction Fraction at which the cast hit122/// @param inContactPoint1 Contact point on shape 1123/// @param inContactPoint2 Contact point on shape 2124/// @param inContactNormalOrPenetrationDepth Contact normal pointing from shape 1 to 2 or penetration depth vector when the objects are penetrating (also from 1 to 2)125/// @param inBackFaceHit If this hit was a back face hit126/// @param inSubShapeID1 Sub shape id for shape 1127/// @param inSubShapeID2 Sub shape id for shape 2128/// @param inBodyID2 BodyID that was hit129ShapeCastResult(float inFraction, Vec3Arg inContactPoint1, Vec3Arg inContactPoint2, Vec3Arg inContactNormalOrPenetrationDepth, bool inBackFaceHit, const SubShapeID &inSubShapeID1, const SubShapeID &inSubShapeID2, const BodyID &inBodyID2) :130CollideShapeResult(inContactPoint1, inContactPoint2, inContactNormalOrPenetrationDepth, (inContactPoint2 - inContactPoint1).Length(), inSubShapeID1, inSubShapeID2, inBodyID2),131mFraction(inFraction),132mIsBackFaceHit(inBackFaceHit)133{134}135136/// Function required by the CollisionCollector. A smaller fraction is considered to be a 'better hit'. For rays/cast shapes we can just use the collision fraction. The fraction and penetration depth are combined in such a way that deeper hits at fraction 0 go first.137inline float GetEarlyOutFraction() const { return mFraction > 0.0f? mFraction : -mPenetrationDepth; }138139/// Reverses the hit result, swapping contact point 1 with contact point 2 etc.140/// @param inWorldSpaceCastDirection Direction of the shape cast in world space141ShapeCastResult Reversed(Vec3Arg inWorldSpaceCastDirection) const142{143// Calculate by how much to shift the contact points144Vec3 delta = mFraction * inWorldSpaceCastDirection;145146ShapeCastResult result;147result.mContactPointOn2 = mContactPointOn1 - delta;148result.mContactPointOn1 = mContactPointOn2 - delta;149result.mPenetrationAxis = -mPenetrationAxis;150result.mPenetrationDepth = mPenetrationDepth;151result.mSubShapeID2 = mSubShapeID1;152result.mSubShapeID1 = mSubShapeID2;153result.mBodyID2 = mBodyID2;154result.mFraction = mFraction;155result.mIsBackFaceHit = mIsBackFaceHit;156157result.mShape2Face.resize(mShape1Face.size());158for (Face::size_type i = 0; i < mShape1Face.size(); ++i)159result.mShape2Face[i] = mShape1Face[i] - delta;160161result.mShape1Face.resize(mShape2Face.size());162for (Face::size_type i = 0; i < mShape2Face.size(); ++i)163result.mShape1Face[i] = mShape2Face[i] - delta;164165return result;166}167168float mFraction; ///< This is the fraction where the shape hit the other shape: CenterOfMassOnHit = Start + value * (End - Start)169bool mIsBackFaceHit; ///< True if the shape was hit from the back side170};171172JPH_NAMESPACE_END173174175