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.
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.
@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.
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.
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.