Scaling of simple boxes... lots of them.

PaloDeQueso
Posts: 17
Joined: Thu Nov 09, 2006 8:50 pm
Location: Middletown, PA

Scaling of simple boxes... lots of them.

Post by PaloDeQueso »

So I'm working on a project for a company with a warehouse. The goal is to create a simulation in 3d of said warehouse. I've decided that in order to accomplish what they want it would be a great idea to add in some phyics simulation. I have tinkered with bullet in the past for a game engine I'm working on which I've adapted for my project at work, however now I've had to delve quite deeply into it.

What I want to do should be very simple, but there has to be some simple things that I am missing. Everything in the warehouse is made out of simple boxes scaled to their appropriate site. I have one and only one OpenGL Vertex Array Object that is a simple unit cube with the position at the center. Before I tried to integrate the physics this was working nicely. I used it to create racking, and boxes on the racking, etc.

Now that I've tried adding in the physics system, things have gotten quite hairy. It seems that I'm having some issues setting the the transformations and communicating between the physics and my graphics system.

I'll show 3 snippets of code:

This is the creation of a box object in my game engine. I use an attribute based object system.

Code: Select all

void Game::ConvertBoxToObject(float mass, std::string object_name, EG::Base::Math::Vector3f dimensions, EG::Base::Math::Vector3f position, std::string decal_map, std::string normal_map){
	// Create Object
	unsigned int object_id = scene_manager->GetScene()->GetObjectManager()->AddObject();
	EG::Engine::Game::Object *new_object = scene_manager->GetScene()->GetObjectManager()->GetObjectById(object_id);
	new_object->SetName(object_name);

	// Add Transformation
	EG::Base::Math::Transformationf object_transformation;
	//object_transformation.Scale(dimensions);
	//object_transformation.Translate(position);
	EG::Engine::Game::ObjectTransformationAttribute *object_transformation_attribute = new EG::Engine::Game::ObjectTransformationAttribute(object_transformation);
	//object_transformation_attribute->SetLocalScaling(dimensions);
	new_object->AddBasicAttribute(object_transformation_attribute);

	// Add Geometry
	EG::Engine::Game::ObjectRenderingMeshGeometryAttribute *geometry_attribute = new EG::Engine::Game::ObjectRenderingMeshGeometryAttribute("box");
	geometry_attribute->SetId("box");
	new_object->AddRenderingAttribute(geometry_attribute);

	// Add Material
	EG::Engine::Graphics::RenderingMaterial *material = new EG::Engine::Graphics::RenderingMaterial();
	material->AddTexture(EG::Engine::Graphics::RenderingMaterial::DECAL, decal_map);
	material->AddTexture(EG::Engine::Graphics::RenderingMaterial::NORMAL, normal_map);
	material->SetLightingParameters(0.5f, 1.0f, 0.2f, true);
	new_object->AddRenderingAttribute(new EG::Engine::Game::ObjectRenderingMaterialAttribute(material));

	// Add Physics
	EG::Engine::Physics::BoxCollisionShape *collision_shape = new EG::Engine::Physics::BoxCollisionShape(dimensions);
	collision_shape->SetMass(mass);

	EG::Base::Math::Transformationf collision_shape_transformation;
	collision_shape_transformation.Scale(dimensions);
	collision_shape_transformation.Translate(position);
	collision_shape->SetTransformation(collision_shape_transformation);

	EG::Engine::Physics::RigidBody *rigid_body = new EG::Engine::Physics::RigidBody(new_object, collision_shape, scene_manager->GetRenderer()->GetMeshManager()->GetMesh("box"));
	rigid_body->SetTargetGeometryAttribute(geometry_attribute);
	new_object->AddControlAttribute(new EG::Engine::Game::ObjectRigidBodyControlAttribute(rigid_body));
}
Next is the code that takes these objects and feeds them into the physics system.

Code: Select all

// First this gets called from the same file as the above code... Game.cpp
std::vector<EG::Engine::Game::ObjectControlAttribute *> *rigid_body_attributes = object->ControlAttributesType(EG::Engine::Game::ObjectAttribute::CONTROL_RIGID_BODY);
EG::Engine::Game::ObjectRigidBodyControlAttribute *rigid_body_attribute = static_cast<EG::Engine::Game::ObjectRigidBodyControlAttribute *>(rigid_body_attributes->at(0));
physics->AddObject(object, rigid_body_attribute->GetRigidBody());


// Then this is the actual Physics::AddObject code
EG::Engine::Physics::CollisionShape *collision_shape = rigid_body->GetCollisionShape();
EG::Base::Math::Transformationf collision_shape_transformation = collision_shape->GetTransformation();
EG::Base::Math::Vector3f local_scaling = collision_shape->GetLocalScaling();
btCollisionShape* bt_shape;

