ChaseCamera glitching while following physics object

I’ve switched to using jme3 (from javafx) a few days ago and am loving porting my game to it. If I cut right to the chase, I noticed that if I use a ChaseCamera and set it to follow a physics object that is being moved rapidly it doesn’t quite follow it correctly - resulting in unwanted shaking and glitching as seen if you test the provided example. My hipotesis would is that the camera is being translated in the rendering thread which is out of sync with the physics thread and that causes the problem. Any ways of fixing this?

package mainpkg;

import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.PhysicsTickListener;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.input.ChaseCamera;
import com.jme3.light.AmbientLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;

public class MCVE extends SimpleApplication implements PhysicsTickListener{

	private static Node object = new Node();;
	private static BulletAppState physics = new BulletAppState();
	private static RigidBodyControl ctrl = new RigidBodyControl(2f);

	@Override
	public void simpleInitApp() {

		stateManager.attach(physics);
		
                flyCam.setEnabled(false); // remove flycam
		ChaseCamera camera = new ChaseCamera (cam, object, inputManager);
		camera.setSmoothMotion(false);
		camera.setDownRotateOnCloseViewOnly(false);
		camera.setMaxVerticalRotation(90);
		camera.setInvertVerticalAxis(true);
		camera.setMinDistance(0.05f);
		camera.setMaxDistance(500);
		
        AmbientLight al=new AmbientLight();
        al.setColor(ColorRGBA.White);
        rootNode.addLight(al);
		
		cam.setFrustumPerspective(80f, (float) cam.getWidth() / cam.getHeight(), 0.01f, 800000f);		
		physics.getPhysicsSpace().setGravity(new Vector3f(0, 0f, 0));
		
		Material blank = new Material(assetManager,"Common/MatDefs/Light/Lighting.j3md");
		
		Geometry brick_geo = new Geometry("box", new Box(1,1,1));
		brick_geo.setMaterial(blank);		
		object.attachChild(brick_geo);
		object.addControl(ctrl);
		rootNode.attachChild(object);		
		physics.getPhysicsSpace().add(ctrl);
		physics.getPhysicsSpace().addTickListener(this);
	}


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



	@Override
	public void prePhysicsTick(PhysicsSpace arg0, float arg1) {
		ctrl.applyCentralForce(new Vector3f(50,0,0));
	}
	
	@Override
	public void physicsTick(PhysicsSpace arg0, float arg1) {}
}

I am currently using the provided ChaseCam but intend to write my own later when I get to it since I need a custom one (answers heading in that direction would be great).

I don’t know if you create the Application object with an empty constructor but if you do then you never remove the default flyCam.

I do make it with an empty constructor, but even adding a flyCam.setEnabled(false); line doesn’t have any effect on the problem.

Then its probably the update order - your camera gets moved before the control applies the physics location to the geometry.

How is that even possible? And how would one fix it…

In the code you’ve posted, you still have a fly cam. Post the code you think doesn’t have a fly cam anymore.

Edited the code.

Have you tried with smooth motion?

camera.setSmoothMotion(true);

Also, dont know if you saw it already, but there is a nice example of ChaseCamera on google code.

Input gets processed, the position of the node is used, controls get processed, the node is moved. In that order.

@afonsolage Yes I have tried smooth motion (along with everything else that the main tutorial explains), it has the exact same problem, but also can’t follow the object properly and slingshots around a bit. I’ll take a look at that example, although it does not use physics movement which is the thing i’m having problems with.

@normen I see. But why isn’t the camera programmed to move last? That’s how I always did it in other engines (when I did it manually) and would make much more sense as it isn’t following the place where the object was, but where it is now.

P.S. If someone actually tried to test the code I provided, yeah that would be great.

You can move the camera last but as its linked to the input by the ChaseCam its moved early, input is processed first (obviously).

Alright so I tried to remove the chasecam alltogether and move the provided cam manually but it gives the same results, no matter if I move it first, last or in the prePhysicsTick method.
Using this:

cam.setLocation(ctrl.getPhysicsLocation());

With chasecam disabled like:

//		ChaseCamera camera = new ChaseCamera (cam, object, inputManager);
//		camera.setSmoothMotion(true);
//		camera.setDownRotateOnCloseViewOnly(false);
//		camera.setMaxVerticalRotation(90);
//		camera.setInvertVerticalAxis(true);
//		camera.setMinDistance(0.05f);
//		camera.setMaxDistance(500);

The ChaseCamera adds a control to the target spatial. Obviously this control is added before the physics control. Do the physics setup first and then do the chase camera setup last.

Then you didn’t really move it last… but we can’t see what you think last is because we didn’t see that code.

You definitely should absolutely not ever ever never ever never ever never move it in the physics tick.

updateLogicalState is happening after the update() method as well, try adding a Control that moves the cam and add that after the physics control

[quote=“pspeed, post:13, topic:32914”]
Do the physics setup first and then do the chase camera setup last.
[/quote] Fine I’ll try that.

I know, thats why I did it like this:

public static boolean done = false;
@Override
public void simpleUpdate(float tpf) {
	if(done)
	{
		cam.setLocation(ctrl.getPhysicsLocation().add(new Vector3f(0,0,-8)));
                cam.lookAt(ctrl.getPhysicsLocation(),Vector3f.UNIT_Y);
		done = false;
	}
}

@Override
public void physicsTick(PhysicsSpace arg0, float arg1) {
	done = true;
}

Alright, this seemed to work. Thanks guys. :smiley: I didn’t know that that actually mattered. Seems so obvious now.

For reference, simpleUpdate() is run BEFORE anything else. Definitely NOT last.

Order goes like this:
-process input
-app state updates
-simpleUpdate
-control updates
-app state render
-actual render
-simpleRender
-app state post render

In this case, the only place to do something “LAST” with the camera is in an app state’s render method or as the last control. (Really FlyByCamera and ChaseCamera should have been app states.)

1 Like

Well in the code I did it should have ran the next frame, thus making it lag behind again apaprently. That order is definitely something I need to keep in the back of my mind.

Yeah, it wasn’t done last… it was done early on the following frame…which is basically your original problem.

Note: I’m not a magician, nor do I have total-code-recall… I simply know the secret (apparently) key to look at engine source code. If you find the secret key then you can look, too.