Skip to content

Instantly share code, notes, and snippets.

@bsjohnson
Last active December 19, 2015 01:39
Show Gist options
  • Save bsjohnson/26cbd6d01583c4cbc871 to your computer and use it in GitHub Desktop.
Save bsjohnson/26cbd6d01583c4cbc871 to your computer and use it in GitHub Desktop.
A work in progress for a LWJGL camera class. Still working through rolling issues.
package com.p2s.game;
import java.nio.FloatBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Quaternion;
import org.lwjgl.util.vector.Vector3f;
import org.lwjgl.util.vector.Vector4f;
public class Camera{
private final static float DEGTORAD = (float)(Math.PI/180);
private static final Vector3f GLOBAL_UP = new Vector3f(0, 1, 0);
private Vector3f eye;
private Vector3f up;
private Vector3f right;
private Vector3f direction;
private float pitchAngle;
private float bearingAngle;
private float rollAngle;
private Quaternion pitch;
private Quaternion bearing;
private Quaternion roll;
private Quaternion change;
private Matrix4f rotation;
private FloatBuffer viewMatrixBuffer = BufferUtils.createFloatBuffer(16);
public Camera(){
this(new Vector3f(0,0,0),0,0,0);
}
/**
* Constructor with initial direction values
* @param initialBearing
* @param initialPitch
* @param initialRoll
*/
public Camera(Vector3f eyePos, float initialBearing, float initialPitch, float initialRoll){
pitch = new Quaternion();
bearing = new Quaternion();
roll = new Quaternion();
change = new Quaternion();
rotation = new Matrix4f();
bearingAngle = initialBearing;
pitchAngle = initialPitch;
rollAngle = initialRoll;
this.eye = new Vector3f(eyePos);
direction = new Vector3f(1,0,0);
right = new Vector3f(1,0,0);
up = new Vector3f(0,1,0);
reorient();
}
/**
* This should be called whenever pitch, bearing, or roll is changed
* to recalculate the matrix
*/
public void reorient(){
//Multiply in order: roll, bearing, pitch.
Quaternion.mul(Quaternion.mul(roll, bearing, change), pitch, change);
change.normalise();
// Update the rotation matrix with the change quaternion.
updateRotationMatrix(change);
//Translate the rotation matrix to the position where the eye has moved.
//Set the direction vector to know our orientation.
direction.x = rotation.m20;
direction.y = rotation.m21;
direction.z = rotation.m22;
direction.normalise();
rotation.invert();
rotation.store(viewMatrixBuffer);
viewMatrixBuffer.rewind();
//Update our right and up orientation vectors.
Vector3f.cross(GLOBAL_UP, direction, null).normalise(right);
Vector3f.cross(right, direction, null).normalise(up);
}
/**
* Change the bearing (yaw)
* @param bearing delta in degrees
*/
public void bearing(float bearingDelta){
bearingAngle += bearingDelta;
if(bearingAngle > 360){
bearingAngle -= 360;
}else if(bearingAngle < 0){
bearingAngle += 360;
}
bearing.setFromAxisAngle(new Vector4f(0f, 1f, 0f, bearingAngle * DEGTORAD));
bearing.normalise();
}
/**
* Change the pitch
* @param pitch delta in degrees
*/
public void pitch(float pitchDelta){
pitchAngle += pitchDelta;
if(pitchAngle > 360){
pitchAngle -= 360;
}else if(pitchAngle < 0){
pitchAngle += 360;
}
pitch.setFromAxisAngle(new Vector4f(1f, 0f, 0f, pitchAngle * DEGTORAD));
pitch.normalise();
}
/**
* @param rollDelta
*/
public void roll(float rollDelta) {
rollAngle += rollDelta;
if(rollAngle > 360){
rollAngle -= 360;
}else if(rollAngle < 0){
rollAngle += 360;
}
roll.setFromAxisAngle(new Vector4f(direction.x, direction.y, direction.z, rollAngle * DEGTORAD));
roll.normalise();
}
/**
* Change direction to focus on a certain point in the world
* @param eye
*/
public void lookThrough(){
reorient();
GL11.glMultMatrix(viewMatrixBuffer);
}
/**
* Move in the direction of view by a certain amount
* @param units
*/
public void move(float units){
eye.x += direction.x * units;
eye.y += direction.y * units;
eye.z += direction.z * units;
}
/**
* Move side to side
* @param units
*/
public void strafe(float units){
// If roll is implemented, up needs to be calculated.
Vector3f cross = Vector3f.cross(direction, up, null);
eye.x += cross.x * units;
eye.y += cross.y * units;
eye.z += cross.z * units;
}
public void elevate(float units) {
//If roll is implemented, right needs to be calculated.
Vector3f cross = Vector3f.cross(direction, right, null);
eye.x += cross.x * units;
eye.y += cross.y * units;
eye.z += cross.z * units;
}
private Matrix4f updateRotationMatrix(Quaternion q){
float xx = q.x * q.x;
float yy = q.y * q.y;
float zz = q.z * q.z;
float xy = q.x * q.y;
float yz = q.y * q.z;
float xz = q.x * q.z;
float xw = q.x * q.w;
float yw = q.y * q.w;
float zw = q.z * q.w;
rotation.m00 = 1.0f - (2.0f * (yy + zz));
rotation.m01 = 2.0f * (xy + zw);
rotation.m02 = 2.0f * (xz - yw);
rotation.m03 = 0;
// Second row
rotation.m10 = 2.0f * (xy - zw);
rotation.m11 = 1.0f - (2.0f * (xx + zz));
rotation.m12 = 2.0f * (yz + xw);
rotation.m13 = 0;
// Third row
rotation.m20 = 2.0f * (xz + yw);
rotation.m21 = 2.0f * (yz - xw);
rotation.m22 = 1.0f - (2.0f * (xx + yy));
rotation.m23 = 0;
// Fourth row
//rotation.m30 = 0;
//rotation.m31 = 0;
//rotation.m32 = 0;
//rotation.m33 = 1.0f;
rotation.m30 = eye.x;
rotation.m31 = eye.y;
rotation.m32 = eye.z;
rotation.m33 = 1;
return rotation;
}
public Vector3f getLookingAt(){
return Vector3f.add(eye, direction, null);
}
/**
* @return the camera's position in the world
*/
public Vector3f getEye(){
return eye;
}
/**
* Place camera at a certain position
* @param position
*/
public void setEye(Vector3f eye){
this.eye = new Vector3f(eye);
}
public Vector3f getDirection(){
return direction;
}
public float getPitchAngle() {
return pitchAngle;
}
public float getBearingAngle() {
return bearingAngle;
}
public float getRollAngle(){
return rollAngle;
}
public String toString(){
StringBuilder value = new StringBuilder(this.getClass().getSimpleName());
value.append("[Eye=").append(eye.x).append(",").append(eye.y)
.append(",").append(eye.z).append(" :: B=").append(bearingAngle)
.append(" :: P=").append(pitchAngle).append(" :: R=").append(rollAngle).append(" :: D=").append(direction.x)
.append(",").append(direction.y).append(",").append(direction.z).append("]");
return value.toString();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment