This is the 4th ODE tutorial.
This ODE tutorial teaches you about the 3D graphics, i.e., the Drawstuff library. ODE’s demo program shows the good appearance that are beautiful sky with clouds and the grid-shaped ground. This is one of the advantage of ODE .
However, Drawstuff is a very simple 3D graphics library. It is not suitable for a commercial game, but it may be sufficient for simulators of your own works. Drawstuff works in Windows and Linux. The alternates of Drawstuff are Ogre3D and Irrlicht, both work in Windows and Linux.
Drawstuff is implemented on the OpenGL 3D graphics library. Drawstuff is very simple library, so it may be useful for learning OpenGL.
The APIs of Drawstuff start with the small letters ” ds”, and the API of ODE start with the small letter ‘d’.
Using Drawstuff
- Include the header file to use the Drawstuff library.
#include <drawstuff/drawstuff.h>
- Settings
In order to use Drawstuff, each member of dsFunctions must be set.
// define of dsFunctions structure typedef struct dsFunctions { int version; /* set DS_VERSION */ void (*start)(); /* start function before simulation */ void (*step) (int pause); /* step function */ void (*command) (int cmd); /* command function for keyboard */ void (*stop)(); /* stop function after simulation */ const char *path_to_textures; /* a path to the texture */ } dsFunctions;
- Drawstuff related settings
- Version: DS_VERSION must be assigned
- fn.version = DS_VERSION
- Pre-processing functions: the simulation will be called before the start of the simulation loop. Here, the camera viewpoint and gaze direction are set.
- fn.start = &start;
- Viewpoint of the camera, eyes
- dsSetViewpoint (point of view, the gaze direction);
- Simulation Loop function: the simLoop function is called in each loop of the Simulation. The function do almost every thing in the simulation, such as compute dynamics, collision detection, and visualization.
- fn.step = &simLoop;
- Key processing function: the command function is called when a key pressed. If you do not need this function. NULL (null pointer) or 0 (zero) must be assignment to it.
- fn.command = &command; // NULL or 0 (when you do not need)
- Post-processing function: the function is called after the simulation loop. If you do not need it, set the NULL pointer.
- fn.stop = &stop; // NULL (when you do not need)
- Texture path
- fn.path_to_textures = “path”;
- Version: DS_VERSION must be assigned
- The Simulation Loop
- The following API must be called only once in the main function.
dsSimulationLoop (argc, argv, witdh, height, & fn);
- argc, argv: main function arguments
- width: The width of the window
- height: The height of the window
- fn: dsFunctions is a structure for Drawstuff
- The following API must be called only once in the main function.
Sample program
/* ODE tutorial by Kosei Demura */ /* Lesson 4 3D Graphics */ #include "ode/ode.h" #include "drawstuff/drawstuff.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // Stop VC++ warnings #endif #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #define dsDrawLine dsDrawLineD #endif #define DENSITY (5.0) struct MyObject { dBodyID body; // a rigid body }; dReal radius = 0.25; // radius dReal length = 1.0; // length dReal sides[3] = {0.5,0.5,1.0}; // length of edges static dWorldID world; // a dynamic world static MyObject sphere, box, capsule, cylinder; // objects // start simulation static void start() { static float xyz[3] = {5,3,0.5}; // view point [m] static float hpr[3] = {-180, 0, 0}; // view direction[°] dsSetViewpoint (xyz,hpr); // set a view point and direction } // Simulation loop static void simLoop (int pause) { const dReal *pos1,*R1,*pos2,*R2,*pos3,*R3; // draw a sphere dsSetColor(1,0,0); // set red color dsSetSphereQuality(3); // set quality of spere. 3 is pretty good pos1 = dBodyGetPosition(sphere.body); // get a position R1 = dBodyGetRotation(sphere.body); // get an orientation dsDrawSphere(pos1,R1,radius); // draw a sphere // draw a cylinder dsSetColorAlpha (0,1,0,1); pos2 = dBodyGetPosition(cylinder.body); R2 = dBodyGetRotation(cylinder.body); dsDrawCylinder(pos2,R2,length,radius); // draw an capsule dsSetColorAlpha (1,1,1,1); pos2 = dBodyGetPosition(capsule.body); R2 = dBodyGetRotation(capsule.body); dsDrawCapsule(pos2,R2,length,radius); // draw a box dsSetColorAlpha (0,0,1,1); pos3 = dBodyGetPosition(box.body); R3 = dBodyGetRotation(box.body); dsDrawBox(pos3,R3,sides); // draw a line dReal posA[3] = {0, 5, 0}, posB[3]={0, 5, 1.9}; dsDrawLine(posA,posB); } int main (int argc, char **argv) { // set drawstuff dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = NULL; fn.stop = NULL; fn.path_to_textures = "../../drawstuff/textures"; dInitODE(); // Initialize ODE world = dWorldCreate(); // Create a world dMass m; // mass parameter dMassSetZero (&m); //set mass parameter to zero // sphere sphere.body = dBodyCreate (world); // create a body dReal radius = 0.5; // radius [m] dMassSetSphere (&m,DENSITY,radius); // Calcurate mass parameter dBodySetMass (sphere.body,&m); // Set mass parameter to the body dBodySetPosition (sphere.body,0,1, 1); // Set a position // Box box.body = dBodyCreate (world); dMassSetBox (&m,DENSITY,sides[0],sides[1],sides[2]); dBodySetMass (box.body,&m); dBodySetPosition (box.body,0,2,1); // Capsule capsule.body = dBodyCreate (world); dMassSetCapsule(&m,DENSITY,3,radius,length); dBodySetMass (capsule.body,&m); dBodySetPosition (capsule.body,0,4,1); // Cylinder cylinder.body = dBodyCreate (world); dMassSetCylinder(&m,DENSITY,3,radius,length); dBodySetMass (cylinder.body,&m); dBodySetPosition (cylinder.body,0,3,1); // Simulation loop dsSimulationLoop (argc,argv,960,480,&fn); dWorldDestroy (world); // destroy the world dCloseODE(); // close ODE return 0; }
Download
That’s all. Next time, let’s learn a body and a geometry.