How best to bind the camera to the object

My implementation:
[java]/**
* Обновление позиции камеры.
*
* @param camera камера, чью позицию надо изменить.
* @param object объект, за которым надо разместить камеру.
*/
public static final void updateCameraPosition(Camera camera, SpaceShip object)
{
// получаем буффер
LocalThread local = LocalThread.get();

	// получаем позицию объекта
	Vector3f loc = object.getLocation();
	
	// создаем новую позицию камеры
	Vector3f cameraLoc = local.getNextVector();

	// добалвяем направление объекта
	cameraLoc.set(object.getDirection());
	
	// получаем отступ от объекта
	int offset = object.getSizeX();

	// добавляем дистанцию до объекта
	cameraLoc.multLocal(offset * -3);
	
	// добалвяем позицию объекта
	cameraLoc.addLocal(loc);
	
	// создаем вектор прицеливания
	Vector3f aiming = local.getNextVector();
	
	// получаем направление вектора
	aiming.set(object.getDirection());
	
	// добавляем дистанцию прицеливания
	aiming.multLocal(object.getAimingDistance());
	
	// добалвяем позицию корабля
	aiming.addLocal(loc);
	
	// создаем вектор вверх
	Vector3f up = local.getNextVector();
	
	// получаем разворот объъекта
	Quaternion rotation = object.getRotation();
	
	// получаем направление ввверх
	rotation.getRotationColumn(1, up);
	
	// поднимаем камеру
	cameraLoc.addLocal(up.mult(offset, local.getNextVector()));
	
	// применяем положение
	camera.setLocation(cameraLoc);
	
	// получаем игровой контролер
	GameController control = GameController.getInstance();
	
	// если режим интерфейса, то выходим
	if(control.getInputMode() == InputMode.INTERFACE_MODE)
		return;
	
	// обновляем разворот
	camera.lookAt(aiming, up);
}[/java]

The problem: the camera vibrates slightly when you move the object, if the camera is undocked, the object moves smoothly

What the heck are you doing there… Why is that method static shiver

Your problem is most probably update order. As you completely ignore the normal ways to do stuff in jme thats kind of prone to happen. I can’t tell you where in your code it is but its the place where you call this method. Normally you modify scene objects from the update call of a Control or AppState and then the update order is kept and you don’t get shaking.

Anyway, I guess you do this funny code because you want to “optimize” or something and tell me that its super good and you have to do it this way. In that case you’re on your own.

Maybe look at this to understand how jme works:

this is util method :wink:

method is called from the GameState

[java]@Override
public void update(float tpf)
{
long current = System.currentTimeMillis();

	SpaceObject[] array = visibleObjects.array();
	
	for(int i = 0, length = visibleObjects.size(); i< length; i++)
		array[i].update(current, tpf);
	
	PlayerShip ship = getPlayerShip();
		
	if(ship != null)
		GameUtil.updateCameraPosition(camera, ship);
	
	for(int i = 0, length = visibleObjects.size(); i< length; i++)
		array[i].getAppearance().updateNameView();
	
	// обновляем индикатор направления
	controller.updateVectorIndicator();
	// обновляем индикатор прицела
	controller.updateAimIndicator();
	
	super.update(tpf);
}[/java]

This changes nothing about my comment.

When you override and replace every normal JME solution then you make it hard for us to help you since you are essentially rewriting everything yourself.

In this case, though, you are updating the camera position before the objects has moved. As normen says, a classic update ordering problem.

