Skip to content

Commit d7b7015

Browse files
committed
which_collision, backport drop_object to pass manifold
1 parent 503a3b6 commit d7b7015

11 files changed

Lines changed: 213 additions & 65 deletions

‎bullet/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ Tested on Bullet 2.83.
1010
1. [Users](users.md)
1111
1. Examples
1212
1. [Gravity](gravity.cpp)
13-
1. [Ground ball](ground_ball.cpp)
13+
1. [Drop object](drop_object.cpp)
1414
1. [gnuplot-run](gnuplot-run)
1515
1. [TODO](TODO.md)

‎bullet/TODO.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# TODO
22

33
- get object rotation: 3 Euler angles. Attempt made at `gravity.cpp`
4+
- get object velocity and angular velocity
5+
- what is the point of motion state?
46
- Stairs physics: http://gamedev.stackexchange.com/questions/74794/make-the-player-run-onto-stairs-smoothly
57
- Voronoi: https://www.youtube.com/watch?v=FIPu9_OGFgc
6-
- what is the point of motion state?
78
- substeps vs smaller time step on stepSimulation?
8-
- collision primitives: http://www.bulletphysics.org/mediawiki-1.5.8/index.php?title=Collision_Shapes
9+
- opengl visualization
10+
- user input

‎bullet/concepts.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@
1515
- Kinematic objects, which are objects without mass, but the user can move them. There is on-way interaction, and Bullet calculates a velocity based on the timestep and previous and current world transform.
1616
- sleeping object: TODO
1717
- island split algorithm?
18+
- collision primitives: <http://www.bulletphysics.org/mediawiki-1.5.8/index.php?title=Collision_Shapes>
19+
- A few efficient geometric ones + more general meshes of points.
Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,53 @@
11
/*
2-
A sphere falling and hitting the ground.
2+
Drop an object to a planar ground.
33
44
It may bounce up a few times depending on the restitution coefficients.
55
6-
Collisions are detected and printed to output. Releated threads:
6+
Collisions are detected and printed to stdout. Releated threads:
77
88
- http://stackoverflow.com/questions/11175694/bullet-physics-simplest-collision-example
99
- http://stackoverflow.com/questions/9117932/detecting-collisions-with-bullet
1010
- http://gamedev.stackexchange.com/questions/22442/how-get-collision-callback-of-two-specific-objects-using-bullet-physics
1111
- http://www.bulletphysics.org/mediawiki-1.5.8/index.php?title=Collision_Callbacks_and_Triggers
12+
13+
Derived from gravity.cpp
1214
*/
1315

1416
#include <cstdio>
1517
#include <cstdlib>
18+
#include <map>
1619
#include <vector>
1720

1821
#include <btBulletDynamicsCommon.h>
1922

2023
#define PRINTF_FLOAT "%7.3f"
2124

2225
constexpr float gravity = -10.0f;
26+
// How inclined the ground plane is towards +x.
27+
constexpr float groundXNormal = 0.0f;
2328
constexpr float initialY = 10.0f;
2429
constexpr float timeStep = 1.0f / 60.0f;
2530
// TODO some combinations of coefficients smaller than 1.0
2631
// make the ball go up higher / not lose height. Why?
2732
constexpr float groundRestitution = 0.9f;
28-
constexpr float sphereRestitution = 0.9f;
33+
constexpr float objectRestitution = 0.9f;
2934
constexpr int maxNPoints = 500;
3035

