Skip to content

Commit

Permalink
Bounding box performance experiments (erincatto#829)
Browse files Browse the repository at this point in the history
- adjusted AABB margin based on performance testing
- compute rotation between vectors
- added macOS samples to GitHub actions

erincatto#833, erincatto#835
  • Loading branch information
erincatto authored and zero-meta committed Nov 11, 2024
1 parent fea4238 commit 4bcae0d
Show file tree
Hide file tree
Showing 18 changed files with 104 additions and 220 deletions.
16 changes: 14 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ jobs:
run: ./bin/${{env.BUILD_TYPE}}/test

samples-windows:
name: windows
name: samples-windows
runs-on: windows-latest
steps:

Expand All @@ -102,4 +102,16 @@ jobs:

- name: Build
run: cmake --build ${{github.workspace}}/build --config Release


samples-macos:
name: samples-macos
runs-on: macos-latest

steps:
- uses: actions/checkout@v4

- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=Release -DBOX2D_SAMPLES=ON -DBUILD_SHARED_LIBS=OFF -DBOX2D_UNIT_TESTS=OFF

- name: Build
run: cmake --build ${{github.workspace}}/build --config Release
2 changes: 1 addition & 1 deletion docs/FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ Box2D also does not have exact collision. There is no continuous collision betwe
Making a worms clone requires arbitrarily destructible terrain. This is beyond the scope of Box2D, so you will have to figure out how to do this on your own.

### Tile Based Environment
Using many boxes for your terrain may not work well because box-like characters can get snagged on internal corners. Box2D proves chain shapes for smooth collision, see `b2ChainDef`. In general you should avoid using a rectangular character because collision tolerances will still lead to undesirable snagging. Box2D provides capsules and rounded polygons that may work better for characters.
Using many boxes for your terrain may not work well because box-like characters can get snagged on internal corners. Box2D provides chain shapes for smooth collision, see `b2ChainDef`. In general you should avoid using a rectangular character because collision tolerances will still lead to undesirable snagging. Box2D provides capsules and rounded polygons that may work better for characters.

### Asteroid Type Coordinate Systems
Box2D does not have any support for coordinate frame wrapping. You would likely need to customize Box2D for this purpose. You may need to use a different broad-phase for this to work.
Expand Down
14 changes: 8 additions & 6 deletions include/box2d/collision.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,17 +249,17 @@ B2_API bool b2PointInCapsule( b2Vec2 point, const b2Capsule* shape );
/// Test a point for overlap with a convex polygon in local space
B2_API bool b2PointInPolygon( b2Vec2 point, const b2Polygon* shape );

/// Ray cast versus circle in shape local space. Initial overlap is treated as a miss.
/// Ray cast versus circle shape in local space. Initial overlap is treated as a miss.
B2_API b2CastOutput b2RayCastCircle( const b2RayCastInput* input, const b2Circle* shape );

/// Ray cast versus capsule in shape local space. Initial overlap is treated as a miss.
/// Ray cast versus capsule shape in local space. Initial overlap is treated as a miss.
B2_API b2CastOutput b2RayCastCapsule( const b2RayCastInput* input, const b2Capsule* shape );

/// Ray cast versus segment in shape local space. Optionally treat the segment as one-sided with hits from
/// Ray cast versus segment shape in local space. Optionally treat the segment as one-sided with hits from
/// the left side being treated as a miss.
B2_API b2CastOutput b2RayCastSegment( const b2RayCastInput* input, const b2Segment* shape, bool oneSided );

/// Ray cast versus polygon in shape local space. Initial overlap is treated as a miss.
/// Ray cast versus polygon shape in local space. Initial overlap is treated as a miss.
B2_API b2CastOutput b2RayCastPolygon( const b2RayCastInput* input, const b2Polygon* shape );

/// Shape cast versus a circle. Initial overlap is treated as a miss.
Expand Down Expand Up @@ -348,8 +348,10 @@ typedef struct b2DistanceProxy
float radius;
} b2DistanceProxy;

/// Used to warm start b2Distance. Set count to zero on first call or
/// use zero initialization.
/// Used to warm start the GJK simplex. If you call this function multiple times with nearby
/// transforms this might improve performance. Otherwise you can zero initialize this.
/// The distance cache must be initialized to zero on the first call.
/// Users should generally just zero initialize this structure for each call.
typedef struct b2DistanceCache
{
/// The number of stored simplex points
Expand Down
8 changes: 8 additions & 0 deletions include/box2d/math_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,9 @@ B2_INLINE b2Rot b2MakeRot( float angle )
return B2_LITERAL( b2Rot ){ cs.cosine, cs.sine };
}

