I have to check collision between two meshes BEFORE creating them in the scene. I’ve searched for a collision code for spatials but jMokey will manage it only between a mesh and a simple object.
So I’ve looked into jBullet, especially with GhostControl that seems to be perfect for the job.
The principle I tried was :
create a compoud/hull collision shape for each spatial,
create ghost controls with these shapes,
attach controls to the spatials and to a newlly created physic space,
update the space immediatly for it to compute collisions,
finally check the collision and destroy the space.
But i’ve failed. It results in a collision whatever the spatial I create. I’ve olso a warning :
Thanks for the anwer @pesegato. It was my first try but as you may read on the page you linked :
An important restriction is that you can only collide geometry vs bounding volumes or rays. (This means for example that a must be of Type Node or Geometry and b respectively of Type BoundingBox, BoundingSphere or Ray.)
MeshCollisionShape […] Limitations: Collisions between two mesh-accurate shapes cannot be detected, only non-mesh shapes can collide with this shape.
But If i’m correctly understanding the wiki page talking about collision shapes, I would be able to find collisions between hull collision shapes (or compound shapes made of many hulls in may case), which is what I’m trying to do.
In fact bullet can do mesh vs mesh dynamic with gimpactshapes, but it is really not useable for games as it is extremly slow (and hence not added to the binding for jme).
Splitting you mesh into a few hullshapes and putting all into a compoundshape is way better.
Static meshes are another thing, they have internal acceleration structures and are pretty fast.
Maybe the second parameter in the HullCollisionShape init?
new HullCollisionShape(mySubGeometry.getMesh()), Vector3f.ZERO);
Maybe the ephemeral physic space?
I’ve checked visually that the spatials where not colliding. But I haven’t found any way to ckeck the ghosts or the collision shapes. Is there a way to create a mesh from a collsion shape to draw it? The physic debug mode seems depreciated and didn’t work.
The physics debug mode is enabled via BulletAppState.setDebugEnabled(), if you never give the physics access to the rendering loop it can obviously not render anything. You could try and use the sweep test to get immediate collision results but you need to actually sweep the testing shape and have the other shape in the physics space as a RigidBody - ghost collisions only work for the axis aligned bounding box (aabb).
What do you actually want to do? I am wondering if simply using bounding box collisions (from jME’s collision system) won’t be enough to e.g. place NPCs or whatever so they don’t slip into each other.
What I am trying to achieve is to place assets on the scene with a procedural engine (more info). I want to enhance the placing by testing collision between candidate asset and already placed ones. So for each candidate, I create two spatials and I want to check the collision between meshes.
Note : the engine has no access to the scene drawing and the assets are managed by jBullet only for this test. After that, assets have a very simple bounding circle to manage collision. So this test must be ephemeral.
Indeed, I’ve been heckled by this point while testing it, but I haven’t found more information. How exactly do you give access to the rendering loop?
I know nothing about the “sweep test”. Is my approach of creating a new local and ephemeral physics space wrong?
Thanks ! Digging into this, I have found the pretty efficient, simple and easy to implement DebugShapeFactory, which can create a mesh from a collision shape.
The hull collision shape seems to be created from the spatial whatever its current transform. In my case, the scale was creating giant shapes that where obviously colliding.
Now I have to understand Why I have so much collisions that are not. @Normen you talked about a limitation to AABB for the Ghost Control but I can’t find precise documentation. Could you tell me more? I will try the sweep test approach with rigid body control tomorrow.
Still stuck to my collision problem. I’ve used a RigidBodyControl and a sweep test and it’s very fine… most of the time !
I have undetected collisions and I can’t understand why. For exemple here (the blue lines ensure that the connected objects were sweep tested) the two shapes are collinding but jBullet doesn’t seem to detect it.
Strange think is that it is perfectly working most of the time, avoiding collisions and placing things closely from each other, as desired. I don’t understand theses cases. Any idea? Thanks in advance.
Here is the code of the collision tester.
public static boolean areColliding(Asset asset1, Asset asset2){
Spatial s1 = getSpatialFromAsset(asset1);
Spatial s2 = getSpatialFromAsset(asset2);
// Transformations for physics don't include the scale, which is set at
// collision shape creation
Transform body1Transform = new Transform();
body1Transform.setRotation(s1.getLocalRotation());
body1Transform.setTranslation(s1.getLocalTranslation());
Transform body2Transform = new Transform();
body2Transform.setRotation(s2.getLocalRotation());
body2Transform.setTranslation(s2.getLocalTranslation());
// We create a physic space and add the body of the first asset
PhysicsSpace space = new PhysicsSpace();
RigidBodyControl body1 = new RigidBodyControl(getCollisionShape(asset1), 0);
s1.addControl(body1);
space.add(body1);
space.update(1);
// We set a sweep test with a body from the second asset.
boolean collision = false;
for(ChildCollisionShape hull : getCollisionShape(asset2).getChildren())
if(!space.sweepTest(hull.shape, Transform.IDENTITY, body2Transform).isEmpty()){
collision = true;
break;
}
space.remove(body1);
if(!collision){
// This is only for drawing and debugging
// spatial 1
Material m = new Material(am, "Common/MatDefs/Misc/Unshaded.j3md");
m.getAdditionalRenderState().setWireframe(true);
m.setColor("Color", ColorRGBA.Green);
Spatial debugS1 = DebugShapeFactory.getDebugShape(getCollisionShape(asset1));
debugS1.setLocalTransform(body1Transform);
debugS1.setMaterial(m);
asset2.links.add(debugS1);
// spatial 2
Material m2 = new Material(am, "Common/MatDefs/Misc/Unshaded.j3md");
m2.getAdditionalRenderState().setWireframe(true);
m2.setColor("Color", ColorRGBA.Red);
Spatial debugS2 = DebugShapeFactory.getDebugShape(getCollisionShape(asset2));
debugS2.setLocalTransform(body2Transform);
debugS2.setMaterial(m2);
asset2.links.add(debugS2);
// link
Material mlink = new Material(am, "Common/MatDefs/Misc/Unshaded.j3md");
mlink.getAdditionalRenderState().setWireframe(true);
mlink.setColor("Color", ColorRGBA.Blue);
Geometry link = new Geometry();
Line l = new Line(debugS1.getLocalTranslation().add(0, 0, 0.5f), debugS2.getLocalTranslation().add(0, 0, 0.5f));
link.setMesh(l);
link.setMaterial(mlink);
asset2.links.add(link);
}
return collision;
}
private static Spatial getSpatialFromAsset(Asset asset){
if (!models.containsKey(asset.modelPath))
models.put(asset.modelPath, am.loadModel("models/" + asset.modelPath));
Spatial res = models.get(asset.modelPath).clone();
res.setLocalScale((float)asset.scale);
res.setLocalTranslation(TranslateUtil.toVector3f(asset.pos));
res.setLocalRotation(new Quaternion().fromAngles(0, 0, (float)asset.yaw));
return res;
}
private static CompoundCollisionShape getCollisionShape(Asset asset){
Spatial s = models.get(asset.modelPath);
CompoundCollisionShape res = new CompoundCollisionShape();
if(s instanceof Node){
for(Spatial child : ((Node)s).getChildren())
if(child instanceof Geometry){
HullCollisionShape hull = new HullCollisionShape(((Geometry)child).getMesh());
hull.setScale(Vector3f.UNIT_XYZ.mult((float)asset.scale));
res.addChildShape(hull, Vector3f.ZERO);
}
} else {
logger.info("Houston, we've got a problem.");
}
return res;
}