if (collision_shape->GetType() == EG::Engine::Physics::CollisionShape::BOX){
	EG::Engine::Physics::BoxCollisionShape *box_collision_shape = static_cast<EG::Engine::Physics::BoxCollisionShape *>(collision_shape);
	EG::Base::Math::Vector3f half_extents = box_collision_shape->GetHalfExtents();
	btVector3 bt_half_extents(half_extents.X(), half_extents.Y(), half_extents.Z());
	bt_shape = new btBoxShape(bt_half_extents);
	bt_shape->setUserPointer(box_collision_shape);
	//bt_shape->setLocalScaling(bt_half_extents);
	all_set = true;
	//std::cout << "Adding BT Collision Box " << object->Name() << std::endl;
}

if (all_set){
	//bt_shape->setLocalScaling(btVector3(local_scaling.X(), local_scaling.Y(), local_scaling.Z()));
	btTransform bt_transform;
	bt_transform.setFromOpenGLMatrix(collision_shape_transformation.Data());
	btDefaultMotionState *bt_motion_state = new btDefaultMotionState(bt_transform);
	btVector3 local_inertia(0, 0, 0);
	btScalar mass = collision_shape->GetMass();
	bt_shape->calculateLocalInertia(mass, local_inertia);
	btRigidBody *bt_rigid_body = new btRigidBody(btRigidBody::btRigidBodyConstructionInfo(mass, bt_motion_state, bt_shape, local_inertia));
	bt_rigid_body->setUserPointer(rigid_body);
	rigid_body->SetBulletRigidBody(bt_rigid_body);
	//bt_rigid_body->applyCentralForce(btVector3(0, -1, 0));
	dynamics_world->addRigidBody(bt_rigid_body);

	// TEST Put and Get
	//btRigidBody *test_body = static_cast<btRigidBody *>(rigid_body->GetBulletRigidbody());
	//EG::Engine::Physics::RigidBody *test_body_2 = static_cast<EG::Engine::Physics::RigidBody *>(test_body->getUserPointer());
	//std::cout << "Get Receive Test: " << test_body_2->GetObject()->Name() << std::endl;
}
And finally the code that updates the object's transformation based on what the physics system has

Code: Select all

void Physics::Update(EG::Engine::Game::ObjectManager *objects, float time_step){
	dynamics_world->stepSimulation(time_step, 10);

	// update all of the objects after the simulation is run!
	btTransform bt_trans;
	EG::Base::Math::Transformationf my_trans;
	float gl_trans[16];
	std::vector<unsigned int> object_ids = objects->ObjectIDs();
	std::vector<unsigned int>::iterator object_id_iterator = object_ids.begin();

	while (object_id_iterator != object_ids.end()){
		EG::Engine::Game::Object *object = objects->GetObjectById(*object_id_iterator);

		if (object->BasicAttributeCountType(EG::Engine::Game::ObjectAttribute::BASIC_TRANSFORMATION) > 0 && object->ControlAttributesCountType(EG::Engine::Game::ObjectAttribute::CONTROL_RIGID_BODY) > 0){
			EG::Engine::Game::ObjectTransformationAttribute *transformation_attribute = static_cast<EG::Engine::Game::ObjectTransformationAttribute *>(object->BasicAttributesType(EG::Engine::Game::ObjectAttribute::BASIC_TRANSFORMATION)->at(0));
			EG::Engine::Game::ObjectRigidBodyControlAttribute *rigid_body_attribute = static_cast<EG::Engine::Game::ObjectRigidBodyControlAttribute *>(object->ControlAttributesType(EG::Engine::Game::ObjectAttribute::CONTROL_RIGID_BODY)->at(0));

			EG::Engine::Physics::RigidBody *rigid_body = rigid_body_attribute->GetRigidBody();
			btRigidBody *bt_rigid_body = static_cast<btRigidBody *>(rigid_body->GetBulletRigidbody());

			bt_rigid_body->getMotionState()->getWorldTransform(bt_trans);
			bt_trans.getOpenGLMatrix(gl_trans);
			my_trans.Set(gl_trans);
			//btVector3 local_scaling = bt_rigid_body->getCollisionShape()->getLocalScaling();
			//my_trans.Scale(local_scaling.getX(), local_scaling.getY(), local_scaling.getZ()); // NOTE: May not work if object gets rotated!
			transformation_attribute->SetTransformation(my_trans);
		}

		++object_id_iterator;
	}
}
First thing you'll notice is I'm not using actual half-extents. If I do that then the physics debug drawer shows that the collision box is much smaller than the graphical representation.

Secondly when I do run this simulation, the scale of the collision boxes seem to be sqauring the scale. So things that are long are really long, and things that are thin, are very very thin.

This is what I'm not sure of. I can't find where that is happening! Is there a better set of commented documentation that I can look at to see where I'm going wrong? Or just better documentation in general. I've been playing with this for a day and this should be almost trivial. I'm sure I'm doing something stupid, but without better docs, I have no idea where to go from where I am.

Thanks in advance for reading my long post and considering responding! :)
Kanttori
Posts: 38
Joined: Thu Jul 08, 2010 12:52 am

Re: Scaling of simple boxes... lots of them.

Post by Kanttori »

Hi!

Looks like collision_shape_transformation is being scaled and it's going bullet-side as a transformation for a rigidbody, imo this is something you shouldn't do. The btTransforms basis, as in the rotation, needs to be just that; no scale or shear can be applied.