After taking a bit of a break, I decided to try and fix this annoying problem. Like written in my previous post, I tried using the functions in btInternalEdgeUtility in order to fix the internal edge collisions, but with little to no success. What I’ve done currently is the following: when creating a mesh collision shape, generate the internal edge info using
btTriangleInfoMap* triangleInfoMap = new btTriangleInfoMap();
btGenerateInternalEdgeInfo(shape, triangleInfoMap);
When creating a rigid body, set the custom material callback collision flag
if (shape->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE) {
body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
}
Set the following callback as the contact added callback (mostly taken from bullet’s InternalEdgeDemo)
gContactAddedCallback = customMaterialCombinerCallback;
...
bool customMaterialCombinerCallback(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper* colObj1Wrap, int partId1, int index1) {
// Find the triangle mesh object and the other object
const btCollisionObjectWrapper *trimesh = colObj0Wrap, *other = colObj1Wrap;
int trimesh_pid = partId0, other_pid = partId1;
int trimesh_id = index0, other_id = index1;
// Make sure we're giving btAdjustInternalEdgeContacts the right arguments
if ( colObj1Wrap->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE ) {
trimesh = colObj1Wrap;
trimesh_pid = partId1;
trimesh_id = index1;
other = colObj0Wrap;
other_pid = partId0;
other_id = index0;
}
btAdjustInternalEdgeContacts(cp, trimesh, other, trimesh_pid, trimesh_id);
float friction0 = other->getCollisionObject()->getFriction();
float friction1 = trimesh->getCollisionObject()->getFriction();
float restitution0 = other->getCollisionObject()->getRestitution();
float restitution1 = trimesh->getCollisionObject()->getRestitution();
if (other->getCollisionObject()->getCollisionFlags() & btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK) {
friction0 = 1.0; //partId0,index0
restitution0 = 0.f;
}
if (trimesh->getCollisionObject()->getCollisionFlags() & btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK) {
if (trimesh_pid & 1) {
friction1 = 1.0f; //partId1,index1
} else {
friction1 = 0.f;
}
restitution1 = 0.f;
}
cp.m_combinedFriction = calculateCombinedFriction(friction0, friction1);
cp.m_combinedRestitution = calculateCombinedRestitution(restitution0, restitution1);
return true;
}
Here is the test case I am using that demonstrates the problem.
package test;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.MeshCollisionShape;
import com.jme3.bullet.control.BetterCharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.math.Vector3f;
import com.jme3.scene.shape.Box;
import com.jme3.terrain.geomipmap.TerrainQuad;
public class CharacterControlTest extends SimpleApplication implements ActionListener{
private BetterCharacterControl characterControl;
public static void main(String[] args){
new CharacterControlTest().start();
}
@Override
public void simpleInitApp(){
characterControl = new BetterCharacterControl(0.1f, 1, 50);
cam.setLocation(new Vector3f(0, 1, 10));
flyCam.setEnabled(false);
BulletAppState bulletAppState = new BulletAppState();
//bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
getStateManager().attach(bulletAppState);
bulletAppState.setDebugEnabled(true);
bulletAppState.getPhysicsSpace().add(characterControl);
RigidBodyControl floorPhysics = new RigidBodyControl(new MeshCollisionShape(new Box(Vector3f.ZERO, 100f, 0.2f, 100f)), 0);
floorPhysics.setPhysicsLocation(new Vector3f(0f, 0, 0f));
floorPhysics.setKinematic(false);
//bulletAppState.getPhysicsSpace().add(floorPhysics);
TerrainQuad terrain = new TerrainQuad("terrain", 32, 129, null);
RigidBodyControl terrainPhysics = new RigidBodyControl(0);
terrain.addControl(terrainPhysics);
// terrainPhysics = new RigidBodyControl(new MeshCollisionShape(DebugShapeFactory.getDebugMesh(terrainPhysics.getCollisionShape())), 0);
// terrain.removeControl(RigidBodyControl.class);
// terrain.addControl(terrainPhysics);
bulletAppState.getPhysicsSpace().add(terrainPhysics);
inputManager.addMapping("Forward", new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping("Backward", new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
inputManager.addListener(this, "Forward", "Backward", "Left", "Right", "Jump");
}
@Override
public void onAction(String name, boolean isPressed, float f){
Vector3f movementDirection = characterControl.getWalkDirection();
if(name.equals("Forward")){
if(isPressed)
movementDirection.addLocal(Vector3f.UNIT_Z.negate().normalize().multLocal(5));
else
movementDirection.subtractLocal(Vector3f.UNIT_Z.negate().normalize().multLocal(5));
}
if(name.equals("Backward")){
if(isPressed)
movementDirection.addLocal(Vector3f.UNIT_Z.normalize().multLocal(5));
else
movementDirection.subtractLocal(Vector3f.UNIT_Z.normalize().multLocal(5));
}
if(name.equals("Left")){
if(isPressed)
movementDirection.addLocal(Vector3f.UNIT_X.negate().normalize().multLocal(5));
else
movementDirection.subtractLocal(Vector3f.UNIT_X.negate().normalize().multLocal(5));
}
if(name.equals("Right")){
if(isPressed)
movementDirection.addLocal(Vector3f.UNIT_X.normalize().multLocal(5));
else
movementDirection.subtractLocal(Vector3f.UNIT_X.normalize().multLocal(5));
}
}
}
By moving using WASD, you can see the character control bouncing off the internal edges of the floor, which is a flat terrain. If instead of using the terrain you use a simple box collision shape for the floor and you aim for the one internal edge, the character gets a slight jump (more noticeable sometimes then others) almost as if like the edge was a ramp.
Some bullet forum discussions that I’ve found regarding the issue:
http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=6662&p=24566&hilit=internal+edge#p24566
https://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=7794
http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=7539&view=next
http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=10946
http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=4603&hilit=btAdjustInternalEdgeContacts
Most discussions I’ve found describe the exact issue and say that using the utility fixes the problem. However I’ve also seen some posts where some people had problems integrating it. At this point I’m just wondering what the best approach is to try and fix this issue.