/// Compute the rotation between two unit vectors
B2_API b2Rot b2ComputeRotationBetweenUnitVectors( b2Vec2 v1, b2Vec2 v2 );

/// Is this rotation normalized?
B2_INLINE bool b2IsNormalized( b2Rot q )
{
Expand All @@ -352,6 +355,7 @@ B2_INLINE bool b2IsNormalized( b2Rot q )

/// Normalized linear interpolation
/// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
/// https://web.archive.org/web/20170825184056/http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/
B2_INLINE b2Rot b2NLerp( b2Rot q1, b2Rot q2, float t )
{
float omt = 1.0f - t;
Expand Down Expand Up @@ -499,6 +503,9 @@ B2_INLINE b2Vec2 b2InvTransformPoint( b2Transform t, const b2Vec2 p )
return B2_LITERAL( b2Vec2 ){ t.q.c * vx + t.q.s * vy, -t.q.s * vx + t.q.c * vy };
}

/// Multiply two transforms. If the result is applied to a point p local to frame B,
/// the transform would first convert p to a point local to frame A, then into a point
/// in the world frame.
/// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p
/// = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p
B2_INLINE b2Transform b2MulTransforms( b2Transform A, b2Transform B )
Expand All @@ -509,6 +516,7 @@ B2_INLINE b2Transform b2MulTransforms( b2Transform A, b2Transform B )
return C;
}

/// Creates a transform that converts a local point in frame B to a local point in frame A.
/// v2 = A.q' * (B.q * v1 + B.p - A.p)
/// = A.q' * B.q * v1 + A.q' * (B.p - A.p)
B2_INLINE b2Transform b2InvMulTransforms( b2Transform A, b2Transform B )
Expand Down
6 changes: 6 additions & 0 deletions include/box2d/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,9 @@ typedef struct b2SensorBeginTouchEvent
} b2SensorBeginTouchEvent;

/// An end touch event is generated when a shape stops overlapping a sensor shape.
/// You will not get an end event if you do anything that destroys contacts outside
/// of the world step. These include things like setting the transform, destroying a body
/// or shape, or changing a filter or body type.
typedef struct b2SensorEndTouchEvent
{
/// The id of the sensor shape
Expand Down Expand Up @@ -1046,6 +1049,9 @@ typedef struct b2ContactBeginTouchEvent
} b2ContactBeginTouchEvent;

/// An end touch event is generated when two shapes stop touching.
/// You will not get an end event if you do anything that destroys contacts outside
/// of the world step. These include things like setting the transform, destroying a body
/// or shape, or changing a filter or body type.
typedef struct b2ContactEndTouchEvent
{
/// Id of the first shape
Expand Down
9 changes: 2 additions & 7 deletions samples/draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,11 +633,6 @@ struct GLTriangles
GLint m_projectionUniform;
};

struct Transform
{
float x, y, c, s;
};

struct CircleData
{
b2Vec2 position;
Expand Down Expand Up @@ -781,7 +776,7 @@ struct GLCircles

struct SolidCircleData
{
Transform transform;
b2Transform transform;
float radius;
RGBA8 rgba;
};
Expand Down Expand Up @@ -926,7 +921,7 @@ struct GLSolidCircles

struct CapsuleData
{
Transform transform;
b2Transform transform;
float radius;
float length;
RGBA8 rgba;
Expand Down
6 changes: 3 additions & 3 deletions samples/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ static inline int CompareSamples( const void* a, const void* b )
return result;
}

static void SortTests()
static void SortSamples()
{
qsort( g_sampleEntries, g_sampleCount, sizeof( SampleEntry ), CompareSamples );
}
Expand Down Expand Up @@ -462,7 +462,7 @@ static void UpdateUI()

ImGuiTreeNodeFlags nodeFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;

if ( ImGui::BeginTabItem( "Tests" ) )
if ( ImGui::BeginTabItem( "Samples" ) )
{
int categoryIndex = 0;
const char* category = g_sampleEntries[categoryIndex].category;
Expand Down Expand Up @@ -538,7 +538,7 @@ int main( int, char** )

s_settings.Load();
s_settings.workerCount = b2MinInt( 8, (int)enki::GetNumHardwareThreads() / 2 );
SortTests();
SortSamples();

glfwSetErrorCallback( glfwErrorCallback );

Expand Down
Loading

0 comments on commit 4bcae0d

Please sign in to comment.