Skip to content

Commit 07e72da

Browse files
committed
[upstream] Kinematic perf (erincatto/box2d#970)
Kinematic perf (erincatto/box2d#970) - b2Shape_SetMaterial -> b2Shape_SetUserMaterial - Reworked surface material access on chain shapes - Removed mouse joint. Functionality is now covered by the motor joint. - Added b2DynamicTree_QueryAll to support debug draw for shapes that don't collide - The user material id is now a 64 bits - Fixed crash when samples app is minimized - Added kinematic washer sample - Fix erincatto/box2d#967 - #968 - draw shapes with 0 category bits and draw sleeping contacts - Kinematic bodies no longer enter graph coloring - The joint and contact solvers no longer write the state of kinematic bodies - Large kinematic bodies touching many dynamic bodies now has better multithreaded scaling - Joints between two non-dynamic bodies no longer simulate - Minor island splitting optimization suggested by Dirk, use the island id instead of a bool mark - Joints now have a constraint damping ratio of 2.0 instead of 0. Intended to reduce overshoot when limits are violated. - Restored island debug draw
1 parent 1cb5e7a commit 07e72da

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+954
-909
lines changed

src/.DS_Store

6 KB
Binary file not shown.

src/Box2D.NET.Samples/Camera.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,17 @@ public void BuildProjectionMatrix(Span<float> m, float zBias)
100100

101101
public B2AABB GetViewBounds()
102102
{
103-
B2AABB bounds;
104-
bounds.lowerBound = ConvertScreenToWorld(new B2Vec2(0.0f, (float)m_height));
105-
bounds.upperBound = ConvertScreenToWorld(new B2Vec2((float)m_width, 0.0f));
106-
return bounds;
103+
if (m_height == 0.0f || m_width == 0.0f)
104+
{
105+
B2AABB bounds = new B2AABB(b2Vec2_zero, b2Vec2_zero);
106+
return bounds;
107+
}
108+
109+
{
110+
B2AABB bounds;
111+
bounds.lowerBound = ConvertScreenToWorld(new B2Vec2(0.0f, (float)m_height));
112+
bounds.upperBound = ConvertScreenToWorld(new B2Vec2((float)m_width, 0.0f));
113+
return bounds;
114+
}
107115
}
108116
}

src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkSensor.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,15 @@ public BenchmarkSensor(SampleContext context) : base(context)
8484

8585
float yStart = 10.0f;
8686
m_filterRow = m_rowCount >> 1;
87-
87+
8888
for (int j = 0; j < m_rowCount; ++j)
8989
{
9090
m_passiveSensors[j] = new ShapeUserData();
9191
m_passiveSensors[j].row = j;
9292
m_passiveSensors[j].active = false;
9393
shapeDef.userData = m_passiveSensors[j];
94-
95-
if ( j == m_filterRow )
94+
95+
if (j == m_filterRow)
9696
{
9797
shapeDef.enableCustomFiltering = true;
9898
shapeDef.material.customColor = (uint)B2HexColor.b2_colorFuchsia;
@@ -199,7 +199,7 @@ public override void Step()
199199
// Modify color while overlapped with a sensor
200200
B2SurfaceMaterial surfaceMaterial = b2Shape_GetSurfaceMaterial(@event.visitorShapeId);
201201
surfaceMaterial.customColor = (uint)B2HexColor.b2_colorLime;
202-
b2Shape_SetSurfaceMaterial(@event.visitorShapeId, surfaceMaterial);
202+
b2Shape_SetSurfaceMaterial(@event.visitorShapeId, ref surfaceMaterial);
203203
}
204204
}
205205

@@ -215,7 +215,7 @@ public override void Step()
215215
// Restore color to default
216216
B2SurfaceMaterial surfaceMaterial = b2Shape_GetSurfaceMaterial(@event.visitorShapeId);
217217
surfaceMaterial.customColor = 0;
218-
b2Shape_SetSurfaceMaterial(@event.visitorShapeId, surfaceMaterial);
218+
b2Shape_SetSurfaceMaterial(@event.visitorShapeId, ref surfaceMaterial);
219219
}
220220

