FPS Camera Algorithm

Posted: January 9, 2010 in Game Programming, Java, Programming
Tags: , , , ,

This is my FPS camera class for my application in computer graphics lecture. Oh yeah, i’m using Java and OpenGL (jOGL)

Camera object is used to store coordinate information and direction of viewing. Object camera has three normal vectors as a constituent component of direction-vector, up-vector, and right-vector. This third vector perpendicular to each other.

In order for viewing camera seemed to move around, over or away from terrain object is using rotation and translation of three vectors cameras mentioned above.

There are six process of camera rotation and translation as follows:

a. Rotation of right-vector (x-axis)
To perform rotation of right-vector is to transform up-vector and direction-vector. Since every of three vectors perpendicular to each other so we just need to find a new vector position of direction-vector with rotation of alpha value and then we get new value of up-vector by multiplying right-vector and direction-vector using cross product.
To find value of new direction-vector using principle of vector addition and subtraction as follows:
vectorDir = vectorDir * cos (alpha) + vectorUp * sin (alpha)
vectorUp = crossProduct (vectorDir, vectorRight)

b. Rotation of up-vector (y-axis)
To perform rotation of up-vector is to transform right-vector and direction-vector. Since every of three vectors perpendicular to each other so we just need to find a new vector position of direction-vector with rotation of alpha value and then we get value of new right-vector by multiplying up-vector and direction vector using cross product.
To find value of new direction-vector using principle vector addition and subtraction as follows:
vectorDir = vectorRight * sin (alpha) – vectorDir * cos (alpha)
vectorRight = crossProduct (vectorDir, vectorUp)

c. Rotation of direction-vector (z-axis camera)
To perform vector rotation of direction-vector is to transform up-vector and right-vector. Since every of three vectors perpendicular to each other so we just need to find a new vector position of right-vector by rotation of alpha value and then we get new value of up-vector by multiplying right-vector and up-vector using cross product.
To find value of new direction-vector used principle of vector addition and subtraction as follows:
vectorRight = vectorRight * cos (alpha) + vectorUp * sin (alpha)
vectorUp = crossProduct (vectorDir, vectorRight)

d. Right-left Translation (x-axis camera)
Add right-vector with distance value.

e. Up-down Translation (y-axis camera)
Add up-vector with distance value.

f. Forward-backward Translation (z-axis camera)
Subtract direction-vector with distance value.

Here’s the code :

Vector3.java


public class Vector3
{
    public float X;
    public float Y;
    public float Z;

    public Vector3()
    {
        X = 0.0f;
        Y = 0.0f;
        Z = 0.0f;
    }

    public Vector3(float X, float Y, float Z)
    {
        this.X = X;
        this.Y = Y;
        this.Z = Z;
    }

    public Vector3 getInverse()
    {
        return new Vector3(-X, -Y, -Z);
    }

    public float getLength()
    {
        return (float)Math.sqrt((X * X) + (Y * Y) + (Z * Z));
    }

    public Vector3 getNormal()
    {
        float l = getLength();

        if(l == 0.0f)
            return null;

        return new Vector3(X / l, Y / l, Z / l);
    }
}

VectorUtils.java


public class VectorUtils
{
    public VectorUtils()
    {
    }

    public Vector3 Vector3Addition(Vector3 u, Vector3 v)
    {
        Vector3 w = new Vector3();

        w.X = u.X + v.X;
        w.Y = u.Y + v.Y;
        w.Z = u.Z + v.Z;

        return w;
    }

    public Vector3 Vector3Substraction(Vector3 u, Vector3 v)
    {
        Vector3 w = new Vector3();

        w.X = v.X - u.X;
        w.Y = v.Y - u.Y;
        w.Z = v.Z - u.Z;

        return w;
    }

    public Vector3 Vector3Multiplication(Vector3 u, float r)
    {
        Vector3 w = new Vector3();

        w.X = u.X * r;
        w.Y = u.Y * r;
        w.Z = u.Z * r;

        return w;
    }

    public Vector3 Vector3CrossProduct(Vector3 u, Vector3 v)
    {
        Vector3 w = new Vector3();

        w.X = u.Y * v.Z - u.Z * v.Y;
        w.Y = u.Z * v.X - u.X * v.Z;
        w.Z = u.X * v.Y - u.Y * v.X;

        return w;
    }

    public float Vector3DotProduct(Vector3 u, Vector3 v)
    {
        return (v.X * u.X) + (v.Y * u.Y) + (v.Z * u.Z);
    }

}

Camera.java


public class Camera
{
    Vector3 origViewDir = new Vector3();
    Vector3 origRightVector = new Vector3(;
    Vector3 origUpVector = new Vector3();
    Vector3 origPosition = new Vector3();

    Vector3 viewDir;
    Vector3 rightVector;
    Vector3 upVector;
    Vector3 position;

    float rotatedX;
    float rotatedY;
    float rotatedZ;

    float PiDiv180 = (float)Math.PI / 180.0f;

    VectorUtils vectorUtils = new VectorUtils();

    public Camera()
    {
        reset();
    }

    public void reset()
    {
        viewDir = origViewDir;
        rightVector = origRightVector;
        upVector = origUpVector;
        position = origPosition;
        viewDir = viewDir.getNormal();

        rotatedX = 0.0f;
        rotatedY = 0.0f;
        rotatedZ = 0.0f;
    }

    public void move(Vector3 direction)
    {
        position = vectorUtils.Vector3Addition(position, direction);
    }

    public void rotateX(float angle)
    {
        rotatedX += angle;

        Vector3 temp1 = vectorUtils.Vector3Multiplication(viewDir, (float)Math.cos(angle * PiDiv180));
        Vector3 temp2 = vectorUtils.Vector3Multiplication(upVector, (float)Math.sin(angle * PiDiv180));

        viewDir = vectorUtils.Vector3Addition(temp1, temp2).getNormal();
        upVector = vectorUtils.Vector3Multiplication(vectorUtils.Vector3CrossProduct(viewDir, rightVector), -1.0f);
    }

    public void rotateY(float angle)
    {
        rotatedY += angle;

        Vector3 temp1 = vectorUtils.Vector3Multiplication(viewDir, (float)Math.cos(angle * PiDiv180));
        Vector3 temp2 = vectorUtils.Vector3Multiplication(rightVector, (float)Math.sin(angle * PiDiv180));

        viewDir = vectorUtils.Vector3Substraction(temp2, temp1);
        viewDir = viewDir.getNormal();
        rightVector = vectorUtils.Vector3CrossProduct(viewDir, upVector);
    }

    public void rotateZ(float angle)
    {
        rotatedZ += angle;

        Vector3 temp1 = vectorUtils.Vector3Multiplication(rightVector, (float)Math.cos(angle * PiDiv180));
        Vector3 temp2 = vectorUtils.Vector3Multiplication(upVector, (float)Math.sin(angle * PiDiv180));

        rightVector = vectorUtils.Vector3Addition(temp1, temp2).getNormal();
        upVector = vectorUtils.Vector3Multiplication(vectorUtils.Vector3CrossProduct(viewDir, rightVector), -1.0f);
    }

    public void moveForward(float distance)
    {
        position = vectorUtils.Vector3Addition(position, vectorUtils.Vector3Multiplication(viewDir, -distance));
    }

    public void strafeRight(float distance)
    {
        position = vectorUtils.Vector3Addition(position, vectorUtils.Vector3Multiplication(rightVector, distance));
    }

    public void moveUpward(float distance)
    {
        position = vectorUtils.Vector3Addition(position, vectorUtils.Vector3Multiplication(upVector, distance));
    }

    public Vector3 getCameraPosition()
    {
        return position;
    }

    public Vector3 getCameraTarget()
    {
        return vectorUtils.Vector3Addition(position, viewDir);
    }

    public Vector3 getUpVector()
    {
        return upVector;
    }

}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s