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
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;
}
}
Thanks,
I'll run some compares and see if I can figure out the diffs.
Jim