221221
foreach (B2BodyId bodyId in zombies)

src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkSleep.cs

Lines changed: 52 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using static Box2D.NET.B2Shapes;
1010
using static Box2D.NET.B2Timers;
1111
using static Box2D.NET.B2Diagnostics;
12+
using static Box2D.NET.B2Joints;
1213

1314
namespace Box2D.NET.Samples.Samples.Benchmarks;
1415

@@ -22,11 +23,8 @@ public class BenchmarkSleep : Sample
2223
private B2BodyId[] m_bodies = new B2BodyId[e_maxBodyCount];
2324
private int m_bodyCount;
2425
private int m_baseCount;
25-
private int m_iterations;
2626
private float m_wakeTotal;
2727
private float m_sleepTotal;
28-
private int m_wakeCount;
29-
private int m_sleepCount;
3028
private bool m_awake;
3129

3230

@@ -44,36 +42,20 @@ public BenchmarkSleep(SampleContext context) : base(context)
4442
m_camera.m_zoom = 25.0f * 2.2f;
4543
}
4644

47-
float groundSize = 100.0f;
48-
49-
B2BodyDef bodyDef = b2DefaultBodyDef();
50-
B2BodyId groundId = b2CreateBody(m_worldId, ref bodyDef);
45+
{
46+
float groundSize = 100.0f;
5147

52-
B2Polygon box = b2MakeBox(groundSize, 1.0f);
53-
B2ShapeDef shapeDef = b2DefaultShapeDef();
54-
b2CreatePolygonShape(groundId, ref shapeDef, ref box);
48+
B2BodyDef bodyDef = b2DefaultBodyDef();
49+
B2BodyId groundId = b2CreateBody(m_worldId, ref bodyDef);
5550

56-
for (int i = 0; i < e_maxBodyCount; ++i)
57-
{
58-
m_bodies[i] = b2_nullBodyId;
51+
B2Polygon box = b2MakeBox(groundSize, 1.0f);
52+
B2ShapeDef shapeDef = b2DefaultShapeDef();
53+
b2CreatePolygonShape(groundId, ref shapeDef, ref box);
5954
}
6055

6156
m_baseCount = m_isDebug ? 40 : 100;
62-
m_iterations = m_isDebug ? 1 : 41;
6357
m_bodyCount = 0;
64-
m_awake = false;
65-
66-
m_wakeTotal = 0.0f;
67-
m_wakeCount = 0;
68-
69-
m_sleepTotal = 0.0f;
70-
m_sleepCount = 0;
71-
72-
CreateScene();
73-
}
7458

