[Bug] CapsuleCollisionShape Axis doesn't match the wireframe or collision

Hello JMonkeys:

I’ve found a bug. I previously reported it in the link below but i got closed!

https://github.com/jMonkeyEngine/jmonkeyengine/issues/1266

Anyways,

In this image you can see the camera is close to the ground.


Yet I clearly set the collision shape to vertical (1).

In this image you can see the camera above the door.


Yet I clearly set the collision shape to horizontal(0).

Don’t pay attention to the pink wireframe. Although it displays in the correct orientation, the ingame collision is not the same as the wireframe. In other words, we don’t need to trouble shoot the wireframe, just the actual collision.

You might be saying “You just don’t know how to code mister!”. Well, I just used the code in the tutorial. So you can try it yourself.
https://wiki.jmonkeyengine.org/jme3/beginner/hello_collision.html

For those curious I’m using: jMonkeyEngine SDK v3.2.4-stable-sdk1.

I just ran a simple test with a Kinematic RigidBodyControl from a PlaneCollisionShape, and a CharacterControl with a CapsuleCollisionShape setting the physics location to 10 units above zero, and setting physics debug to true (no meshes)

setting the axis to 1 provided a “vertical” debug capsule wireframe which fell onto the plane until it touched and stopped, standing straight up.

setting the axis to 0 provided a “horizontal” debug capsule wireframe pointing left and right which also fell onto the plane until it touched, and did not roll.

setting the axis to 2 provided a “horziontal” debug capsule wireframe pointing toward the camera which also fell onto the plane until it touched, and did not roll.

This seems to be expected behaviour, but I did not implement any custom input controls. (although I did have to initialize the gravity manually to keep the CharacterControl from flying awkwardly into the negative x direction.)

Are you setting/updating the CharacterControl’s (or the terrain rigid body control’s) physics location manually somewhere each frame?

Edit:
after creating and adding the BulletAppState and setting debug to true, this is the relevant code i used to setup my test:

public void setupCapsuleCollisonShapeTest() {
        // 0 = x axis, 1 = y axis, 2 = z axis
        CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 0); 
        CharacterControl capsule = new CharacterControl(capsuleShape, 0.05f);
        bulletAppState.getPhysicsSpace().add(capsule );
        capsule.setGravity(new Vector3f(0f, -9.81f, 0f)); // reset gravity to -y
        capsule .setPhysicsLocation(new Vector3f(0f, 10f, 0f));

        Plane plane = new Plane(Vector3f.UNIT_Y, 0f);
        PlaneCollisionShape planeShape = new PlaneCollisionShape(plane);
        RigidBodyControl terrain = new RigidBodyControl(planeShape, 0);
        bulletAppState.getPhysicsSpace().add(terrain);
    }

I literally just copy and pasted the ‘hello collision’ example. So I strongly suggest for people to use it. It only takes a minute to get the test going.

I tried that first, but unfortunately I couldnt see the capsule debug wireframe. I guess it is closer to the camera than the near clipping plane would allow to be visible.
Also, that tutorial may need updating.

You have to pull back the camera by adding a vector offset in order to view your own capsule wireframe. Like this:

private Vector3f cameraOffset = new Vector3f(0,0,5);

cam.setLocation(cameraOffset.add(player.getPhysicsLocation().getX(),
                                         player.getPhysicsLocation().getY(),
                                         player.getPhysicsLocation().getZ()));

I’m trying to stick to the tutorial because people come up with too many questions and doubt too many things if you don’t specify a clear source such as a tutorial.

@ decoyhiding Also your height of 6 is too small to see the difference. There is a reason why I put 18 on mine. You won’t notice the capsule clipping through the floor because the debug wireframe overlays over everything. My test was crafted to make the bug obvious. It took sometime. It is hard to make it obvious.

As I said when I closed the bug, I think you are confused about what a vertical and a horizontal capsule are.

Left, vertical capsule… ie: y axis, ie: axis index 1

Right, horizontal capsule, ie: x axis, ie: axis index 0

@pspeed Thanks for the reply.

How come my 0 is so tall in the picture? Yet the 1 is so close to the floor? That’s what I’m trying to point out.

From your picture it is impossible to tell… but it looks like a capsule laying on its side that’s about 3 meters tall and 18 meters long to me.

Back up so we can see it not filling the whole screen, I guess.

No @pspeed. Don’t look at the wireframe. It is displayed correctly as per the values. Yes the wireframe is vertical when I set it to 1 in the picture. BUT the collision remain horizontal.

I’m touching the wall/door on both pictures.

Your picture is not at all clear. In one it looks like the door is halfway through the ground and in the other it looks like the door is fully underground.

In the first picture you are looking at the bottom of the door because you are short. In the second picture you are looking at the top of the door because you are tall. The camera rotation has not changed a bit. And the character is touching the door. That’s not my model. That’s the town.zip example if you wall forward when you load the level.

ok, after trying adjustments on the tutorial I must admit, I do see the behaviour @Pixelapp is describing.

if i set the axis to 0 for horizontal (x), the capsule debug wireframe does hover above the expected point of contact, and setting axis to 1 for vertical (y) seems to make the wireframe sink into the terrain. it is best noticed when offsetting the camera and “walking” along the angled building rooftops

