How to Use the ode physical engine in the irrlich Engine
Translation
Note: ODE is an open-source rigid physical engine, which sounds scary. in fact, it is not complicated, and it is not difficult to combine with the rendering engine. just a few small steps to convert the data, call the ode process, rendering engine
With powerful collision detection and other physical features, this article combines the irrlicht engine with ode through a small example to quickly learn about Ode. Further, you can
Read the ode documentation and multiple examples in ode. This article is suitable for people who are not familiar with ode. (It doesn't matter if you are not familiar with the irrlicht engine. The parameters used and mesh and other references
)
See http://thomas.webtracker.ch/jahia/Jahia/pid/481
)
This tutorial describes how to integrate ode (Open Dynamics Engine: http://www.ode.org) with irrlicht.
Here we will not elaborate on the ode process. Instead, we will give you a basic understanding of ODE through specific examples. after understanding this example, you can read the ode manual in detail to implement more functions.
I. Key Points of ODE compilation in Windows:
In makefile. msvc or msvc-DLL (under the ode directory/config), add the following content:
Ifeq ($ (build), release)
Opt = 2
C_flags + =/Oy/MD
Endif
Ifeq ($ (build), debug)
C_flags + =/MDD
Opt = d
Endif
(Note: set the project property to/Mt or MTD)
You need to download ode 0.039 or later (with opcode support). irrlicht is 0.6 or later.
2. Example of bounce
The program we set up below contains the fluctuating terrain, and many square boxes keep falling and popping up on the ground.
We can move the camera (W, S, D, A) in the drop box, control the angle of view with the mouse, pause with the tab key, change the drop distance of the box with the Enter key, and exit with the ESC key.
(Program screen, I won't map, it's a lot of green boxes falling onto the mountains)
1. Start:
Use Visual Studio. NET 2003 to add the include and Lib of Ode to the system settings. Add the include of irrlicht and the DLL of irrlicht to the Lib. Execution directory.
Open the bounce project file.
2. program entry
Very simple:
Int winapi winmain (hinstance, hinstance hprevinstance,
Lpstr lpcmdline, int ncmdshow)
{
Bounce: bounceable: runapplication (); // execute the following bounce class
Return 0;
}
See bouncemain. cpp, line 12-15
3. Main bounce process (bounceable class)
The specific implementation of the class is not detailed. For more information, see program.
Parameters:
Dworldid world; Object Location handle
Dspaceid space; object space handle (for collision detection)
Dbodyid body; volume data handle of an object, which is used for physical interaction
Dgeomid Geom; The ry handle of an object, used for collision interaction.
Method functions:
Static void nearcollisioncallback (void * data, dgeomid O1, dgeomid O2 );
Collision callback function: This callback function is called when the two geometries are close enough to each other during the ode execution.
Static void quaterniontoeuler (const dquaternion quaternion, IRR: CORE: vector3df & Euler );
Rotation Parameter Conversion Function: Convert the Rotation Parameter of irrlicht to the four element group of ode.
Void setgeomdata (IRR: Scene: imesh * m); convert the irrlicht mesh structure to an opcode collision structure for trimeshes
Ry conversion: Convert the mesh data of irrlicht to the trimeshes structure of the opcode of ode.
Void setgeomdata ();
Box conversion: converts irrlicht's box into an opcode collision structure as the shape of physical process detection.
3. Run ode Simulation
The basic simulation cycle is as follows:
1. Add a force to move and rotate ode objects.
2. Calculate the collision between different objects.
3. Clear the combined information
4. Get the new position and Rotation Angle of the object, set and display the object
5. Loop execution step 1
In this example, the ode simulation process is as follows:
If (simulate ){
// Updateentitiesbeforephysics ();
// Add the collision callback function to ode
Dspacecollide (thespace, 0, & nearcollisioncallback );
// Set the simulation step size
Dworldstep (theworld, 0.1f );
// You can use the following process to make it faster
// Dworldstepfast1 (theworld, 0.1, 1 );
// Clear the node group
Djointgroupempty (thejointgroup );
// Get a new position and rotate it
Updateentitiesafterphysics ();
}
See bounce. cpp, line 136-151
Collision callback function:
Void bounceable: nearcollisioncallback (void * data, dgeomid O1, dgeomid O2 ){
Int I = 0;
Dbodyid b1 = dgeomgetbody (O1); // ry 1
Dbodyid b2 = dgeomgetbody (O2); // ry 2
If (B1 & B2 & dareconnectedexcluding (B1, B2, djointtypecontact) return; // if the two objects are connected, no detection is performed.
Dcontact contact [max_contacts];
For (I = 0; I contact [I]. Surface. mode = dcontactbounce | dcontactsoftcfm;
Contact [I]. Surface. MU = dinfinity;
Contact [I]. Surface. mu2 = 0;
Contact [I]. Surface. Bounce = 1e-5f;
Contact [I]. Surface. bounce_vel = 1e-9f;
Contact [I]. Surface. soft_cfm = 1e-6f;
}
Int numc = dcollide (O1, O2, max_contacts, & contact [0]. Geom, sizeof (dcontact); // calculate the contact point
// If there are other force functions, we can add them here for detection.
If (numc> 0) {// contacts
For (I = 0; I
Djointid c = djointcreatecontact (theworld, thejointgroup, & contact [I]); // obtain the contact point
Djointattach (C, b1, b2); // Add the impact (in this example, bounce). We can add the collision voice here.
}
}
}
See bounce. cpp, line 326-358
Obtain the object change result:
Void bounceable: updateentitiesafterphysics (){
IRR: CORE: vector3df Pos;
IRR: CORE: vector3df rot;
STD: List: iterator iter = NULL;
For (iter = bounceables. Begin (); iter! = Bounceables. End (); ++ ITER ){
Bounceable * entity = (* ITER );
Dgeomid Geom = entity-> Geom;
If (Geom! = 0 ){
Dreal * ode_pos = (dreal *) dgeomgetposition (Geom); // get a new location from ODE
POS. set (IRR: f32) ode_pos [0], (IRR: f32) ode_pos [1], (IRR: f32) ode_pos [2]); // set the position of the irrlicht object
Entity-> node-> setposition (POS );
Dquaternion result;
Dgeomgetquaternion (Geom, result); // get the ode rotation value
Quaterniontoeuler (result, rot); // convert
Entity-> node-> setrotation (ROT); // you can specify the rotation of an irrlicht object.
}
}
}
See bounce. cpp, line 174-196
The rotation parameters for converting an ode rotator to irrlicht:
Void bounceable: quaterniontoeuler (const dquaternion quaternion, vector3df & Euler ){
Dreal w, x, y, z;
W = quaternion [0];
X = quaternion [1];
Y = quaternion [2];
Z = quaternion [3];
Double SQW = W * W;
Double sqx = x * X;
Double sqy = y * Y;
Double sqz = z * z;
Euler. z = (IRR: f32) (atan2 (2.0 * (x * Y + z * w), (sqx-sqy-sqz + SQW) // not strong enough, clear at a glance
* IRR: CORE: grad_pi );
Euler. x = (IRR: f32) (atan2 (2.0 * (y * z + x * w), (-sqx-sqy + sqz + SQW ))
* IRR: CORE: grad_pi );
Euler. Y = (IRR: f32) (asin (-2.0 * (x * z-y * w ))
* IRR: CORE: grad_pi );
}
See bounce. cpp, line 359-375
Convert the meshes ry data of irrlicht to the trimesh ry data of ODE:
(I will not explain it much. It is nothing more than different vertices and faces)
Void bounceable: setgeomdata (IRR: Scene: imesh * m ){
// Do nothing if the mesh or node is null
If (mesh = NULL | node = NULL) return;
Int I, j, CI, CIF, CV;
Indexcount = 0;
Vertexcount = 0;
// Count vertices and indices
For (I = 0; igetmeshbuffercount (); I ++ ){
IRR: Scene: imeshbuffer * MB = mesh-> getmeshbuffer (I );
Indexcount + = Mb-> getindexcount ();
Vertexcount + = Mb-> getvertexcount ();
}
// Build structure for ODE trimesh Geom
Vertices = new dvector3 [vertexcount];
Indices = new int [indexcount];
// Fill trimesh Geom
Ci = 0; // current index in the indices Array
CIF = 0; // offset of the irrlicht-vertex-index in the vetices Array
CV = 0; // current index in the vertices Array
For (I = 0; igetmeshbuffercount (); I ++ ){
IRR: Scene: imeshbuffer * MB = mesh-> getmeshbuffer (I );
// Fill indices
IRR: 2010* mb_indices = Mb-> getindices ();
For (j = 0; jgetindexcount (); j ++ ){
// Scale the indices from multiple meshbuffers to single index array
Indices [CI] = CIF + mb_indices [J];
CI ++;
}
// Update the offset for the next meshbuffer
CIF = CIF + MB-> getvertexcount ();
// Fill vertices
If (MB-> getvertextype () = IRR: Video: evt_standard ){
IRR: Video: s3dvertex * mb_vertices =
(IRR: Video: s3dvertex *) MB-> getvertices ();
For (j = 0; jgetvertexcount (); j ++ ){
Vertices [CV] [0] = mb_vertices [J]. Pos. X;
Vertices [CV] [1] = mb_vertices [J]. Pos. Y;
Vertices [CV] [2] = mb_vertices [J]. Pos. Z;
CV ++;
}
} Else if (MB-> getvertextype () = IRR: Video: evt_2tcoords ){
IRR: Video: s3dvertex2tcoords * mb_vertices =
(IRR: Video: s3dvertex2tcoords *) MB-> getvertices ();
For (j = 0; jgetvertexcount (); j ++ ){
Vertices [CV] [0] = mb_vertices [J]. Pos. X;
Vertices [CV] [1] = mb_vertices [J]. Pos. Y;
Vertices [CV] [2] = mb_vertices [J]. Pos. Z;
CV ++;
}
}
}
IRR: CORE: vector3df Pos = node-> getposition ();
// Build the trimesh data
Dtrimeshdataid DATA = dgeomtrimeshdatacreate ();
Dgeomtrimeshdatabuildsimple (data, (dreal *) vertices,
Vertexcount, indices, indexcount );
// Build the trimesh Geom
Geom = dcreatetrimesh (space, Data, 0, 0 );
// Set the Geom position
Dgeomsetposition (Geom, POS. X, POS. Y, POS. z );
// Lets have a pointer to our bounceable
// We cocould need this in the collision callback
Dgeomsetdata (Geom, (void *) This );
// In our application we don't want geoms
// Converted from meshes to have a body
Dgeomsetbody (Geom, 0 );
}
See bounce. cpp, line 261-319
Set the irrlicht object's enclosure to the object and body detected by ode:
The square box's surrounding box is the same as the object, so the ball won't work. of course, for different objects, we should make simple collision ry. If we all detect the mesh, we should not exhaust ode.
(It is said that ode is already supported by hardware, but it is hard to say when it will be widely used)
The following process does not need to be explained in detail.
Void bounceable: setgeomdata (){
// Get the boundingbox
IRR: CORE: aabbox3d box = node-> getboundingbox ();
IRR: CORE: vector3df extend = Box. getextend ();
// Get the position of the scenenode
IRR: CORE: vector3df Pos = node-> getposition ();
// Build a box shaped geometry for ODE
Geom = dcreatebox (space, (dreal) Extend. X, (dreal) Extend. Y, (dreal) Extend. z );
// Set the position of the ode Geom
Dgeomsetposition (Geom, POS. X, POS. Y, POS. z );
// Set a pointer to our bounceable,
// This will come in handy when we do more complicated collisions
Dgeomsetdata (Geom, (void *) This );
// Create a body for this object
Body = dbodycreate (World );
// Setup the mass
Dmasssetbox (& mass, 5.0, (dreal) Extend. X, (dreal) Extend. Y, (dreal) Extend. z );
// Combine body and mass
Dbodysetmass (body, & mass );
// Add the body to the Geom
Dgeomsetbody (Geom, body );
// Set the bodys position (same as Geom position)
Dbodysetposition (body, POS. X, POS. Y, POS. z );
Dbodysetdata (body, (void *) This );
}
See bounce. cpp, line 262-277
Conclusion:
After the above simple process, irrlicht has a powerful collision detection function, and other rendering engines can also work like this.