75-
void CreateScene()
76-
{
7759
for (int i = 0; i < e_maxBodyCount; ++i)
7860
{
7961
if (B2_IS_NON_NULL(m_bodies[i]))
@@ -89,77 +71,73 @@ void CreateScene()
8971
float centerx = shift * count / 2.0f;
9072
float centery = shift / 2.0f + 1.0f;
9173

92-
B2BodyDef bodyDef = b2DefaultBodyDef();
93-
bodyDef.type = B2BodyType.b2_dynamicBody;
74+
{
75+
B2BodyDef bodyDef = b2DefaultBodyDef();
76+
bodyDef.type = B2BodyType.b2_dynamicBody;
9477

95-
B2ShapeDef shapeDef = b2DefaultShapeDef();
96-
shapeDef.density = 1.0f;
97-
shapeDef.material.friction = 0.5f;
78+
B2ShapeDef shapeDef = b2DefaultShapeDef();
79+
shapeDef.density = 1.0f;
80+
shapeDef.material.friction = 0.5f;
9881

99-
float h = 0.5f;
100-
B2Polygon box = b2MakeRoundedBox(h, h, 0.0f);
82+
float h = 0.5f;
83+
B2Polygon box = b2MakeRoundedBox(h, h, 0.0f);
10184

102-
int index = 0;
85+
int index = 0;
10386

104-
for (int i = 0; i < count; ++i)
105-
{
106-
float y = i * shift + centery;
107-
108-
for (int j = i; j < count; ++j)
87+
for (int i = 0; i < count; ++i)
10988
{
110-
float x = 0.5f * i * shift + (j - i) * shift - centerx;
111-
bodyDef.position = new B2Vec2(x, y);
89+
float y = i * shift + centery;
90+
91+
for (int j = i; j < count; ++j)
92+
{
93+
float x = 0.5f * i * shift + (j - i) * shift - centerx;
94+
bodyDef.position = new B2Vec2(x, y);
11295

113-
B2_ASSERT(index < e_maxBodyCount);
114-
m_bodies[index] = b2CreateBody(m_worldId, ref bodyDef);
115-
b2CreatePolygonShape(m_bodies[index], ref shapeDef, ref box);
96+
B2_ASSERT(index < e_maxBodyCount);
97+
m_bodies[index] = b2CreateBody(m_worldId, ref bodyDef);
98+
b2CreatePolygonShape(m_bodies[index], ref shapeDef, ref box);
11699

117-
index += 1;
100+
index += 1;
101+
}
118102
}
119-
}
120103

121-
m_bodyCount = index;
104+
m_bodyCount = index;
105+
m_wakeTotal = 0.0f;
106+
m_sleepTotal = 0.0f;
107+
}
122108
}
123109

124110
public override void Step()
125111
{
126-
ulong ticks = b2GetTicks();
127-
128-
for (int i = 0; i < m_iterations; ++i)
112+
// These operations don't show up in b2Profile
113+
if (m_stepCount > 20)
129114
{
130-
b2Body_SetAwake(m_bodies[0], m_awake);
131-
if (m_awake)
132-
{
133-
m_wakeTotal += b2GetMillisecondsAndReset(ref ticks);
134-
m_wakeCount += 1;
135-
}
136-
else
137-
{
138-
m_sleepTotal += b2GetMillisecondsAndReset(ref ticks);
139-
m_sleepCount += 1;
140-
}
115+
// Creating and destroying a joint will engage the island splitter.
116+
b2FilterJointDef jointDef = b2DefaultFilterJointDef();
117+
jointDef.@base.bodyIdA = m_bodies[0];
118+
jointDef.@base.bodyIdB = m_bodies[1];
119+
B2JointId jointId = b2CreateFilterJoint(m_worldId, ref jointDef);
141120

142-
m_awake = !m_awake;
143-
}
121+
ulong ticks = b2GetTicks();
144122

123+
// This will wake the island
124+
b2DestroyJoint(jointId);
125+
m_wakeTotal += b2GetMillisecondsAndReset(ref ticks);
126+
127+
// Put the island back to sleep. It must be split because a constraint was removed.
128+
b2Body_SetAwake(m_bodies[0], false);
129+
m_sleepTotal += b2GetMillisecondsAndReset(ref ticks);
130+
}
145131

146132
base.Step();
147133
}
148134

149135
public override void Draw(Settings settings)
150136
{
151137
base.Draw(settings);
152-
153-
if (m_wakeCount > 0)
154-
{
155-
DrawTextLine($"wake ave = {m_wakeTotal / m_wakeCount:g} ms");
156-
157-
}
158138

159-
if (m_sleepCount > 0)
160-
{
161-
DrawTextLine($"sleep ave = {m_sleepTotal / m_sleepCount:g} ms");
162-
163-
}
139+
int count = m_stepCount - 20;
140+
DrawTextLine($"wake ave = {m_wakeTotal / count:g} ms");
141+
DrawTextLine($"sleep ave = {m_sleepTotal / count:g} ms");
164142
}
165143
}

src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkTumbler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public BenchmarkTumbler(SampleContext context) : base(context)
2020
if (m_context.settings.restart == false)
2121
{
2222
m_camera.m_center = new B2Vec2(1.5f, 10.0f);
23-
m_camera.m_zoom = 25.0f * 0.6f;
23+
m_camera.m_zoom = 15.0f;
2424
}
2525

