Below is a small code showing the problem.
I used the TestCDD example and modified it a little bit to include collision groups.
As a refresher, from the source documentation (setCollisionGroup):
Groups are represented by integer bit masks with exactly 1 bit set.
Pre-made variables are available in PhysicsCollisionObject. By default, physics objects are in COLLISION_GROUP_01.
Two objects can collide only if one of them has the collisionGroup of the other in its collideWithGroups set.
In my example there is:
- a wall and a ground that are in group 1 and collide with objects of group 2
- a ball (made by makeBallCCD1): no collision group specified, so ball is in group 1 and collide with group 1
- another ball (made by makeBallCCD2): collision group is 3, and collide with group 4 (nothing in that group)
- both ball use CCD
what i would expect:
- wall/ground should not collide with any ball (ball1 and ball2 are not in collision group 2)
- ball1 should collide with wall/ground (wall/ground are in collision group 1) (how does it work ? which is taken into account ?)
- ball2 should definitely not collide with wall/ground (nor with ball1)
What i see:
- ball2 collide with wall/ground but do not roll as ball1 does …
- if you shoot a ball1 so that the ball hit the wall straight ahead and without much velocity you can throw a ball2 at the first ball1 and the ball2 will collide with ball1 …
- after 2 or 3 rebound, ball2 will go trough the ground as if it remembered it was not supposed to collide !
- ball1 collide happily with ground and wall (as intended ?)
i used jme3-bullet-3.3.0-beta1, with 3.2.4-stable,ball2 will get through wall/ground most of the time, but at some angle there will still be some collision but with the wrong normal (which is abnormal ), also ball2 will still collide with ball1.
(i also opened an issue on github)
FILE TestCCD.java:
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.scene.Geometry;
public class TestCCD extends SimpleApplication implements ActionListener {
BulletAppState bas;
@Override
public void simpleInitApp() {
bas = new BulletAppState();
bas.setDebugEnabled(true);
Tools.initGlobals(rootNode, bas, assetManager, getCamera());
stateManager.attach(bas);
Tools.makeWall();
Tools.makeGround();
flyCam.setEnabled(true);
flyCam.setMoveSpeed(40f);
inputManager.addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addMapping("shoot2", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
inputManager.addListener(this, "shoot");
inputManager.addListener(this, "shoot2");
}
@Override
public void onAction(String binding, boolean value, float tpf) {
if (binding.equals("shoot") && !value) {
Tools.makeBallCCD1();
} else if (binding.equals("shoot2") && !value) {
Tools.makeBallCCD2();
}
}
public static void main(String[] args) {
TestCCD app = new TestCCD();
app.start();
}
}
File: Tools.java
import com.jme3.asset.AssetManager;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.PhysicsCollisionObject;
import com.jme3.bullet.collision.shapes.MeshCollisionShape;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
public class Tools {
static Node rootNode;
static BulletAppState bullet;
static AssetManager am;
static Sphere ball;
static SphereCollisionShape ballCS;
static Camera cam;
static void initGlobals(Node root, BulletAppState bas, AssetManager am, Camera camera) {
rootNode = root;
bullet = bas;
Tools.am = am;
cam = camera;
ball = new Sphere(32, 32, 0.4f, true, false);
ball.setTextureMode(Sphere.TextureMode.Projected);
ballCS = new SphereCollisionShape(0.5f);
}
static Node createCollisionBox(String name, Vector3f position, Vector3f extend) {
Node box = new Node();
box.setLocalTranslation(position);
RigidBodyControl boxRBC = new RigidBodyControl(new MeshCollisionShape(new Box(extend.x, extend.y, extend.z)), 0f);
boxRBC.setCollisionGroup(PhysicsCollisionObject.COLLISION_GROUP_01);
boxRBC.setCollideWithGroups(PhysicsCollisionObject.COLLISION_GROUP_02);
box.addControl(boxRBC);
rootNode.attachChild(box);
bullet.getPhysicsSpace().add(box);
return box;
}
static Node makeWall() {
return createCollisionBox("Wall", new Vector3f(2.5f, 0f, 0f), new Vector3f(4f, 5f, 0.0f));
}
static Node makeGround() {
return createCollisionBox("Ground", new Vector3f(0f, -6f, 0f), new Vector3f(100f, 1f, 100f));
}
static void makeBallCCD1() {
Geometry ballGeom = new Geometry("ball1", ball);
Material mat = new Material(am, "Common/MatDefs/Misc/Unshaded.j3md");
mat.getAdditionalRenderState().setWireframe(true);
mat.setColor("Color", ColorRGBA.Green);
ballGeom.setMaterial(mat);
ballGeom.setName("ball1");
ballGeom.setLocalTranslation(cam.getLocation());
ballGeom.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
ballGeom.addControl(new RigidBodyControl(ballCS, 1));
ballGeom.getControl(RigidBodyControl.class).setCcdMotionThreshold(0.01f);
ballGeom.getControl(RigidBodyControl.class).setLinearVelocity(cam.getDirection().mult(40));
rootNode.attachChild(ballGeom);
bullet.getPhysicsSpace().add(ballGeom);
}
static void makeBallCCD2() {
Geometry ballGeom = new Geometry("ball2", ball);
Material mat2 = new Material(am, "Common/MatDefs/Misc/Unshaded.j3md");
mat2.getAdditionalRenderState().setWireframe(true);
mat2.setColor("Color", ColorRGBA.Red);
ballGeom.setMaterial(mat2);
ballGeom.setName("ball2");
ballGeom.setLocalTranslation(cam.getLocation());
ballGeom.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
RigidBodyControl rbc = new RigidBodyControl(ballCS, 1);
rbc.setCollisionGroup(PhysicsCollisionObject.COLLISION_GROUP_03);
rbc.setCollideWithGroups(PhysicsCollisionObject.COLLISION_GROUP_04);
ballGeom.addControl(rbc);
ballGeom.getControl(RigidBodyControl.class).setCcdMotionThreshold(0.01f);
ballGeom.getControl(RigidBodyControl.class).setLinearVelocity(cam.getDirection().mult(40));
rootNode.attachChild(ballGeom);
bullet.getPhysicsSpace().add(ballGeom);
}
}