[ODE] dCylinder bugs?

slipch slipch <slipch at gsc-game.kiev.ua>
Tue Feb 18 03:02:01 2003


Hello ,

  I am sorry. I examined the code.
  I am not right.
  This must not happen at least with "normal"
  It is a bug in dCollideCylS.
  Instead of
  sign = (dDOT14(normal,R+1) > 0) ? REAL(1.0) : REAL(-1.0);
  must be
  sign = (dDOT14(Ax,R+1) > 0) ? REAL(1.0) : REAL(-1.0);
  normal is not definite in this point.

  I am very appreciate if someone try it.
  Unfortunately I can not do it right now.
  
  The problem is in cylinder edge - sphere collision.

  
The whole function:
 
int dCollideCylS (dxGeom *o1, dxGeom *o2, int flags,
                dContactGeom *contact, int skip)
{
 

  dIASSERT (skip >= (int)sizeof(dContactGeom));
  dIASSERT (dGeomGetClass(o2) == dSphereClass);
  dIASSERT (dGeomGetClass(o1) == dCylinderClassUser);
  const dReal* p1=dGeomGetPosition(o1);
  const dReal* p2=dGeomGetPosition(o2);
  const dReal* R=dGeomGetRotation(o1);
  dVector3 p,normalC,normal;
  const dReal *normalR = 0;
  dReal cylRadius;
  dReal hl;
  dGeomCylinderGetParams(o1,&cylRadius,&hl);
  dReal sphereRadius;
  sphereRadius=dGeomSphereGetRadius(o2);
  
  int i,invert_normal;

  // get vector from centers of cyl to shere
  p[0] = p2[0] - p1[0];
  p[1] = p2[1] - p1[1];
  p[2] = p2[2] - p1[2];
 
dReal s,s2;
unsigned char code;
#define TEST(expr1,expr2,norm,cc) \
  s2 = dFabs(expr1) - (expr2); \
  if (s2 > 0) return 0; \
  if (s2 > s) { \
    s = s2; \
    normalR = norm; \
    invert_normal = ((expr1) < 0); \
    code = (cc); \
  }

  s = -dInfinity;
  invert_normal = 0;
  code = 0;

  // separating axis cyl ax 

  TEST (dDOT14(p,R+1),sphereRadius+hl,R+1,2);
  // note: cross product axes need to be scaled when s is computed.
  // normal (n1,n2,n3) is relative to 
#undef TEST
#define TEST(expr1,expr2,n1,n2,n3,cc) \
  s2 = dFabs(expr1) - (expr2); \
  if (s2 > 0) return 0; \
  if (s2 > s) { \
      s = s2; \
          normalR = 0; \
      normalC[0] = (n1); normalC[1] = (n2); normalC[2] = (n3); \
      invert_normal = ((expr1) < 0); \
      code = (cc); \
    } 
 
//making ax which is perpendicular to cyl1 ax to sphere center//
 
dReal proj,_cos,_sin,cos1,cos3;
dVector3 Ax;
        proj=dDOT14(p2,R+1)-dDOT14(p1,R+1);

        Ax[0]=p2[0]-p1[0]-R[1]*proj;
        Ax[1]=p2[1]-p1[1]-R[5]*proj;
        Ax[2]=p2[2]-p1[2]-R[9]*proj;
dNormalize3(Ax);
TEST(dDOT(p,Ax),sphereRadius+cylRadius,Ax[0],Ax[1],Ax[2],9);


Ax[0]=p[0];
Ax[1]=p[1];
Ax[2]=p[2];
dNormalize3(Ax);

        dVector3 pa;
    dReal sign, factor;
    for (i=0; i<3; i++) pa[i] = p1[i];

        cos1 = dDOT14(Ax,R+0);
        cos3 = dDOT14(Ax,R+2) ;
        factor=_sqrt(cos1*cos1+cos3*cos3);
        cos1/=factor;
        cos3/=factor;
    for (i=0; i<3; i++) pa[i] += cos1 * cylRadius * R[i*4];
    sign = (dDOT14(Ax,R+1) > 0) ? REAL(1.0) : REAL(-1.0);
    for (i=0; i<3; i++) pa[i] += sign * hl * R[i*4+1];
    for (i=0; i<3; i++) pa[i] += cos3 * cylRadius  * R[i*4+2];

Ax[0]=p2[0]-pa[0];
Ax[1]=p2[1]-pa[1];
Ax[2]=p2[2]-pa[2];
dNormalize3(Ax);

 _cos=dFabs(dDOT14(Ax,R+1));
 cos1=dDOT14(Ax,R+0);
 cos3=dDOT14(Ax,R+2);
 _sin=_sqrt(cos1*cos1+cos3*cos3);
TEST(dDOT(p,Ax),sphereRadius+cylRadius*_sin+hl*_cos,Ax[0],Ax[1],Ax[2],14);


#undef TEST

  if (normalR) {
    normal[0] = normalR[0];
    normal[1] = normalR[4];
    normal[2] = normalR[8];
  }
  else {

        normal[0] = normalC[0];
        normal[1] = normalC[1];
        normal[2] = normalC[2];
                }
  if (invert_normal) {
    normal[0] = -normal[0];
    normal[1] = -normal[1];
    normal[2] = -normal[2];
  }
   // compute contact point(s)
contact->depth=-s;
contact->normal[0]=-normal[0];
contact->normal[1]=-normal[1];
contact->normal[2]=-normal[2];
contact->g1=const_cast<dxGeom*> (o1);
contact->g2=const_cast<dxGeom*> (o2);
contact->pos[0]=p2[0]-normal[0]*sphereRadius;
contact->pos[1]=p2[1]-normal[1]*sphereRadius;
contact->pos[2]=p2[2]-normal[2]*sphereRadius;
return 1;
}  
-- 
Best regards,
Konstantin Slipchenko                          mailto:slipch@gsc-game.kiev.ua