Squirrely dynamic bodies resting on flat static surface (video)

Mwni
Posts: 9
Joined: Thu Jul 12, 2018 4:43 pm

Re: Squirrely dynamic bodies resting on flat static surface (video)

Post by Mwni »

Just found out this could have something to do with the collision margins.

Quote from lazenby:
There are some default collision margins in the Bullet simulation and if the dimensions of the important details of your model are near those margins then you'll get unexpected results and easier tunneling. If you haven't heard about these margins yet you could watch this video. The default margin is around 0.04m (as I recall, dunno if Blender messes with that), which means your smallest important "flange" must be several multiples of that dimension before the simulation will start to look "correct".
Had the same weird behavour on a very thin cylinder...setting the margin to 0 fixed it.
User avatar
goosesensor
Posts: 15
Joined: Tue Jul 17, 2018 3:50 am
Location: Santa Cruz, CA

Re: Squirrely dynamic bodies resting on flat static surface (video)

Post by goosesensor »

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! :|

Image
User avatar
goosesensor
Posts: 15
Joined: Tue Jul 17, 2018 3:50 am
Location: Santa Cruz, CA

Re: Squirrely dynamic bodies resting on flat static surface (video)

Post by goosesensor »

GOT IT. rollingFriction needs to be 0.

Apparently this parameter is there to allow things to not roll indefinitely.... (like pool balls):

"the m_rollingFriction prevents rounded shapes, such as spheres, cylinders and capsules from rolling forever."

I had (incorrectly) assumed it was kinetic/sliding friction, and that the "friction" parameter was static friction. That will teach me to read the docs and stop asking stupid questions! :lol:

Does bullet differentiate between static and kinetic friction?
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Squirrely dynamic bodies resting on flat static surface (video)

Post by drleviathan »

When I look at the behavior of some of your objects one idea does occur to me. I've seen similar behavior for small objects whose inertia tensors were too large for their mass.

Suppose you make an object and give it a low mass (like it was made of styrofoam or lighter material) but then give it a very large inertia tensor (like it was a giant granite bolder). What would be the behavior of such an object? It turns out the torques its linear mass applies under gravity on contact points are not strong enough to significantly affect the objects rotational motion, so it continues to slowly roll around instead of settling down.

So my questions would be: How are you computing/assigning mass and inertia? Are you sure your inertia tensors are correct?
Post Reply