Java port of Bullet Physics Library

I’m playing with HingeConstraint, and I have a issue :

There is two constructors to join bodies, one which takes Transform, and one where you specify Vectors …
With the first one, hinge Limits and angularMotor work very well, but with the other constructor the physic explodes when it reaches limits !

Maybe I do something wrong, here is the 2 methods I use :

HingeConstraint hingeC;                
Transform localA = stack.transforms.get();
Transform localB = stack.transforms.get();
localA.setIdentity();
localA.origin.set(1.0f, 0.0f, 0.0f);                              
localB.setIdentity();                
localB.origin.set(-1.0f, 0.0f, 0.0f);                                          
hingeC = new HingeConstraint(bodies.get(1), bodies.get(2), localA, localB);

And my current issue :

HingeConstraint hingeC; 
Vector3f pivotInA = stack.vectors.get();
Vector3f pivotInB = stack.vectors.get();
Vector3f axisInA = stack.vectors.get();
Vector3f axisInB = stack.vectors.get();
pivotInA.set(1.0f, 0.0f, 0.0f);
pivotInB.set(-1.0f, 0.0f, 0.0f);
axisInA.set(0.0f, 0.0f, 1.0f);
axisInB.set(0.0f, 0.0f, 1.0f);                
hingeC = new HingeConstraint(bodies.get(1), bodies.get(2), pivotInA, pivotInB, axisInA, axisInB);

Jezek, I can send you a test if you want to check by yourself.

I’m trying to debug :
In the first case which works, I get Tranforms for HingeContraints like this:

rbAFrame
(1.0, 0.0, 0.0)
1.0, 0.0, 0.0 
0.0, 1.0, 0.0
0.0, 0.0, 1.0

rbBFrame
(-1.0, 0.0, 0.0)
1.0, 0.0, -0.0
0.0, 1.0, -0.0
0.0, 0.0, -1.0

but the computed Tranforms from Vectors are like this :

rbAFrame
(1.0, 0.0, 0.0)
0.0, 1.0, 0.0
1.0, 0.0, 0.0
0.0, 0.0, 1.0

rbBFrame
(-1.0, 0.0, 0.0)
0.0, 1.0, -0.0
1.0, 0.0, -0.0
0.0, 0.0, -1.0

Hi

I inspect HingeConstraint code, and there is some things a bit weird (also present in “upstream” Bullet), if I remember well my maths (which are years behind me now …)
So I’ ve rewrite the constructor public HingeConstraint(RigidBody rbA, RigidBody rbB, Vector3f pivotInA, Vector3f pivotInB, Vector3f axisInA, Vector3f axisInB) and it seems ok :

Here is the original code :

rbAFrame.origin.set(pivotInA);

// since no frame is given, assume this to be zero angle and just pick rb transform axis
Vector3f rbAxisA1 = stack.vectors.get();
rbA.getCenterOfMassTransform().basis.getColumn(0, rbAxisA1);

float projection = rbAxisA1.dot(axisInA);
if (projection > BulletGlobals.FLT_EPSILON) {
	rbAxisA1.scale(projection);
	rbAxisA1.sub(axisInA);
} else {
	rbA.getCenterOfMassTransform().basis.getColumn(1, rbAxisA1);
}

Vector3f rbAxisA2 = stack.vectors.get();
rbAxisA2.cross(rbAxisA1, axisInA);

rbAFrame.basis.setRow(0, rbAxisA1.x, rbAxisA2.x, axisInA.x);
rbAFrame.basis.setRow(1, rbAxisA1.y, rbAxisA2.y, axisInA.y);
rbAFrame.basis.setRow(2, rbAxisA1.z, rbAxisA2.z, axisInA.z);

Quat4f rotationArc = stack.quats.get(QuaternionUtil.shortestArcQuat(axisInA, axisInB));
Vector3f rbAxisB1 = stack.vectors.get(QuaternionUtil.quatRotate(rotationArc, rbAxisA1));
Vector3f rbAxisB2 = stack.vectors.get();
rbAxisB2.cross(rbAxisB1, axisInB);

rbBFrame.origin.set(pivotInB);
rbBFrame.basis.setRow(0, rbAxisB1.x, rbAxisB2.x, -axisInB.x);
rbBFrame.basis.setRow(1, rbAxisB1.y, rbAxisB2.y, -axisInB.y);
rbBFrame.basis.setRow(2, rbAxisB1.z, rbAxisB2.z, -axisInB.z);

And my code :

rbAFrame.origin.set(pivotInA);    

