[ODE] Cylinder2 and plane

Matthew Hancher mdh at email.arc.nasa.gov
Sat Jan 29 12:21:53 MST 2005


> I added support for it in my test program.
> The cylinders seem to fall right through the floor
> while others like Box, Sphere, CCylinder work fine.
> When the Cylinder2 hits the other objects, the
> collision  works except I experienced a ODE Internal
> error and then I guess ODE called abort.

Your cylinders are falling through the floor because
the dCylinder2 contrib doesn't include a cylinder-
plane collider.  You could probably get the plane
collider from the dCylinder contrib to work for ya.
However, I wrote a simple plane collider for dCylinder2
a few weeks ago as a warm-up in writing colliders.  I
have attached it below.  Perhaps it will work for you
as well.

To make this work you'll need to:

* Copy this text into a new file collision_cylinder_plane.cpp
* Add the function dCollideCylinderPlane to ode/src/collision_std.h
* Add an appropriate call to setCollider() in 
ode/src/collision_kernel.cpp

(As you would do when adding any new collider or geom
type.)  Last but quite important:

* Follow the instructions in the dTerrain contrib for
   adding the dOP macro and friends to ode/include/ode/odemath.h

(I use those macros in this collider too.)

Now try dropping a cylinder on your plane; hopefully
it'll work fine.

As far as why cylinders don't collide properly with
other objects, they *ought* to be colliding fine with
spheres, boxes, other cyliners, now planes, and nothing
else.  If even those things are failing for you, you've
probably done something wrong in either installing or
using dCylinder2.  Can you run your program in a
debugger and figure out what ODE was trying to do when
it crashed?

Okay, here's my plane-cylinder2 collider.  Appologies
for the code formatting not being quite ODE-standard.  I
hadn't intended to release this code to the ODE
community.  If it turns out that this code is useful, I
can uglify it.  Er, i mean, tidy it up. ;)  Notably
still missing are a cylinder-ccylinder collider and, of
course, a cylinder-trimesh collider.

Let me know how this goes if ya try it.

mdh

Matthew D. Hancher
NASA Ames Research Center
mdh at email.arc.nasa.gov

-----

#include <ode/collision.h>
#include <ode/matrix.h>
#include <ode/rotation.h>
#include <ode/odemath.h>
#include "collision_util.h"

#define SQRT3_2 ((dReal)0.86602540378443864676)

/*
  *  There are five cases: no collision, one-point collision when one 
edge
  *  circle intersects the plane, two-point collision when both edge 
circles
  *  intersect the plane, three-point collision when the two edge 
circles are
  *  on opposite sides of the plane, and deep collision when the center 
of
  *  the cylinder has penetrated the plane (ugh).  The contact normal is
  *  always perpendicular to the plane.
  */

static void generatePlaneContact(dxGeom *geom, dxGeom *plane,
                                  dContactGeom *contact, int skip,
                                  dVector4 pparams, dVector3 point) {
     dContactGeom *c = CONTACT(contact,skip);
     dReal depth = -dDOT(pparams,point);
     c->pos[0] = point[0] + depth*pparams[0];
     c->pos[1] = point[1] + depth*pparams[1];
     c->pos[2] = point[2] + depth*pparams[2];
     c->normal[0] = pparams[0];
     c->normal[1] = pparams[1];
     c->normal[2] = pparams[2];
     c->depth = depth;
     c->g1 = geom;
     c->g2 = plane;
}

