The following is example code that would be used to determine collision in a complicated envirnment. In this case there is a large array of pendulums disrupted by a falling wood block.

 

This is a simulation for only one set of objects, you can imagine how complex this would get if you had an entire environment to provide reactons for.

Main Page

References

 

 /*
  Copyright MathEngine PLC 2000
  www.mathengine.com

  $Name: AUTO_TEMP_MeTKMakeRelease_1_299 $

  $Id: ManyPendulums.c,v 1.16 2000/08/31 13:52:45 lyndonh Exp $
*/

/*
  This example shows the collision detection, Dynamics Event Manager
  and Kea Dynamics working on a complicated environment.
*/

#pragma warning( disable : 4305 )

#include "MePrecision.h"
#include "McdFrame.h"
#include "McdPrimitives.h"
#include "McdDtBridge.h"
#include "Mdt.h"
#include "MeMath.h"

#include "MeViewer.h"

extern struct MeMemoryAPI MeMemoryAPIMalloc;
struct MeMemoryOptions opts;

/* Global declarations */

/* Number of pendulums down one side of grid */
#define NSIDE       20
#define NPENDULUMS  (NSIDE * NSIDE)

#define penRadius  (MeReal)0.5
#define penHeight  (MeReal)2.0
#define penJoint   (MeReal)5.0
#define penDensity (MeReal)8.0
#define penSpacing (MeReal)3.0

/*  MeReal penRadius  = (MeReal)0.5; */
/*  MeReal penHeight  = (MeReal)2.0; */
/*  MeReal penJoint   = (MeReal)5.0; */
/*  MeReal penDensity = (MeReal)8.0; */
/*  MeReal penSpacing = (MeReal)3.0; */

MeReal    thingDensity = 1.0;
MeVector3 thingDim = {3.8, 3.8, 3.8};
MeVector3 thingStart = {0.8, 20.0, 0.01};

/* color of pendulums in the corners */
MeVector3 topLeftColor     = {1, 0, 0};
MeVector3 topRightColor    = {1, 1, 0};
MeVector3 bottomLeftColor  = {0, 1, 0};
MeVector3 bottomRightColor = {0, 0, 1};

/* Force applied to the box to drag it around */
MeReal thingForce = 1000;

/* World for the Dynamics Toolkit simulation */
MdtWorldID world;

/* Collision */
McdDtBridge *cdHandler;
McdSpaceID space;

/* Kea solver workspace */
void *KeaMemoryArea;

/* Physics representations */
MdtBodyID    thing;
MdtBodyID    pen[NPENDULUMS];
MdtBSJointID joint[NPENDULUMS];

/* Graphical representations */
RGraphic *groundG;
RGraphic *thingG;
RGraphic *penG[NPENDULUMS];
RGraphic *lineG[NPENDULUMS];

/* Collision reps */
McdModelID groundCM;
McdModelID thingCM;
McdModelID penCM[NPENDULUMS];
McdGeometryID plane_prim, box_prim, pen_prim[NPENDULUMS];

MeReal gravity[3] = { 0, -10, 0 };

/* Render context */
RRender *rc;

/* Timestep size */
MeReal step = (MeReal)(0.04);

MeReal groundTransform[4][4] =
{
    {1, 0, 0, 0},
    {0, 0, -1, 0},
    {0, 1, 0, 0},
    {0, -1, 0, 1}
};

MeReal groundRenderTransform[16] =
{
    1, 0, 0, 0,
    0, 0, -1, 0,
    0, 1, 0, 0,
    0, -1.5, 0, 1
};

/* Functions to add forces to block to drag it around. */
void increaseXForce(void)
{
    MdtBodyEnable(thing);
    MdtBodyAddForce(thing, thingForce, 0, 0);
}


void decreaseXForce(void)
{
    MdtBodyEnable(thing);
    MdtBodyAddForce(thing, -thingForce, 0, 0);
}


void increaseZForce(void)
{
    MdtBodyEnable(thing);
    MdtBodyAddForce(thing, 0, 0, thingForce);
}