2626
CreateTumbler(m_worldId);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using static Box2D.NET.Shared.Benchmarks;
2+
3+
namespace Box2D.NET.Samples.Samples.Benchmarks;
4+
5+
public class BenchmarkWasher : Sample
6+
{
7+
private static int SampleBenchmarkWasher = SampleFactory.Shared.RegisterSample("Benchmark", "Washer", Create);
8+
9+
private static Sample Create(SampleContext context)
10+
{
11+
return new BenchmarkWasher(context);
12+
}
13+
14+
private BenchmarkWasher(SampleContext context) : base(context)
15+
{
16+
if (m_context.settings.restart == false)
17+
{
18+
m_context.camera.m_center = new B2Vec2(1.5f, 10.0f);
19+
m_context.camera.m_zoom = 20.0f;
20+
}
21+
22+
CreateWasher(m_worldId, true);
23+
}
24+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// SPDX-FileCopyrightText: 2025 Erin Catto
2+
// SPDX-FileCopyrightText: 2025 Ikpil Choi([email protected])
3+
// SPDX-License-Identifier: MIT
4+
5+
using static Box2D.NET.B2Geometries;
6+
using static Box2D.NET.B2Types;
7+
using static Box2D.NET.B2Bodies;
8+
using static Box2D.NET.B2Shapes;
9+
10+
11+
namespace Box2D.NET.Samples.Samples.Bodies;
12+
13+
public class SetVelocity : Sample
14+
{
15+
private static int SampleSetVelocity = SampleFactory.Shared.RegisterSample("Bodies", "Set Velocity", Create);
16+
17+
private static Sample Create(SampleContext context)
18+
{
19+
return new SetVelocity(context);
20+
}
21+
22+
private B2BodyId m_bodyId;
23+
24+
private SetVelocity(SampleContext context) : base(context)
25+
{
26+
if (m_context.settings.restart == false)
27+
{
28+
m_context.camera.m_center = new B2Vec2(0.0f, 2.5f);
29+
m_context.camera.m_zoom = 3.5f;
30+
}
31+
32+
{
33+
B2BodyDef bodyDef = b2DefaultBodyDef();
34+
bodyDef.position = new B2Vec2(0.0f, -0.25f);
35+
B2BodyId groundId = b2CreateBody(m_worldId, ref bodyDef);
36+
37+
B2ShapeDef shapeDef = b2DefaultShapeDef();
38+
B2Polygon box = b2MakeBox(20.0f, 0.25f);
39+
b2CreatePolygonShape(groundId, ref shapeDef, ref box);
40+
}
41+
42+
{
43+
B2BodyDef bodyDef = b2DefaultBodyDef();
44+
bodyDef.type = B2BodyType.b2_dynamicBody;
45+
46+
B2ShapeDef shapeDef = b2DefaultShapeDef();
47+
B2Polygon box = b2MakeSquare(0.5f);
48+
bodyDef.position = new B2Vec2(0.0f, 0.5f);
49+
m_bodyId = b2CreateBody(m_worldId, ref bodyDef);
50+
b2CreatePolygonShape(m_bodyId, ref shapeDef, ref box);
51+
}
52+
}
53+
54+
public override void Step()
55+
{
56+
base.Step();
57+
b2Body_SetLinearVelocity(m_bodyId, new B2Vec2(0.0f, -20.0f));
58+
}
59+
60+
public override void Draw(Settings settings)
61+
{
62+
base.Draw(settings);
63+
B2Vec2 position = b2Body_GetPosition(m_bodyId);
64+
DrawTextLine($"(x, y) = {position.X:G}, {position.Y:G})");
65+
}
66+
}

src/Box2D.NET.Samples/Samples/Bodies/Weeble.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,12 @@ public Weeble(SampleContext context) : base(context)
7979
m_explosionMagnitude = 8.0f;
8080
}
8181

82-
static float FrictionCallback(float frictionA, int materialA, float frictionB, int materialB)
82+
static float FrictionCallback(float frictionA, ulong materialA, float frictionB, ulong materialB)
8383
{
8484
return 0.1f;
8585
}
8686

87-
static float RestitutionCallback(float restitutionA, int materialA, float restitutionB, int materialB)
87+
static float RestitutionCallback(float restitutionA, ulong materialA, float restitutionB, ulong materialB)
8888
{
8989
return 1.0f;
9090
}

0 commit comments

Comments
 (0)