Scaling a capsule shape

I’m seeing some puzzling behavior when I scale a CapsuleCollisionShape, and I hope someone can help me figure out what’s going on. Here’s my test program:

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.app.state.ScreenshotAppState;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Sphere;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Main extends SimpleApplication {

    // scaling factors for geometry and physics
    float geoScale = 1f;
    float phyScale = 1f;

    public static void main(String[] args) {
        Logger.getLogger("").setLevel(Level.WARNING);
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        ScreenshotAppState screenShotState = new ScreenshotAppState();
        stateManager.attach(screenShotState);

        flyCam.setMoveSpeed(10f);
        flyCam.setZoomSpeed(20f);

        Material blue = new Material(assetManager,
                "Common/MatDefs/Misc/Unshaded.j3md");
        blue.setColor("Color", ColorRGBA.Blue);

        float ballRadius = 0.4f;
        Sphere mesh = new Sphere(16, 16, ballRadius);

        Geometry b1 = new Geometry("b1", mesh);
        rootNode.attachChild(b1);
        b1.setLocalTranslation(0f, ballRadius, 0f);
        b1.setMaterial(blue);

        Geometry b2 = new Geometry("b2", mesh);
        rootNode.attachChild(b2);
        b2.setLocalTranslation(0f, -ballRadius, 0f);
        b2.setMaterial(blue);

        BulletAppState bulletAppState = new BulletAppState();
        getStateManager().attach(bulletAppState);
        bulletAppState.setDebugEnabled(true);
        bulletAppState.setSpeed(0f);

        float capsuleHeight = 2f * ballRadius;
        CapsuleCollisionShape shape =
                new CapsuleCollisionShape(ballRadius, capsuleHeight);

        shape.setScale(new Vector3f(phyScale, phyScale, phyScale));

        RigidBodyControl rbc = new RigidBodyControl(shape, 0f);
        bulletAppState.getPhysicsSpace().add(rbc);
        rootNode.addControl(rbc);

        rootNode.setLocalScale(geoScale);
    }

    @Override
    public void simpleUpdate(float fps) {
        String message = String.format("geoScale=%.2f   phyScale=%.2f",
                geoScale, phyScale);
        fpsText.setText(message);
    }
}

With geoScale = 1, phyScale = 1, the capsule collision shape’s debug wireframe closely matches the geometries:

But if I change both scales to 2, they no longer match:

In fact, it looks like maybe the collision shape’s radius gets scaled twice:

Of course, these screenshots show the debug shape, not the actual physics object. I’m not sure yet whether the physics object has the same issue.

By adding a shooter to my test program, I convinced myself that the debug shape does not match the physical object unless phyScale=1.

In fact, shape.setScale(phyScale) seems to have no effect on the physical object. Regardless of what value I assign to phyScale, the object behaves as if it has radius of 0.4 world unit, a cylinder height of 0.8 wu, and a total height of 1.6 wu.

Meanwhile, phyScale=2 results in a debug shape with a radius of 1.6 wu and a total height of 4.8 wu. I expected it to be twice the size of phyScale=1, in other words, radius of 0.8 wu and a total height of 3.2 wu. Apparently phyScale gets applied to the radius twice and never to the cylinder height.

So now I have two issues: (1) I can’t set the scale using setScale() and (2) when I use setScale(phyScale) with phyScale>1, the debug shape doesn’t match the physics object.

I’ll poke around in the JME3 source code, but the physics section is rather obscure so I’d appreciate some help here.

This is so for static shapes in jbullet:
https://code.google.com/p/bullet/issues/detail?id=178

1 Like
@normen said: This is so for static shapes in jbullet: https://code.google.com/p/bullet/issues/detail?id=178

Thanks for the pointer, Normen. For the moment I’ll bypass setScale() and set the shape’s dimensions directly.

That probably explains issue 1, though #178 is a report from 2009 that was closed in 2012. How long before the fix propagates to JME3?

Regarding issue 2, I thought JME3 generated the debug shapes. Was I mistaken?

It won’t be in jME before we move to native bullet completely, but it should be in the alpha native bullet implementation already. jbullet doesn’t seem to be extended anymore. jME gets a mesh from the bullet debug system, it doesn’t do much more than display it.

1 Like
@normen said: It won't be in jME before we move to native bullet completely, but it should be in the alpha native bullet implementation already. jbullet doesn't seem to be extended anymore. jME gets a mesh from the bullet debug system, it doesn't do much more than display it.

Thanks for that info. I’ll try native bullet.

@sgold said: Thanks for that info. I'll try native bullet.

I don’t know if using alpha software to circumvent an issue that you already have a solution for makes sense but as you like.

Native bullet provides a friendly runtime warning that “CapsuleCollisionShape cannot be scaled” and generates a debug shape that’s not scaled. Good enough!

@sgold said: Native bullet provides a friendly runtime warning that "CapsuleCollisionShape cannot be scaled" and generates a debug shape that's not scaled. Good enough!

I this is probably from a workaround warning that was in the initial jbullet version but was removed as the statement isn’t exactly true (its just a bug in bullet and only applies to immovable shapes). When we finally move I’ll remove that check too.

I’ve hit this issue again, this time in JME 3.1-stable, using native Bullet and a BoxCollisionShape (which is scalable).

Apparently the native getVertices() method invoked by DebugShapeFactory.getDebugMesh() takes the shape’s scale into account. If the collision shape has scale != (1,1,1) when getDebugMesh() is invoked, the debug mesh reflects that scaling. Later, when the debug mesh is rendered, the shape’s scale is also applied to the geometry (by the AbstractPhysicsDebugControl’s controlUpdate() method).

To summarize, the scale is applied 2x in the visualization, which explains why it doesn’t match the physics. The issue is currently present in the JME ‘master’ branch (on which 3.2 will be based). I will file an issue and submit a fix.

1 Like

issue 772 scale of a physics shape is applied 2x by BulletDebugAppState · Issue #772 · jMonkeyEngine/jmonkeyengine · GitHub
pull request 773 fix for issue #772: populate bullet debug mesh using unscaled shape by stephengold · Pull Request #773 · jMonkeyEngine/jmonkeyengine · GitHub

Wouldn’t it make more sense to not scale the jme geometry and just use whatever bullet returns? Or are there any specific reasons preventing this?

Hm. If we didn’t scale the geometry, we’d need to re-generate the debug mesh every time setScale() was invoked on the shape.

Hm alsonot optimal,
do you by chance know how softshapes might report the vertices? If they do not show the actual deformation, I guess we loose nothing with the approach in your fix.

I’ve not looked at soft bodies in Bullet yet.