@normen said: This changes nothing about my comment.
Can not see the video, even a hint of an answer my question: (
@pspeed said: When you override and replace every normal JME solution then you make it hard for us to help you since you are essentially rewriting everything yourself.

In this case, though, you are updating the camera position before the objects has moved. As normen says, a classic update ordering problem.


I gave a piece of code that describes how to update the game scene, so that your version is not correct, though your version is obvious

  1. update position and rotation all objects
  2. update camera position and rotation
  3. update nickname position
  4. update HUD

I develop a MMO game, here are some other rules in architecture :slight_smile:

@javasabr said: Can not see the video, even a hint of an answer my question: (

I gave a piece of code that describes how to update the game scene, so that your version is not correct, though your version is obvious

  1. update position and rotation all objects
  2. update camera position and rotation
  3. update nickname position
  4. update HUD

I develop a MMO game, here are some other rules in architecture :slight_smile:

See… because the code you posted doesn’t do that. Why do you waste our time posting code that doesn’t do what you say it does?

The code you posted updates any objects with controls last because it calls super.update() last.

But if you aren’t using controls and you aren’t using any JME stuff then how can we ever hope to help you? This is not a JME problem. Something is wrong in your code and you are updating the position of one thing before the position of the other really gets updated. But that problem is in your code… the stuff we can’t see.

If you were using standard JME stuff then we could guess at what might be wrong. Since you don’t, it is impossible for us to guess. You will have to ask whoever wrote your framework to help you. :wink:

My class GameState extends AbstractAppState, Is not that part of the jME? :slight_smile:
SimpleApplication.update() -> current app state.update(float tpf), Is not that part of the jME? :slight_smile:

We cannot guess about parts we can’t see.

The bottom line is that if you update positions in the right order then everything is fine. I do it all the time.

If you do not update positions in the right order (update camera to object position then update object position, for example) then you will definitely see jitter.

The problem is in your code so only you can find it.

@pspeed said: We cannot guess about parts we can't see.

The bottom line is that if you update positions in the right order then everything is fine. I do it all the time.

If you do not update positions in the right order (update camera to object position then update object position, for example) then you will definitely see jitter.

The problem is in your code so only you can find it.


I have shown you some of the code, which describes the sequence of updates. I have no more places are update.

@javasabr said: 1. update position and rotation all objects 2. update camera position and rotation 3. update nickname position 4. update HUD

public class GameState extends AbstractAppState

[java]@Override
public void update(float tpf)
{
super.update(tpf);

	//get the current time
	long current = System.currentTimeMillis();

	// get all visible objects
	SpaceObject[] array = visibleObjects.array();

	// upfdate position and rotation
	for(int i = 0, length = visibleObjects.size(); i< length; i++)
		array[i].update(current, tpf);
	// get my ship
	PlayerShip ship = getPlayerShip();

	if(ship != null)
	// update camera position and rotation
		GameUtil.updateCameraPosition(camera, ship);

	// update object name labels
	for(int i = 0, length = visibleObjects.size(); i< length; i++)
		array[i].getAppearance().updateNameView();
	
	controller.updateVectorIndicator();
	controller.updateAimIndicator();
}[/java]

all as it should be: (

We can’t see the parts that are broken.

What does SpaceObject.update() do? What does SpaceObject.getLocation() do?

Anyway… try simplifying updateCameraPosition to just do a direct fixed direction offset from the ship or something instead of all of the math. Rule the math out as a problem. If it’s still jittery then you can look into why getLocation() is returning something different than the location of the real spatial.

@pspeed said: We can't see the parts that are broken.

What does SpaceObject.update() do? What does SpaceObject.getLocation() do?

Anyway… try simplifying updateCameraPosition to just do a direct fixed direction offset from the ship or something instead of all of the math. Rule the math out as a problem. If it’s still jittery then you can look into why getLocation() is returning something different than the location of the real spatial.


If you detach the camera, all the objects move without vibration. This means that the problem is not in the update objects.
If you just keep the camera back, the vibration is also present, so I turned to you for help
[java]// получаем позицию объекта
Vector3f loc = object.getLocation();

	// создаем новую позицию камеры
	Vector3f cameraLoc = local.getNextVector();

	// добалвяем направление объекта
	cameraLoc.set(object.getDirection());
	
	// получаем отступ от объекта
	int offset = object.getSizeX();

	// добавляем дистанцию до объекта
	cameraLoc.multLocal(offset * -3);
	
	// добалвяем позицию объекта
	cameraLoc.addLocal(loc);[/java]

object.getDirection() is updated with each change in its turn

If the camera is moving then how do you know which one is vibrating?

@pspeed said: If the camera is moving then how do you know which one is vibrating?
If the camera to stop and observe the movement of objects, the objects do not vibrate.
@javasabr said: If the camera to stop and observe the movement of objects, the objects do not vibrate.

So it’s the camera vibrating. The camera position is updated to a value that is different than the Spatial has. Or something similar.

We can’t help because we don’t see enough of the code. If you can put together a simple test case then it would be helpful. Likely, the test case will work and you will know what’s wrong with your code… or the test case won’t and we can show you what’s wrong with the test case. As it is, we cannot guess all of the parts of the code we can’t see.

After a couple of new tests, came to the conclusion that all the same objects vibrate when the execute flyTask

SpaceObject.update() -> flyTask.update()

[java]public void update(long currentTime)
{
// текущая скорость
float lastSpeed = getLastSpeed();

	// получаем ускорение
	float accel = getAccel();
	
	try
	{
		if(accel < 1 && lastSpeed < 1)
			return;
		
		// прлучаем владельца
		SpaceShip owner = getOwner();

		// получаем время прошлого рассчета
		long last = getLast();
	
		// получаем разницу во времени
		long diff = currentTime - last;
		
		// рассчитываем текующую скорость
		lastSpeed = Math.max(Math.min(lastSpeed + (diff / 1000F) * accel, maxSpeed), 0);
		
		// рассчитываем пройденное расстояние
		float dist = diff * lastSpeed / 1000F;
		
		// получаем вектор изменения
		Vector3f changed = getChanged();
		// получаем вектор полета
		Vector3f flyVector = getFlyVector();
		
		// получаем вектор направления
		changed.set(owner.getDirection());
		
		// увеличиваем его на пройденое расстояние
		changed.multLocal(dist);
		
		// получаем итоговую позицию
		flyVector.set(changed).addLocal(owner.getLocation());

		// применяем новую позицию
		owner.setLocation(flyVector, changed);
	}
	finally
	{
		// сохраняем время
		setLast(currentTime);
		
		// сохраняем скорость
		setLastSpeed(lastSpeed);
	}
}[/java]

How can you tell if all of the objects are vibrating or if the camera is vibrating? It’s impossible.

anyway, we can’t help anymore unless you make a simple test case showing the issue.

It is impossible to replicate in a simple test: (

[java]/**

  • @author Ronn
    */
    public class CameraTest extends SimpleApplication
    {
    private static final float FLY_ACCEL = 1.5f;

    private static final float ROTATE_SPEED = 0.3f;

    public static void main(String[] args)
    {
    CameraTest app = new CameraTest();

     AppSettings settings = new AppSettings(true);
     
     settings.setFrameRate(60);
     
     app.setSettings(settings);
    
     app.setLast(System.currentTimeMillis());
     
     app.start();
    

    }

    private Geometry geom;

    private long last;

    private float lastSpeed;

    @Override
    public void simpleInitApp()
    {
    geom = newBox();

     PointLight light = new PointLight();
     
     light.setRadius(1000);
     
     rootNode.addLight(light);
     
     rootNode.attachChild(geom);
     
     Random random = new Random();
     
     for(int i = 0, length = 10; i < length; i++)
     {
     	Geometry geom = newBox();
     	
     	int x = random.nextInt(20);
     	int y = random.nextInt(20);
     	int z = random.nextInt(20);
     	
     	geom.setLocalTranslation(x, y, z);
     	
     	rootNode.attachChild(geom);
     }
    

    }

    private Geometry newBox()
    {
    Box box = new Box(1, 1, 1);

     Geometry geom = new Geometry("Box", box);
     
     Material material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
     
     material.setTexture("DiffuseMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg"));
     material.setTexture("NormalMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond_normal.png"));
     material.setBoolean("UseMaterialColors", true);
     material.setColor("Specular", ColorRGBA.White);
     material.setColor("Diffuse", ColorRGBA.White);
     
     geom.setMaterial(material);
     
     return geom;
    

    }

    @Override
    public void simpleUpdate(float tpf)
    {
    long currentTime = System.currentTimeMillis();

     float lastSpeed = getLastSpeed();
     
     try
     {
     	long last = getLast();
     	
     	long diff = currentTime - last;
     	
     	// рассчитываем текующую скорость
     	lastSpeed = Math.max(Math.min(lastSpeed + (diff / 1000F) * FLY_ACCEL, 2), 0);
     				
     	float dist = lastSpeed * diff / 1000F;
     	
     	float rotate = ROTATE_SPEED * diff / 1000F;
     	
     	geom.rotate(rotate, rotate, rotate);
     	
     	Quaternion rotation = geom.getLocalRotation();
     	
     	Vector3f direction = rotation.getRotationColumn(2);
     	
     	direction.multLocal(dist);
     	
     	direction.addLocal(geom.getLocalTranslation());
     	
     	geom.setLocalTranslation(direction);
     	
     	super.simpleUpdate(tpf);
     	
     	updateCameraPosition(cam, geom);
     }
     finally
     {
     	setLast(currentTime);
     	
     	setLastSpeed(lastSpeed);
     }
    

    }

    public long getLast()
    {
    return last;
    }

    public void setLast(long last)
    {
    this.last = last;
    }

    public void setLastSpeed(float lastSpeed)
    {
    this.lastSpeed = lastSpeed;
    }

    public float getLastSpeed()
    {
    return lastSpeed;
    }

    public static final void updateCameraPosition(Camera camera, Geometry object)
    {
    Vector3f loc = object.getLocalTranslation();

     Quaternion rotation = object.getLocalRotation();
     
     Vector3f cameraLoc = rotation.getRotationColumn(2);
    
     int offset = 10;
    
     cameraLoc.multLocal(offset * -3);
     
     cameraLoc.addLocal(loc);
     
     Vector3f aiming = rotation.getRotationColumn(2);
     
     aiming.multLocal(50);
     
     aiming.addLocal(loc);
     
     Vector3f up = rotation.getRotationColumn(1);
     
     cameraLoc.addLocal(up.mult(offset));
     
     camera.setLocation(cameraLoc);
     
     camera.lookAt(aiming, up);
    

    }
    }[/java]

@javasabr said: It is impossible to replicate in a simple test: (

Then the problem is definitely in your code. Something is updating in the wrong order. You haven’t even shown us how and when the spatials get updated so we cannot possibly help.