# ODE bouncing problem - wrong direction

This topic is 2880 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi everyone. I'm trying to integrate ODE into a project of mine due to its seemingly ease of use, but I've run into a roadblock that I've spent the past couple days trying to figure out. To that end, I'm hoping someone can help me.

I'm trying to do a simple object bounce off a ground plane. The problem I'm encountering is that, when an object collides with the ground plane, the y-component of its velocity is not what is being adjusted (despite the normal vector of the collision being (0,1,0) ). Instead, the z-component is adjusted, causing the object to shoot off in the -z direction once underground, while still falling according to gravity (parabolic motion).

I've scoured the web for as many tutorials as I could find, and searched to my best efforts through these forums for any info, but have not found anything similar to this problem.

So, does anyone know why it might be changing the z-component instead of the y-component of the object's velocity? Any help would be greatly appreciated as this has been driving me a tad crazy. Thanks!

void initODE(){    World = dWorldCreate();    MAX_CONTACTS=20;    Space = dSimpleSpaceCreate(0);    contactgroup = dJointGroupCreate(0);    dCreatePlane(Space, 0, 1, 0, 0);	    dWorldSetGravity(World, 0, -9.8, 0);    dWorldSetERP(World, 0.2);    dWorldSetCFM(World, 1e-5);    dWorldSetContactMaxCorrectingVel(World, 0.9); 	    dWorldSetContactSurfaceLayer(World, 0.001);    dWorldSetAutoDisableFlag(World, 0);}void worldObject::addToWorld(){    dMatrix3 R, R1,R2,R3,R4;    float DEGTORAD=3.1415/180.0;    Body = dBodyCreate(World);    dBodySetPosition(Body, pos.x, pos.y, pos.z);    dBodySetLinearVel(Body, 0,0,0);    switch (type)    {           case (RECTANGLE):           {                dMassSetBox(&Mass, 1,width, height, length);                Geom = dCreateBox(Space, width, height, length);                break;           }           case (SPHERE):           {                dMassSetSphere(&Mass, 1, radius);                Geom = dCreateSphere(Space, radius);                break;           }           case (CYLINDER):           {                dMassSetCylinder(&Mass, 1, 1, radius1, length_cyl);             //   Geom = dCreateCCylinder(Space, radius1, length_cyl);                break;           }    }    dBodySetMass(Body, &Mass);    dGeomSetBody(Geom, Body);    // Get the rotation from the editing and apply it    dRFromAxisAndAngle(R1,0,0,1,chi*DEGTORAD);    dRFromAxisAndAngle(R2,0,1,0,phi*DEGTORAD);    dRFromAxisAndAngle(R3,1,0,0,theta*DEGTORAD);    dMULTIPLY0_333(R4,R1,R2);    dMULTIPLY0_333(R,R4,R3);    dBodySetRotation(Body, R);}static void nearCallback (void *data, dGeomID o1, dGeomID o2){    int i;    dBodyID b1 = dGeomGetBody(o1);    dBodyID b2 = dGeomGetBody(o2);    dContact contact[MAX_CONTACTS];    for (i = 0; i < MAX_CONTACTS; i++)    {        contact.surface.mode = dContactBounce | dContactSoftCFM;        contact.surface.mu = dInfinity;        contact.surface.mu2 = 0;        contact.surface.bounce = 0.51;        contact.surface.bounce_vel = 0.1;        contact.surface.soft_cfm = 1.01;    }    if (int numc = dCollide(o1, o2, MAX_CONTACTS, &contact[0].geom, sizeof(dContact)))    {        for (i = 0; i < numc; i++)        {            dJointID c = dJointCreateContact(World, contactgroup, &contact);            dJointAttach(c, b1, b2);        }    }}    void collide(){     dSpaceCollide(Space, 0, &nearCallback);     dWorldQuickStep(World, gameTime);     dJointGroupEmpty(contactgroup);  }

##### Share on other sites
If the contact detection is good (normal.y = 1), you should look at contact resolver function.

##### Share on other sites
Thanks; the relevant function is included in the code above. It's copied near directly from a tutorial (which works) save for variable names. This has me baffled. Is there anyone with any ODE experience that can see what I'm missing?

Thanks

##### Share on other sites
Hi. I have about 4 hours ODE experience.

From what I understand from ODE, there is a simple unison of geometries and actual bodies in 3d space; the geometries possessing the physics attributes
while the actual bodies that the programmer binds to geometries, inherit features from these preset characteristics. It is this which allows for easy and pain free usage.
ODE is essentially "paste geometry to actual object library".

So, it is very important that you have unique geometries for each actual body type for example. Maybe when I have more than a day of ODE experience, I can validate my initial understanding.

I was able to scratch code a simple little demonstration of ODE in action. And i mean as minimal action as possible. Just fall and bounce. I jsut wanted to test how
quickly I could create a gl+ode app, and it was also good practice.

ode test

##### Share on other sites
This is my exact code ( well the ode section )

// :----: global ode variables
#define geometries_per_body 1
#define maximum_colission_joints 4 // :----: a cube will have 4 joints in a colission instance
#define geometry_density 0.5
MATRIX geometry_matrix;
struct my_object
{
dBodyID cube_body;
dGeomID cube_geometry [ geometries_per_body ];
};
my_object cube_solid;
dWorldID environment;
dSpaceID continuom;
dJointGroupID colission_joints;
GLuint cube_solid_y_pos = 10;
[/quote]

I love object oriented programming, so almost anithing i do is objected oriented, from python to c. If you want to use it, just take out the "program::" bit

bool program::initiate_ode ( )
{
// :----: world setup
environment = dWorldCreate ( );
continuom = dSimpleSpaceCreate ( 0 );
colission_joints = dJointGroupCreate ( 0 );
dCreatePlane ( continuom, 0, 1, 0, 0 );
dWorldSetGravity ( environment, 0, -1.0, 0 );
dWorldSetERP ( environment, 0.2 );
dWorldSetCFM ( environment, 1e-5 );
dWorldSetContactMaxCorrectingVel ( environment, 0.9 );
dWorldSetContactSurfaceLayer ( environment, 0.001 );
dWorldSetAutoDisableFlag ( environment, 1 );
// :----: object setup vars
dMatrix3 geometry_rotation;
VECTOR geometry_temp_vector ( 0.0, 0.0, 0.0 );
size_t geometry_data = 0;
dMass geometry_mass;
dReal geometry_sides [ 3 ];
geometry_sides [ 0 ] = 2.0, geometry_sides [ 1 ] = 2.0, geometry_sides [ 2 ] = 2.0;
// :----: object setup
cube_solid.cube_body = dBodyCreate ( environment );
dBodySetPosition ( cube_solid.cube_body, -1.5, cube_solid_y_pos, 3 );

dRFromAxisAndAngle ( geometry_rotation, dRandReal ( ) * 2.0 - 1.0, dRandReal ( ) * 2.0 - 1.0, dRandReal ( ) * 2.0 - 1.0, dRandReal ( ) * 10.0 - 5.0 );
dBodySetRotation ( cube_solid.cube_body, geometry_rotation );

dBodySetLinearVel ( cube_solid.cube_body, geometry_temp_vector.x, geometry_temp_vector.y, geometry_temp_vector.z );

dBodySetData ( cube_solid.cube_body, ( void * ) geometry_data );

dMassSetBox ( &geometry_mass, geometry_density, geometry_sides [ 0 ], geometry_sides [ 1 ], geometry_sides [ 2 ] );
dBodySetMass ( cube_solid.cube_body, &geometry_mass );

cube_solid.cube_geometry [ 0 ] = dCreateBox ( continuom, geometry_sides [ 0 ], geometry_sides [ 1 ], geometry_sides [ 2 ] );
dGeomSetBody ( cube_solid.cube_geometry [ 0 ], cube_solid.cube_body );
}

bool program::de_initiate_ode ( )
{
dWorldDestroy ( environment );
dSpaceDestroy ( continuom );
dJointGroupDestroy ( colission_joints );
}

static void ode_callback ( void *geometry_data, dGeomID geometry_zero, dGeomID geometry_one )
{
int ode_index;
dBodyID _geometry_zero = dGeomGetBody ( geometry_zero );
dBodyID _geometry_one = dGeomGetBody ( geometry_one );
dContact colission_contact [ maximum_colission_joints ];

for ( ode_index = 0; ode_index < maximum_colission_joints; ode_index ++ )
{
colission_contact [ ode_index ].surface.mode = dContactBounce | dContactSoftCFM;
colission_contact [ ode_index ].surface.mu = dInfinity;
colission_contact [ ode_index ].surface.mu2 = 0;
colission_contact [ ode_index ].surface.bounce = 0.01;
colission_contact [ ode_index ].surface.bounce_vel = 0.1;
colission_contact [ ode_index ].surface.soft_cfm = 0.01;
}

if ( int ode_cardinality = dCollide ( geometry_zero, geometry_one, maximum_colission_joints, &colission_contact [ 0 ].geom, sizeof ( dContact ) ) )
{
for ( ode_index = 0; ode_index < ode_cardinality; ode_index ++ )
{
dJointID ode_joint_id = dJointCreateContact ( environment, colission_joints, colission_contact + ode_index );
dJointAttach ( ode_joint_id, _geometry_zero, _geometry_one );
}
}
}

bool program::ode_cycle ( )
{
dSpaceCollide ( continuom, 0, &ode_callback );
dWorldQuickStep ( environment, 0.05 );
dJointGroupEmpty ( colission_joints );
program ( ).project_geometry ( cube_solid.cube_geometry [ 0 ], 0, 0, 0 );
}

// draws geometry
void program::project_geometry ( dGeomID geometry_body, const dReal *geometry_position, const dReal *geometry_rotation, int project_ode )
{
if ( !geometry_body ) return;
if ( !geometry_position ) geometry_position = dGeomGetPosition ( geometry_body );
if ( !geometry_rotation ) geometry_rotation = dGeomGetRotation ( geometry_body );
int geometry_type = dGeomGetClass ( geometry_body );
if ( geometry_type == dBoxClass )
{
dReal geometry_sides [ 3 ];
dGeomBoxGetLengths ( geometry_body, geometry_sides );
program ( ).project_actual_cube_solid ( geometry_sides, geometry_position, geometry_rotation );
}
}

//draws actual object
bool program::project_actual_cube_solid ( const dReal geometry_sides [ 3 ], const dReal geometry_position [ 3 ], const dReal geometry_rotation [ 12 ] )
{
glPushMatrix ( );
geometry_matrix.ode_to_gl ( geometry_position, geometry_rotation );
glMultMatrixf ( geometry_matrix.Element );
generate_image ( "data/images/cube solid texture.bmp" );
project_cube_solid ( ); // this is just a normal cube, drawn in the normal gl way
glPopMatrix ( );
}
[/quote]

ODE DONE!!!!

Dont't mind the "project ( ).method" bit. It's just another way of doing this:
//normal declaration
project run;
run.method ( )

//my shortcut
project ( ).method ( );

It's an accident i found out when i used to code SDL games....: )

##### Share on other sites
I then use this function to reset object's orientation at runtime.

bool program::controls ( )
{
// :----: in addition to position, the cube's geometry rotation needs to also be reset, so it's different each fall
dMatrix3 geometry_rotation;

if ( ( key [ 'R' ] ) && ( pressingr == false ) )
{
pressingr = true;
dBodySetPosition ( cube_solid.cube_body, 0, cube_solid_y_pos, 0 );
dRFromAxisAndAngle ( geometry_rotation, dRandReal ( ) * 2.0 - 1.0, dRandReal ( ) * 2.0 - 1.0, dRandReal ( ) * 2.0 - 1.0, dRandReal ( ) * 10.0 - 5.0 );
dBodySetRotation ( cube_solid.cube_body, geometry_rotation );
}
else
{
pressingr = false;
}
}
[/quote]

1. 1
2. 2
3. 3
Rutin
15
4. 4
khawk
14
5. 5
frob
12

• 9
• 11
• 11
• 23
• 12
• ### Forum Statistics

• Total Topics
633660
• Total Posts
3013221
×