Why btRigidBody has velocity when move in kinematics?

Post Reply
Winson
Posts: 8
Joined: Thu Apr 09, 2020 8:43 am

Why btRigidBody has velocity when move in kinematics?

Post by Winson »

Hello everyone,

I'm new to Bullet, I'm trying to move a box in kinematics.
As far as I know, when in kinematics, I should move the box by the following method:

Code: Select all

btRigidBody->getMotionState()->setWorldTransform(const btTransform& worldTrans);
instead of:

Code: Select all

btRigidBody->setLinearVelocity(const btVector3& lin_vel);
I didn't use the method "setLinearVelocity()", but why the box's linear velocity is not zero?
I want to know which method is used for calculating velocity according to the offset of world transform? and where is this method called?

Thank you!

The following is my test code.

Code: Select all

#include "RollingFrictionDemo.h"
///btBulletDynamicsCommon.h is the main Bullet include file, contains most common include files.
#include "btBulletDynamicsCommon.h"
#include <stdio.h>  //printf debugging

#include "../CommonInterfaces/CommonRigidBodyBase.h"
#include "../Utils/b3ResourcePath.h"


///The RollingFrictionDemo shows the use of rolling friction.
///Spheres will come to a rest on a sloped plane using a constraint. Damping cannot achieve the same.
///Generally it is best to leave the rolling friction coefficient zero (or close to zero).
class RollingFrictionDemo : public CommonRigidBodyBase
{
public:
	RollingFrictionDemo(struct GUIHelperInterface* helper)
		: CommonRigidBodyBase(helper)
	{
	}
	virtual ~RollingFrictionDemo()
	{
	}
	void initPhysics();
	virtual bool keyboardCallback(int key, int state);
	virtual void stepSimulation(float deltaTime);

	void resetCamera()
	{
		float dist = 7.66;
		float pitch = -41.2;
		float yaw = 150;
		float targetPos[3] = {1, 1, 1};
		m_guiHelper->resetCamera(dist, yaw, pitch, targetPos[0], targetPos[1], targetPos[2]);
	}
};

btRigidBody* kBox;

void RollingFrictionDemo::initPhysics()
{
	m_guiHelper->setUpAxis(1);

	createEmptyDynamicsWorld();
	
	m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld);

	if (m_dynamicsWorld->getDebugDrawer())
		m_dynamicsWorld->getDebugDrawer()->setDebugMode(btIDebugDraw::DBG_DrawWireframe + btIDebugDraw::DBG_DrawContactPoints);
	btVector4 color = btVector4(0, 0, 1, 1);

	btBoxShape* groundShape = createBoxShape(btVector3(btScalar(50.), btScalar(2.), btScalar(50.)));
	groundShape->setMargin(btScalar(0.004f));
	btTransform startTransform;
	startTransform.setIdentity();
	startTransform.setOrigin(btVector3(0, -2, 0));
	btRigidBody* floor = createRigidBody(btScalar(0), startTransform, groundShape, color);

	btScalar mass(1.f);
	btCollisionShape* shape = createBoxShape(btVector3(.2, .2, .2));
	startTransform.setIdentity();
	startTransform.setOrigin(btVector3(0, 0.2, 0));
	kBox = createRigidBody(mass, startTransform, shape, color);
	kBox->setCollisionFlags(kBox->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
	kBox->setActivationState(DISABLE_DEACTIVATION);

	for (int i = 0; i < 5; i++)
	{
		btTransform startTransform2;
		startTransform2.setIdentity();
		startTransform2.setOrigin(btVector3((i + 1) * 1, 0, 0));
		shape = createBoxShape(btVector3(.2, .2, .2));
		createRigidBody(10, startTransform2, shape, color);
	}
	m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld);
}

bool run123 = false;
bool printEnabled = true;
bool RollingFrictionDemo::keyboardCallback(int key, int state)
{
	bool handle = false;
	if (state)
	{
		switch (key)
		{
			case B3G_F6:
			{
				handle = true;
				run123 = !run123;
				break;
			}
			case B3G_F7:
			{
				printEnabled = !printEnabled;
				break;
			}
		}
	}
	return handle;
}

void RollingFrictionDemo::stepSimulation(float deltaTime)
{
	CommonRigidBodyBase::stepSimulation(deltaTime);
	if (run123)
	{

		//btVector3 v = btVector3(2, 0, 0);
		//kBox->setLinearVelocity(v);
		
		btMotionState* state = kBox->getMotionState();
		btTransform s;
		state->getWorldTransform(s);
		
		s.setOrigin(s.getOrigin() + btVector3(deltaTime, 0, 0));
		
		state->setWorldTransform(s);
		//kBox->setCenterOfMassTransform(s);
		//kBox->proceedToTransform(s);
		
		//kBox->saveKinematicState(deltaTime);
	}
	if (printEnabled)
		printf("(%f,%f,%f)\n", float(kBox->getLinearVelocity().getX()), 
								float(kBox->getLinearVelocity().getY()), 
								float(kBox->getLinearVelocity().getZ()));
	
}

class CommonExampleInterface* RollingFrictionCreateFunc(struct CommonExampleOptions& options)
{
	return new RollingFrictionDemo(options.m_guiHelper);
}
The results are as follows.
Image

Thanks again!
Attachments
RollingFrictionDemo.cpp
(4.54 KiB) Downloaded 176 times
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Why btRigidBody has velocity when move in kinematics?

Post by drleviathan »

When you create kbox you give it non-zero mass --> it is a DYNAMIC object. Later you OR the btCollisionObject::CF_KINEMATIC_OBJECT bit into the CollisionFlags --> it is a KINEMATIC object... but does it have zero mass, or is it still non-zero? I wonder if you've stumbled on a bug where some "is it kinematic?" logic checks the flag and other "is it kinematic?" logic checks the mass and assumes non-zero means otherwise. Try using zero mass when you create the kbox RigidBody.

Meanwhile, about MotionStates...

Every sub-step of every step: Bullet will check active objects to see if they have a MotionState. If true then Bullet will call body->setMotionState()->setWorldTransform(T) for DYNAMIC bodies and body->getMotionState()->getWorldTransform(T) for KINEMATIC.

So the pattern is: you don't call the MotionState::set/getWorldTransform() methods yourself. Instead you derive MyCustomMotionState from the pure virtual btMotionState base class and then implement those methods to do the Right Thing when Bullet calls them for you. In particular, when Bullet has a new transform for a DYNAMIC object it will tell you what it is through the MotionState, and when Bullet wants to know what is the new transform it should be using for the KINEMATIC object it will ask for it through the MotionState.

As I mentioned above: Bullet only does that ^^^ when the object is active, and it will normally deactivate an object whose velocities are less than minimum thresholds for longer than 2 seconds. Other moving objects may re-activate an object (e.g. during collisions or near-miss collisions) but sometimes you need to manually activate an object when you want to start pushing/moving it around.
Post Reply