Collision groups, why the 1st collision is unavoidable? (Ccd incompatibility)

or there is some problem here?

the cube should be moving smoothly, but it collides once with each floor:

import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.BulletAppState.ThreadingType;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.PhysicsTickListener;
import com.jme3.bullet.collision.PhysicsCollisionGroupListener;
import com.jme3.bullet.collision.PhysicsCollisionObject;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.objects.PhysicsRigidBody;
import com.jme3.math.Vector3f;

public class TestSkipGroupCollide extends SimpleApplication implements PhysicsTickListener, PhysicsCollisionGroupListener {
	public static void main(String[] args) {
		TestSkipGroupCollide test = new TestSkipGroupCollide();
		test.start();
	}

	private BulletAppState	bullet;
	private PhysicsSpace	ps;
	private long	lWait;
	private RigidBodyControl	rbcLast;
	private BoxCollisionShape	csProjectile;

	@Override
	public void simpleInitApp() {
		bullet = new BulletAppState();
		bullet.setThreadingType(ThreadingType.PARALLEL);
		getStateManager().attach(bullet);
		ps = bullet.getPhysicsSpace();
		
		bullet.setDebugEnabled(true);
		ps.addTickListener(this);
		
		ps.addCollisionGroupListener(this,PhysicsCollisionObject.COLLISION_GROUP_01);
		
		getCamera().setLocation(new Vector3f(0,0,20));
		
		for(int i=0;i<5;i++)
		{
		BoxCollisionShape csfloor = new BoxCollisionShape(new Vector3f(5,0.05f,5));
		RigidBodyControl rbc = new RigidBodyControl(csfloor);
		rbc.setPhysicsLocation(new Vector3f(0,2-i,0));
		rbc.setMass(0f);
		ps.add(rbc);
		}
		
		csProjectile = new BoxCollisionShape(new Vector3f(0.05f,0.05f,0.05f));
		
		RigidBodyControl rbc = new RigidBodyControl(csProjectile);
		rbc.setPhysicsLocation(new Vector3f(0,10,0));
		rbc.setMass(1f);
		rbc.setCcdMotionThreshold(0.05f);
		rbc.setCcdSweptSphereRadius(0.05f);
		ps.add(rbc);
		
		rbcLast=rbc;
		
		lWait=System.currentTimeMillis();

	}
	
	@Override
	public void simpleUpdate(float tpf) {
		super.simpleUpdate(tpf);
		getFlyByCamera().setEnabled(true);
		org.lwjgl.input.Mouse.setGrabbed(true);//getInputManager().setCursorVisible(false);
		getFlyByCamera().setMoveSpeed(10f);
	}

	@Override
	public void prePhysicsTick(PhysicsSpace space, float tpf) {
	}

	@Override
	public void physicsTick(PhysicsSpace space, float tpf) {
		for(PhysicsRigidBody r:space.getRigidBodyList()){
			if(r.getMass()>0){
				if(r.getPhysicsLocation().y < -3){
					r.setGravity(new Vector3f(0,10,0));
				}else 
				if(r.getPhysicsLocation().y > 3){
					r.setGravity(new Vector3f(0,-10,0));
				}
			}
		}
	}

	@Override
	public boolean collide(PhysicsCollisionObject nodeA,PhysicsCollisionObject nodeB) {
		System.out.println(System.currentTimeMillis()+","+((PhysicsRigidBody)nodeA).getLinearVelocity()+","+((PhysicsRigidBody)nodeB).getLinearVelocity());
		return false; //why the 1st group collide cant be skipped/ignored?
	}
}

ps.: for this test, the gravity is alternated when it is below to hit upwards and back again endless

1 Like

setCcdMotionThreshold();
setCcdSweptSphereRadius();

You yourself asked this behavior.

2 Likes

yep! worked! thx!

so group collision and Ccd are incompatible behaviors or is there some workaround so that we could use both?

