I just tried the margin at 0 again but without luck. :\
I also did two other things:
1. Dropped a fresh source clone from the bullet repo into my extern/ directory and re-build the project (can't believe it built without CMake mods!). No change in behavior.
2. Instead of relying on a bunch of abstraction layers with bullet code buried under my framework's API, I exposed the Bullet headers to a test application and re-created the simulation manually. Here is a stripped-down version:
----- HEADER -----
Code: Select all
class Test {
public:
int run(const std::vector<std::string>& args);
void updateCallback(RenderContext& renderContext, float time); // called every frame
private:
btBroadphaseInterface* m_broadphase;
btCollisionConfiguration* m_collisionConfiguration;
btCollisionDispatcher* m_dispatcher;
btConstraintSolver* m_solver;
btDynamicsWorld* m_world;
std::vector<btDefaultMotionState*> m_motionStates;
std::vector<std::shared_ptr<Node>> m_boxNodes;
};
----- IMPLEMENTATION -----
Code: Select all
int Test::run(const vector<string>& args) {
// <make a window, make a scene, set callbacks>
// init bullet
m_collisionConfiguration = new btDefaultCollisionConfiguration();
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
m_broadphase = new btDbvtBroadphase();
m_solver = new btSequentialImpulseConstraintSolver();
m_world = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration);
// create falling boxes
{
constexpr unsigned OBJECT_ARRAY_SIZE_X = 2;
constexpr unsigned OBJECT_ARRAY_SIZE_Y = 4;
constexpr unsigned OBJECT_ARRAY_SIZE_Z = 2;
constexpr unsigned SPACING = 1.0;
constexpr unsigned DROP_HEIGHT = 40.0;
for (int k=0; k<OBJECT_ARRAY_SIZE_Y; ++k) {
for (int i=0;i <OBJECT_ARRAY_SIZE_X; ++i) {
for(int j = 0; j<OBJECT_ARRAY_SIZE_Z; ++j) {
vec3 position = {
SPACING * i - (OBJECT_ARRAY_SIZE_X / 2.0),
DROP_HEIGHT + SPACING * k - (OBJECT_ARRAY_SIZE_Y / 2.0),
SPACING * j - (OBJECT_ARRAY_SIZE_Z / 2.0) };
// create bullet model
{
btBoxShape* boxShape = new btBoxShape(btVector3(1.0f/2.0, 1.0f/2.0, 1.0f/2.0));
// (makes no difference)
//boxShape->setMargin(0);
btTransform transform;
transform.setIdentity();
transform.setOrigin(btVector3(position.x, position.y, position.z));
btDefaultMotionState* motionState = new btDefaultMotionState(transform);
m_motionStates.push_back(motionState);
float mass = 2.0;
btVector3 localInertia = {0, 0, 0};
boxShape->calculateLocalInertia(mass, localInertia);
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, motionState, boxShape, localInertia);
rbInfo.m_friction = 0.25;
rbInfo.m_rollingFriction = 0.25;
rbInfo.m_restitution = 0.25;
btRigidBody* rigidBody = new btRigidBody(rbInfo);
m_world->addRigidBody(rigidBody);
}
// create visual model
{
auto node = Node::GeometryNode(make_shared<Box>(1.0, 1.0, 1.0));
node->position(position);
m_boxNodes.push_back(node);
scene->rootNode()->addChild(node);
}
}
}
}
}
// create ground box
{
constexpr float GROUND_DIM = 50.0;
// create bullet model
{
btBoxShape* groundShape = new btBoxShape(btVector3(GROUND_DIM/2.0, 0.25/2.0, GROUND_DIM/2.0));
// (makes no difference)
//groundShape->setMargin(0);
btTransform transform;
transform.setIdentity();
transform.setOrigin(btVector3(0, 0, 0));
btDefaultMotionState* motionState = new btDefaultMotionState(transform);
btVector3 localInertia = {0, 0, 0};
groundShape->calculateLocalInertia(0, localInertia);
btRigidBody::btRigidBodyConstructionInfo rbInfo(0, motionState, groundShape, localInertia);
rbInfo.m_mass = 0;
rbInfo.m_friction = 1.0;
rbInfo.m_rollingFriction = 1.0;
rbInfo.m_restitution = 0.1;
btRigidBody* rigidBody = new btRigidBody(rbInfo);
m_world->addRigidBody(rigidBody);
}
// create visual model
{
auto groundNode = make_shared<Node>("Box");
groundNode->geometry(make_shared<Box>(GROUND_DIM, 0.25, GROUND_DIM));
auto gridImage = TestImageNamed("grid10");
auto planeDiffuseProperty = make_shared<MaterialProperty>(gridImage);
planeDiffuseProperty->wrapS(WRAP_MODE::REPEAT);
planeDiffuseProperty->wrapT(WRAP_MODE::REPEAT);
planeDiffuseProperty->maxAnisotropy(16);
planeDiffuseProperty->minificationFilter(FILTER_MODE::LINEAR_MIPMAP_LINEAR);
planeDiffuseProperty->magnificationFilter(FILTER_MODE::LINEAR);
auto planeMaterial = make_shared<Material>(nullptr, planeDiffuseProperty, nullptr);
planeMaterial->uvScale(GROUND_DIM/10.0);
planeMaterial->doubleSided(true);
groundNode->geometry()->addMaterial(planeMaterial);
groundNode->position({0, 0, 0});
scene->rootNode()->addChild(groundNode);
}
}
// <set background, lights, etc>
m_window->display(); // blocks until closed by the callback below
return 0;
}
void Test::updateCallback(RenderContext& renderContext, float time) { // called every frame
static float previousSeconds = time;
float deltaSeconds = time - previousSeconds;
previousSeconds = time;
// step the simulation
{
m_world->stepSimulation(deltaSeconds, 10, 1.0/120.0);
}
// update visual model
{
for (unsigned i=0; i<m_motionStates.size(); ++i) {
auto motionState = m_motionStates[i];
auto boxNode = m_boxNodes[i];
btTransform btWorldTransform;
btWorldTransform.setIdentity();
motionState->getWorldTransform(btWorldTransform);
mat4 worldMat;
btWorldTransform.getOpenGLMatrix(value_ptr(worldMat));
boxNode->transform(worldMat);
}
}
}
Here's what happens.. same thing!