Hi Guys,
I could use some input on this one. I currently need a method to perform a Mesh / Capsule collision detection, using my own physics ( Basicly the capsule is controlled directly by a robotic arm ( a haptic device ) and the mesh will be static. I currently use a ray to define the robotic arm, but I need something “thicker”, a capsule would be perfect ).
There-for I am trying to separate the Bullet collision detection out from the bullet world. Has anyone done this before?
I currently have the below code, with two different methods of running the collision detection. But as you will see if you run it the collisions flicker a bit, sometimes triggering when there is no over lap ( seen in image ), and sometimes off when there is clear overlap. It is quite hard to debug since there is little to no javadoc, so I am hoping someone has a clue.
Note: Press to enable ‘bullet time’, to observe the flickering.
Note 2: I did not bother making an actual capsule mesh, so the spheres show the extremes of each capsule, the small spheres are the local collision points.
- To change this template, choose Tools | Templates
- and open the template in the editor.
*/
package mygame;
import com.bulletphysics.collision.broadphase.AxisSweep3;
import com.bulletphysics.collision.broadphase.CollisionAlgorithm;
import com.bulletphysics.collision.dispatch.CollisionDispatcher;
import com.bulletphysics.collision.dispatch.CollisionObject;
import com.bulletphysics.collision.dispatch.CollisionWorld;
import com.bulletphysics.collision.dispatch.DefaultCollisionConfiguration;
import com.bulletphysics.collision.dispatch.ManifoldResult;
import com.bulletphysics.collision.narrowphase.ManifoldPoint;
import com.bulletphysics.collision.narrowphase.PersistentManifold;
import com.bulletphysics.util.ObjectArrayList;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.collision.shapes.CompoundCollisionShape;
import com.jme3.bullet.objects.PhysicsRigidBody;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.debug.Grid;
import com.jme3.scene.shape.Sphere;
public class CollisionInterfaceDemo extends SimpleApplication {
private CollisionWorld collisionWorld;
private javax.vecmath.Vector3f worldAabbMin;
private javax.vecmath.Vector3f worldAabbMax;
private CollisionObject objects[] = new CollisionObject[ 2 ];
private Node debugModel[] = new Node[ 2 ];
private PhysicsRigidBody body;
private Material capsuleMaterial;
private Material pointMaterial;
private boolean bulletTime = false;
@Override
public void simpleInitApp() {
this.capsuleMaterial = new Material( this.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
this.capsuleMaterial.setColor( "Color", ColorRGBA.Orange );
this.capsuleMaterial.getAdditionalRenderState().setWireframe( true );
this.pointMaterial = new Material( this.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
this.pointMaterial.setColor( "Color", ColorRGBA.Red );
this.initCollsionDetection();
this.attachGrid( Vector3f.ZERO, 31, ColorRGBA.Yellow );
this.attachGrid( Vector3f.ZERO, 31, ColorRGBA.Yellow );
this.inputManager.addListener( new ActionListener(){
public void onAction( String name, boolean isPressed, float tpf ) {
bulletTime = isPressed;
}
}, new String[]{ "BulletTime" } );
this.inputManager.addMapping("BulletTime", new KeyTrigger( KeyInput.KEY_SPACE ) );
}
private void attachGrid(Vector3f pos, int size, ColorRGBA color) {
Geometry g = new Geometry("wireframe grid", new Grid( size, size, 1f ) );
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.getAdditionalRenderState().setWireframe(true);
mat.setColor("Color", color);
g.setMaterial(mat);
g.center().move(pos);
rootNode.attachChild( g );
}
float time = 0;
@Override
public void simpleUpdate( float tpf ) {
time += bulletTime ? 0.01f * tpf : tpf;
time = time > FastMath.DEG_TO_RAD * 50 ? -FastMath.DEG_TO_RAD * 50 : time;
Vector3f position = new Vector3f( 3 * FastMath.sin( time ), FastMath.abs( 3 * FastMath.sin( 10f * time ) ), 5 * FastMath.cos( time ) - 5 + 0.3f );
body.setPhysicsLocation( position );
this.debugModel[ 0 ].setLocalTranslation( position );
boolean collision = this.collide();
if( collision ){
capsuleMaterial.setColor("Color", ColorRGBA.Red );
} else {
capsuleMaterial.setColor("Color", ColorRGBA.Green );
}
}
private void initCollsionDetection()
{
DefaultCollisionConfiguration collisionConfiguration = new DefaultCollisionConfiguration();
CollisionDispatcher dispatcher = new CollisionDispatcher( collisionConfiguration );
worldAabbMin = new javax.vecmath.Vector3f(-1000,-1000,-1000);
worldAabbMax = new javax.vecmath.Vector3f(1000,1000,1000);
AxisSweep3 broadphase = new AxisSweep3( worldAabbMin, worldAabbMax );
collisionWorld = new CollisionWorld( dispatcher, broadphase, collisionConfiguration );
float height = 2f;
float radius = 0.5f;
debugModel[ 0 ] = this.createCapsuleModel( height, radius );
debugModel[ 1 ] = this.createCapsuleModel( height, radius );
this.getRootNode().attachChild( this.debugModel[ 0 ] );
this.getRootNode().attachChild( this.debugModel[ 1 ] );
body = new PhysicsRigidBody( this.createCapsule( new Vector3f( 0, 0, 0 ), height, radius ), 5f );
objects[ 0 ] = body.getObjectId();
objects[ 1 ] = new PhysicsRigidBody( this.createCapsule( new Vector3f(), height, radius ), 5f ).getObjectId();
collisionWorld.addCollisionObject( objects[ 0 ] );
collisionWorld.addCollisionObject( objects[ 1 ] );
}
/**
* Create a visual model for the two capsules
* @param height
* @param radius
* @return
*/
private Node createCapsuleModel( float height, float radius ){
Node n = new Node();
float offset = height / 2f - radius;
Geometry s1 = new Geometry( "Hi-Sphere", new Sphere( 20, 20, radius ) );
s1.setLocalTranslation( 0, offset, 0 );
s1.setMaterial( this.capsuleMaterial );
n.attachChild( s1 );
Geometry collisionPoint = new Geometry( "CollisionPoint", new Sphere( 20, 20, 0.1f ) );
collisionPoint.setLocalTranslation( 0, offset, 0 );
collisionPoint.setMaterial( this.pointMaterial );
n.attachChild( collisionPoint );
Geometry s2 = new Geometry( "Lo-Sphere", new Sphere( 20, 20, radius ) );
s2.setLocalTranslation( 0, -offset, 0 );
s2.setMaterial( this.capsuleMaterial );
n.attachChild( s2 );
return n;
}
/**
* Setup a collision capsule
* @param location
* @param height
* @param radius
* @return
*/
protected CollisionShape createCapsule( Vector3f location, float height, float radius ) {
CapsuleCollisionShape capsuleCollisionShape = new CapsuleCollisionShape( radius, height );
CompoundCollisionShape compoundCollisionShape = new CompoundCollisionShape();
compoundCollisionShape.addChildShape( capsuleCollisionShape, location );
return compoundCollisionShape;
}
/**
* Classic collision detection, colliding the entire 'world'
* @return
*/
private boolean collideClassic(){
boolean collision = false;
int numManifolds = collisionWorld.getDispatcher().getNumManifolds();
for ( int i = 0; i 0;
for (int j=0;j<numContacts;j++)
{
ManifoldPoint pt = contactManifold.getContactPoint( i );
System.out.println("At: " + pt );
}
}
return collision;
}
/**
* Direct collision detection, specifying which two objects to check collision on.
* @return
*/
private boolean collideDirect(){
boolean collision = false;
CollisionAlgorithm algo = collisionWorld.getDispatcher().findAlgorithm( objects[0], objects[1] );
ManifoldResult contactPointResult = new ManifoldResult( objects[0], objects[1] );
algo.processCollision( objects[0], objects[1], collisionWorld.getDispatchInfo(), contactPointResult );
ObjectArrayList manifoldArray = new ObjectArrayList();
algo.getAllContactManifolds( manifoldArray );
int numManifolds = manifoldArray.size();
for ( int i = 0; i 0;
for ( int j = 0; j < numContacts; j++ )
{
ManifoldPoint pt = contactManifold.getContactPoint( j );
javax.vecmath.Vector3f ptA = swap ? pt.getPositionWorldOnA( new javax.vecmath.Vector3f() ) : pt.getPositionWorldOnB( new javax.vecmath.Vector3f() );
javax.vecmath.Vector3f ptB = swap ? pt.getPositionWorldOnB( new javax.vecmath.Vector3f() ) : pt.getPositionWorldOnA( new javax.vecmath.Vector3f() );
this.debugModel[ 0 ].getChild( "CollisionPoint" ).setLocalTranslation( ptA.x, ptA.x, ptA.z );
this.debugModel[ 1 ].getChild( "CollisionPoint" ).setLocalTranslation( ptB.x, ptB.x, ptB.z );
}
contactManifold.clearManifold();
}
return collision;
}
/**
* Performs collision detection, with a choice of two methods
* @return
*/
private boolean collide() {
collisionWorld.performDiscreteCollisionDetection();
/**
* If TRUE: use the collision dispatcher
* FALSE: process collisions directly between objects
*/
boolean METHOD = false;
if( METHOD ){
return this.collideClassic();
}
else {
return this.collideDirect();
}
}
public static void main( String args[] ){
CollisionInterfaceDemo demo = new CollisionInterfaceDemo();
demo.start();
}
}
[/java]