31-
std::vector<btVector3> collisions;
36+
std::map<const btCollisionObject*,std::vector<btManifoldPoint*>> objectsCollisions;
3237
void myTickCallback(btDynamicsWorld *dynamicsWorld, btScalar timeStep) {
33-
collisions.clear();
38+
objectsCollisions.clear();
3439
int numManifolds = dynamicsWorld->getDispatcher()->getNumManifolds();
3540
for (int i = 0; i < numManifolds; i++) {
3641
btPersistentManifold *contactManifold = dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
37-
// TODO those are unused. What can be done with them?
38-
// I think they are the same objects as those in the main loop
39-
// dynamicsWorld->getCollisionObjectArray() and we could compare
40-
// the pointers to see which object collided with which.
41-
{
42-
const btCollisionObject *objA = contactManifold->getBody0();
43-
const btCollisionObject *objB = contactManifold->getBody1();
44-
}
42+
auto *objA = contactManifold->getBody0();
43+
auto *objB = contactManifold->getBody1();
44+
auto& collisionsA = objectsCollisions[objA];
45+
auto& collisionsB = objectsCollisions[objB];
4546
int numContacts = contactManifold->getNumContacts();
4647
for (int j = 0; j < numContacts; j++) {
4748
btManifoldPoint& pt = contactManifold->getContactPoint(j);
48-
const btVector3& ptA = pt.getPositionWorldOnA();
49-
const btVector3& ptB = pt.getPositionWorldOnB();
50-
const btVector3& normalOnB = pt.m_normalWorldOnB;
51-
collisions.push_back(ptA);
52-
collisions.push_back(ptB);
53-
collisions.push_back(normalOnB);
49+
collisionsA.push_back(&pt);
50+
collisionsB.push_back(&pt);
5451
}
5552
}
5653
}
@@ -77,7 +74,7 @@ int main() {
7774
btCollisionShape* groundShape;
7875
#if 1
7976
// x / z plane at y = -1.
80-
groundShape = new btStaticPlaneShape(btVector3(0, 1, 0), -1);
77+
groundShape = new btStaticPlaneShape(btVector3(groundXNormal, 1, 0), -1);
8178
#else
8279
// A cube of width 10 at y = -6.
8380
// Does not fall because we won't call:
@@ -96,9 +93,17 @@ int main() {
9693
dynamicsWorld->addRigidBody(body);
9794
}
9895

99-
// Sphere.
96+
// Object.
10097
{
101-
btCollisionShape* colShape = new btSphereShape(btScalar(1.0));
98+
btCollisionShape *colShape;
99+
#if 1
100+
colShape = new btSphereShape(btScalar(1.0));
101+
#else
102+
// Because of numerical instabilities, the cube spins all over,
103+
// moving on the x and y directions.
104+
colShape = new btBoxShape(
105+
btVector3(btScalar(1.0), btScalar(1.0), btScalar(1.0)));
106+
#endif
102107
collisionShapes.push_back(colShape);
103108
btTransform startTransform;
104109
startTransform.setIdentity();
@@ -109,7 +114,7 @@ int main() {
109114
btDefaultMotionState *myMotionState = new btDefaultMotionState(startTransform);
110115
btRigidBody *body = new btRigidBody(btRigidBody::btRigidBodyConstructionInfo(
111116
mass, myMotionState, colShape, localInertia));
112-
body->setRestitution(sphereRestitution);
117+
body->setRestitution(objectRestitution);
113118
dynamicsWorld->addRigidBody(body);
114119
}
115120

@@ -128,22 +133,22 @@ int main() {
128133
}
129134
btVector3 origin = trans.getOrigin();
130135
std::printf("%d %d " PRINTF_FLOAT " " PRINTF_FLOAT " " PRINTF_FLOAT " ",
131-
i,
132-
j,
133-
float(origin.getX()),
134-
float(origin.getY()),
135-
float(origin.getZ()));
136-
if (collisions.empty()) {
136+
i, j, origin.getX(), origin.getY(), origin.getZ());
137+
auto& manifoldPoints = objectsCollisions[body];
138+
if (manifoldPoints.empty()) {
137139
std::printf("0 ");
138140
} else {
139141
std::printf("1 ");
140-
// Yes, this is getting reprinted for all bodies when collisions happen.
141-
// It's just a quick and dirty way to visualize it, should be outside
142-
// of this loop normally.
143-
for (auto& v : collisions) {
144-
std::printf(
145-
PRINTF_FLOAT " " PRINTF_FLOAT " " PRINTF_FLOAT " ",
146-
v.getX(), v.getY(), v.getZ());
142+
for (auto& pt : manifoldPoints) {
143+
std::vector<btVector3> data;
144+
data.push_back(pt->getPositionWorldOnA());
145+
data.push_back(pt->getPositionWorldOnB());
146+
data.push_back(pt->m_normalWorldOnB);
147+
for (auto& v : data) {
148+
std::printf(
149+
PRINTF_FLOAT " " PRINTF_FLOAT " " PRINTF_FLOAT " ",
150+
v.getX(), v.getY(), v.getZ());
151+
}
147152
}
148153
}
149154
puts("");

‎bullet/drop_object.gnuplot‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env gnuplot
2+
set key autotitle columnheader
3+
plot 'drop_object.tmp' using 1:($2 == 1 ? $3 : 1/0), \
4+
'' using 1:($2 == 1 ? $4 : 1/0), \
5+
'' using 1:($2 == 1 ? $5 : 1/0), \
6+
'' using 1:($2 == 1 ? $6 : 1/0)

‎bullet/gravity.cpp‎

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,10 @@ int main() {
6161
trans = obj->getWorldTransform();
6262
}
6363
btVector3 origin = trans.getOrigin();
64-
// TODO: how to get numbers out of this?
64+
// TODO: how to get 3 euler rotation numbers out of this?
6565
btQuaternion rotation = trans.getRotation();
66-
std::printf("%d %d " PRINTF_FLOAT " " PRINTF_FLOAT " " PRINTF_FLOAT "\n",
67-
i,
68-
j,
69-
float(origin.getX()),
70-
float(origin.getY()),
71-
float(origin.getZ()));
66+
std::printf("%d %d " PRINTF_FLOAT " " PRINTF_FLOAT " " PRINTF_FLOAT " ",
67+
i, j, origin.getX(), origin.getY(), origin.getZ());
7268
}
7369
}
7470

‎bullet/ground_ball.gnuplot‎

Lines changed: 0 additions & 4 deletions
This file was deleted.

‎bullet/which_collision.cpp‎

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
Determine which object has collided with which object:
3+
http://gamedev.stackexchange.com/questions/22442/how-get-collision-callback-of-two-specific-objects-using-bullet-physics
4+
5+
Derived from drop_object.cpp
6+
*/
7+
8+
#include <cstdio>
9+
#include <cstdlib>
10+
#include <map>
11+
#include <vector>
12+
13+
#include <btBulletDynamicsCommon.h>
14+
15+
#define PRINTF_FLOAT "%7.3f"
16+
17+
constexpr float gravity = -10.0f;
18+
constexpr float timeStep = 1.0f / 60.0f;
19+
constexpr float groundRestitution = 0.9f;
20+
constexpr float objectRestitution = 0.9f;
21+
constexpr int maxNPoints = 500;
22+
constexpr float initialXs[] = { 0.0f, 5.0f };
23+
constexpr float initialYs[] = { 10.0f, 5.0f };
24+
constexpr size_t nObjects = sizeof(initialYs) / sizeof(*initialYs);
25+
26+
std::map<const btCollisionObject*,std::vector<btManifoldPoint*>> objectsCollisions;
27+
void myTickCallback(btDynamicsWorld *dynamicsWorld, btScalar timeStep) {
28+
objectsCollisions.clear();
29+
int numManifolds = dynamicsWorld->getDispatcher()->getNumManifolds();
30+
for (int i = 0; i < numManifolds; i++) {
31+
btPersistentManifold *contactManifold = dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
32+
auto *objA = contactManifold->getBody0();
33+
auto *objB = contactManifold->getBody1();
34+
auto& collisionsA = objectsCollisions[objA];
35+
auto& collisionsB = objectsCollisions[objB];
36+
int numContacts = contactManifold->getNumContacts();
37+
for (int j = 0; j < numContacts; j++) {
38+
btManifoldPoint& pt = contactManifold->getContactPoint(j);
39+
collisionsA.push_back(&pt);
40+
collisionsB.push_back(&pt);
41+
}
42+
}
43+
}
44+
45+
int main() {
46+
int i, j;
47+
48+
btDefaultCollisionConfiguration *collisionConfiguration
49+
= new btDefaultCollisionConfiguration();
50+
btCollisionDispatcher *dispatcher = new btCollisionDispatcher(collisionConfiguration);
51+
btBroadphaseInterface *overlappingPairCache = new btDbvtBroadphase();
52+
btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;
53+
btDiscreteDynamicsWorld *dynamicsWorld = new btDiscreteDynamicsWorld(
54+
dispatcher, overlappingPairCache, solver, collisionConfiguration);
55+
dynamicsWorld->setGravity(btVector3(0, gravity, 0));
56+
dynamicsWorld->setInternalTickCallback(myTickCallback);
57+
btAlignedObjectArray<btCollisionShape*> collisionShapes;
58+
59+
// Ground.
60+
{
61+
btTransform groundTransform;
62+
groundTransform.setIdentity();
63+
groundTransform.setOrigin(btVector3(0, 0, 0));
64+
btCollisionShape* groundShape;
65+
groundShape = new btStaticPlaneShape(btVector3(0, 1, 0), -1);
66+
collisionShapes.push_back(groundShape);
67+
btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
68+
btRigidBody::btRigidBodyConstructionInfo rbInfo(0, myMotionState, groundShape, btVector3(0, 0, 0));
69+
btRigidBody* body = new btRigidBody(rbInfo);
70+
body->setRestitution(groundRestitution);
71+
dynamicsWorld->addRigidBody(body);
72+
}
73+
74+
// Objects.
75+
for (size_t i = 0; i < nObjects; ++i) {
76+
btCollisionShape *colShape;
77+
colShape = new btSphereShape(btScalar(1.0));
78+
collisionShapes.push_back(colShape);
79+
btTransform startTransform;
80+
startTransform.setIdentity();
81+
startTransform.setOrigin(btVector3(initialXs[i], initialYs[i], 0));
82+
btVector3 localInertia(0, 0, 0);
83+
btScalar mass(1.0f);
84+
colShape->calculateLocalInertia(mass, localInertia);
85+
btDefaultMotionState *myMotionState = new btDefaultMotionState(startTransform);
86+
btRigidBody *body = new btRigidBody(btRigidBody::btRigidBodyConstructionInfo(
87+
mass, myMotionState, colShape, localInertia));
88+
body->setRestitution(objectRestitution);
89+
dynamicsWorld->addRigidBody(body);
90+
}
91+
92+
// Main loop.
93+
std::printf("step body x y z collision2 collision1\n");
94+
for (i = 0; i < maxNPoints; ++i) {
95+
dynamicsWorld->stepSimulation(timeStep);
96+
for (j = dynamicsWorld->getNumCollisionObjects() - 1; j >= 0; --j) {
97+
btCollisionObject *obj = dynamicsWorld->getCollisionObjectArray()[j];
98+
btRigidBody *body = btRigidBody::upcast(obj);
99+
btTransform trans;
100+
if (body && body->getMotionState()) {
101+
body->getMotionState()->getWorldTransform(trans);
102+
} else {
103+
trans = obj->getWorldTransform();
104+
}
105+
btVector3 origin = trans.getOrigin();
106+
std::printf("%d %d " PRINTF_FLOAT " " PRINTF_FLOAT " " PRINTF_FLOAT " ",
107+
i, j, origin.getX(), origin.getY(), origin.getZ());
108+
auto& manifoldPoints = objectsCollisions[body];
109+
if (manifoldPoints.empty()) {
110+
std::printf("0");
111+
} else {
112+
std::printf("1");
113+
}
114+
puts("");
115+
}
116+
}
117+
118+
// Cleanup.
119+
for (i = dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; --i) {
120+
btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[i];
121+
btRigidBody* body = btRigidBody::upcast(obj);
122+
if (body && body->getMotionState()) {
123+
delete body->getMotionState();
124+
}
125+
dynamicsWorld->removeCollisionObject(obj);
126+
delete obj;
127+
}
128+
for (i = 0; i < collisionShapes.size(); ++i) {
129+
delete collisionShapes[i];
130+
}
131+
delete dynamicsWorld;
132+
delete solver;
133+
delete overlappingPairCache;
134+
delete dispatcher;
135+
delete collisionConfiguration;
136+
collisionShapes.clear();
137+
}

‎bullet/which_collision.gnuplot‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/usr/bin/env gnuplot
2+
set key autotitle columnheader
3+
plot 'which_collision.tmp' \
4+
using 1:($2 == 1 ? $4 : 1/0), \
5+
'' using 1:($2 == 1 ? $6 : 1/0), \
6+
'' using 1:($2 == 2 ? $4 : 1/0), \
7+
'' using 1:($2 == 2 ? $6 : 1/0)

‎cpp/map.cpp‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,15 @@ int main() {
132132
assert(m[0] == "zero");
133133
assert(m[1] == "one");
134134

135-
//inserts `(3,"")` because `""` is the value for the default string constructor
135+
// Inserts `(2,"")` because `""` is the value for the default String constructor.
136136
assert(m[2] == "");
137137
assert(m.size() == 3);
138138
}
139139

140140
/*
141-
# find #check if in map
141+
# find
142+
143+
# check if in map
142144
143145
Similar to `std::set` find with respect to the keys:
144146
returns an iterator pointing to the pair which has given key, not the value.

0 commit comments

Comments
 (0)