Camera Code

Started by jjones7947, July 05, 2005, 23:36:12

Previous topic - Next topic

jjones7947

Have tried a dozen different ways to impliment "camera" code in a separate class.  All results to this point were bizarre. This one comes the closest, but the frame alternately flips when mouse input is supplied. I want to eliminate the rotation about the z axis, which is why I'm using the flatRotate method on rotation about the Y. Can anyone spot my problem?
Using vecmath package.
package core;


/*
 * Created on Jun 7, 2005
 *
 * GameCamera
 */
/**
 * @author Jim Jones
 *
 * Sharp Productions
 */
import java.nio.FloatBuffer;

import javax.vecmath.AxisAngle4f;
import javax.vecmath.Matrix4f;
import javax.vecmath.Vector3f;

import org.lwjgl.BufferUtils;

import utils.TestUtil;



public class GameCamera {
	boolean gMousing = true;
	float gMoveSpeed = 0.1f;
	float gElapseTime;
	double gCurTime;
	double gLastTime = 0.0f;
	Vector3f gEye;
	Vector3f gLook;
	Vector3f tmpLook = new Vector3f();
	Vector3f gUp;
	final Vector3f stdUp = new Vector3f(0.0f, 1.0f, 0.0f);
	Vector3f gRight;
	Vector3f tmpRight = new Vector3f();
	final int FORWARD = 0;
	final int BACKWARD = 1;
	final int RIGHT = 3;
	final int LEFT = 4;
	Matrix4f view;
	FloatBuffer transform;
	Matrix4f matrix = new Matrix4f();
	Matrix4f tMatrix = new Matrix4f();
	float[] matArray = new float[16];
	
	public GameCamera(Vector3f pos) {
		gEye = pos;
		gLook = new Vector3f(0.0f, 0.0f, 1.0f);
		gUp = new Vector3f(0.0f, 1.0f, 0.0f);
		gRight = new Vector3f(1.0f, 0.0f, 0.0f);
		transform = BufferUtils.createFloatBuffer(16);
		updateMatrix();
	}
/**	
	public void handleInput() {
	    if (Keyboard.isKeyDown(Keyboard.KEY_UP)) {
			translateCamera(FORWARD, gElapseTime);
		}   
		if (Keyboard.isKeyDown(Keyboard.KEY_DOWN)) {
			translateCamera(BACKWARD, gElapseTime);
		} 
		if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT)) {
			translateCamera(RIGHT, gElapseTime);
		} 
		if (Keyboard.isKeyDown(Keyboard.KEY_LEFT)) {
			translateCamera(LEFT, gElapseTime);
		}
		float xMove = (float)Mouse.getDX();
		float yMove = (float)Mouse.getDY();
//System.out.println("Mouse X"+ xMove);
//System.out.println("Mouse Y"+ yMove );
		//if((xMove != 0)||(yMove != 0)) {
		//	float xAngle = ((xMove/(float)halfWidth) * halfViewHorz);
		//	float yAngle = ((yMove/(float)halfHeight) * halfViewVert);
		//	mouseRotate(xAngle, yAngle);
		//}
	}
*/	
	public void translateCamera(int flag, float gElapseTime) {
		tmpLook.set(gLook);
		tmpRight.set(gRight);
		if(flag == FORWARD) {
			tmpLook.scale(-gMoveSpeed);
//System.out.println("Scale 1 "+ tmpLook.toString());
			tmpLook.scale(gElapseTime);
//System.out.println("Scale 2 "+ tmpLook.toString());
			gEye.sub(tmpLook);
//System.out.println("gEye "+ gEye.toString());
		} else if(flag == BACKWARD) {
			tmpLook.scale(-gMoveSpeed);
			tmpLook.scale(gElapseTime);
			gEye.add(tmpLook);
		} else if(flag == LEFT) {
			tmpRight.scale(gMoveSpeed);
			tmpRight.scale(gElapseTime);
			gEye.sub(tmpRight);
		} else if(flag == RIGHT) {
			tmpRight.scale(gMoveSpeed);
			tmpRight.scale(gElapseTime);
			gEye.add(tmpRight);
		}
	}
	