void decreaseZForce(void)
{
    MdtBodyEnable(thing);
    MdtBodyAddForce(thing, 0, 0, -thingForce);
}


void ThingCameraTrack()
{
    MeVector3 pos;
    MdtBodyGetPosition(thing, pos);
    rc->m_cameraLookAt[0] = pos[0];
    rc->m_cameraLookAt[1] = pos[1];
    rc->m_cameraLookAt[2] = pos[2];
    RUpdateCamera();
}


/*
  Tick() is a callback function called from the renderer's main loop
  to evolve the world by 'step' seconds
*/
void tick(RRender * rc)
{
    /*
      These timer calls are for the OpenGL performance bar.
    */
    RStopTimer(kRRender);

    /* Update collision */
    RStartTimer(kRCollision);
    McdDtBridgeUpdateAllFreezeFlags(space);
    McdPairHandlerUpdate();
    RStopTimer(kRCollision);

    /* Update dynamics */
    RStartTimer(kRDynamics);
    MdtWorldStep(world, step);
    RStopTimer(kRDynamics);

    RStartTimer(kRRender);

    ThingCameraTrack();
}


/*
  Reset boxes and pendulums to initial positions
*/
void reset(void)
{
    int i,j;

    /* Offset to start making pendulums from */
    MeReal start = (NSIDE-1) * -penSpacing * (MeReal)0.5;

    MdtBodySetPosition(thing, thingStart[0], thingStart[1], thingStart[2]);
    MdtBodySetQuaternion(thing, 1, 0, 0, 0);
    MdtBodySetLinearVelocity(thing, 0, 0, 0);
    MdtBodySetAngularVelocity(thing, 0, 0, 0);
    MdtBodyEnable(thing);

    for (i = 0; i < NSIDE; i++)
    {
        for(j=0; j < NSIDE; j++)
        {
            MdtBodySetPosition(pen[(i*NSIDE)+j], start + i * penSpacing, penHeight, start + j * penSpacing);
            MdtBodySetQuaternion(pen[(i*NSIDE)+j], 1, 0, 0, 0);
            MdtBodySetLinearVelocity(pen[(i*NSIDE)+j], 0, 0, 0);
            MdtBodySetAngularVelocity(pen[(i*NSIDE)+j], 0, 0, 0);
            MdtBodyEnable(pen[(i*NSIDE)+j]);
        }
    }
}

void cleanup(void)
{
    int i;
    McdGeometryDestroy(plane_prim);
    McdModelDestroy(groundCM);

    McdGeometryDestroy(box_prim);
    McdModelDestroy(thingCM);

    for (i = 0; i < NPENDULUMS; i++)
    {
        McdGeometryDestroy(pen_prim[i]);
        McdModelDestroy(penCM[i]);
    }

    McdSpaceDestroy(space);
    McdDtBridgeDestroy(cdHandler);
    McdDtBridgeTerm();
    McdTerm();

    MdtWorldDestroy(world);
    free(KeaMemoryArea);

    RDeleteRenderContext(rc);
}

/*
    Main Routine
  */