Vector3f rbAxisA1 = stack.vectors.get();
Vector3f rbAxisA2 = stack.vectors.get();
Vector3f tmpVect = stack.vectors.get(axisInA);
rbA.getCenterOfMassTransform().basis.getColumn(0, rbAxisA1);

float projection = axisInA.dot(rbAxisA1);
if (Math.abs(projection) >= 1.0f - BulletGlobals.SIMD_EPSILON) {
            rbA.getCenterOfMassTransform().basis.getColumn(1, rbAxisA2);                                                        
            tmpVect.scale(axisInA.dot(rbAxisA2));
            rbAxisA2.sub(tmpVect);   
            rbAxisA1.cross(rbAxisA2, axisInA);                                                
} else {           
            tmpVect.scale(projection);
            rbAxisA1.sub(tmpVect);                            
            rbAxisA2.cross(axisInA, rbAxisA1);                   
}

rbAFrame.basis.setRow(0, rbAxisA1.x, rbAxisA2.x, axisInA.x);
rbAFrame.basis.setRow(1, rbAxisA1.y, rbAxisA2.y, axisInA.y);
rbAFrame.basis.setRow(2, rbAxisA1.z, rbAxisA2.z, axisInA.z);

Quat4f rotationArc = stack.quats.get(QuaternionUtil.shortestArcQuat(axisInA, axisInB));
Vector3f rbAxisB1 = stack.vectors.get(QuaternionUtil.quatRotate(rotationArc, rbAxisA1));
Vector3f rbAxisB2 = stack.vectors.get();

rbAxisB2.cross(axisInB, rbAxisB1);

rbBFrame.origin.set(pivotInB);
rbBFrame.basis.setRow(0, rbAxisB1.x, rbAxisB2.x, -axisInB.x);
rbBFrame.basis.setRow(1, rbAxisB1.y, rbAxisB2.y, -axisInB.y);
rbBFrame.basis.setRow(2, rbAxisB1.z, rbAxisB2.z, -axisInB.z);

Maybe I should also post on Bullet forum ?

I looked into code and this particular constructor is not used in any demo, also HingeConstraint is same in both 2.66 and 2.67. So I think it might be bug in upstream, you should post there as well (in new thread).

First of all, thanks Jezek for such impressive effort. I just PM’ed the moderator to make this topic sticky.

Small advice: moving trimeshes (GIMPACT), BulletMultiThreaded, BulletColladaConverter are not part of the core Bullet but optional Extras. btContinuousDynamicsWorld is currently work-in-progress, so I recommend waiting to port that and focus first on the remaining parts of the core parts in the Bullet/src folder.

The constructor was created before the hinge limit contribution was added. It doesn’t properly support hinge limits indeed.
The pivot+axis doesn’t provide a full frame, so the limits are ambiguous. If we change the implementation, we break backwards compatibility.

One idea is to apply/reset the transform properly inside the ‘setLimit’ method, would that help? See issue report here:
http://code.google.com/p/bullet/issues/detail?id=41

Please discuss details in the Bullet forums, we will sort it out.
Erwin

…says who? ;D

I’ve written a jPCT-implementation of IGL, but a very limited one. It can play the basic demo but that’s it (i.e. it can only draw cubes). It was just meant as a proof of concept and as a training exercise if it’s actually possible to develop on the Asus EEEPC…it is! To use jBullet (great work btw…multithreading would be a cool addition) with a 3d engine, one shouldn’t use the demo framework IMHO, because it’s bound too much to the way how OpenGL does things. However, it IS possible to use it anyway…as you can see.

Keep up the good work!

That looks nice. What method is used for the real-time shadows?

Do you have a link to the source code/demo?

THanks,
Erwin

It’s shadow mapping. The sources are here: http://www.jpct.net/forum2/index.php/topic,1079.0.html But they aren’t pure OGL, they are using jPCT as 3d engine. The demo framework is too low level to make a nice fit for the engine, so i’m trying to mimic the state machine that OpenGL is with jPCT, which looks quite hacky… :wink:

Hi, AWESOME work.

jME http://www.jmonkeyengine.com/ would like to utilize this physics library. Currently it is using a java port of ODE, if included this would be another available physics library.

I was wondering a couple of things though. How are you going to handle Bullet updates? and What is the the state of this current endeavor. If it is still going to be changed quite a bit, would it be better to wait to implement it with jME?

Thanx, basixs

No nitpicking intended, but I want to correct this a little bit: it would be great to use jBullet in jME Physics 2. No official plans yet. And it currently uses ODEJava (which is not a java port, though JOODE is supported as well)

