[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