	public void mouseRotate(float xAngle, float yAngle) {
System.out.println("mouseRot X "+xAngle+" Y "+yAngle);
		if(gMousing == false) {
			return;
		}
		if(yAngle != 0) {
			float rad = (float)Math.toRadians(yAngle);
			matrix.set(new AxisAngle4f(gRight, rad));
			matrix.transform(gLook);
			matrix.transform(gRight);
			gUp.cross(gLook, gRight);
		}
		if(xAngle != 0) {
			float rad = (float)Math.toRadians(yAngle);
			matrix.set(new AxisAngle4f(stdUp, rad));
			gLook = flatRotate(gLook);
			//gLook.normalize();
			gRight = flatRotate(gRight);
			gRight.normalize();
			gUp.cross(gLook, gRight);
		}
	}
	
	public Vector3f flatRotate(Vector3f v) {
		Vector3f tmp = new Vector3f(v.x, 0.0f, v.z);
		matrix.transform(tmp);
		return(new Vector3f(tmp.x, v.y, tmp.z));
	}
	
	public void updateMatrix() {
		gLook.normalize();
		TestUtil.printVector("gLook", gLook);
		gRight.cross(gLook, gUp);
		TestUtil.printVector("gRight", gRight);
		gRight.normalize();
		gUp.cross(gRight, gLook);
		TestUtil.printVector("gUp", gUp);
		gUp.normalize();
		matArray[0] = gRight.x;
		matArray[1] = gUp.x;
		matArray[2] = -gLook.x;
		matArray[3] = 0.0f;
		matArray[4] = gRight.y;
		matArray[5] = gUp.y;
		matArray[6] = -gLook.y;
		matArray[7] = 0.0f;
		matArray[8] = gRight.z;
		matArray[9] = gUp.z;
		matArray[10] = -gLook.z;
		matArray[11] = 0.0f;
		matArray[12] = -gRight.dot(gEye);
		matArray[13] = -gUp.dot(gEye);
		matArray[14] = gLook.dot(gEye);
		matArray[15] = 1.0f;
	}
	
	public FloatBuffer getMatrix() {
		transform.put(matArray);
		return((FloatBuffer)transform.rewind());
	}
}

Thanks,
Jim

Funkapotamus

Sorry for the size guys!  (is there any way to make the code fit in it's own textbox?)

move(float speed) - Move the camera where it's looking.
strafe(float speed) - Strafe left/right and maintain the camera's current look.

You can get some nifty things by messing with strafe();
For example, if you remove the part where it updates the target vector you'll get automatic circlestrafing around a point.

And if you mess with "currentXRot -= angleZ;" that in getMouseAngle() you can give the camera the option of flipping upsidedown- useful for flight sim games.

All the math functions should be self explanitory.  The exception is "crappyNormalize()"- which you should just assume a plain normalize.  I was messing with some equations and ended up with two normalize methods.  One was crappier than the other so hence "crappyNormalize" :)  I used it because it was faster though.  This code is old- I havn't gotten around to updating things.

import org.jon.crs.util.FunkMath;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.glu.GLU;

public final class Camera3D
{
	public static final float FOV = 80.0f;
	
	private Vector3D origin = new Vector3D();
	private Vector3D target = new Vector3D();
	private Vector3D upVector = new Vector3D();
	private Vector3D strafe = new Vector3D();

	private boolean inverted = false;
	private float sensitivity = 750.0f;

	private float currentXRot = 0.0f;
	
	public Camera3D()
	{}

	public void setOrigin(Vector3D origin, Vector3D target, Vector3D upVector)
	{
		// I'm copying things here just because it's safer.  It's also easier to send vectors rather than points.
		this.origin.copy(origin);
		this.target.copy(target);
		this.upVector.copy(upVector);
	}

	public void update() 
	{
		// Normalize the strafe vector.
		strafe = FunkMath.crossProduct(FunkMath.subtract(target, origin), upVector);
		strafe.crappyNormalize();

		// Update view based on mouse.
		getMouseAngle();
	}
	