Anyways, basixs is right overall - awesome work! any eta for a kind of release/stable or similar?

After base features will be ported, I would like to keep syncing with newer versions. It seems that differencies of code between versions are not that big. The API will be changing a little in some versions, both because of Java port and original Bullet. But nothing significant I think. Therefore, I don’t think you should wait with using JBullet.

No ETA is set, but I think that base features will be ported in month or two. I would like to switch to a new, more “official” versioning scheme that matches the original Bullet version, eg. 2.67-1, where 2.67 is original Bullet version and 1 is Java port version for that Bullet version. It will increase when bugfixes or other enhancements are made in Java version, or when some yet unported code was ported (eg. from extras).

@jezek2, I was wondering if you could clarify something for me.

I’ve been trying to link my rendering engine to javabullet to test it without the debug drawer. However, when I create a box with half extent <1, 1, 1>, to get the visuals right, I need to draw a cube with side lengths 1. Do half extents in bullet represent actual side lengths or half the dimension (as the name seems to imply)?

Thanks

Just for your info: I have added this feature now.

Marvin

LvR: your suggested fixes are now in Bullet 2.68 beta 2, C++ version. http://code.google.com/p/bullet/downloads/list

Jerez: I would wait porting the upcoming soft body dynamics, it is work-in-progress. There are some important fixes in btConeTwistConstraint, btQuaternion and RagdollDemo that you might need to integrate in the Java version.

Thanks a lot for the feedback,
Erwin

Thank you Erwin.

Jezek, I have the same fixes available for jbullet.
With a mtn status or mtn diff I can see the changes. How I can commit safely just one file (I’ve have some other files I’ve changed for some test) ?

Should be just about specifying the file name on command line, like this: mtn commit SomeFile.java or mtn commit path/to/SomeFile.java (both relative to your current dir). You’ll get then summary of changes when editing commit message. Remember to sync afterwards :slight_smile:

Thanks for your advice, nice stuff btw! :slight_smile: I’ll probably still leave JBullet on 2.66 for some time, with exception of important fixes like these. And in some near future I’ll upgrade directly to 2.68.

ok, HingeConstraint fix should be commited.

I’ve a pb when I try to remove rigidbodies from my dynamicworld (it’s not systematic, and arryy index causing this exception change)

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 13
        at gnu.trove.THashMap.removeAt(THashMap.java:414)
        at gnu.trove.THashMap.retainEntries(THashMap.java:315)
        at com.bulletphysics.util.HashUtil$TroveHashMapImpl.retainEntries(HashUtil.java:114)
        at com.bulletphysics.collision.broadphase.OverlappingPairCache.processAllOverlappingPairs(OverlappingPairCache.java:123)
        at com.bulletphysics.collision.broadphase.OverlappingPairCache.removeOverlappingPairsContainingProxy(OverlappingPairCache.java:127)
        at com.bulletphysics.collision.broadphase.SimpleBroadphase.destroyProxy(SimpleBroadphase.java:73)
        at com.bulletphysics.collision.dispatch.CollisionWorld.removeCollisionObject(CollisionWorld.java:164)
        at com.bulletphysics.dynamics.DiscreteDynamicsWorld.removeRigidBody(DiscreteDynamicsWorld.java:375)

Here is how I do (I only have box rigidbodies and HingeConstraint) :

public void deleteWorld() {
		
		// Delete joints
		int numConstraints = dynamicsWorld.getNumConstraints();
		for (int i=0; i<numConstraints; i++) {
			TypedConstraint joints = dynamicsWorld.getConstraint(0);
			dynamicsWorld.removeConstraint(joints);
		}
		
		// Delete nodes	and RigidBodies
		for (Node node : sceneGraph) {
			if (node instanceof PhysicNode) {
				RigidBody body = ((PhysicNode)node).getCollisionObject();			
				dynamicsWorld.removeRigidBody(body);
				body.destroy();
			}
		}
		sceneGraph = new ArrayList<Node>();
		
		// Delete dynamicWorld		
		dynamicsWorld.destroy();
		dynamicsWorld = null;
		
	}
	

Any idea ?

This looks like bug in GNU Trove itself, try latest version of it. I’ve seen that they fixed some bug with retainEntries in newer version. If that doesn’t help you can try to remove it from classpath, JBullet will then use normal HashMap.

BTW: thanks for the commit, I will just fix minor divergence of the code style to match other code (the else blocks starts on same line as ‘}’).

With trove-2.0.3, I can’t reproduce it so it was a trove bug.
thx for the help.