I just thought on stretching the collision shape on the fast flying direction, so it would work like a Ccd workaround, while I still would be able to use the collision groups, have to try it… I think basically the stretch would be as big as the speed, and… this sounds quite messy, I expect it works tho. it wont work with unscalable spheres collision shapes tho :(, mmm may be a stretched cube replacing the real shape until it is moving slow may do the trick.

1 Like

Looks like bullet doesn’t use the group callback for CCD, dunno if that has a reason or not… Maybe you can achieve what you want with collideWith groups? Could be they get processed by CCD.

3 Likes

It seems to me that it’s just a hack, to reset the speed and get more frames for calculations.

2 Likes

I tried to put both the floors and the cube as

rbc.setCollisionGroup(PhysicsCollisionObject.COLLISION_GROUP_02);
rbc.addCollideWithGroup(PhysicsCollisionObject.COLLISION_GROUP_02);

but nothing changed, was that what you meant?

btw, I wonder if that could be a native bullet option that could be re-enabled (as it seems a missing feature that breaks collision groups usability). Or if we could patch it to work properly, that would be interesting too, even if the physics simulation become slower, may be it could be enabled not for all rigid bodies, but just for a selected few, to not compromise much bullet ticks per second.

1 Like

I did not understand, you need a collision?

1 Like

btw, whenever a collision of a high speed object is about to happen here, I do a rayTest (only from its center) because the collide order is not correct (the 1st is not necessarily the one just in front), and all the “single collisions” here are really precise because of that, so, Ccd became unnecessary for this specific usage as such objects are destroyed after the 1st collision, other than that I guess Ccd would be good if it worked with groups.

1 Like

well, I am still trying to let the force of the impact be applied, and still destroy the projectile just after.
right now, such force is not being applied.

that initial test was just to understand what was happening, the real thing is quite different tho :slight_smile:

1 Like

As far as I understand, groups, just to count the clashes for different groups. But not unified into one group of objects.

1 Like

the only way I found to prevent specific collisions was using the collision group listener.
I currently have only one collision group btw.

also, it is working now.
I disabled Ccd to let groups work.
rayTest at collision group check to determine if the next hit is valid.
if the hit is valid, I re-enable Ccd and then the impact impuse is applied, while I can also use the collision groups!

could that be the way they intended it to be used?

1 Like

Perhaps this only works after the actual collision, it gives such an effect. And the very shutdown of Ccd, gives a slip. But the way out of the wall, collision stop. And you get a false message.

You need something to generate events, not collisions.

1 Like

I tried something else. And it works.

package test;

import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.BulletAppState.ThreadingType;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.PhysicsCollisionGroupListener;
import com.jme3.bullet.collision.PhysicsCollisionObject;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.objects.PhysicsGhostObject;
import com.jme3.bullet.objects.PhysicsRigidBody;
import com.jme3.math.Vector3f;

public class Main extends SimpleApplication implements PhysicsCollisionGroupListener {
	public static void main(String[] args) {
		Main test = new Main();
		test.start();
	}

	private BulletAppState bullet;
	private PhysicsSpace ps;
	private BoxCollisionShape csProjectile;
	private RigidBodyControl rbc;

	@Override
	public void simpleInitApp() {

		getCamera().setLocation(new Vector3f(0, 0, 20));
		getFlyByCamera().setEnabled(true);
		getFlyByCamera().setMoveSpeed(10f);

		bullet = new BulletAppState();
		bullet.setThreadingType(ThreadingType.PARALLEL);
		bullet.setDebugEnabled(true);

		getStateManager().attach(bullet);

		ps = bullet.getPhysicsSpace();
		ps.addCollisionGroupListener(this, PhysicsCollisionObject.COLLISION_GROUP_01);

		for (int i = 0; i < 5; i++) {
			PhysicsGhostObject csfloor = new PhysicsGhostObject(new BoxCollisionShape(new Vector3f(5, 0.06f, 5)));
			csfloor.setPhysicsLocation(new Vector3f(0, 2 - i, 0));
			ps.add(csfloor);
		}

		csProjectile = new BoxCollisionShape(new Vector3f(0.05f, 0.05f, 0.05f));

		rbc = new RigidBodyControl(csProjectile);
		rbc.setPhysicsLocation(new Vector3f(0, 10, 0));
		rbc.setCcdMotionThreshold(0.05f);
		rbc.setCcdSweptSphereRadius(0.05f);
		rbc.setMass(1f);
		ps.add(rbc);

	}

	@Override
	public boolean collide(PhysicsCollisionObject nodeA, PhysicsCollisionObject nodeB) {

		System.out.println(System.currentTimeMillis() + "," + ((PhysicsRigidBody) nodeB).getLinearVelocity());

		return false;
	}

	@Override
	public void simpleUpdate(float tpf) {
		if (rbc.getPhysicsLocation().y < -3) {
			rbc.setGravity(new Vector3f(0, 10, 0));
		} else if (rbc.getPhysicsLocation().y > 3) {
			rbc.setGravity(new Vector3f(0, -10, 0));
		}
	}
}
2 Likes

as I understand, the collision() (that could be collisionEvent()) events that is run in the main thread is a result of collide(){return true;} (that should be something like atPhysicsThreadCheckIfGroupCollides() for clarity)

in my real project I actually need the collision happening most of the times, applying forces and generating events. so I need such collisions to not happen other specific times.

interesting, PhysicsGhostObject is for collision detection w/o interaction (w/o applying any forces derived from collisions) right?

in this case, I would need other objects to stay resting on the floors, while the small cube would sometimes collide, other times not. I think the ghost cant be used alone then, but may be it could be used together with a bigger scale for other helpful things, thx :slight_smile:

1 Like

Well, then a dilemma arises: the use of a CCD implies a ban on entering an object. Simplified geometry for the CCD is not reported on other behaviors. Therefore, it collides and disappears, then the cube only passes. It seems to me that I figuratively understood what is happening. Then the use of the ray is the right choice.

2 Likes

I just would like to add that my solution is not perfect even to a “first hit only” situation. As Ccd is required to apply precise impulses from fast moving objects and groups are ignored by it, whenever I turn on Ccd, it does its mess by hitting what it shouldnt (by its nearby boundings).

may be the only solution is to apply the force manually on the thing that would be hit,
and redirect the projectile movement manually too, using the hit spot/normal and spending the impulse energy in some way,
basically doing what bullet should be doing but manually,

am I right?

1 Like

Perhaps you should try to report a bug to the developers. Because, most likely, they forgot about the behavior of Ccd when using groups.

3 Likes

http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=11744

EDIT: I think we need to prepare a native bullet test for that forum for the ppl there be able to test case the issue :confused:

1 Like

I was trying to understand exactly what bullet we use
jmonkeyengine/jme3-bullet-native/src/native/cpp at master · jMonkeyEngine/jmonkeyengine · GitHub
if I am not wrong, it is an exclusive port/fork to java/jmonkey right?

I dont remember why I had to giveup on JBullet and use Native Bullet, but was something quite problematic so I had no choice other than make the move.

the jme3 native bullet port (right?) works really well btw, and it seems a great effort was put on it, thx!

but I still wonder in what bullet version it is based?
I found there is quite new bullet version around
Releases · bulletphysics/bullet3 · GitHub

I wonder if Ccd VS collisionGroups (1st hit) works with the latest bullet there?
my post at their forum makes no sense unless I use the latest release of them, but I am not sure if we can wrap it back to JMonkeyEngine, therefore learning how to and preparing the test case there would be more out of curiosity than practical use (to me at least), as it may simply work there after all…

Much better would be to spend time trying to improve jme3 bullet’s fork (right?) I guess.

I tried browsing jme’s bullet native code for Ccd and found this:

but I am having a hard time trying to understand it, I abbandoned C and C++ 15-20 years ago xD

can anyone hint on it?

I also tried to find the Makefile to compile it on linux, unless it is graddle (which I still need to learn how to use).

[details=EDIT: more stuff at bullet3]
bullet3/btCollisionWorld.cpp at master · bulletphysics/bullet3 · GitHub
bullet3/btCollisionWorld.h at master · bulletphysics/bullet3 · GitHub

EDIT: I thought, if we could add a call, in the native jme’s bullet during the sweepTest, to see if the collision will be allowed or not (the same way we use collide() for groups), we would have a chance to do anything at that method in java, even test to see if the group collision is allowed, so that group stuff would not be required to be coded in the native bullet. I am trying to understand where it could be put there at the sweepTest, but the ‘struct’ cpp thing is quite confusing…

1 Like

Repeated this code on Panda3D, same problem :frowning:

3 Likes