[Odejava] Box won't tip over

Hi,

I’m new to Odejava (to physics in general). I have a scene set up which consists of a floor and several walls. I’m dropping a small cube onto the floor with a random velocity and rotation.

Everything works great, until the cube starts to slow down from the friction. If the cube was rolling along the ground, and the friction slows it to a stop, it will completely stop, even if it is sitting on the ground at a massive angle (will sit on it’s edge instead of a face):

Is there something wrong with the way that I’m setting up my objects?

Worldwide Settings:

physics_JavaCollision.setSurfaceMu(1.0f);
physics_JavaCollision.setSurfaceBounce(0f);
physics_JavaCollision.setSurfaceBounceVel(5000.1f);
physics_JavaCollision.setSurfaceMode(Ode.dContactBounce);
physics_World.setStepInteractions(50);
physics_World.setStepSize(0.05f);

Contact between cube and wall:

physics_Contact.setMode(Ode.dContactBounce | Ode.dContactApprox1);
physics_Contact.setBounce(0.2f);
physics_Contact.setBounceVel(0.01f);

Creating the cube:

this.myBody = new Body(physics_World);
this.myBody.setGeom(new GeomBox(DIAMETER * 2, DIAMETER * 2, DIAMETER * 2));
this.myBody.adjustMass(1.0f);
this.myBody.resetRotationAndForces();
physics_HashSpace.addBodyGeoms(this.myBody);

The floor and walls of the box are simple GeomBoxes which have been added to the world without a Body.

Thanks for any help! :slight_smile: More code is available is needed to diagnose the problem.

sounds like auto-disabled - raise the thresholds for the auto-disable feature

I’ve tried adding the following to the creation of my bodies:

this.myBody.setAutoDisable(false);
this.myBody.setAngularVelocityDisableThreshold(5f);

…but it has no effect. isAutoDisabling() returns false on both the world and the bodies, even before I added that code.

In fact, it is very rare that a box actually lands on a face, the majority of the tie is spent either partly or fully resting on a single edge as shown above, but the physics seem to work fine otherwise. Would adding a mass to the corner of each box help at all?

Also, here’s how I’m positioning my boxes and giving them initial force and spin:

boxObject.translate(-(FIELD_WIDTH / 2f) - CAMERA_BUFFER_SPACE * 0.3f, -(FIELD_HEIGHT * 1.5f), (FIELD_WIDTH * 0.1f));
boxObject.myBody.setForce(500.0f + (float)((Math.random() - 0.5) * 400), 0f, (float)((Math.random() - 0.5) * 600));
boxObject.myBody.setAngularVel(0f, (float)(Math.random() * 2), (float)(Math.random() * 2));
myWorld.addObject(boxObject);

Yet another thing I’ve noticed: when the boxes are landing on the base and flipping around, it almost looks like there is some kind of force holding it upwards. Ex. when a box is rolling around in one direction, and is in the position above, something appears to pull it backward back onto it’s edge. In my simulation, the Y axis is reversed (is positive going down). Could this have something to do with it?

hmm - could it be, that you’ve set the mass incorrectly?

This error could happen, if you create your geom, set the position of the geom and then attach a body. The mass of the geom is centered at the origin of the Body’s coordinate system. To solve the problem, change your Box’ position by modifing the position of the body and not of the geom itself.

Whoops, forgot that the ‘boxObject.translate(…);’ call that I posted above actually refers to a 3D engine call and not a physics engine call. It actually refers to this:

public void translate(float x, float y, float z)
{
	this.myBody.setPosition(x, y, z);
	//3D engine stuff...
}

So, putting this together, the code from the creation of the object all the way to it’s positioning, relating to mass, position, and rotation, is:

this.myBody = new Body(physics_World);
this.myBody.setGeom(new GeomBox(DIAMETER * 2, DIAMETER * 2, DIAMETER * 2));
this.myBody.adjustMass(1.0f);
this.myBody.resetRotationAndForces();
physics_HashSpace.addBodyGeoms(this.myBody);

this.myBody.setPosition(-(FIELD_WIDTH / 2f) - CAMERA_BUFFER_SPACE * 0.3f, -(FIELD_HEIGHT * 1.5f), (FIELD_WIDTH * 0.1f));
this.myBody.setForce(500.0f + (float)((Math.random() - 0.5) * 400), 0f, (float)((Math.random() - 0.5) * 600));
this.myBody.setAngularVel(0f, (float)(Math.random() * 2), (float)(Math.random() * 2));

Is that the correct way to set the mass?

Now that you mention it, on closer inspection I can see that the boxes which land perfectly flat always land on the same face, making it look like the mass is to blame.

What kind of function calls should I be looking for which could be upsetting the mass?

Could it have something to do with the way that I’m displaying the boxes in my 3D engine?

Here’s what I do on every step of the physics engine:

//Get ODEJava's position & rotation
Vector3f myPosition = this.myBody.getPosition();
Matrix3f myRotation = this.myBody.getRotation();