	public void look()
	{
		// Camera Position, Direction the Camera's looking, "Up"
		GLU.gluLookAt(origin.x, origin.y, origin.z,	target.x, target.y, target.z, upVector.x, upVector.y, upVector.z);
	}
		
	public void move(float speed)
	{
		origin.x += (target.x - origin.x) * speed;
		origin.y += (target.y - origin.y) * speed;
		origin.z += (target.z - origin.z) * speed;
		
		target.x += (target.x - origin.x) * speed;
		target.y += (target.y - origin.y) * speed;
		target.z += (target.z - origin.z) * speed;
	}
		
	public void strafe(float speed)
	{
		// Add strafe vector to origin & target.		
		origin.x += strafe.x * speed;
		origin.z += strafe.z * speed;

		target.x += strafe.x * speed;
		target.z += strafe.z * speed;
	}
	
	public void setInverted(boolean inverted)
	{
		this.inverted = inverted;
	}
	
	public void setSensitivity(float sensitivity)
	{
		this.sensitivity = sensitivity;
	}
	
	public Vector3D getOrigin()
	{
		return origin;
	}
	
	public Vector3D getTarget()
	{
		return target;
	}
		
	private void getMouseAngle()
	{
		float angleY = 0.0f;
		float angleZ = 0.0f;
		final Vector3D axis;

		// Get the direction the mouse moved in, and bring it down to a reasonable amount.
		angleY = -(float)(Mouse.getDX()) / sensitivity;
		angleZ = (float)(Mouse.getDY()) / sensitivity;

		// If mouse is inverted, invert rotation on Z axis.
		if(inverted)
			angleZ = -angleZ;

		// Keep track of the current X Rotation so the camera can't do a full loop.
		// TODO Mess with this so looping is possible (fly like an old lerk in NS).
		currentXRot -= angleZ;

		// Cap the X Rotation within 1 radian (+/- 90 degrees)
		if(currentXRot > 1.0f)
			currentXRot = 1.0f;
		else if(currentXRot < -1.0f)
			currentXRot = -1.0f;
		else
		{
			axis = FunkMath.crossProduct(FunkMath.subtract(target, origin), upVector);
			axis.crappyNormalize();

			// Rotate Z and Y axis.
			rotate(angleZ, axis.x, axis.y, axis.z);
			rotate(angleY, 0, 1, 0);
		}
	}

	private void rotate(float angle, float x, float y, float z)
	{
		Vector3D newTarget = new Vector3D();
		Vector3D currentTarget = new Vector3D();	

		// Get the current facing direction
		currentTarget.x = target.x - origin.x;
		currentTarget.y = target.y - origin.y;
		currentTarget.z = target.z - origin.z;

		// Store Sin/Cos
		float cosTheta = (float)Math.cos(angle);
		float sinTheta = (float)Math.sin(angle);

		newTarget.x  = (cosTheta + (1 - cosTheta) * x * x)		* currentTarget.x;
		newTarget.x += ((1 - cosTheta) * x * y - z * sinTheta)	* currentTarget.y;
		newTarget.x += ((1 - cosTheta) * x * z + y * sinTheta)	* currentTarget.z;

		newTarget.y  = ((1 - cosTheta) * x * y + z * sinTheta)	* currentTarget.x;
		newTarget.y += (cosTheta + (1 - cosTheta) * y * y)		* currentTarget.y;
		newTarget.y += ((1 - cosTheta) * y * z - x * sinTheta)	* currentTarget.z;

		newTarget.z  = ((1 - cosTheta) * x * z - y * sinTheta)	* currentTarget.x;
		newTarget.z += ((1 - cosTheta) * y * z + x * sinTheta)	* currentTarget.y;
		newTarget.z += (cosTheta + (1 - cosTheta) * z * z)		* currentTarget.z;

		target.x = origin.x + newTarget.x;
		target.y = origin.y + newTarget.y;
		target.z = origin.z + newTarget.z;
	}
}

jjones7947

Thanks,
I'll run some compares and see if I can figure out the diffs.
Jim