So I have spent a long time trying to work on a collision detection system from scratch for own game engine and came up fruitless due to lack of time. Finally I decided to try to use Jbullet to try to make things quicker. Now the documentation is basically useless, and I am having somewhat of a difficulty trying to transfer over the bullet code to java (or what I transfer over is not working). I have been ripping out my hair trying to search through the library code, but then time-saving that I was hoping for has almost been useless. So, I am going to explain what I am doing, maybe you guys can help me out. I am only looking for simple collision detection, like you hit something then just print a line for now. The rest I can probably work out on my own.
So I create my world:
BroadphaseInterface broadphase = new DbvtBroadphase();
CollisionConfiguration collisionConfig = new DefaultCollisionConfiguration();
Dispatcher dispatcher = new CollisionDispatcher(collisionConfig);
ConstraintSolver solver = new SequentialImpulseConstraintSolver();
DynamicsWorld dynamicsWorld = new DiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfig);
return dynamicsWorld;
So I have my entity Class and in there I have another class that stores all the info for the physics object attached to that entity. This allows me to simply do: entity.getPhysics().getCollisionObject()/.setPosition() etc...
Then I create my CollisionObject in that class:
List<org.lwjgl.util.vector.Vector3f> mesh = model.getModel().getVertices();
ObjectArrayList<javax.vecmath.Vector3f> vertices = new ObjectArrayList<javax.vecmath.Vector3f>();
for(org.lwjgl.util.vector.Vector3f vertex:mesh){
javax.vecmath.Vector3f v = new javax.vecmath.Vector3f(vertex.x, vertex.y, vertex.z);
vertices.add(v);
}
ConvexHullShape shape = new ConvexHullShape(vertices);
ShapeHull hull = new ShapeHull(shape);
hull.buildHull(shape.getMargin());
ConvexHullShape newShape = new ConvexHullShape(hull.getVertexPointer());
CollisionObject result = newShape;
I believe this converts already made mesh, which I use to render my entity, from Vector3f of the LWJGL library, and Jbullets Vector3f. Then it creates a ConvexHullShape out of those vertices in the mesh, and I believe that the:
hull.buildHull(shape.getMargin());
is supposed to kind of simplify the mesh (from the documentation). Then I just create the Collision Object. Pretty simple, I think...
I create my rigidbody (although I am not sure I need a rigid body or just a collision Object, and If someone could let me know if this is true, that would be great):
//mass = 0, so that there is not any gravity application?
float mass = 0;
Transform transform = new Transform(new Matrix4f(new Quat4f(rotation.x, rotation.y, rotation.z, 1), position, scale));
this.transform = transform;
MotionState state = new DefaultMotionState(transform);
RigidBodyConstructionInfo info = new RigidBodyConstructionInfo(mass, state, shape);
RigidBody body = new RigidBody(info);
Then I go through my game loop:
dynamicsWorld.stepSimulation(DisplayManager.getFrameTimeSeconds(), 7);
dynamicsWorld.performDiscreteCollisionDetection();
dynamicsWorld.setInternalTickCallback(new InternalTickCallback(){
@Override
public void internalTick(DynamicsWorld world, float delta) {
Dispatcher dispatcher = world.getDispatcher();
int manifoldCount = dispatcher.getNumManifolds();
for(int i = 0; i < manifoldCount; i ++){
PersistentManifold manifold = dispatcher.getManifoldByIndexInternal(i);
RigidBody object1 = (RigidBody)manifold.getBody0();
RigidBody object2 = (RigidBody)manifold.getBody1();
CollisionObject physicsObject1 = (CollisionObject)object1.getUserPointer();
CollisionObject physicsObject2 = (CollisionObject)object2.getUserPointer();
boolean contact = false;
javax.vecmath.Vector3f normal = null;
for (int j = 0; j < manifold.getNumContacts(); j++) {
ManifoldPoint contactPoint = manifold.getContactPoint(j);
if (contactPoint.getDistance() < 0.0f) {
contact = true;
normal = contactPoint.normalWorldOnB;
break;
}
}
if (contact) {
System.out.println("hit");
}
}
}
}, null);
I got this from someone... I forgot where though. So, basically nothing is happening... I am not sure but maybe I have to add the objects to the manifold, or something like that. Don't know how to do so. Any help?
EDIT: What I have done now is create the Collision Shape just as a random sized box:
CollisionShape result = new BoxShape(new Vector3f(10,10,10));
Then I create The ghost Body:
Transform transform = new Transform(new Matrix4f(new Quat4f(rotation.x, rotation.y, rotation.z, 1), position, scale));
this.transform = transform;
transform.origin.set(position);
GhostObject body = new GhostObject();
body.setCollisionShape(shape);
body.setWorldTransform(transform);
then I just do as you said, It still does not return "hit";
int overlaps = player.getPhysics().getBody().getNumOverlappingObjects();
for(int i = 0; i < overlaps; i++){
//player.getPhysics().getBody().getOverlappingObject(i).
System.out.println("hit");
}
EDIT 2:
So I create the object as like this in my entity class:
if(collision){
physics = new PhysicsEntity(dynamicsWorld, model,new javax.vecmath.Vector3f(position.x, position.y, position.z), new javax.vecmath.Vector3f(rotX, rotY, rotZ), scale);
physics.updatePosition(new javax.vecmath.Vector3f(position.x, position.y, position.z));
physics.updateRotation(new javax.vecmath.Vector3f(rotX, rotY, rotZ));
}
and to update position and stuff:
public void increasePosition(float dx,float dy, float dz){
this.position.x += dx;
this.position.y += dy;
this.position.z += dz;
physics.updatePosition(new javax.vecmath.Vector3f(position.x, position.y, position.z));
}
public void increaseRotation(float dx, float dy, float dz){
this.rotX += dx;
this.rotY += dy;
this.rotZ += dz;
physics.updateRotation(new javax.vecmath.Vector3f(rotX, rotY, rotZ));
}
Okay so this is my PhysicsEntity class, where I set it up:
public PhysicsEntity(DynamicsWorld world, TexturedModel model, Vector3f position, Vector3f rotation, float scale){
this.model = model;
this.position = position;
this.rotation = rotation;
this.scale = scale;
shape = createShape();
body = createBody();
object = new CollisionObject();
object.setCollisionShape(shape);
world.addCollisionObject(body);
}
private GhostObject createBody(){
Transform transform = new Transform(new Matrix4f(new Quat4f(rotation.x, rotation.y, rotation.z, 1), position, scale));
this.transform = transform;
transform.origin.set(position);
GhostObject body = new GhostObject();
body.setCollisionShape(shape);
body.setWorldTransform(transform);
return body;
}
private CollisionShape createShape(){
CollisionShape result = new BoxShape(new Vector3f(10,10,10));
return result;
}
public void updatePosition(Vector3f position){
transform.origin.set(position);
body.setWorldTransform(transform);
}
public void updateRotation(Vector3f rotation){
transform.basis.set(new Quat4f(rotation.x, rotation.y, rotation.z, 1));
body.setWorldTransform(transform);
}
Thanks,
My experience with Bullet is limited to C++ but maybe I will be able to help. What do you mean by saying that nothing happens? Is the object affected by gravity correctly but no collision callback is called or the problem is that it doesn't move at all? It obviously won't move because its mass is 0 so it is static. An object with mass 0 can also be kinematic if you call
body.setCollisionFlags(body .getCollisionFlags() | CollisionFlags.KINEMATIC_OBJECT);
body.setActivationState(CollisionObject.DISABLE_DEACTIVATION);
Both static and kinematic objects detect collisions but only with dynamic objects (mass greater than 0). I suggest using a simple collision shape to begin with, such as a sphere. This way you can verify if the simulation works at all. Convex hulls can be tricky. Start with something simple to produce a working example. Now about the collision detection method. When you call dynamicsWorld.stepSimulation
all forces are applied and the collision detection and resolution happens. So right after that you can iterate through PersistentManifolds
just like you do to check which objects collided with each other in this simulation step. Now I'm not sure but when you call dynamicsWorld.performDiscreteCollisionDetection();
it is quite possible that there are no collisions detected because they were all just solved.
In almost all standard cases you want to use RigidBody
. Exceptions are soft bodies like clothes and ghost objects that can be used to detect collisions without any reactions.
EDIT.
In a situation when no collision is needed, only a hit detection, you don't want a RigidBody
. It can be either static, dynamic or kinematic, neither of which is your case. Instead you want to use a GhostObject
. It just detects collisions but doesn't react. You can easily check if it overlaps with something by first calling its getNumOverlappingObjects()
and then getOverlappingObject(int index)
.
EDIT2.
It looks like you create the object correctly. Assuming that transformations are correct and object really should overlap what you might be missing is dynamicsWorld.addCollisionObject(body);
I missed that at the first glimpse but it looks like you only create the object but don't add it to the world so Bullet engine is not aware of its existence.
EDIT3.
Ok, so a few more suggestions just to make sure that collision should be detected. How many physics objects (ghosts or rigid bodies) have you created and added to the world (using dynamicsWorld.add...
)? If there is only one, obviously no collision can be detected. Bullet won't collide physics object with the scene geometry, but only with another physics object. Could you post your code, where you are creating and moving those objects?
EDITn.
So you've posted the functions creating PhysicsEntity but still I have no idea how many entities do you create and with what parameters. It is neccessary to check what are their world coordinates and verify if they really should collide.
Your usage of Quaternion is a little bit disturbing. You probably pass the arguments x,y,z as the rotation in x,y,z-axis respectively. That's not how it works. I would advise to use the other constuctor, which takes rotation axis and angle as parameters.
Because the code and the problem is very complex and I can't see the direct reason in the code you've posted, I would advise to use a debugger and step through the code to see if all object are initialized correctly, their positions are as expected and finally step into the collision code to see, why it doesn't happen.