Simple Chain

From Physics Simulation Wiki

Jump to: navigation, search

Contents

Introduction

In this tutorial, we will see how to create a set of boxes linked together to form a chain using a pair of point to point constraints between each pair of adjacent boxes. This tutorial will combine concepts learned from the Multiple Boxes and Simple Distance Joint tutorials. You may refer to them first if you need to refresh your memory.

Overview

There are situations when we need to create a link of rigid bodies that behave as a single flexible chain. This sort of functionality may be obtained by using primitive objects like point to point constraint and box rigid bodies. We create a set of boxes as we did in the Multiple Boxes tutorial. Then we link each adjacent pair of boxes by using a pair of point to point constraints as shown in the figure below.

This ensures that each pair remains within the distance limits constraint by each pair of point to point (distance) constraint.

Setup

The following sources are defined Chain.h and Chain.cpp.

Chain.h

Lets look at the header file Chain.h. As before, we are simply declaring our create function.

class CommonExampleInterface* ET_ChainCreateFunc(struct CommonExampleOptions& options);

Chain.cpp

The includes are the following

#include "Chain.h"

#include "btBulletDynamicsCommon.h"
#include "LinearMath/btVector3.h"
#include "LinearMath/btAlignedObjectArray.h" 
#include "../CommonInterfaces/CommonRigidBodyBase.h"

In the Chain.cpp file, we define the create function as follows:

CommonExampleInterface* ET_ChainCreateFunc(CommonExampleOptions& options)
{
   return new ChainExample(options.m_guiHelper);
}

Our example class ChainExample is declared and partially defined as follows.

struct ChainExample : public CommonRigidBodyBase {
   ChainExample(struct GUIHelperInterface* helper):CommonRigidBodyBase(helper) {}
   virtual ~ChainExample(){}
   virtual void initPhysics();
   virtual void renderScene();
   void resetCamera() {
      float dist = 41;
      float pitch = 52;
      float yaw = 35;
      float targetPos[3]={0,0.46,0};
      m_guiHelper->resetCamera(dist,pitch,yaw,targetPos[0],targetPos[1],targetPos[2]);
   }
};

[TODO:CONTINUE] The resetCamera and renderScene remain unchanged. The only difference is in the initPhysics function which is defined as follows.

void ChainExample::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);

   btBoxShape* groundShape = createBoxShape(btVector3(btScalar(50.),btScalar(50.),btScalar(50.)));
   m_collisionShapes.push_back(groundShape);

   btTransform groundTransform;
   groundTransform.setIdentity();
   groundTransform.setOrigin(btVector3(0,-50,0)); 
   
   {
      btScalar mass(0.);
      createRigidBody(mass,groundTransform,groundShape, btVector4(0,0,1,1));
   }

The above lines should be familiar as we are first setting our up axis and then we create an empty dynamic world. We then enable debug rendering and then create our static ground rigid body.

   {
      btBoxShape* colShape = createBoxShape(btVector3(1,1,0.25));
      m_collisionShapes.push_back(colShape);
      btTransform startTransform;
      startTransform.setIdentity();
      btScalar	mass(1.f);     

In the above lines of code, we create the individual chain piece as a box shape having dimensions (1,1,0.25). It is scaled to a quarter of its size in Z axis to create a box with a small depth. We then add our shape to the list of collision shapes. Next we initialize a transform and set it identity. We also create the mass for our chain element.

      btAlignedObjectArray<btRigidBody*> boxes;
      int lastBoxIndex = TOTAL_BOXES-1;
      for(int i=0;i<TOTAL_BOXES;++i) { 
         startTransform.setOrigin(btVector3(btScalar(0),btScalar(5+i*2),btScalar(0)));
         boxes.push_back(createRigidBody((i==lastBoxIndex)?0:mass,startTransform,colShape));		 
      }

In the above lines of code, we create a container (boxes) to store all our rigid bodies. This is done so that we could refer to each adjacent pair of rigid body when we create our point2point constraint. In each loop iteration, we create a new position for our chain link and then create our rigid body box by calling parent class's createRigidBody function. All boxes except the last box are made dynamic (by assigning them a non-zero mass). The last box is made static (by assigning it a mass of zero). This ensures that the chain remains suspended in mid air and does not fall down on the floor.

      for(int i=0;i<TOTAL_BOXES-1;++i) {
         btRigidBody* b1 = boxes[i];
	 btRigidBody* b2 = boxes[i+1];
	
         btPoint2PointConstraint* leftSpring = new btPoint2PointConstraint(*b1, *b2, btVector3(-0.5,1,0), btVector3(-0.5,-1,0));
	 m_dynamicsWorld->addConstraint(leftSpring);
	  
         btPoint2PointConstraint* rightSpring = new btPoint2PointConstraint(*b1, *b2, btVector3(0.5,1,0), btVector3(0.5,-1,0));
         m_dynamicsWorld->addConstraint(rightSpring);
      }

We then run another loop as shown in the code snippet above. This loop is run N-1 times where N is the total number of chain elements. then create two point2pointConstraints. The first two arguments are our two adjacent rigid body boxes. The last two arguments are the distance constraint offsets for each rigid body. Once the two constraints are created they are then added to the physics dynamics world.

Finally, we issue a call to m_guiHelper to autogenerate graphical objects from the given dynamics world.

      
   }
   m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld);
} 

Build Scipts

For the example browser application, the build scripts are present in the {BULLET_ROOT}/examples/ExampleBrowser sub-folder.

Editing Premake4.lua for premake

Open the premake4.lua script file. Ensure that the first line (i.e. the project name) is App_BulletExampleBrowser. Next, scroll down until you see another project named BulletExampleBrowserLib. Scroll further down until you see a files section. You must enter the relative path of your sources. Supposing we store our sources (Chain.h/cpp) in the examples/ExtendedTutorials sub-folder, we would then add the following entry in the files section.

files {
   --list of existing source files 
   "../ExtendedTutorials/Chain.cpp",
   "../ExtendedTutorials/Chain.h",
   --additional source files 

Note that you may omit adding headers as they will be included with the source files. Advanced user could also use wild card to include all source files in a given folder as follows.

files {
   --list of existing source files 
   "../ExtendedTutorials/*", 
   --additional source files  

An important note. After you have edited premake4.lua file, ensure that the root folder premake batch script is rerun to ensure that the new changes take effect and our sources are included.

Editing CMakeLists.txt for CMake

Open the CMakeLists.txt script file. Next, scroll down until you see the following variable definition

SET(BulletExampleBrowser_SRCS

You must enter the relative path of your sources. Supposing we store our sources (Chain.h/cpp) in the examples/ExtendedTutorials sub-folder, we would then add the following enteries.

SET(BulletExampleBrowser_SRCS
   #list of existing source files 
   "../ExtendedTutorials/Chain.cpp",
   "../ExtendedTutorials/Chain.h",
   #additional source files 

Note that you may omit adding headers as they will be included with the source files. Note that the wild card enteries do not work in case of CMake and the best approach is to add all sources individually.

An important note. After you have edited CMakeLists.txt file, rerun CMake to ensure that the new changes take effect and our sources are included in the BulletExampleBrowser project.

Snapshot

Thats it. We can then add our entry in the ExampleEnteries.cpp file as was shown earlier in Simple Box example. Running this example shows a chain of rigid bodies that interact cohesively. Clicking and dragging the mouse on the dynamic rigid body forces it to move subject to the constraint enforce by the point to point constraint as shown in the snapshot below.

File:SimpleChain.png

We have now covered how to create a chain of connected rigid bodies. In the next tutorial, we see how to extend the chain approach to model a bridge.

Personal tools