int dCollideCylinderPlane(dxGeom *o1, dxGeom *o2, int flags,
                           dContactGeom *contact, int skip)
{
     int maxContacts = flags&0xFFFF, numContacts = 0;
     dReal radius, half_length;
     dGeomCylinderGetParams( o1, &radius, &half_length );
     half_length /= 2;
     const dReal *pos = dGeomGetPosition( o1 );
     const dReal *rot = dGeomGetRotation( o1 );

     dVector4 pparams;
     dGeomPlaneGetParams( o2, pparams );

     // Early-out now by colliding against the cylinder's bounding 
sphere?

     dVector3 axis = { rot[2], rot[6], rot[10] };
     dVector3 ctop = { pos[0]+half_length*axis[0],
                       pos[1]+half_length*axis[1],
                       pos[2]+half_length*axis[2] };
     dVector3 cbot = { pos[0]-half_length*axis[0],
                       pos[1]-half_length*axis[1],
                       pos[2]-half_length*axis[2] };

     dVector3 cross, rvec;
     dCROSS(cross,=,pparams,axis);
     dReal projectedRadius = radius * dLENGTH(cross);
     dNormalize3(cross);
     dCROSS(rvec,=,cross,axis);
     dNormalize3(rvec);
     dOPC(rvec,*,rvec,radius);
     if( dDOT(pparams,rvec) > 0 ) {
         dOPE(rvec,=-,rvec);
     }
     dReal dtop = dDOT(pparams,ctop);
     dReal dbot = dDOT(pparams,cbot);
     dVector3 point;

     // Has the center penetrated?
     if( dDOT(pparams,pos) <= pparams[3] ) {
         // Drat.  Hopefully this will blast us out of the plane.
         if( dtop < dbot ) { dOP(point,+,ctop,rvec); }
         else { dOP(point,+,cbot,rvec); }
         generatePlaneContact(o1,o2,contact,(numContacts++)*skip,
                              pparams,point);
     }
     else {
         // Has the top face penetrated?
         if( dtop - projectedRadius <= pparams[3] ) {
             dOP(point,+,ctop,rvec);
             generatePlaneContact(o1,o2,contact,(numContacts++)*skip,
                                  pparams,point);
             // Are we allowed to look for more contacts?
             if( maxContacts >= 2 ) {
                 // Has the bottom face penetrated too?
                 if( dbot - projectedRadius <= pparams[3] ) {
                     dOP(point,+,cbot,rvec);
                     
generatePlaneContact(o1,o2,contact,(numContacts++)*skip,
                                          pparams,point);
                 }
                 // Has the *whole* top face penetrated?
                 else if( dtop + projectedRadius <= pparams[3] ) {
                     if( maxContacts >= 3 ) {
                         dVector3 rvec2;
                         dCROSS(rvec2,=,axis,rvec);
                         dOPC(rvec,/,rvec,2);
                         dOPC(rvec2,*,rvec2,SQRT3_2);
                         point[0] = ctop[0]-rvec[0]+rvec2[0];
                         point[1] = ctop[1]-rvec[1]+rvec2[1];
                         point[2] = ctop[2]-rvec[2]+rvec2[2];
                         generatePlaneContact(o1,o2,contact,
                                              (numContacts++)*skip,
                                              pparams,point);
                         point[0] = ctop[0]-rvec[0]-rvec2[0];
                         point[1] = ctop[1]-rvec[1]-rvec2[1];
                         point[2] = ctop[2]-rvec[2]-rvec2[2];
                         generatePlaneContact(o1,o2,contact,
                                              (numContacts++)*skip,
                                              pparams,point);
                     }
                     else {
                         dOP(point,-,ctop,rvec);
                         generatePlaneContact(o1,o2,contact,
                                              (numContacts++)*skip,
                                              pparams,point);
                     }
                 }
             }
         }
         // Has the bottom face penetrated?
         else if( dbot - projectedRadius <= pparams[3] ) {
             dOP(point,+,cbot,rvec);
             generatePlaneContact(o1,o2,contact,(numContacts++)*skip,
                                  pparams,point);
             // Are we allowed to look for more contacts?
             if( maxContacts >= 2 ) {
                 // Has the *whole* bottom face penetrated?
                 if( dbot + projectedRadius <= pparams[3] ) {
                     if( maxContacts >= 3 ) {
                         dVector3 rvec2;
                         dCROSS(rvec2,=,axis,rvec);
                         dOPC(rvec,/,rvec,2);
                         dOPC(rvec2,*,rvec2,SQRT3_2);
                         point[0] = cbot[0]-rvec[0]+rvec2[0];
                         point[1] = cbot[1]-rvec[1]+rvec2[1];
                         point[2] = cbot[2]-rvec[2]+rvec2[2];
                         generatePlaneContact(o1,o2,contact,
                                              (numContacts++)*skip,
                                              pparams,point);
                         point[0] = cbot[0]-rvec[0]-rvec2[0];
                         point[1] = cbot[1]-rvec[1]-rvec2[1];
                         point[2] = cbot[2]-rvec[2]-rvec2[2];
                         generatePlaneContact(o1,o2,contact,
                                              (numContacts++)*skip,
                                              pparams,point);
                     }
                     else {
                         dOP(point,-,cbot,rvec);
                         generatePlaneContact(o1,o2,contact,
                                              (numContacts++)*skip,
                                              pparams,point);
                     }
                 }
             }
         }
     }
     return numContacts;
}



More information about the ODE mailing list