Scale values in transform Matrix of a rigid body LOST

Post Reply
yaoyansi
Posts: 17
Joined: Thu Jan 01, 2009 2:14 pm

Scale values in transform Matrix of a rigid body LOST

Post by yaoyansi »

Hi, all
I need the transform matrix which contains the scale value to set the original transform of the rigid body, and after simulation I update the vertex of the rigid body under the original transform. So, the scale value is important to me.

I set the scale values to (3.0,3.0,3.0) before simulation, and get the scale values after simulation, it is (1.0, 1.0, 1.0).It seems that the scale values lost.


Here is the complete code which is modified from HelloWorld.cpp:

#include "btBulletDynamicsCommon.h"
#include <stdio.h>
#include <string>
#include <iostream>
using namespace std;

const float scale = 3.0f;
btScalar stm[4][4] =
{
{scale, 0.0f, 0.0f, 0.0f},
{0.0f, scale, 0.0f, 0.0f},
{0.0f, 0.0f, scale, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f},
};

/// This is a Hello World program for running a basic Bullet physics simulation
void printMatrix(const std::string& tip, const btScalar m[][4] )
{
//btScalar &m[4][4] = matrix;
cout <<tip<<endl;
cout <<"matrix: {"<<endl;
for(int i=0; i<4; ++i)
{
printf("\t{%f, %f, %f, %f}\n", m[0], m[1], m[2], m[3] );
}
cout <<"}"<<endl;
}
void printObjMatrix( btRigidBody* body, const string& tip )
{
//
btTransform trans;
btScalar tmp[4][4];
body->getMotionState()->getWorldTransform(trans);
trans.getOpenGLMatrix(&(tmp[0][0]));
printMatrix(tip, tmp);
}

int main(int argc, char** argv)
{

int i;

///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);

///the maximum size of the collision world. Make sure objects stay within these boundaries
///Don't make the world AABB size too large, it will harm simulation quality and performance
btVector3 worldAabbMin(-10000,-10000,-10000);
btVector3 worldAabbMax(10000,10000,10000);
int maxProxies = 1024;
btAxisSweep3* overlappingPairCache = new btAxisSweep3(worldAabbMin,worldAabbMax,maxProxies);

///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,-10,0));

///create a few basic rigid bodies
btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(50.),btScalar(50.),btScalar(0.5)));

//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;

collisionShapes.push_back(groundShape);

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

{
btScalar mass(0.);

//rigidbody is dynamic if and only if mass is non zero, otherwise static
bool isDynamic = (mass != 0.f);

btVector3 localInertia(0,0,0);
if (isDynamic)
groundShape->calculateLocalInertia(mass,localInertia);

//using motionstate is recommended, 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);
}


{
//create a dynamic rigidbody

//btCollisionShape* colShape = new btBoxShape(btVector3(1,1,1));
btCollisionShape* colShape = new btSphereShape(btScalar(1.));
collisionShapes.push_back(colShape);

/// Create Dynamic Objects
btTransform startTransform;
startTransform.setIdentity();

//************* set the scale component *****************
startTransform.setFromOpenGLMatrix(&(stm[0][0]));
//*******************************************************


btScalar mass(1.f);

//rigidbody is dynamic if and only if mass is non zero, otherwise static
bool isDynamic = (mass != 0.f);

btVector3 localInertia(0,0,0);
if (isDynamic)
colShape->calculateLocalInertia(mass,localInertia);

startTransform.setOrigin(btVector3(2,10,0));

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

dynamicsWorld->addRigidBody(body);

//********* out put Matrix of before simulation ***********
printObjMatrix(body, "get matrix before bullet sim:");
//*********************************************************

}



/// Do some simulation



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

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

btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[j];
btRigidBody* body = btRigidBody::upcast(obj);
if (body && body->getMotionState())
{
btTransform trans;
body->getMotionState()->getWorldTransform(trans);
//printf("world pos = %f,%f,%f\n",float(trans.getOrigin().getX()),float(trans.getOrigin().getY()),float(trans.getOrigin().getZ()));

//********* out put Matrix of the last frame ***********
if(i==99){
printObjMatrix(body, "get matrix after bullet sim:");
}
//******************************************************


}
// }
}




//cleanup in the reverse order of creation/initialization

//remove the rigidbodies from the dynamics world and delete them
for (i=dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
{
btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray();
btRigidBody* body = btRigidBody::upcast(obj);
if (body && body->getMotionState())
{
delete body->getMotionState();
}
dynamicsWorld->removeCollisionObject( obj );
delete obj;
}

//delete collision shapes
for (int j=0;j<collisionShapes.size();j++)
{
btCollisionShape* shape = collisionShapes[j];
collisionShapes[j] = 0;
delete shape;
}

//delete dynamics world
delete dynamicsWorld;

//delete solver
delete solver;

//delete broadphase
delete overlappingPairCache;

//delete dispatcher
delete dispatcher;

delete collisionConfiguration;

//next line is optional: it will be cleared by the destructor when the array goes out of scope
collisionShapes.clear();

}




