Object moves,no collision [EDIT:Collision between kinematic]

Post Reply
aserrin55
Posts: 6
Joined: Wed Feb 08, 2017 11:30 pm

Object moves,no collision [EDIT:Collision between kinematic]

Post by aserrin55 »

Hi everybody. First, thanks for the work of this community. If I have made something is because of you.

The question...well:

I'm in a experiment in which i have to create one ground and 2 objects, one will collide and move the other.

I have created each one "correctly"
When I started to study their position I obtain this data:

Image

As you can see, object0 equals to ground, object1 to the moving object and object2 to the goal object (the one that has to move after being collided.

The 2 numOfCollisions are between the ground and each other, so i supose to have another collision whenever object 1 and object 2 collide.

But when I start to move object1 ...

Image

The position of both objects seem to be the same, but they don't collide and numOfCollision does not increase.

What can i do? What am i doing wrong?

Here is the way how i'm moving the object

Code: Select all

float linealVelocity = 0.5f;
float theeta = 0.f;

if (j == 1) {
					float x = float(trans.getOrigin().getX()) + linealVelocity * cos(theeta);
					trans.setOrigin(btVector3(x, float(trans.getOrigin().getY()), 1));
					body->getMotionState()->setWorldTransform(trans);
		}
Thanks a lot
Last edited by aserrin55 on Mon Mar 13, 2017 11:48 pm, edited 1 time in total.
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Object moves but no collision

Post by drleviathan »

First, a summary of how the MotionState is supposed to work:

btMotionState defines an interface by which Bullet can transmit and receive updates between the btRigidBody instance and its corresponding GameObject. The interface contract is as follows:

If the RigidBody has a MotionState:

(a) MotionState::getWorldTransform() is called when the body is first added to the CollisionWorld
(b) If the body is DYNAMIC and active then MotionState::setWorldTransform() is called at the end of each substep.
(c) else if the body is KINEMATIC and active then MotionState::getWorldTransform() is called at the end of each substep.

No as to your example. It looks like you're trying to move a KINEMATIC object.

In theory you're supposed to implement your own custom MotionState class that does the right thing inside getWorldTransform(). If you use the btDefaultMotionState then what happens is the body's transform is copied to, or copied from, btDefaultRigidBody::m_graphicsWorldTrans for the set- and getWorldTransform() methods respectively.

You're calling body->getMotionState()->setWorldTransform(trans) which doesn't do what you think it does. It doesn't set the body's world transform... it set's the MotionState's internal transform which Bullet is supposed to call on active DYNAMIC objects. For those you harvest the m_graphicsWorldTransform later to update your GameObject.

This is how you make KINEMATIC objects move: before the stepSimulation() you are supposed to slam the MotionState's internal m_graphicsWorldTransform directly, then you call stepSimulation(), and if the body is KINEMATIC and active then at the right time Bullet will call MotionState::getWorldTransform() which will copy the internal transform (which you had set) to the body (and it will move to the new transform! just as you told it too). The trick is to use some custom logic (an animation for example) to properly slam the internal m_graphicsWorldTransform.
Last edited by drleviathan on Mon Feb 13, 2017 1:41 pm, edited 1 time in total.
aserrin55
Posts: 6
Joined: Wed Feb 08, 2017 11:30 pm

Re: Object moves but no collision

Post by aserrin55 »

Thanks for the answer.
I don't understand what you are saying just because I don't understand a lot Bullet. I have changed my code in order to approach... This is the result:

Code: Select all

///-----includes_start-----
#include "btBulletDynamicsCommon.h"
#include <stdio.h>


int main(int argc, char** argv)
{
	///-----includes_end-----

	int i;
	///-----initialization_start-----

	///collision configuration contains default setup for memory, collision setup. Advanced users can create their own configuration.
	btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();

	///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
	btCollisionDispatcher* dispatcher = new	btCollisionDispatcher(collisionConfiguration);

	///btDbvtBroadphase is a good general purpose broadphase. You can also try out btAxis3Sweep.
	btBroadphaseInterface* overlappingPairCache = new btDbvtBroadphase();

	///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
	btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;

	btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration);

	dynamicsWorld->setGravity(btVector3(0, -9.8, 0));

	///-----initialization_end-----

	//keep track of the shapes, we release memory at exit.
	//make sure to re-use collision shapes among rigid bodies whenever possible!
	btAlignedObjectArray<btCollisionShape*> collisionShapes;


	///create a few basic rigid bodies

	//Creating the ground the ground is a box of side 100x50 at position y = 0.
	{
		btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(1000.), btScalar(1.), btScalar(500.)));
		collisionShapes.push_back(groundShape);

		btTransform groundTransform;
		groundTransform.setIdentity();
		groundTransform.setOrigin(btVector3(0, 0, 0));

		btScalar mass(0.);
		btVector3 localInertia(0, 0, 0);

		//using motionstate is optional, it provides interpolation capabilities, and only synchronizes 'active' objects
		btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
		btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, groundShape, localInertia);
		btRigidBody* body = new btRigidBody(rbInfo);

		//add the body to the dynamics world
		dynamicsWorld->addRigidBody(body);
	}
	//creating a kinematic robot obj1 
	{

		btCollisionShape* robot1Shape = new btSphereShape(btScalar(1.));
		collisionShapes.push_back(robot1Shape);

		btTransform robot1startTransform;
		robot1startTransform.setIdentity();

		// if mass != 0.f object is dynamic
		btScalar	robot1mass(0.f);

		btVector3 robot1localInertia(0, 0, 0);
		robot1Shape->calculateLocalInertia(robot1mass, robot1localInertia);

		robot1startTransform.setOrigin(btVector3(50, 2, 0));

		//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
		btDefaultMotionState* myMotionState2 = new btDefaultMotionState(robot1startTransform);
		btRigidBody::btRigidBodyConstructionInfo Robot1rbInfo(robot1mass, myMotionState2, robot1Shape, robot1localInertia);
		btRigidBody* Robot1body = new btRigidBody(Robot1rbInfo);
		Robot1body->setCollisionFlags(Robot1body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
		Robot1body->setActivationState(DISABLE_DEACTIVATION);

		dynamicsWorld->addRigidBody(Robot1body);
	}
	//creating a dynamic box obj2
	{
		btCollisionShape* boxShape = new btBoxShape(btVector3(btScalar(1.), btScalar(1.), btScalar(1.)));
		collisionShapes.push_back(boxShape);

		btTransform boxTransform;
		boxTransform.setIdentity();
		boxTransform.setOrigin(btVector3(20, 8, 0));

		btScalar massBox(1.);
		btVector3 BoxlocalInertia(0, 0, 0);
		boxShape->calculateLocalInertia(massBox, BoxlocalInertia);

		//using motionstate is optional, it provides interpolation capabilities, and only synchronizes 'active' objects
		btDefaultMotionState* myMotionState = new btDefaultMotionState(boxTransform);
		btRigidBody::btRigidBodyConstructionInfo BoxrbInfo(massBox, myMotionState, boxShape, BoxlocalInertia);
		btRigidBody* Boxbody = new btRigidBody(BoxrbInfo);

		//add the body to the dynamics world
		dynamicsWorld->addRigidBody(Boxbody);
	}

	/// Simulation
	///-----stepsimulation_start-----
	int numCollision;
	btVector3 linealVel(0.5, 0, 0);

	for (i = 0; i < 350; i++)
	{
		dynamicsWorld->stepSimulation(1.f / 60.f, 10);

		numCollision = dynamicsWorld->getDispatcher()->getNumManifolds();
		//print positions of all objects
		for (int j = dynamicsWorld->getNumCollisionObjects() - 1; j >= 0; j--)
		{

			btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[j];
			btRigidBody* body = btRigidBody::upcast(obj);
			btTransform trans;
			if (j == 2) {
				if (body && body->getMotionState())
				{
					body->getMotionState()->getWorldTransform(trans);
				}
				else
				{
					trans = obj->getWorldTransform();
				}
			}
			if (j == 1) {
				body->activate();
				body->getMotionState()->getWorldTransform(trans);
				body->setLinearVelocity(linealVel);
				body->getMotionState()->setWorldTransform(trans);
			}

			if (i % 10 == 0)
			{
				printf("world pos object %d = %f,%f,%f\n", j, float(trans.getOrigin().getX()), float(trans.getOrigin().getY()), float(trans.getOrigin().getZ()));
				printf("\n numOfCollisions =  %d", numCollision); printf("\n");
			}
		}
	}
Then, I delete all the objects.
But the object1 is not moving now, while i expect to move each step simulation 0,5 in x.

What am i doing bad?
Thanks again.
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Object moves but no collision

Post by drleviathan »

Ok I edited my previous answer in an attempt to make things more clear.

As to your second example... you've got three objects:

(0) static box floor
(1) kinematic robot
(2) dynamic box

Every frame you stepSimulation() then loop through the objects in reverse order and...

(j==2) For dynamic box:
(a) copy MotionState's transform to trans (which you may print out later). Bullet would have updated the MotionState's internal transform in the previous stepSimulation()... if the box had been active and moving.

(j==1) For kinematic robot:
(a) activate
(b) copy the transform out of its MotionState (which was initialized to robot1startTransform) into trans
(c) slam the velocity
(d) copy trans back into the MotionState (which Bullet will use to set the body in the next stepSimulation())

One of the problems is that you never set the dynamic box active. Also, it doesn't look like you ever gave the dynamic box a velocity.

The robot isn't going anywhere since you're just resetting its MotionState's transform to the same thing every time.

For your simple example you don't even need MotionState's. The purpose of the MotionState system is to provide an abstraction layer between the game logic and the physics code. If written correctly an abstraction layer can reduce future pain if the game developer were to decide to switch to a different physics engine, or to move the physics simulation to another thread, etc.
aserrin55
Posts: 6
Joined: Wed Feb 08, 2017 11:30 pm

Re: Object moves but no collision

Post by aserrin55 »

Well, thanks i finally got it.
But now I have another problem, one "big" problem in my opinion.

Now i have:
  • * an static object (ground)
  • * a dinamic object --> box
  • * a kinematic object --> robot
But I need another kinematic object that should be moved by me.
When I create this one, I need to collide and interact with the other kinematic object, not only with the dinamic object.

How can detect and proccess the collision between two kinematic objects?
Thanks a lot again.
Post Reply