Scaling world unit

I’m trying to scale the world unit such that 1wu = 0.1m, while maintaining identical physics behaviors as when 1wu == 1m.

I modified:

  1. object dimensions x 10
  2. linear speed x 10
  3. gravity x 10

Now I did this to HelloPhysics example, the wall collapsed immediately (see code below). I assume this is due to the physics space accuracy being too low. So, what would be an appropriate value to achieve identical physics as when 1wu == 1m? 1/600 looks terrible.

What else need to be scaled? sleeping threshold? friction? max sub steps? restitution?

[java]
package jme3test.helloworld;

import com.jme3.app.SimpleApplication;
import com.jme3.asset.TextureKey;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.font.BitmapText;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.scene.shape.Sphere.TextureMode;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;

/**

  • Example 12 - how to give objects physical properties so they bounce and fall.
  • @author base code by double1984, updated by zathras
    */
    public class HelloJME3 extends SimpleApplication {

public static void main(String args[]) {
HelloJME3 app = new HelloJME3();
app.start();
}

/** Prepare the Physics Application State (jBullet) */
private BulletAppState bulletAppState;

/** Prepare Materials */
Material wall_mat;
Material stone_mat;
Material floor_mat;

/** Prepare geometries and physical nodes for bricks and cannon balls. */
private RigidBodyControl brick_phy;
private static final Box box;
private RigidBodyControl ball_phy;
private static final Sphere sphere;
private RigidBodyControl floor_phy;
private static final Box floor;

/** dimensions used for bricks and wall */
private static final float brickLength = 4.8f;
private static final float brickWidth = 2.4f;
private static final float brickHeight = 1.2f;

static {
/** Initialize the cannon ball geometry /
sphere = new Sphere(32, 32, 4f, true, false);
sphere.setTextureMode(TextureMode.Projected);
/
* Initialize the brick geometry /
box = new Box(brickLength, brickHeight, brickWidth);
box.scaleTextureCoordinates(new Vector2f(1f, 0.5f));
/
* Initialize the floor geometry */
floor = new Box(100f, 1f, 50f);
floor.scaleTextureCoordinates(new Vector2f(3, 6));
}

@Override
public void simpleInitApp() {
/** Set up Physics Game */
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
//bulletAppState.getPhysicsSpace().enableDebug(assetManager);
Vector3f gravity = new Vector3f();
bulletAppState.getPhysicsSpace().getGravity(gravity);
gravity.y *= 10;
bulletAppState.getPhysicsSpace().setGravity(gravity);
// bulletAppState.getPhysicsSpace().setAccuracy(1f/200f);

/** Configure cam to look at scene */
cam.setLocation(new Vector3f(0, 40f, 60f));
cam.lookAt(new Vector3f(20, 20, 0), Vector3f.UNIT_Y);
/** Add InputManager action: Left click triggers shooting. */
inputManager.addMapping("shoot", 
        new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(actionListener, "shoot");
/** Initialize the scene, materials, and physics space */

initMaterials();
initWall();
initFloor();
initCrossHairs();

}

/**

  • Every time the shoot action is triggered, a new cannon ball is produced.
  • The ball is set up to fly from the camera position in the camera direction.
    */
    private ActionListener actionListener = new ActionListener() {
    public void onAction(String name, boolean keyPressed, float tpf) {
    if (name.equals(“shoot”) && !keyPressed) {
    makeCannonBall();
    }
    }
    };

/** Initialize the materials used in this scene. */
public void initMaterials() {
wall_mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
TextureKey key = new TextureKey(“Textures/Terrain/BrickWall/BrickWall.jpg”);
key.setGenerateMips(true);
Texture tex = assetManager.loadTexture(key);
wall_mat.setTexture(“ColorMap”, tex);

stone_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG");
key2.setGenerateMips(true);
Texture tex2 = assetManager.loadTexture(key2);
stone_mat.setTexture("ColorMap", tex2);

floor_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
TextureKey key3 = new TextureKey("Textures/Terrain/Pond/Pond.jpg");
key3.setGenerateMips(true);
Texture tex3 = assetManager.loadTexture(key3);
tex3.setWrap(WrapMode.Repeat);
floor_mat.setTexture("ColorMap", tex3);

}

/** Make a solid floor and add it to the scene. /
public void initFloor() {
Geometry floor_geo = new Geometry(“Floor”, floor);
floor_geo.setMaterial(floor_mat);
floor_geo.setLocalTranslation(0, -1f, 0);
this.rootNode.attachChild(floor_geo);
/
Make the floor physical with mass 0.0f! */
floor_phy = new RigidBodyControl(0.0f);
floor_geo.addControl(floor_phy);
bulletAppState.getPhysicsSpace().add(floor_phy);
}

/** This loop builds a wall out of individual bricks. */
public void initWall() {
float startpt = brickLength / 4;
float height = 0;
for (int j = 0; j < 15; j++) {
for (int i = 0; i < 6; i++) {
Vector3f vt =
new Vector3f(i * brickLength * 2 + startpt, brickHeight + height, 0);
makeBrick(vt);
}
startpt = -startpt;
height += 2 * brickHeight;
}
}

/** This method creates one individual physical brick. /
public void makeBrick(Vector3f loc) {
/
* Create a brick geometry and attach to scene graph. /
Geometry brick_geo = new Geometry(“brick”, box);
brick_geo.setMaterial(wall_mat);
rootNode.attachChild(brick_geo);
/
* Position the brick geometry /
brick_geo.setLocalTranslation(loc);
/
* Make brick physical with a mass > 0.0f. /
brick_phy = new RigidBodyControl(2f);
/
* Add physical brick to physics space. */
brick_geo.addControl(brick_phy);
// brick_phy.setSleepingThresholds(8, 10);
// System.err.println(brick_phy.getLinearSleepingThreshold() + " " + brick_phy.getAngularSleepingThreshold());
bulletAppState.getPhysicsSpace().add(brick_phy);

}

/** This method creates one individual physical cannon ball.

  • By defaul, the ball is accelerated and flies
  • from the camera position in the camera direction.*/
    public void makeCannonBall() {
    /** Create a cannon ball geometry and attach to scene graph. /
    Geometry ball_geo = new Geometry(“cannon ball”, sphere);
    ball_geo.setMaterial(stone_mat);
    rootNode.attachChild(ball_geo);
    /
    * Position the cannon ball /
    ball_geo.setLocalTranslation(cam.getLocation());
    /
    * Make the ball physcial with a mass > 0.0f /
    ball_phy = new RigidBodyControl(1f);
    /
    * Add physical ball to physics space. /
    ball_geo.addControl(ball_phy);
    bulletAppState.getPhysicsSpace().add(ball_phy);
    /
    * Accelerate the physcial ball to shoot it. */
    ball_phy.setLinearVelocity(cam.getDirection().mult(250));
    }

/** A plus sign used as crosshairs to help the player with aiming.*/
protected void initCrossHairs() {
guiNode.detachAllChildren();
guiFont = assetManager.loadFont(“Interface/Fonts/Default.fnt”);
BitmapText ch = new BitmapText(guiFont, false);
ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
ch.setText("+"); // fake crosshairs :slight_smile:
ch.setLocalTranslation( // center
settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2,
settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
guiNode.attachChild(ch);
}
}
[/java]

1 Like

This might give some hints: http://www.bulletphysics.org/mediawiki-1.5.8/index.php?title=Scaling_The_World

1 Like

I’m just curious… why do you want to do this?

The reason I’m curious is because many people who think they need to do this are either misinformed or are trying to rigidly adapt an existing coordinate system for non-technical reasons. It’s not necessarily the case but it does beg the question.

The reason is that I need to simulate small objects laying on the top of a table. Object dimensions typically range from 0.5cm to 50cm. Since Bullet don’t work well with objects smaller than 0.05wu (or 0.02wu?), my intuition is to scale down the world unit.

If this is a terrible way to do it, I’d appreciate it if someone could provide suggestions. I’ve searched past discussions but nothing really works so far.

For people who are interested, I’ve also found this discussion http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=&f=9&t=2535 about how to tune Bullet parameters for simulating small objects. Not all parameters are accessible in JME3, though.

1 Like

Just seems to me like you could just pretend 1 unit is 1 centimeter and adjust mass accordingly… though I guess maybe bullet would get weird with that, too.

My apology if I didn’t make it clear.

This is exactly what I’m trying to do, except I’m pretending 1 unit is 10 cm. I did not change the mass, but did change the gravity to 98.1 (should be the same, right?). This leads to the wall collapsing…

Just to be certain, I just tested modifying the mass. What I did is using gravity = 9.81, and make bricks and cannon balls weigh 1000 times their original weights. This should be physically equivalent to increasing gravity while leaving mass untouched. To my surprise the wall did not collapse with the default physics space accuracy (60Hz). However the physics feel unnatural, like bricks feel lighter and everything looks like in slow motion.

My head is not really in physics right now so it’s hard for me to wrap my brain around it…

I too, initially thought 10x scale = 1000x mass (10^3) but now I’m not sure that’s right either. For example, it does strange things to F = ma… it seems on one hand acceleration would work at 10x but then mass at 1000x? One of these things is wrong but my head’s not in it. So I don’t think the mass really scales like that… or if it does then gravity would need to also change.

I mean, 10 (meters per (second squared)) = 1000 centimeters per (second squared)… so you’d think 98.1 should be right for 10x upscale given normal masses.

Actually, thinking about how my own physics engine would react to these things messing with these numbers would throw everything out of balance. Physics is a simulation and must dampen and deal with constraints and small forces in such a way that the whole thing doesn’t blow apart. So rescaling may always be fraught with issues.

So it could be that your math is right by the engine just can’t deal with it. Or I could be confused.

Thanks, pspeed. I tried many other configurations with gravity, mass, sizes, etc, but none of them really worked. Perhaps scaling world unit is a terrible idea after all.

In particular, I feel that whenever I scale the gravity, bricks start to act weirdly. For example, I had a scene of one brick falling a short distance down to the ground. After the brick lied flat on the ground, it started to jitter for a long time. Increasing sleeping threshold did not help either.

Perhaps I’ll just leave the gravity alone and pretend that I’m dealing with objects that are 10 times their normal sizes (like playing basketball-sized billiards).

I think this is a lot better, there is (almost) never a reason to scale the physics simulation in a game. The resolver will for example have a hard time with high gravity, the gravity will force the brick to penetrate the ground and the constraint resolver will try to push it outside again - and repeat…
It has similar problems where the masses are very different. A battle tank running over a rigid football will not simulate very good.

@Di-WeiHuang, so did you finally made it work well?
I am trying to create small objects like dices and coins, and I am still at rootNode.setLocalScale(100f); (where 1.0f = 1cm)

@Quote I ended up scale everything up manually (1.0f = 10cm) without touching the gravity. The physics looks OK.

Never tried setLocalScale(), but I assume it works the same way as manual scaling?

at my thread http://hub.jmonkeyengine.org/forum/topic/fall-thru-ground-how-to-scale-everything-easily/#post-301188
I found that this: bulletAppState.getPhysicsSpace().setAccuracy(1.0f/240f);
worked very well, on a terrain, for a small cube of 0.02f size (x,y,z had each 0.02f dimension)
but with 0.01f size, it still fell thru ground like 50% of the time.

also, when there were too many objects moving (30+), the fps went as low as 5fps, what is not good

so, I am still considering scaling everything up, but that is too troubling, to many spots to not fail on coding or things will mess up as specified here: http://www.bulletphysics.org/mediawiki-1.5.8/index.php?title=Scaling_The_World

Scale collision shapes about origin by X Scale all positions by X Scale all linear (but not angular) velocities by X Scale linear [Sleep Threshold] by X Scale gravity by X Scale all impulses you supply by X Scale all torques by X^2 Scale all inertias by X if not computed by Bullet

and interesting that you said you didnt change gravity as they specify it should be done, so I guess that list may not be fully required…

I am still beginning the tests, I will see what happens, if a simpler approach may work, or I will be forced to go on the harder coding way :slight_smile:

I’m curious why you want to scale anything at all? A coin will fall as fast as a battle ship since there is no air resistance. Unless you are talking about running a physics simulation that includes large relative differences in mass/volume. If that is the case (footballs and battle tanks in the same simulation) I don’t think bullet will do a good job regardless of the tweaks.

@JohanMaasing, my single goal, at least, is to have precise physics (at least as much precise as we can see in games that use the Havoc physics engine like Fallout; Because objects falling thru the ground is utterly immersion breaking, and if they fall out of the reach of players, it will also be utterly disappointing (mostly also for the ones that have hard time dealing with console commands);

I just thought also that, may be Havoc is so precise because it disables most of the physics so it can spend a huge lot of cpu to be very precise with just a few objects… mmm… may be I can make bullet 99% precise too in some way…