Tutorial 26 :
Moving in a 3D world - Camera

Time based movement is essential for a fluid and a constant movement.
Moreover, it is very simple to add it to our camera.

Instead of increasing movement just when a key is pressed, we keep the deplacement in a variable :

Variables

/** Next position/orientation - For time based movement */
protected Vector3f nextPos = null;
protected Vector3f nextOrientation = null;

At each frame, we will move the camera depending on its speed, the rendering/frame time and the above deplacement variables.
For this, we need to call a method at each frame : update.
 

Update (1)

public synchronized void update()
{
    //Calculate frame time in seconds
    float time = (float)counter.getLastFrameTime() / 1000.0f;

    ...
 

Now, we know the time and the wanted deplacement.
You've have to specify the camera speed and you can calculate the deplacement for the current frame :
    currentDeplacement = speed * time
 


Time based movement

This allow to move to a constant speed.
 

Update (2)

    //Maximum deplacement = speed * time
    Vector3f max = multiplyByScaler(translationSpeed, time);    //Note : speed different for each axis

    //Check that the maximum deplacement don't exceed the max deplacement
    Vector3f move = new Vector3f(
        Math.abs(nextPos.getX()) > max.getX() ? Math.signum(nextPos.getX()) * max.getX() : nextPos.getX(),
        Math.abs(nextPos.getY()) > max.getY() ? Math.signum(nextPos.getY()) * max.getY() : nextPos.getY(),
        Math.abs(nextPos.getZ()) > max.getZ() ? Math.signum(nextPos.getZ()) * max.getZ() : nextPos.getZ()
    );

    //New wanted deplacement is wanted deplacement minus current deplacement
    nextPos.addX(-move.getX());
    nextPos.addY(-move.getY());
    nextPos.addZ(-move.getZ());

    //Now, translate with the given deplacement
    translate(move);

 

Third person view is very easy to implement.

In case of a camera attached to a person, "classic" view is when the camera is positionned at the person's eye location and look at the same direction.
For a third person view, the camera is positionned at a different location than the person's eye, generally behind.


There are basically two differents third person view :
  - the camera is attached somewhere behind the person. The camera follow the person (ie move when person move).
  - the camera is fix and look toward the person location.

I've choose to use the first kind.
This picture represents what is a third person view :


Third person view description

  Now, how to do this ?

First, we need to store cameraOffset to know where the camera should be positionned :
 

Variable

/** Camera offset (3rd person view) */
protected float cameraOffset = 0.0f;         //Offset = 0.0f <=> Normal view
protected float nextCameraOffset = 0.0f;     //For time based movement

You can notive that I also use newCameraOffset to use time based movement.


The only thing changed for take third person view in account is the camera location when calling lookAt.
Camera position is the eye position to which it is subtract the forward vector multiplied by cameraOffset
ie cameraPosition = eyePosition - cameraOffset * forward
 

New LookAt

public void lookAt(GLDrawable glDrawable)
{
    Vector3f up = getUp();
    Vector3f forward = getForward();
    Vector3f pos = getCameraPosition();

    /*
     * Set the view to the eye coordinates system
     * The direction is the z axis, the sens is the value of: sens
     */

    glDrawable.getGLU().gluLookAt(pos.getX(), pos.getY(), pos.getZ(),
        pos.getX()+forward.getX(), pos.getY()+forward.getY(), pos.getZ()+forward.getZ(),
        up.getX(), up.getY(), up.getZ());
}

public Vector3f getCameraPosition()
{
    //Viewer position + its height
    Vector3f cameraPos = getViewable().getPosition().clone();
    cameraPos.addY(getViewable().getViewerHeight());
   
    //Camera offset (3rd person view) : move backward from view direction
    if(getCameraOffset() != 0.0f)
        cameraPos = add(cameraPos, multiplyByScaler(getForward(), -cameraOffset));
    return cameraPos;
}

Here is the difference between a normal view and a third person view :

 
Normal vs Third person view

This mode is associated with a terrain.

At the camera location, the camera check the terrain height. If the camera is above the terrain, it should be falling due to gravity (free fall). Fall stop when camera location is equal to terrain height (can't goes throw terrain).
Gravity also take place when jumping.
 

A solid is submit to the gravity force due to his mass m. The fondamentale principle of the dynamic says : sum of the forces applied to a solid equals to the solid mass multiply to its acceleration.

The only force for a free fall is the gravity force (m*g), so we have : m*g = m*acceleration ie acceleration = g
By integrating two times, position = g*t²/2 + v0*t    //v0 : initial speed along vertical direction

Jumping is a free fall. An initial (positive) speed along the vertical direction is applied to an object. This speed will decrease due to the gravity force, and will becomes negative.
 

To implement duck action, I use a factor (heightFactor) applied to the viewer height. Its value goes from 1 (normal state) to 0.5 for a half duck (half percent of the viewer height).

getCameraPosition change

public Vector3f getCameraPosition()
{
    ...
    cameraPos.addY(getViewable().getViewerHeight() * heightFactor);

Value of this factor is change into update method to apply a constant deplacement from normal and duck state :

getCameraPosition change

if(duck)
{
    if(heightFactor > DUCK_FACTOR)
    {
         //Duck
         float factor = heightFactor - heightFactorSpeed * time;
         if(factor < DUCK_FACTOR)
             factor = DUCK_FACTOR;
         heightFactor = factor;
    }
}
else if(heightFactor != 1.0f)
{
    //Un-Duck
    float factor = heightFactor + heightFactorSpeed * time;
    if(factor > 1.0f)
        factor = 1.0f;
    heightFactor = factor;
}

 

Return to Tutorial 26

Last modified on 06/01/2007
Copyright © 2004-2012 Jérôme JOUVIE - All rights reserved. http://jerome.jouvie.free.fr/