Jolt Physics
A multi core friendly Game Physics Engine
Loading...
Searching...
No Matches
InternalEdgeRemovingCollector.h
Go to the documentation of this file.
1// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2// SPDX-FileCopyrightText: 2024 Jorrit Rouwe
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
9
10//#define JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
11
12#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
14#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
15
17
21{
22 static constexpr uint cMaxDelayedResults = 16;
23 static constexpr uint cMaxVoidedFeatures = 128;
24
26 inline bool IsVoided(Vec3 inV) const
27 {
28 for (const Float3 &vf : mVoidedFeatures)
29 if (inV.IsClose(Vec3::sLoadFloat3Unsafe(vf), 1.0e-8f))
30 return true;
31 return false;
32 }
33
35 inline void VoidFeatures(const CollideShapeResult &inResult)
36 {
37 for (const Vec3 &v : inResult.mShape2Face)
38 if (!IsVoided(v))
39 {
40 if (mVoidedFeatures.size() == cMaxVoidedFeatures)
41 break;
42 Float3 f;
43 v.StoreFloat3(&f);
44 mVoidedFeatures.push_back(f);
45 }
46 }
47
49 inline void Chain(const CollideShapeResult &inResult)
50 {
51 // Make sure the chained collector has the same context as we do
52 mChainedCollector.SetContext(GetContext());
53
54 // Forward the hit
55 mChainedCollector.AddHit(inResult);
56
57 // If our chained collector updated its early out fraction, we need to follow
59 }
60
62 inline void ChainAndVoid(const CollideShapeResult &inResult)
63 {
64 Chain(inResult);
65 VoidFeatures(inResult);
66
67 #ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
70 #endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
71 }
72
73public:
76 mChainedCollector(inChainedCollector)
77 {
78 }
79
80 // See: CollideShapeCollector::Reset
81 virtual void Reset() override
82 {
84
85 mChainedCollector.Reset();
86
87 mVoidedFeatures.clear();
88 mDelayedResults.clear();
89 }
90
91 // See: CollideShapeCollector::OnBody
92 virtual void OnBody(const Body &inBody) override
93 {
94 // Just forward the call to our chained collector
95 mChainedCollector.OnBody(inBody);
96 }
97
98 // See: CollideShapeCollector::AddHit
99 virtual void AddHit(const CollideShapeResult &inResult) override
100 {
101 // We only support welding when the shape is a triangle or has more vertices so that we can calculate a normal
102 if (inResult.mShape2Face.size() < 3)
103 return ChainAndVoid(inResult);
104
105 // Get the triangle normal of shape 2 face
106 Vec3 triangle_normal = (inResult.mShape2Face[1] - inResult.mShape2Face[0]).Cross(inResult.mShape2Face[2] - inResult.mShape2Face[0]);
107 float triangle_normal_len = triangle_normal.Length();
108 if (triangle_normal_len < 1e-6f)
109 return ChainAndVoid(inResult);
110
111 // If the triangle normal matches the contact normal within 1 degree, we can process the contact immediately
112 // We make the assumption here that if the contact normal and the triangle normal align that the we're dealing with a 'face contact'
113 Vec3 contact_normal = -inResult.mPenetrationAxis;
114 float contact_normal_len = inResult.mPenetrationAxis.Length();
115 if (triangle_normal.Dot(contact_normal) > 0.999848f * contact_normal_len * triangle_normal_len) // cos(1 degree)
116 return ChainAndVoid(inResult);
117
118 // Delayed processing
119 if (mDelayedResults.size() == cMaxDelayedResults)
120 return ChainAndVoid(inResult);
121 mDelayedResults.push_back(inResult);
122 }
123
125 void Flush()
126 {
127 // Sort on biggest penetration depth first
128 uint sorted_indices[cMaxDelayedResults];
129 for (uint i = 0; i < uint(mDelayedResults.size()); ++i)
130 sorted_indices[i] = i;
131 QuickSort(sorted_indices, sorted_indices + mDelayedResults.size(), [this](uint inLHS, uint inRHS) { return mDelayedResults[inLHS].mPenetrationDepth > mDelayedResults[inRHS].mPenetrationDepth; });
132
133 // Loop over all results
134 for (uint i = 0; i < uint(mDelayedResults.size()); ++i)
135 {
136 const CollideShapeResult &r = mDelayedResults[sorted_indices[i]];
137
138 // Determine which vertex or which edge is the closest to the contact point
139 float best_dist_sq = FLT_MAX;
140 uint best_v1_idx = 0;
141 uint best_v2_idx = 0;
142 uint num_v = uint(r.mShape2Face.size());
143 uint v1_idx = num_v - 1;
144 Vec3 v1 = r.mShape2Face[v1_idx] - r.mContactPointOn2;
145 for (uint v2_idx = 0; v2_idx < num_v; ++v2_idx)
146 {
147 Vec3 v2 = r.mShape2Face[v2_idx] - r.mContactPointOn2;
148 Vec3 v1_v2 = v2 - v1;
149 float denominator = v1_v2.LengthSq();
150 if (denominator < Square(FLT_EPSILON))
151 {
152 // Degenerate, assume v1 is closest, v2 will be tested in a later iteration
153 float v1_len_sq = v1.LengthSq();
154 if (v1_len_sq < best_dist_sq)
155 {
156 best_dist_sq = v1_len_sq;
157 best_v1_idx = v1_idx;
158 best_v2_idx = v1_idx;
159 }
160 }
161 else
162 {
163 // Taken from ClosestPoint::GetBaryCentricCoordinates
164 float fraction = -v1.Dot(v1_v2) / denominator;
165 if (fraction < 1.0e-6f)
166 {
167 // Closest lies on v1
168 float v1_len_sq = v1.LengthSq();
169 if (v1_len_sq < best_dist_sq)
170 {
171 best_dist_sq = v1_len_sq;
172 best_v1_idx = v1_idx;
173 best_v2_idx = v1_idx;
174 }
175 }
176 else if (fraction < 1.0f - 1.0e-6f)
177 {
178 // Closest lies on the line segment v1, v2
179 Vec3 closest = v1 + fraction * v1_v2;
180 float closest_len_sq = closest.LengthSq();
181 if (closest_len_sq < best_dist_sq)
182 {
183 best_dist_sq = closest_len_sq;
184 best_v1_idx = v1_idx;
185 best_v2_idx = v2_idx;
186 }
187 }
188 // else closest is v2, but v2 will be tested in a later iteration
189 }
190
191 v1_idx = v2_idx;
192 v1 = v2;
193 }
194
195 // Check if this vertex/edge is voided
196 bool voided = IsVoided(r.mShape2Face[best_v1_idx])
197 && (best_v1_idx == best_v2_idx || IsVoided(r.mShape2Face[best_v2_idx]));
198
199 #ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
200 Color color = voided? Color::sRed : Color::sYellow;
204 DebugRenderer::sInstance->DrawMarker(RVec3(r.mShape2Face[best_v1_idx]), IsVoided(r.mShape2Face[best_v1_idx])? Color::sRed : Color::sYellow, 0.1f);
205 DebugRenderer::sInstance->DrawMarker(RVec3(r.mShape2Face[best_v2_idx]), IsVoided(r.mShape2Face[best_v2_idx])? Color::sRed : Color::sYellow, 0.1f);
206 #endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
207
208 // No voided features, accept the contact
209 if (!voided)
210 Chain(r);
211
212 // Void the features of this face
213 VoidFeatures(r);
214 }
215
216 // All delayed results have been processed
217 mVoidedFeatures.clear();
218 mDelayedResults.clear();
219 }
220
222 static void sCollideShapeVsShape(const Shape *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 = { })
223 {
224 JPH_ASSERT(inCollideShapeSettings.mCollectFacesMode == ECollectFacesMode::CollectFaces); // Won't work without collecting faces
225
226 InternalEdgeRemovingCollector wrapper(ioCollector);
227 CollisionDispatch::sCollideShapeVsShape(inShape1, inShape2, inScale1, inScale2, inCenterOfMassTransform1, inCenterOfMassTransform2, inSubShapeIDCreator1, inSubShapeIDCreator2, inCollideShapeSettings, wrapper, inShapeFilter);
228 wrapper.Flush();
229 }
230
231private:
232 CollideShapeCollector & mChainedCollector;
233 StaticArray<Float3, cMaxVoidedFeatures> mVoidedFeatures; // Read with Vec3::sLoadFloat3Unsafe so must not be the last member
235};
236
@ CollectFaces
mShape1/2Face is desired
unsigned int uint
Definition Core.h:448
#define JPH_NAMESPACE_END
Definition Core.h:377
#define JPH_NAMESPACE_BEGIN
Definition Core.h:371
#define JPH_ASSERT(...)
Definition IssueReporting.h:33
constexpr T Square(T inV)
Square a value.
Definition Math.h:52
void QuickSort(Iterator inBegin, Iterator inEnd, Compare inCompare)
Implementation of the quick sort algorithm. The STL version implementation is not consistent across p...
Definition QuickSort.h:53
Vec3 RVec3
Definition Real.h:29
JPH_SUPPRESS_WARNINGS_STD_BEGIN JPH_SUPPRESS_WARNINGS_STD_END JPH_NAMESPACE_BEGIN String StringFormat(const char *inFMT,...)
Definition StringTools.cpp:15
Definition Body.h:35
ECollectFacesMode mCollectFacesMode
If colliding faces should be collected or only the collision point.
Definition CollideShape.h:80
Class that contains all information of two colliding shapes.
Definition CollideShape.h:19
Vec3 mContactPointOn2
Contact point on the surface of shape 2 (in world space or relative to base offset)....
Definition CollideShape.h:60
Vec3 mPenetrationAxis
Direction to move shape 2 out of collision along the shortest path (magnitude is meaningless,...
Definition CollideShape.h:61
float mPenetrationDepth
Penetration depth (move shape 2 by this distance to resolve the collision)
Definition CollideShape.h:62
Face mShape2Face
Colliding face on shape 2 (optional result, in world space or relative to base offset)
Definition CollideShape.h:67
Settings to be passed with a collision query.
Definition CollideShape.h:94
Virtual interface that allows collecting multiple collision results.
Definition CollisionCollector.h:45
virtual void AddHit(const ResultType &inResult)=0
This function will be called for every hit found, it's up to the application to decide how to store t...
virtual void Reset()
If you want to reuse this collector, call Reset()
Definition CollisionCollector.h:62
float GetEarlyOutFraction() const
Get the current early out value.
Definition CollisionCollector.h:89
const TransformedShape * GetContext() const
Definition CollisionCollector.h:71
virtual void OnBody(const Body &inBody)
Definition CollisionCollector.h:67
void UpdateEarlyOutFraction(float inFraction)
Update the early out fraction (should be lower than before)
Definition CollisionCollector.h:77
void SetContext(const TransformedShape *inContext)
Set by the collision detection functions to the current TransformedShape that we're colliding against...
Definition CollisionCollector.h:70
static void sCollideShapeVsShape(const Shape *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={ })
Definition CollisionDispatch.h:33
Class that holds an RGBA color with 8-bits per component.
Definition Color.h:16
static const Color sGreen
Definition Color.h:57
static const Color sRed
Definition Color.h:55
static const Color sYellow
Definition Color.h:60
virtual void DrawText3D(RVec3Arg inPosition, const string_view &inString, ColorArg inColor=Color::sWhite, float inHeight=0.5f)=0
Draw text.
void DrawMarker(RVec3Arg inPosition, ColorArg inColor, float inSize)
Draw a marker on a position.
Definition DebugRenderer.cpp:172
static DebugRenderer * sInstance
Singleton instance.
Definition DebugRenderer.h:168
void DrawWirePolygon(RMat44Arg inTransform, const VERTEX_ARRAY &inVertices, ColorArg inColor, float inArrowSize=0.0f)
Draw a wireframe polygon.
Definition DebugRenderer.h:83
void DrawArrow(RVec3Arg inFrom, RVec3Arg inTo, ColorArg inColor, float inSize)
Draw an arrow.
Definition DebugRenderer.cpp:184
Class that holds 3 floats. Used as a storage class. Convert to Vec3 for calculations.
Definition Float3.h:13
Definition InternalEdgeRemovingCollector.h:21
virtual void OnBody(const Body &inBody) override
Definition InternalEdgeRemovingCollector.h:92
void Flush()
After all hits have been added, call this function to process the delayed results.
Definition InternalEdgeRemovingCollector.h:125
InternalEdgeRemovingCollector(CollideShapeCollector &inChainedCollector)
Constructor, configures a collector to be called with all the results that do not hit internal edges.
Definition InternalEdgeRemovingCollector.h:75
static void sCollideShapeVsShape(const Shape *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={ })
Version of CollisionDispatch::sCollideShapeVsShape that removes internal edges.
Definition InternalEdgeRemovingCollector.h:222
virtual void Reset() override
If you want to reuse this collector, call Reset()
Definition InternalEdgeRemovingCollector.h:81
virtual void AddHit(const CollideShapeResult &inResult) override
Definition InternalEdgeRemovingCollector.h:99
Holds a 4x4 matrix of floats, but supports also operations on the 3x3 upper left part of the matrix.
Definition Mat44.h:13
static JPH_INLINE Mat44 sIdentity()
Identity matrix.
Definition Mat44.inl:35
Filter class.
Definition ShapeFilter.h:17
Base class for all shapes (collision volume of a body). Defines a virtual interface for collision det...
Definition Shape.h:178
Simple variable length array backed by a fixed size buffer.
Definition StaticArray.h:14
void push_back(const T &inElement)
Add element to the back of the array.
Definition StaticArray.h:61
void clear()
Destruct all elements and set length to zero.
Definition StaticArray.h:52
size_type size() const
Returns amount of elements in the array.
Definition StaticArray.h:89
Definition SubShapeID.h:108
Definition Vec3.h:17
JPH_INLINE bool IsClose(Vec3Arg inV2, float inMaxDistSq=1.0e-12f) const
Test if two vectors are close.
Definition Vec3.inl:342
JPH_INLINE float Dot(Vec3Arg inV2) const
Dot product.
Definition Vec3.inl:645
JPH_INLINE float Length() const
Length of vector.
Definition Vec3.inl:677
JPH_INLINE Vec3 NormalizedOr(Vec3Arg inZeroValue) const
Normalize vector or return inZeroValue if the length of the vector is zero.
Definition Vec3.inl:716
JPH_INLINE float LengthSq() const
Squared length of vector.
Definition Vec3.inl:661
static JPH_INLINE Vec3 sZero()
Vector with all zeros.
Definition Vec3.inl:107
static JPH_INLINE Vec3 sLoadFloat3Unsafe(const Float3 &inV)
Load 3 floats from memory (reads 32 bits extra which it doesn't use)
Definition Vec3.inl:134