after my isolated test with a plane, i suspect this is related to the implementation of input controls in the tutorial, or maybe an error with the collision shape of the scene in town.zip.

YES YES YES YES. Finally!!!

And look at the git hub picture I posted. You’ll see character correctly standing. Yet the capsule is hovering.

Still, I am not convinced this is a bug with CapsuleCollisionShape. It is mostly a wrapper for bullet’s native class.

But regarding your “bug”, as stated, it’s not true… because literally everyone who ever uses a character control and tons of examples that don’t seem to have no issues at all with CapsuleCollisionShape. It’s probably used by literally everyone who has ever used bullet.

Maybe there is something wrong with the tutorial… but even for me who barely used bullet, capsule has always worked the way I want it.

That’s okay if not a bug. But at least a post of correct use would be ok.

The thing is that is really hard to notice if you don’t make the character big.

I don’t care much to be claiming that is a bug. But if it a bug I just want it written up.

I wonder if it’s specific to character control. I guess internally it’s casting rays or somesuch to do part of it’s job and maybe it doesn’t work well with non-vertical capsules.

My guess is that a regular rigid body would fall/lay as expected.

1 Like

I added input controls to the CharacterControl in my simple test and changed plane to box. The behavior is still as expected, it even stays on top of the box until the very last part moves off the edge, whereas in the tutorial, the horizontal capsule will fall off the building roof as soon as the vertical capsule would have moved off.

I really think something in the tutorial code is causing this unexpected effect.
i checked the libraries and the helloCollision tutorial built from the JmeTests project is using:

jme3-bullet - jme3-bullet-3.2.2-stable.jar
jme3-bullet-native - jme3-bullet-native-3.2.2-stable.jar

@Pixelapp here is my “quick and dirty” test case showing expected behavior in an environment isolated from the HelloCollision tutorial, if you want to verify.

  • movement keys: i, j, k, l to not conflict with flyCam controls

Edit: disclaimer - no best practices here.

import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.CharacterControl;
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.renderer.RenderManager;

public class CapsuleCollisionShapeTest extends SimpleApplication implements ActionListener {
    public BulletAppState bulletAppState;
    private boolean left, right, up, down;
    private CharacterControl capsule;
    private Vector3f walkDirection;
    
    
    public static void main(String[] args) {        
        CapsuleCollisionShapeTest app = new CapsuleCollisionShapeTest();
        app.start();
    }

    @Override
    public void simpleInitApp() {  
        
        this.flyCam.setMoveSpeed(20f);
        bulletAppState = new BulletAppState();
        stateManager.attach(bulletAppState);
        bulletAppState.setDebugEnabled(true);
        
        setupCapsuleCollisonShapeTest();
        
        walkDirection = new Vector3f();
        setUpKeys();
        
    }
    
    public void setupCapsuleCollisonShapeTest() {
        CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 0);
        capsule = new CharacterControl(capsuleShape, 0.05f);
        bulletAppState.getPhysicsSpace().add(capsule );
        capsule.setGravity(new Vector3f(0f, -9.81f, 0f));
        capsule .setPhysicsLocation(new Vector3f(0f, 10f, 0f));
        
        BoxCollisionShape boxShape = new BoxCollisionShape(new Vector3f(6f, 1f, 6f));
        RigidBodyControl terrain = new RigidBodyControl(boxShape, 0);
        bulletAppState.getPhysicsSpace().add(terrain);
    }

    private void setUpKeys() {
        inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_J));
        inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_L));
        inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_I));
        inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_K));
        inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
        inputManager.addListener(this, "Left");
        inputManager.addListener(this, "Right");
        inputManager.addListener(this, "Up");
        inputManager.addListener(this, "Down");
        inputManager.addListener(this, "Jump");
      }

  public void onAction(String binding, boolean value, float tpf) {
    if (binding.equals("Left")) {
      if (value) { left = true; } else { left = false; }
    } else if (binding.equals("Right")) {
      if (value) { right = true; } else { right = false; }
    } else if (binding.equals("Up")) {
      if (value) { up = true; } else { up = false; }
    } else if (binding.equals("Down")) {
      if (value) { down = true; } else { down = false; }
    } else if (binding.equals("Jump")) {
      capsule.jump(new Vector3f(0f, 10f, 0f));
    }
  }
    @Override
    public void simpleUpdate(float tpf) {
        walkDirection.set(0, 0, 0);
        if (left) {
            walkDirection.subtractLocal(Vector3f.UNIT_X);
        }
        if (right) {
            walkDirection.addLocal(Vector3f.UNIT_X);
        }
        if (up) {
            walkDirection.subtractLocal(Vector3f.UNIT_Z);
        }
        if (down) {
            walkDirection.addLocal(Vector3f.UNIT_Z);
        }
        capsule.setWalkDirection(walkDirection);
    
    }

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }
        
}

Although, I’m still not sure why I have to re-initialize the gravity on the CharacterControl to keep it from falling in the x axis. :crazy_face:

Your code works. I don’t know what you did differently. Can you expand on what you did differently?