//This function converts the position into something that the 3D renderer can handle, and moves the displayed cube there
moveTo(new SimpleVector(myPosition.x, myPosition.y, myPosition.z));

//Converts the rotation matrix to put into the 3D renderer
this.setRotationMatrix(Matrix3fToMatrix(myRotation));

//Add position history (for telling when the box stops moving)
if (this.previousPositions.size() >= POSITION_HISTORY_DEPTH)
{
	this.previousPositions.removeElementAt(0);
	this.previousPositions.addElement(myPosition);
} else {
	this.previousPositions.push(myPosition);
}

Here’s how I’m converting the matrix format:

protected Matrix Matrix3fToMatrix(Matrix3f input)
{
	//Declare variables
	float[] insertDump = new float[16]; //The array holding the values in the new Matrix
	float[] rowDump = new float[3];     //The array for temporarily holding values from the rows of the Matrix3f
	int targetElement = 0;              //Points to the next location in the insertDump to add data
	
	//Loop through the rows of the Matrix3f
	for (int sourceRow = 0; sourceRow < 3; sourceRow++)
	{
		//Grab the row from the Matrix3f
		input.getRow(sourceRow, rowDump);
		
		//Insert the 3 elements from the Matrix3f into the Matrix.  The fourth element has been initialized to 0.0f.
		insertDump[targetElement] = rowDump[0];
		insertDump[targetElement + 1] = rowDump[1];
		insertDump[targetElement + 2] = rowDump[2];
		
		//Move the target ahead by four spaces
		targetElement += 4;
	}
	
	//The final row consists of { 0.0f, 0.0f, 0.0f, 1.0f }, since this is a rotation matrix
	insertDump[15] = 1.0f;
	
	//Create the new Matrix and load in the values
	Matrix output = new Matrix();
	output.setDump(insertDump);
	
	//Return
	return output;
}

Also, the 3D engine that I’m using has a coordinate system in which the Y-axis is positive going downward, the X-axis is positive going right, and the Z-axis is positive moving into the screen. Could this be messing up ODE?

Maybe these rather exotic values are to blame:


physics_JavaCollision.setSurfaceMu(1.0f); // try 0.8-0.9
physics_JavaCollision.setSurfaceBounce(0f); // try 0.1
physics_JavaCollision.setSurfaceBounceVel(5000.1f); // try 2.0
physics_JavaCollision.setSurfaceMode(Ode.dContactBounce);

	physics_World.setGravity(0.0f, 9.81f, 0.0f);
	physics_JavaCollision = new org.odejava.collision.JavaCollision(physics_World);
	physics_Contact = new org.odejava.collision.Contact(physics_JavaCollision.getContactIntBuffer(), physics_JavaCollision.getContactFloatBuffer());
	environment_IDs = new HashMap();
	physics_JavaCollision.setSurfaceMu(0.8f);
	physics_JavaCollision.setSurfaceBounce(0.1f);
    	physics_JavaCollision.setSurfaceBounceVel(2.0f);
	physics_JavaCollision.setSurfaceMode(Ode.dContactBounce);
	physics_World.setStepInteractions(10);
	physics_World.setStepSize(0.05f);

…produced the same results.

Alright, after a week of debugging I found the answer. For the record, the 3D engine I was interfacing with was jPCT.

The problem was with the display of the rotation. My Matrix3fToMatrix() function (see above) was being used to transfer the rotation matrix from OdeJava to jPCT. Either the OdeJava matrix was wrong, the conversion was wrong, or the engines are incompatible. Either way, the solution was to use Quaternions.

Here’s the function that I used to convert the Quaternion from Body.getQuaternion() to a Matrix for jPCT:

protected Matrix Quat4fToMatrix(javax.vecmath.Quat4f input)
{
	float[] MatrixDump = new float[16];
	float xx = input.x * input.x;
	float xy = input.x * input.y;
	float xz = input.x * input.z;
	float xw = input.x * input.w;
	float yy = input.y * input.y;
	float yz = input.y * input.z;
	float yw = input.y * input.w;
	float zz = input.z * input.z;
	float zw = input.z * input.w;
	
	MatrixDump[0] = 1 - 2 * ( yy + zz );
	MatrixDump[4] = 2 * ( xy - zw );
	MatrixDump[8] = 2 * ( xz + yw );
	MatrixDump[1] = 2 * ( xy + zw );
	MatrixDump[5] = 1 - 2 * ( xx + zz );
	MatrixDump[9] = 2 * ( yz - xw );
	MatrixDump[2] = 2 * ( xz - yw );
	MatrixDump[6] = 2 * ( yz + xw );
	MatrixDump[10] = 1 - 2 * ( xx + yy );
	MatrixDump[15] = 1;
	
	Matrix buffer = new Matrix();
	buffer.setDump(MatrixDump);
	return buffer;
}

Thanks for all the help guys! :wink: