Kinematic problems

I made a test case, which is kinda odd to me and I think it shows problems with kinematic spatials. Please run it and look at sphere, how it become merged with kinematic box on collision. If the speeds of the box are higher, sphere merges deeper in the box, so I think there is a problem with physics here.



[java]

import com.jme3.app.SimpleApplication;

import com.jme3.bullet.BulletAppState;

import com.jme3.bullet.collision.shapes.BoxCollisionShape;

import com.jme3.bullet.collision.shapes.SphereCollisionShape;

import com.jme3.bullet.control.RigidBodyControl;

import com.jme3.light.AmbientLight;

import com.jme3.light.DirectionalLight;

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.Box;

import com.jme3.scene.shape.Sphere;



public final class TestKinematic extends SimpleApplication {

private BulletAppState bulletAppState;

private Geometry box;

private boolean goingUp = true;



public static void main(String[] args) {

TestKinematic app = new TestKinematic();

app.start();

}



@Override

public void simpleInitApp() {

bulletAppState = new BulletAppState();

stateManager.attach(bulletAppState);

bulletAppState.getPhysicsSpace().setGravity(new Vector3f(0, -30f, 0));

bulletAppState.getPhysicsSpace().enableDebug(assetManager);



cam.setLocation(new Vector3f(50, 100, 50));

cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);

flyCam.setMoveSpeed(100f);



AmbientLight light = new AmbientLight();

light.setColor(ColorRGBA.LightGray);

rootNode.addLight(light);

DirectionalLight dLight = new DirectionalLight();

dLight.setColor(ColorRGBA.White);

dLight.setDirection(new Vector3f(3f, -2f, 4f));

rootNode.addLight(dLight);



Material floorMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");

floorMat.setBoolean("UseMaterialColors", true);

floorMat.setColor("Ambient", ColorRGBA.Orange);

floorMat.setColor("Diffuse", ColorRGBA.Orange);

floorMat.setColor("Specular", ColorRGBA.White);

floorMat.setFloat("Shininess", 100f);

Box floorBox = new Box(140, 0.25f, 140);

Geometry floorGeometry = new Geometry("Floor", floorBox);

floorGeometry.setMaterial(floorMat);

floorGeometry.setLocalTranslation(0, -15, 0);

floorGeometry.addControl(new RigidBodyControl(0));

rootNode.attachChild(floorGeometry);

bulletAppState.getPhysicsSpace().add(floorGeometry);



Material boxMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");

boxMat.setBoolean("UseMaterialColors", true);

boxMat.setColor("Ambient", ColorRGBA.LightGray);

boxMat.setColor("Diffuse", ColorRGBA.LightGray);

boxMat.setColor("Specular", ColorRGBA.White);

boxMat.setFloat("Shininess", 100f);

box = new Geometry("box", new Box(8, 8, 8));

box.setMaterial(boxMat);

RigidBodyControl rbc = new RigidBodyControl(new BoxCollisionShape(new Vector3f(8, 8, 8)), 50f);

rbc.setFriction(1.0f);

rbc.setRestitution(0f);

rbc.setKinematic(true);

rbc.setKinematicSpatial(true);

box.addControl(rbc);

rootNode.attachChild(box);

bulletAppState.getPhysicsSpace().add(rbc);



Material sphereMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");

sphereMat.setBoolean("UseMaterialColors", true);

sphereMat.setColor("Ambient", ColorRGBA.DarkGray);

sphereMat.setColor("Diffuse", ColorRGBA.DarkGray);

sphereMat.setColor("Specular", ColorRGBA.White);

sphereMat.setFloat("Shininess", 100f);

Geometry sphere = new Geometry("sphere", new Sphere(30, 30, 5));

sphere.setLocalTranslation(0, 80, 0);

sphere.setMaterial(sphereMat);

RigidBodyControl srbc = new RigidBodyControl(new SphereCollisionShape(5), 15f);

srbc.setFriction(1.0f);

srbc.setRestitution(0f);

sphere.addControl(srbc);

rootNode.attachChild(sphere);

bulletAppState.getPhysicsSpace().add(srbc);

}



public void simpleUpdate(float tpf) {

Vector3f v = box.getLocalTranslation();

float newy = 0;

if (goingUp)

{

newy = v.y + 30 * tpf;

}

else

{

newy = v.y - 30 * tpf;

}



if (newy > 80)

{

goingUp = false;

}

if (newy < 0)

{

goingUp = true;

}

box.setLocalTranslation(v.x, newy, v.z);

}

}

[/java]



Can someone look at this issue please? :slight_smile:

Nothing is wrong, kinematic nodes can be moved anywhere you like, if you produce overlappings thats your fault. Try making some objects not kinematic, then you can push around these with the kinematic body.

Like this:

http://normen.bitwaves.de/download/jme3test.bullet.TestBoneRagdoll004.mov



To generally avoid (non-kinematic) objects moving into each other, use ccd.

I actually don’t want to produce overlappings. :slight_smile: They just happen because of physics. Notice that in this test case, only the moving box is kinematic object, sphere is dynamic, so imho shouldn’t be merged with the box when it falls on it. Or am I wrong? :confused:

I dont know, maybe you can increase the margin of the collision shape, maybe this is the problem the character sometimes has when its got a sphere collision shape. In any instance its an internal jbullet/bullet thing, so if its a bug it will probably vanish when we move to native bullet.

Are there any physics settings that I can play with besides friction and restitution? And what are their recommended values? :slight_smile:

I think I know what it is. The thing is that your update where you set the location is called after the physics control update but before the geometry is rendered. Thus the local translation is not set to the physics rigidbody (the control update does that). If my theory is right you should be able to move a kinematic node with input listeners and get correct results (input listeners are called before the controls). You could maybe avoid this problem by setting the location in a callable that you enqueue in the application.

In other words, I should somehow update the physics after manual updating of geometry?

No, you should update the spatial data before the physics control reads it to relocate the rigidbody

Ok I have extended RigidBodyControl and overridden its update method. Now it looks like this:

[java]

import com.jme3.app.SimpleApplication;

import com.jme3.bullet.BulletAppState;

import com.jme3.bullet.collision.shapes.BoxCollisionShape;

import com.jme3.bullet.collision.shapes.CollisionShape;

import com.jme3.bullet.collision.shapes.SphereCollisionShape;

import com.jme3.bullet.control.RigidBodyControl;

import com.jme3.light.AmbientLight;

import com.jme3.light.DirectionalLight;

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.Box;

import com.jme3.scene.shape.Sphere;

public final class TestKinematic extends SimpleApplication {

private BulletAppState bulletAppState;

private Geometry box;

private boolean goingUp = true;

public static void main(String[] args) {

TestKinematic app = new TestKinematic();

app.start();

}

@Override

public void simpleInitApp() {

bulletAppState = new BulletAppState();

stateManager.attach(bulletAppState);

bulletAppState.getPhysicsSpace().setGravity(new Vector3f(0, -30f, 0));

bulletAppState.getPhysicsSpace().enableDebug(assetManager);

cam.setLocation(new Vector3f(50, 100, 50));

cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);

flyCam.setMoveSpeed(100f);

AmbientLight light = new AmbientLight();

light.setColor(ColorRGBA.LightGray);

rootNode.addLight(light);

DirectionalLight dLight = new DirectionalLight();

dLight.setColor(ColorRGBA.White);

dLight.setDirection(new Vector3f(3f, -2f, 4f));

rootNode.addLight(dLight);

Material floorMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");

floorMat.setBoolean("UseMaterialColors", true);

floorMat.setColor("Ambient", ColorRGBA.Orange);

floorMat.setColor("Diffuse", ColorRGBA.Orange);

floorMat.setColor("Specular", ColorRGBA.White);

floorMat.setFloat("Shininess", 100f);

Box floorBox = new Box(140, 0.25f, 140);

Geometry floorGeometry = new Geometry("Floor", floorBox);

floorGeometry.setMaterial(floorMat);

floorGeometry.setLocalTranslation(0, -15, 0);

floorGeometry.addControl(new RigidBodyControl(0));

rootNode.attachChild(floorGeometry);

bulletAppState.getPhysicsSpace().add(floorGeometry);

Material boxMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");

boxMat.setBoolean("UseMaterialColors", true);

boxMat.setColor("Ambient", ColorRGBA.LightGray);

boxMat.setColor("Diffuse", ColorRGBA.LightGray);

boxMat.setColor("Specular", ColorRGBA.White);

boxMat.setFloat("Shininess", 100f);

box = new Geometry("box", new Box(8, 8, 8));

box.setMaterial(boxMat);

RigidBodyControl rbc = new BoxControl(new BoxCollisionShape(new Vector3f(8, 8, 8)), 50f);

rbc.setFriction(1.0f);

rbc.setRestitution(0f);

rbc.setKinematic(true);

rbc.setKinematicSpatial(true);

box.addControl(rbc);

rootNode.attachChild(box);

bulletAppState.getPhysicsSpace().add(rbc);

Material sphereMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");

sphereMat.setBoolean("UseMaterialColors", true);

sphereMat.setColor("Ambient", ColorRGBA.DarkGray);

sphereMat.setColor("Diffuse", ColorRGBA.DarkGray);

sphereMat.setColor("Specular", ColorRGBA.White);

sphereMat.setFloat("Shininess", 100f);

Geometry sphere = new Geometry("sphere", new Sphere(30, 30, 5));

sphere.setLocalTranslation(0, 80, 0);

sphere.setMaterial(sphereMat);

RigidBodyControl srbc = new RigidBodyControl(new SphereCollisionShape(5), 15f);

srbc.setFriction(1.0f);

srbc.setRestitution(0f);

sphere.addControl(srbc);

rootNode.attachChild(sphere);

bulletAppState.getPhysicsSpace().add(srbc);

}

private class BoxControl extends RigidBodyControl

{

public BoxControl(CollisionShape shape, float mass)

{

super(shape, mass);

}

@Override

public void update(float tpf)

{

Vector3f v = box.getLocalTranslation();

float newy = 0;

if (goingUp)

{

newy = v.y + 30 * tpf;

}

else

{

newy = v.y - 30 * tpf;

}

if (newy > 80)

{

goingUp = false;

}

if (newy < 0)

{

goingUp = true;

}

box.setLocalTranslation(v.x, newy, v.z);

super.update(tpf);

}

}

}

[/java]

So now I actually set box new location first and then call super.update(tpf) on rigid body control but there is still the same problem… :confused: I will try to use input listeners to see if the bug still happens, but to enqueue location setting on every update seems like an ugly cheat to me… :slight_smile: There should be some other solution for this…

And I noticed one more thing, which is the right thing to call: setKinematic(true) or setKinematicSpatial(true)?? Because from my observations, things work without calling setKinematicSpatial(true), but not viceversa…

I have just tried with input listener and its the same. Also if you don’t move this kinematic box, when the ball first falls on it, it goes into it but its then corrected to stand on it. Then I tried and substituted ball with box and the problem stays the same… Seems like physics problem. Is maybe the physics little too late or smth? :slight_smile:

All physics is applied at the same moment, so no its not “late”. About the methods you were asking for, they have javadoc.

About physics “late”, I was wondering about if maybe the physics (of kinematic objects) for current frame is calculated/rendered in the next frame. But its only a wild thought, don’t know how things are really implemented and meant to be. :slight_smile:

So what do you propose me to do to fix this kinematic problem (except waiting for native bullet)? :slight_smile:

Hm actually the thing is that kinematic objects get their location from the scenegraph in the moment other objects set the physics location to the scenegraph. So actually the kinematic is one frame too early. Try setting setKinematicSpatial(false) and set the physics location of the kinematic rigidbody instead of setting the localtranslation of the spatial.

Also tried that but no luck. :slight_smile: Anyway, after some more testing, I could see that if the box is simply defined as static and the ball (or any other shape) just falls on it, it is also for the moment collided and merged with it but is then corrected. I suppose those “problems” are connected and that I am probably making problems where there are none (hopefully someone else can run this test and report if he has the same problem). :slight_smile: Don’t really know how the physics work internally, but are there any settings to play with (what are good values for accuracy for example or other similar variables…)? Also, does this jbullet physics predict physics or calculate it every frame or smth? Thanks for bearing with me. :slight_smile:

To find out if its really inaccuracies in the physics you can try driving up the accuracy just for testing.

Edit: Also maybe try a higher poly hull mesh than a box.