and the result is:
get matrix before bullet sim:
matrix: {
{3.000000, 0.000000, 0.000000, 0.000000}
{0.000000, 3.000000, 0.000000, 0.000000}
{0.000000, 0.000000, 3.000000, 0.000000}
{2.000000, 10.000000, 0.000000, 1.000000}
}
get matrix after bullet sim:
matrix: {
{1.000000, -0.000002, 0.000000, 0.000000}
{0.000002, 1.000000, 0.000000, 0.000000}
{-0.000000, -0.000000, 1.000000, 0.000000}
{2.000000, 0.999999, -0.000000, 1.000000}
}



so, could you tell me why? whether it is a bug, or Is there any reason for doing this?
Thank you.
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: Scale values in transform Matrix of a rigid body LOST

Post by Erwin Coumans »

You cannot apply scale or shear etc. to a rigid body world transform.

If you like to use scaling, you can use the local scaling of the collision shape.
Thanks,
Erwin
User avatar
Kotik
Posts: 7
Joined: Tue Oct 04, 2016 7:12 pm

Re: Scale values in transform Matrix of a rigid body LOST

Post by Kotik »

Erwin Coumans wrote:You cannot apply scale or shear etc. to a rigid body world transform.

If you like to use scaling, you can use the local scaling of the collision shape.
Thanks,
Erwin
But what if I have a lot of rigid bodies with one shape but different scaling? Is there any way I can save memory by avoiding creating a new shape for every body?
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: Scale values in transform Matrix of a rigid body LOST

Post by Erwin Coumans »

Yes, most collision shapes have some local scaling. Most primitive shapes have a setLocalScaling method.

For triangle meshes, you can use btScaledBvhTriangleMeshShape, to add local scaling and re-use the same (unscaled) vertices with different local scaling of each instance. In a similar way for convex hulls there is btConvexPointCloudShape etc.
User avatar
Kotik
Posts: 7
Joined: Tue Oct 04, 2016 7:12 pm

Re: Scale values in transform Matrix of a rigid body LOST

Post by Kotik »

Erwin Coumans wrote:Yes, most collision shapes have some local scaling. Most primitive shapes have a setLocalScaling method.

For triangle meshes, you can use btScaledBvhTriangleMeshShape, to add local scaling and re-use the same (unscaled) vertices with different local scaling of each instance. In a similar way for convex hulls there is btConvexPointCloudShape etc.
Do you mean that I can create a shape, set its scaling, feed the shape to a body, and then change its scaling again to feed it to another body?
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: Scale values in transform Matrix of a rigid body LOST

Post by Erwin Coumans »

Do you mean that I can create a shape, set its scaling, feed the shape to a body, and then change its scaling again to feed it to another body?
No. You can create 1 unscaled btBvhTriangleMeshShape. Then you create a btScaledBvhTriangleMeshShape for each scale, and pass in the same btBvhTriangleMeshShape. This is for static world geometry that don't move.

For convex hulls, you can create 1 set of unscaled vertices, and then create a btConvexPointCloudShape for each scale.

It is best to become more familiar with the inner workings of Bullet yourself if you want to apply such optimizations, the source code is available and with some C++ experience it should be easy to navigate.
User avatar
Kotik
Posts: 7
Joined: Tue Oct 04, 2016 7:12 pm

Re: Scale values in transform Matrix of a rigid body LOST

Post by Kotik »

Erwin Coumans wrote:
Do you mean that I can create a shape, set its scaling, feed the shape to a body, and then change its scaling again to feed it to another body?
No. You can create 1 unscaled btBvhTriangleMeshShape. Then you create a btScaledBvhTriangleMeshShape for each scale, and pass in the same btBvhTriangleMeshShape. This is for static world geometry that don't move.

For convex hulls, you can create 1 set of unscaled vertices, and then create a btConvexPointCloudShape for each scale.

It is best to become more familiar with the inner workings of Bullet yourself if you want to apply such optimizations, the source code is available and with some C++ experience it should be easy to navigate.
Thanks for the reply. I'll try to read the source code.
User avatar
Kotik
Posts: 7
Joined: Tue Oct 04, 2016 7:12 pm

Re: Scale values in transform Matrix of a rigid body LOST

Post by Kotik »

Erwin Coumans wrote:
Do you mean that I can create a shape, set its scaling, feed the shape to a body, and then change its scaling again to feed it to another body?
No. You can create 1 unscaled btBvhTriangleMeshShape. Then you create a btScaledBvhTriangleMeshShape for each scale, and pass in the same btBvhTriangleMeshShape. This is for static world geometry that don't move.

For convex hulls, you can create 1 set of unscaled vertices, and then create a btConvexPointCloudShape for each scale.

It is best to become more familiar with the inner workings of Bullet yourself if you want to apply such optimizations, the source code is available and with some C++ experience it should be easy to navigate.
After reading some code I've found out that btConvexPointCloudShape does not copy vertices, unlike btConvexHullShape. And that seems to be the crucial difference between them. Naming here is quite non-obvious =/
Post Reply