So, I don't really know how to explain the problem I'm currently having too well, but I know it involves the model/view/projection matrices for drawing a cube. I have imported a cube from blender and now I'm trying to create a camera system to view from different angles. I first applied scaling, rotation, and translation to the cube sent this matrix to my vertex shader class, and the cube appears where it should, with the correct size, and is rotating in whatever direction I give it. The next step was setting up the camera view, so I multiplied the current world coordinates of the cube by the a view matrix so I can move the "camera" and look from different directions. So now I have camera coordinates and everything looks as it should. The cube is still spinning and when I change "camera" the cube rotates in the direction it should. So finally, when I add the projection matrix to the shader, everything looks like it works... initially. However, I notice that the cube doesn't seem to look correct anymore. I can now rotate/move the camera, but the cube looks morphed in a way that some of the faces are not square shaped. Now the weird thing is that if I get really close to the cube, it's almost as if all the colors that are on the outside go on the inside and you can see a perfect cube shape. Here is a link to what it's doing since that's probably really hard to understand: http://youtu.be/QHY7ZVADeiQ. Below is the code I use to transform the cube (ModelTransformation), the code for the camera class, and how my vertex shader is set. Any ideas would be greatly appreciated. And I apologize for the huge code blocks.
ModelTransformation class:
package engine;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;
public class ModelTransformation {
private static Matrix4f identity;
private static Matrix4f scaleMatrix;
private static Matrix4f rotationMatrix;
private static Matrix4f translationMatrix;
public ModelTransformation(){
scaleMatrix = new Matrix4f();
rotationMatrix = new Matrix4f();
translationMatrix = new Matrix4f();
}
public Matrix4f getScaleMatrix(){
return scaleMatrix;
}
public void setScaleMatrix(Vector3f axis){
Matrix4f.setIdentity(scaleMatrix);
Matrix4f.scale(axis, scaleMatrix, scaleMatrix);
}
public Matrix4f getRotationMatrix(){
return rotationMatrix;
}
public void setRotationMatrix(Vector3f amount){
Matrix4f.setIdentity(rotationMatrix);
if(amount.x == 0 && amount.y == 0 && amount.z == 0)
return;
else{
Matrix4f.rotate(amount.z, new Vector3f (0, 0, 1), rotationMatrix, rotationMatrix);
Matrix4f.rotate(amount.y, new Vector3f (0, 1, 0), rotationMatrix, rotationMatrix);
Matrix4f.rotate(amount.x, new Vector3f (1, 0, 0), rotationMatrix, rotationMatrix);
}
}
public Matrix4f getTranslationMatrix(){
return translationMatrix;
}
public void setTranslationMatrix(Vector3f axis) {
Matrix4f.setIdentity(translationMatrix);
Matrix4f.translate(axis, translationMatrix, translationMatrix);
}
public Matrix4f getTransformationMatrix() {
return Matrix4f.mul(translationMatrix, Matrix4f.mul(rotationMatrix, scaleMatrix, null), null);
}
}
Camera class:
package engine;
import org.lwjgl.input.Keyboard;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;
public class Camera {
private float fov;
private float aspect;
private float zNear;
private float zFar;
private Vector3f position;
private Vector3f rotation;
private Vector3f xAxis;
private Vector3f yAxis;
private Vector3f zAxis;
private Matrix4f viewMatrix;
private Matrix4f viewTranslationMatrix;
private Matrix4f viewRotationMatrix;
private Matrix4f projectionMatrix;
public Camera(float fov, float aspect, float zNear, float zFar){
this.fov = fov;
this.aspect = aspect;
this.zNear = zNear;
this.zFar = zFar;
position = new Vector3f(0, 0, 0);
rotation = new Vector3f(0, 0, 0);
xAxis = new Vector3f(1, 0, 0);
yAxis = new Vector3f(0, 1, 0);
zAxis = new Vector3f(0, 0, 1);
viewMatrix = new Matrix4f();
viewTranslationMatrix = new Matrix4f();
viewRotationMatrix = new Matrix4f();
projectionMatrix = new Matrix4f();
}
public Matrix4f getViewMatrix(){
viewMatrix.setIdentity();
rotateCamera();
translateCamera();
viewMatrix = Matrix4f.mul(viewRotationMatrix, viewTranslationMatrix, null);
return viewMatrix;
}
public void rotateCamera(){
viewRotationMatrix.setIdentity();
Matrix4f.rotate((float) Math.toRadians(rotation.x), xAxis, viewRotationMatrix, viewRotationMatrix);
Matrix4f.rotate((float) Math.toRadians(rotation.y), yAxis, viewRotationMatrix, viewRotationMatrix);
Matrix4f.rotate((float) Math.toRadians(rotation.z), zAxis, viewRotationMatrix, viewRotationMatrix);
}
public void translateCamera(){
viewTranslationMatrix.setIdentity();
Matrix4f.translate(position, viewTranslationMatrix, viewTranslationMatrix);
}
public Matrix4f getProjectionMatrix(){
projectionMatrix.setIdentity();
float tanFOV = (float)Math.tan(Math.toRadians(fov / 2));
float zRange = (zFar - zNear);
projectionMatrix.m00 = ((1 / tanFOV) / aspect); projectionMatrix.m10 = 0; projectionMatrix.m20 = 0; projectionMatrix.m30 = 0;
projectionMatrix.m01 = 0; projectionMatrix.m11 = ((1 / tanFOV)); projectionMatrix.m21 = 0; projectionMatrix.m31 = 0;
projectionMatrix.m02 = 0; projectionMatrix.m12 = 0; projectionMatrix.m22 = -((zFar + zNear) / zRange); projectionMatrix.m32 = -((2 * zFar * zNear) / zRange);
projectionMatrix.m03 = 0; projectionMatrix.m13 = 0; projectionMatrix.m23 = -1; projectionMatrix.m33 = 0;
return projectionMatrix;
}
public void input() {
if (Input.isKeyDown(Keyboard.KEY_UP))
addRotation(-1f, 0, 0);
if (Input.isKeyDown(Keyboard.KEY_DOWN))
addRotation(1f, 0, 0);
if (Input.isKeyDown(Keyboard.KEY_LEFT))
addRotation(0, -1f, 0);
if (Input.isKeyDown(Keyboard.KEY_RIGHT))
addRotation(0, 1f, 0);
if (Input.isKeyDown(Keyboard.KEY_W))
move(0.01f, 1);
if (Input.isKeyDown(Keyboard.KEY_S))
move(-0.01f, 1);
if (Input.isKeyDown(Keyboard.KEY_A))
move(0.01f, 0);
if (Input.isKeyDown(Keyboard.KEY_D))
move(-0.01f, 0);
if(Input.isKeyDown(Keyboard.KEY_SPACE))
position.y -= 0.01f;
if(Input.isKeyDown(Keyboard.KEY_LSHIFT))
position.y += 0.01f;
}
private void addRotation(float rx, float ry, float rz) {
rotation.x += rx;
rotation.y += ry;
rotation.z += rz;
}
public void move(float amount, float direction){
position.z += amount * Math.sin(Math.toRadians(rotation.y + 90 * direction));
position.x += amount * Math.cos(Math.toRadians(rotation.y + 90 * direction));
}
}
Vertex Shader:
#version 430
in vec3 position;
out vec4 color;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
void main(){
vec4 worldCoord = modelMatrix * vec4(position.xyz, 1.0);
vec4 cameraCoord = viewMatrix * worldCoord;
vec4 homogeneousCoord = projectionMatrix * cameraCoord;
color = vec4(clamp(position, 0.0, 1.0), 1.0);
gl_Position = homogeneousCoord;
}
Edit: Added some more classes that might help and added more tags
RenderUtility class:
public class RenderUtility {
//clearScreen - clears the screen with the color buffer bit and depth buffer bit
//then loads the identity projection matrix
public static void clearScreen(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
}
//Determines how the game is going to run
public static void initilizeGraphics(){
glMatrixMode(GL_PROJECTION);
glClearColor(0, 0, 0, 0);
glFrontFace(GL_CW);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_FRAMEBUFFER_SRGB);
}
//getOpenGLVersion - returns the currently used version of OpenGL
public static String getOpenGLVersion(){
return glGetString(GL_VERSION);
}
}
Game Class:
public class Game {
private static ShaderProgram program;
private static Model model2;
private static ModelTransformation transformation;
private static Camera camera;
private static Transformation transform;
private static float temp = 0.0f;
// Game - creates the program for the shaders
// Creates the entities necessary for the game
public Game() {
camera = new Camera(70, Window.getWidth()/Window.getHeight(), 0.001f, 100f);
program = new ShaderProgram();
program.addVertexShaderFrom("rsc/shaders/shader.vertex");
program.addFragmentShaderFrom("rsc/shaders/shader.fragment");
program.linkAndValidateProgram();
program.addUniform("modelMatrix");
program.addUniform("viewMatrix");
program.addUniform("projectionMatrix");
transform = new Transformation();
transformation = new ModelTransformation();
model2 = new Model("rsc/box3.obj");
}
// render - renders all items used in the game
// This is where shaders are implemented
public void render() {
program.useShaders();
program.setUniform("viewMatrix", camera.getViewMatrix());
program.setUniform("modelMatrix", transformation.getTransformationMatrix());
program.setUniform("projectionMatrix", camera.getProjectionMatrix());
model2.draw();
program.stopUsingShaders();
}
// input - takes input from keyboard/mouse and do something useful
public static void input(List<Integer> currentKeys, List<Integer> currentMouseButtons, Vector2f mouseLocation) {
// TODO: Add what each input button/key should accomplish
camera.input();
}
// update - updates values using the time difference between frames
public void update(double deltaTime) {
temp += deltaTime;
float sinTemp = 90 * (float)Math.sin(Math.toRadians(temp));
float cosTemp = (float)Math.cos(Math.toRadians(temp));
transformation.setTranslationMatrix(new Vector3f(0f, 0f, -3));
transformation.setRotationMatrix(new Vector3f(sinTemp, 0, sinTemp));
transformation.setScaleMatrix(new Vector3f(1f, 1f, 1f));
}
}