Tutorial:
demo_collision.cpp
A bunch of random shapes will fall into a box, stacking in random order.
Differently from the two examples above, here a special object is used to
encapsulate Chrono::Engine rigid bodies, and some 'shortcuts' are used to manage them in Irrlicht.
Learn about:
- collisions, contacts and friction
- use the easy ChBodySceneNode class for managing Irrlicht objects which encapsulates ChBody items.
- describe compound shapes
#include "physics/CHapidll.h" #include "physics/CHsystem.h" #include "irrlicht_interface/CHbodySceneNode.h" #include "irrlicht_interface/CHbodySceneNodeTools.h" #include "irrlicht_interface/CHdisplayTools.h" #include "irrlicht_interface/CHirrWizard.h" #include "core/CHrealtimeStep.h" #include <irrlicht.h> // Use the namespace of Chrono using namespace chrono; // Use the main namespaces of Irrlicht using namespace irr; using namespace core; using namespace scene; using namespace video; using namespace io; using namespace gui; static int STATIC_lcp_iters = 5; static int STATIC_lcp_iters_stab = 3;The following function fill be used to populate the system with the colliding bodies: the many falling objects (created simply with a for() loop) and the five walls of the box.
void create_some_falling_items(ChSystem& mphysicalSystem, ISceneManager* msceneManager, IVideoDriver* driver) { ChBodySceneNode* mrigidBody; for (int bi = 0; bi < 30; bi++) { // Create a bunch of ChronoENGINE rigid bodies (spheres and // boxes) which will fall.. // Falling bodies are Irrlicht nodes of the special class ChBodySceneNode, // which encapsulates ChBody items). // Note that ChBodySceneNode have collision turned ON by default (so if you // want to have them 'transparent' to collision detection, you may use // mrigidBody->GetBody()->SetCollide(false) if you need..) mrigidBody = (ChBodySceneNode*)addChBodySceneNode_easySphere( &mphysicalSystem, msceneManager, 1.0, ChVector<>(-5+CHrandom()*10, 4+bi*0.05, -5+CHrandom()*10), 1.2); mrigidBody->GetBody()->SetImpactC(0.6); mrigidBody->GetBody()->SetSfriction(0.2); mrigidBody->GetBody()->SetKfriction(0.2); mrigidBody = (ChBodySceneNode*)addChBodySceneNode_easyBox( &mphysicalSystem, msceneManager, 1.0, ChVector<>(-5+CHrandom()*10, 4+bi*0.05, -5+CHrandom()*10), ChQuaternion<>(1,0,0,0), ChVector<>(1.5,1.5,1.5) ); mrigidBody->GetBody()->SetInertiaXX(ChVector<>(1.2,1.2,1.2)); mrigidBody->GetBody()->SetImpactC(0.6); mrigidBody->GetBody()->SetSfriction(0.4); mrigidBody->GetBody()->SetKfriction(0.4); mrigidBody = (ChBodySceneNode*)addChBodySceneNode_easyCylinder( &mphysicalSystem, msceneManager, 1.0, ChVector<>(-5+CHrandom()*10, 4+bi*0.05, -5+CHrandom()*10), ChQuaternion<>(1,0,0,0), ChVector<>(1.5,0.5,1.5) ); mrigidBody->GetBody()->SetInertiaXX(ChVector<>(1.2,1.2,1.2)); mrigidBody->GetBody()->SetImpactC(0.6); mrigidBody->GetBody()->SetSfriction(0.4); mrigidBody->GetBody()->SetKfriction(0.4); } // Create the five walls of the rectangular container, using // fixed rigid bodies of 'box' type: mrigidBody = (ChBodySceneNode*)addChBodySceneNode_easyBox( &mphysicalSystem, msceneManager, 1.0, ChVector<>(0,-5,0), ChQuaternion<>(1,0,0,0), ChVector<>(20,1,20) ); mrigidBody->GetBody()->SetBodyFixed(true); mrigidBody->GetBody()->SetImpactC(0.6); video::ITexture* cubeMap = driver->getTexture("../data/cubetexture.png"); mrigidBody->setMaterialTexture(0, cubeMap); mrigidBody = (ChBodySceneNode*)addChBodySceneNode_easyBox( &mphysicalSystem, msceneManager, 1.0, ChVector<>(-10,0,0), ChQuaternion<>(1,0,0,0), ChVector<>(1,10,20) ); mrigidBody->GetBody()->SetBodyFixed(true); mrigidBody->setMaterialTexture(0, cubeMap); mrigidBody = (ChBodySceneNode*)addChBodySceneNode_easyBox( &mphysicalSystem, msceneManager, 1.0, ChVector<>(10,0,0), ChQuaternion<>(1,0,0,0), ChVector<>(1,10,20) ); mrigidBody->GetBody()->SetBodyFixed(true); mrigidBody->setMaterialTexture(0, cubeMap); mrigidBody = (ChBodySceneNode*)addChBodySceneNode_easyBox( &mphysicalSystem, msceneManager, 1.0, ChVector<>(0,0,-10), ChQuaternion<>(1,0,0,0), ChVector<>(20,10,1) ); mrigidBody->GetBody()->SetBodyFixed(true); mrigidBody->setMaterialTexture(0, cubeMap); mrigidBody = (ChBodySceneNode*)addChBodySceneNode_easyBox( &mphysicalSystem, msceneManager, 1.0, ChVector<>(0,0, 10), ChQuaternion<>(1,0,0,0), ChVector<>(20,10,1) ); mrigidBody->GetBody()->SetBodyFixed(true); mrigidBody->setMaterialTexture(0, cubeMap); }NOTE: Instead of creating five separate 'box' bodies to make the walls of the bowl, you could have used a single body made of five box shapes, which build a single collision description, as in the following alternative approach.
// create a plain ChBodySceneNode (no colliding shape nor visualization mesh is used yet)
mrigidBody = (ChBodySceneNode*)addChBodySceneNode(
&mphysicalSystem, msceneManager,
0, 1.0,
ChVector<>(0,0,0) );
// set the ChBodySceneNode as fixed body, and turn collision ON, otherwise no collide by default
mrigidBody->GetBody()->SetBodyFixed(true);
mrigidBody->GetBody()->SetCollide(true);
// Clear model. The colliding shape description MUST be between ClearModel() .. BuildModel() pair.
mrigidBody->GetBody()->GetCollisionModel()->ClearModel();
// Describe the colliding shape by adding five boxes (the walls and floor)
mrigidBody->GetBody()->GetCollisionModel()->AddBox(20,1,20, &ChVector<>( 0,-10, 0));
mrigidBody->GetBody()->GetCollisionModel()->AddBox(1,40,20, &ChVector<>(-11, 0, 0));
mrigidBody->GetBody()->GetCollisionModel()->AddBox(1,40,20, &ChVector<>( 11, 0, 0));
mrigidBody->GetBody()->GetCollisionModel()->AddBox(20,40,1, &ChVector<>( 0, 0,-11));
mrigidBody->GetBody()->GetCollisionModel()->AddBox(20,40,1, &ChVector<>( 0, 0, 11));
// Complete the description.
mrigidBody->GetBody()->GetCollisionModel()->BuildModel();
// Maybe that you want to add a mesh for Irrlicht 3D viewing, maybe a
// mesh representing the 5 walls, and use it for this ChBodySceneNode
IAnimatedMesh* wallsMesh = msceneManager->getMesh("../data/nice_box_with_walls.obj");
mrigidBody->setMesh(wallsMesh);
The following is the main function, where - as usual - the Irrlicht device is created, the Chrono::Engine globals
are initialized, and the real-time simulation loop is performed. See the previous tutorials for more explainations.
int main(int argc, char* argv[]) { // In CHRONO engine, The DLL_CreateGlobals() - DLL_DeleteGlobals(); pair is needed if // global functions are needed. ChGlobals* GLOBAL_Vars = DLL_CreateGlobals(); // Create the IRRLICHT context (device, etc.) IrrlichtDevice* device = createDevice(video::EDT_DIRECT3D9, core::dimension2d<s32>(640, 480)); if (device == 0) { GetLog() << "Cannot use DirectX - switch to OpenGL \n"; device = createDevice(video::EDT_OPENGL, core::dimension2d<s32>(640, 480)); if (!device) return 1; } device->setWindowCaption(L"Collisions between objects"); IVideoDriver* driver = device->getVideoDriver(); ISceneManager* msceneManager = device->getSceneManager(); IGUIEnvironment* guienv = device->getGUIEnvironment(); timer = device->getTimer(); // timer declared in CHbodySceneNode.h // Easy shortcuts to add camera, lights, logo and sky in Irrlicht scene: ChIrrWizard::add_typical_Logo(device); ChIrrWizard::add_typical_Sky(device); ChIrrWizard::add_typical_Lights(device); ChIrrWizard::add_typical_Camera(device, core::vector3df(0,14,-20)); // // HERE YOU CREATE THE MECHANICAL SYSTEM OF CHRONO... // // create a ChronoENGINE physical system ChSystem mphysicalSystem; // Create all the rigid bodies. create_some_falling_items(mphysicalSystem, msceneManager, driver); // Prepare the physical system for the simulation, maybe that LCP solver iterations require higer values for more stable stacking simulation mphysicalSystem.SetIntegration(INT_TASORA); // can handle collisions & large penetrations mphysicalSystem.SetIterLCPmaxItersSpeed(STATIC_lcp_iters); mphysicalSystem.SetIterLCPmaxItersStab(STATIC_lcp_iters_stab); // // THE SOFT-REAL-TIME CYCLE // while(device->run()) { driver->beginScene(true, true, SColor(255,140,161,192)); msceneManager->drawAll(); guienv->drawAll(); mphysicalSystem.DoStepDynamics( 0.01); driver->endScene(); } // This safely delete every Irrlicht item (including the // scene nodes, so also the encapsulated Chrono bodies will // be deleted) device->drop(); // Remember this at the end of the program, if you started // with DLL_CreateGlobals(); DLL_DeleteGlobals(); return 0; }that's all.