int main(int argc, const char **argv)
{
  const RRenderType render = RParseRenderType(&argc, &argv);

#ifndef PS2
  static char *help[] =
  {
    "Left Mouse Drag - move camera",
    "          Enter - reset",
    "        w,a,s,d - drag block around"
  };
#else
  static char *help[] =
  {
    "          Start - reset",
    "        Directional pad - drag block around"
  };
#endif
  const int helpNum = sizeof (help) / sizeof (help[0]);

  int i, j, k, id;
  float color[3];
  short material1;
  MeReal mass, start;
  MeMatrix3 I;
  AcmeReal lineStart[3] = { 0.0, penRadius, 0.0};
  AcmeReal lineEnd[3] = { 0.0, penJoint - penHeight, 0.0};
  
  MeVector3 tempColorTop, tempColorBottom;
  MeReal propI, propJ;
  MdtContactParamsID props;
    
  if (render == kRD3D) {
    MeInfo(0,"Direct3D not supported for this example.\n");
    exit(1);
  }

  MeMemorySetDefaults(&opts);
  (*MeMemoryAPI.setOptions)(&opts);

    /*
      Initialise dynamics
    */

  KeaMemoryArea = malloc(2000000);

  world = MdtWorldCreate(NPENDULUMS + 1, NPENDULUMS + 100, KeaMemoryArea, 2000000);

  MdtWorldSetGravity(world, gravity[0], gravity[1], gravity[2]);

    /* 
       In this demo, a lot of objects are stationary a lot of the time.
       To speed things up we tell Mdt to AutoDisable objects when they 
       come to rest. Disabled MdtBodies are automatically re-Enabled 
       when an Enabled body contacts them.
    */
  MdtWorldSetDEMMode(world, MdtDEMModePartitionAutoDisable);

    /*
      THING:
    */

  thing = MdtBodyCreate(world);
    
  mass = thingDensity * thingDim[0] * thingDim[1] * thingDim[2];
    
  MdtMakeInertiaTensorBox(mass, thingDim[0], thingDim[1], thingDim[2], I);
    
  MdtBodySetMass(thing, mass);
  MdtBodySetInertiaTensor(thing, I);
    
    /*
      Add a little (angular)velocity damping
    */
  MdtBodySetAngularVelocityDamping(thing, 0.03);
  MdtBodySetLinearVelocityDamping(thing, 0.02);

    /*
      PENDULUMS:
    */
    
  mass = PI * penRadius * penRadius * penDensity;
  MdtMakeInertiaTensorSphere(mass, penRadius, I);

  for (i = 0; i < NPENDULUMS; i++)
  {
    pen[i] = MdtBodyCreate(world);

    MdtBodySetMass(pen[i], mass);
    MdtBodySetInertiaTensor(pen[i], I);

    MdtBodySetLinearVelocityDamping(pen[i], (MeReal)(0.2));
    MdtBodySetAngularVelocityDamping(pen[i], (MeReal)(0.1));
  }

    /* reset pendulums to correct positions.. */
  reset();

    /* offset to start making pendulums from */
  start = (NSIDE-1) * -penSpacing * (MeReal)0.5;

    /* now make all the joints */
  for (i = 0; i < NSIDE; i++)
  {
    for(j=0; j < NSIDE; j++)
    {
      joint[(i*NSIDE)+j] = MdtBSJointCreate(world, pen[(i*NSIDE)+j], 0);
      MdtBSJointSetPosition(joint[(i*NSIDE)+j], start + i * penSpacing, penJoint, start + j * penSpacing);
      MdtBSJointEnable(joint[(i*NSIDE)+j]);
    }
  }


    /*
      Collision detection
    */
  McdInit(McdPrimitivesGetTypeCount());
    
  McdPrimitivesRegisterTypes();
  McdPrimitivesRegisterInteractions();
    
  McdDtBridgeInit(0);
    
    /* max objects and pairs */
  space = McdSpaceAxisSortCreate(McdAllAxes, NPENDULUMS + 2, 150);
  McdPairHandlerRegisterSpace(space);
    
  cdHandler = McdDtBridgeCreate();
    
    /* max pairs at a time */
  McdDtBridgeSetPairListMaxCount(cdHandler, 150);
    
    /*
      Set parameters for contacts.
    */
  material1 = McdDtBridgeGetDefaultMaterialID();
  props = McdDtBridgeGetContactParams(material1, material1);
    
  MdtContactParamsSetType(props, MdtContactTypeFriction2D);
  MdtContactParamsSetFriction(props, 2.0);
  MdtContactParamsSetRestitution(props, 0.3);
    
    /*
      Only use 3 contacts per pair.
    */
  id = McdIntersectGetDefaultRequestID();
  McdIntersectRequestSetContactMaxCount(id, id, 3);
    
  plane_prim = McdPlaneCreate();
  groundCM = McdModelCreate(plane_prim);
  McdSpaceInsertModel(space, groundCM);
  McdDtBridgeSetBody(cdHandler, groundCM, 0);
    
  McdModelSetTransformPtr(groundCM, groundTransform);
    
  McdModelFreezeInSpace(groundCM);
    
  box_prim = McdBoxCreate(thingDim[0],
                          thingDim[1], thingDim[2]);
  thingCM = McdModelCreate(box_prim);
  McdDtBridgeSetBody(cdHandler, thingCM, thing);
  McdSpaceInsertModel(space, thingCM);
    
    
  for (i = 0; i < NPENDULUMS; i++)
  {
    pen_prim[i] = McdBoxCreate(2 * penRadius,
                               2 * penRadius, 2 * penRadius);
    penCM[i] = McdModelCreate(pen_prim[i]);
    McdDtBridgeSetBody(cdHandler, penCM[i], pen[i]);
    McdSpaceInsertModel(space, penCM[i]);
  }
    
  McdSpaceBuild(space);

    /*
      Initialise rendering attributes
    */

  rc = RNewRenderContext(render, kRQualitySmooth);

  rc->m_cameraOffset = 30;

  RUpdateCamera();

    /*
      GROUND:
    */

  color[0] = 0.0f;
  color[1] = 0.75f;
  color[2] = 0.1f;

  groundG =
    RCreateCube(rc, 84.0f, 84.0f, 0.5f, color,
                groundRenderTransform);
#ifndef PS2
  RSetTexture(groundG, "checkerboard");
#endif
  color[0] = 0.1;
  color[1] = 0.1;
  color[2] = 0.8;
    
  thingG =
    RCreateCube(rc, thingDim[0], thingDim[1], thingDim[2],
                color, MdtBodyGetTransformPtr(thing));

#ifndef PS2
  RSetTexture(thingG, "wood1");
#endif
    
    /* make graphics (pretty colours) */
  for (i = 0; i < NSIDE; i++)
  {
    for(j=0; j < NSIDE; j++)
    {
      propI = (MeReal)i/((MeReal)NSIDE-1);
      propJ = (MeReal)j/((MeReal)NSIDE-1);

      for(k=0; k<3; k++)
      {
        tempColorTop[k] =
          (propI * (topRightColor[k] - topLeftColor[k])) + topLeftColor[k];
        tempColorBottom[k] =
          (propI * (bottomRightColor[k] - bottomLeftColor[k])) + bottomLeftColor[k];
        color[k] =
          (propJ * (tempColorTop[k] - tempColorBottom[k])) + tempColorBottom[k];
      }

      penG[(i*NSIDE)+j] =
        RCreateCube(rc, 2*penRadius, 2*penRadius, 2*penRadius,
                    color, MdtBodyGetTransformPtr(pen[(i*NSIDE)+j]));
      lineG[(i*NSIDE)+j] =
        RCreateLine(rc, lineStart, lineEnd,
                    color, MdtBodyGetTransformPtr(pen[(i*NSIDE)+j]));
    }
  }

    /*
      KEYS:
    */

#ifndef PS2
  RUseKey('w', increaseZForce);
  RUseKey('s', decreaseZForce);
  RUseKey('a', decreaseXForce);
  RUseKey('d', increaseXForce);
    
  RUseKey('\r', reset);
#else
  RUsePadKey(PADLup,    increaseZForce);
  RUsePadKey(PADLdown,  decreaseZForce);
  RUsePadKey(PADLright,  decreaseXForce);
  RUsePadKey(PADLleft, increaseXForce);
  RUsePadKey(PADstart, reset);
#endif

    /* selects a fixed-width font */
  RSetOGLFont(3);

  RCreateUserHelp(help, helpNum);
  rc->m_title = "ManyPendulums example";

    /*
      Cleanup after simulation.
    */
#ifndef PS2
  atexit(cleanup);
#endif
    /*
      Run the Simulation.
    */

    /*
      RRun() executes the main loop.

      Pseudocode: while no exit-request { Handle user input call Tick() to
      evolve the simulation and update graphic transforms Draw graphics }
    */

  RRun(rc, tick);

  return 0;
}


Main Page

References