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.