[DEV] tutorial 8 'camera and projection' implementation

This commit is contained in:
Edouard DUPIN 2020-04-19 01:06:31 +02:00
parent 5d2acb70c7
commit 201eacbd69
9 changed files with 419 additions and 68 deletions

View File

@ -1,6 +1,10 @@
package engineTester;
import javax.vecmath.Vector3f;
import entities.Camera;
import entities.Entity;
import models.RawModel;
import models.TexturedModel;
import renderEngine.DisplayManager;
@ -29,38 +33,127 @@ public class MainGameLoop {
DisplayManager manager = new DisplayManager();
Loader loader = new Loader();
Renderer renderer = new Renderer();
manager.init();
StaticShader shader = new StaticShader();
Renderer renderer = new Renderer(shader);
float[] vertices = {
-0.5f, 0.5f, 0f,//v0
-0.5f, -0.5f, 0f,//v1
0.5f, -0.5f, 0f,//v2
0.5f, 0.5f, 0f,//v3
// float[] vertices = {
// -0.5f, 0.5f, 0f,//v0
// -0.5f, -0.5f, 0f,//v1
// 0.5f, -0.5f, 0f,//v2
// 0.5f, 0.5f, 0f,//v3
// };
// float[] textureCoords = {
// 0.0f, 0.0f,//v0
// 0.0f, 1.0f,//v1
// 1.0f, 1.0f,//v2
// 1.0f, 0.0f,//v3
// };
//
// int[] indices = {
// 0,1,3,//top left triangle (v0, v1, v3)
// 3,1,2//bottom right triangle (v3, v1, v2)
// };
//
float[] vertices = {
-0.5f,0.5f,-0.5f,
-0.5f,-0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,0.5f,-0.5f,
-0.5f,0.5f,0.5f,
-0.5f,-0.5f,0.5f,
0.5f,-0.5f,0.5f,
0.5f,0.5f,0.5f,
0.5f,0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,-0.5f,0.5f,
0.5f,0.5f,0.5f,
-0.5f,0.5f,-0.5f,
-0.5f,-0.5f,-0.5f,
-0.5f,-0.5f,0.5f,
-0.5f,0.5f,0.5f,
-0.5f,0.5f,0.5f,
-0.5f,0.5f,-0.5f,
0.5f,0.5f,-0.5f,
0.5f,0.5f,0.5f,
-0.5f,-0.5f,0.5f,
-0.5f,-0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,-0.5f,0.5f
};
float[] textureCoords = {
0.0f, 0.0f,//v0
0.0f, 1.0f,//v1
1.0f, 1.0f,//v2
1.0f, 0.0f,//v3
0,0,
0,1,
1,1,
1,0,
0,0,
0,1,
1,1,
1,0,
0,0,
0,1,
1,1,
1,0,
0,0,
0,1,
1,1,
1,0,
0,0,
0,1,
1,1,
1,0,
0,0,
0,1,
1,1,
1,0
};
int[] indices = {
0,1,3,//top left triangle (v0, v1, v3)
3,1,2//bottom right triangle (v3, v1, v2)
0,1,3,
3,1,2,
4,5,7,
7,5,6,
8,9,11,
11,9,10,
12,13,15,
15,13,14,
16,17,19,
19,17,18,
20,21,23,
23,21,22
};
RawModel model = loader.loadToVAO(vertices, textureCoords, indices);
ModelTexture texture = new ModelTexture(loader.loadTexture("tree_sample"));
TexturedModel texturedModel = new TexturedModel(model, texture);
TexturedModel staticModel = new TexturedModel(model, texture);
Entity entity = new Entity(staticModel, new Vector3f(0,0,-2), new Vector3f(0,0,0), 1);
Camera camera = new Camera();
manager.setDrawer(new DisplayManagerDraw() {
@Override
public void draw() {
//entity.increasePosition(0.0f, 0, -0.01f);
//entity.increaseRotation(0, 0, 0.01f);
entity.increaseRotation(0.01f, 0.01f, 0.0f);
camera.move();
renderer.prepare();
shader.start();
renderer.render(texturedModel);
shader.loadViewMatrix(camera);
renderer.render(entity, shader);
shader.stop();
}
});

46
src/entities/Camera.java Normal file
View File

@ -0,0 +1,46 @@
package entities;
import javax.vecmath.Vector3f;
import renderEngine.DisplayManager;
public class Camera {
private Vector3f position = new Vector3f(0,0,0);
private float pitch;
private float yaw;
private float roll;
public Camera() {
}
public void move() {
if (DisplayManager.isKeyDown('z')) {
position.x -= 0.02f;
}
if (DisplayManager.isKeyDown('s')) {
position.x += 0.02f;
}
if (DisplayManager.isKeyDown('d')) {
position.y -= 0.02f;
}
if (DisplayManager.isKeyDown('q')) {
position.y += 0.02f;
}
}
public Vector3f getPosition() {
return position;
}
public float getPitch() {
return pitch;
}
public float getYaw() {
return yaw;
}
public float getRoll() {
return roll;
}
}

58
src/entities/Entity.java Normal file
View File

@ -0,0 +1,58 @@
package entities;
import javax.vecmath.Vector3f;
import models.TexturedModel;
public class Entity {
private TexturedModel model;
private Vector3f position;
private Vector3f rotation;
private float scale;
public Entity(TexturedModel model, Vector3f position, Vector3f rotation, float scale) {
this.model = model;
this.position = position;
this.rotation = rotation;
this.scale = scale;
}
public void increasePosition(float dx, float dy, float dz) {
this.position = new Vector3f(position.x + dx, position.y + dy, position.z + dz);
}
public void increasePosition(Vector3f delta) {
this.position = new Vector3f(position.x + delta.x, position.y + delta.y, position.z + delta.z);
}
public void increaseRotation(float dx, float dy, float dz) {
this.rotation = new Vector3f(rotation.x + dx, rotation.y + dy, rotation.z + dz);
}
public void increaseRotation(Vector3f delta) {
this.rotation = new Vector3f(rotation.x + delta.x, rotation.y + delta.y, rotation.z + delta.z);
}
public TexturedModel getModel() {
return model;
}
public void setModel(TexturedModel model) {
this.model = model;
}
public Vector3f getPosition() {
return position;
}
public void setPosition(Vector3f position) {
this.position = position;
}
public Vector3f getRotation() {
return rotation;
}
public void setRotation(Vector3f rotation) {
this.rotation = rotation;
}
public float getScale() {
return scale;
}
public void setScale(float scale) {
this.scale = scale;
}
}

View File

@ -7,6 +7,8 @@ import org.lwjgl.system.*;
import java.nio.*;
import javax.vecmath.Vector2f;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
@ -67,8 +69,13 @@ public class DisplayManager {
// }
// The window handle
private long window;
private static long window;
public static Vector2f getSize() {
return new Vector2f(WIDTH, HEIGHT);
}
public void init() {
System.out.println("Hello LWJGL " + Version.getVersion() + "!");
@ -93,6 +100,25 @@ public class DisplayManager {
glfwTerminate();
glfwSetErrorCallback(null).free();
}
private static boolean valueS = false;
private static boolean valueZ = false;
private static boolean valueQ = false;
private static boolean valueD = false;
public static boolean isKeyDown(char value) {
if (value == 's') {
return valueS;
}
if (value == 'z') {
return valueZ;
}
if (value == 'q') {
return valueQ;
}
if (value == 'd') {
return valueD;
}
return false;
}
private void initWindows() {
// Setup an error callback. The default implementation
@ -115,8 +141,45 @@ public class DisplayManager {
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE ) {
glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop
}
if ( key == GLFW_KEY_Z ) {
if (action == GLFW_PRESS ) {
System.out.println("Key Z is pressed");
valueZ = true;
} else if (action == GLFW_RELEASE ) {
System.out.println("Key Z is release");
valueZ = false;
}
}
if ( key == GLFW_KEY_S ) {
if (action == GLFW_PRESS ) {
System.out.println("Key S is pressed");
valueS = true;
} else if (action == GLFW_RELEASE ) {
System.out.println("Key S is release");
valueS = false;
}
}
if ( key == GLFW_KEY_Q ) {
if (action == GLFW_PRESS ) {
System.out.println("Key Q is pressed");
valueQ = true;
} else if (action == GLFW_RELEASE ) {
System.out.println("Key Q is release");
valueQ = false;
}
}
if ( key == GLFW_KEY_D ) {
if (action == GLFW_PRESS ) {
System.out.println("Key D is pressed");
valueD = true;
} else if (action == GLFW_RELEASE ) {
System.out.println("Key D is release");
valueD = false;
}
}
});
// Get the thread stack and push a new frame

View File

@ -1,12 +1,19 @@
package renderEngine;
import javax.vecmath.Matrix4f;
import javax.vecmath.Vector2f;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.system.windows.DISPLAY_DEVICE;
import entities.Entity;
import models.RawModel;
import models.TexturedModel;
import shaders.StaticShader;
import toolbox.Maths;
/**
* Handles the rendering of a model to the screen.
@ -16,59 +23,97 @@ import models.TexturedModel;
*/
public class Renderer {
/**
* This method must be called each frame, before any rendering is carried
* out. It basically clears the screen of everything that was rendered last
* frame (using the glClear() method). The glClearColor() method determines
* the colour that it uses to clear the screen. In this example it makes the
* entire screen red at the start of each frame.
*/
private static final float FOV = 70;
private static final float NEAR_PLANE = 0.1f;
private static final float FAR_PLANE = 10000;
private Matrix4f projectionMatrix;
public Renderer(StaticShader shader) {
createProjectionMatrix();
shader.start();
shader.loadProjectionMatrix(projectionMatrix);
shader.stop();
}
public void prepare() {
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glClearColor(1, 0, 0, 1);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT|GL11.GL_DEPTH_BUFFER_BIT);
}
/**
* Renders a model to the screen.
*
* Before we can render a VAO it needs to be made active, and we can do this
* by binding it. We also need to enable the relevant attributes of the VAO,
* which in this case is just attribute 0 where we stored the position data.
*
* The VAO can then be rendered to the screen using glDrawElements(). Using
* this draw method tells OpenGL that we want to use the index buffer to
* determine how the vertices should be connected instead of just connecting
* the vertices together in the order that they are stored in the VAO.
*
* We tell it what type of shapes to render and the number of vertices that
* it needs to render. We also tell it was format the index data is in (we
* used ints) and finally we indicate where in the index buffer it should
* start rendering. We want it to start right at the beginning and render
* everything, so we put 0.
*
* After rendering we unbind the VAO and disable the attribute.
*
* @param model
* - The model to be rendered.
*/
public void render(RawModel model) {
GL30.glBindVertexArray(model.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL11.glDrawElements(GL11.GL_TRIANGLES, model.getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
}
public void render(TexturedModel texturedModel) {
RawModel model = texturedModel.getRawModel();
GL30.glBindVertexArray(model.getVaoID());
public void render(Entity entity, StaticShader shader) {
TexturedModel texturedModel = entity.getModel();
RawModel rawModel = texturedModel.getRawModel();
GL30.glBindVertexArray(rawModel.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
Matrix4f transformationMatrix = Maths.createTransformationMatrix(entity.getPosition(), entity.getRotation(), entity.getScale());
shader.loadTransformationMatrix(transformationMatrix);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texturedModel.getTexture().getTexturedID());
GL11.glDrawElements(GL11.GL_TRIANGLES, model.getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
GL11.glDrawElements(GL11.GL_TRIANGLES, rawModel.getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
GL20.glDisableVertexAttribArray(0);
GL20.glDisableVertexAttribArray(1);
GL30.glBindVertexArray(0);
}
private void createProjectionMatrix() {
//float aspectRatio = (float) Display.getWidth() / (float) Display.getHeight();
Vector2f windowsSize = DisplayManager.getSize();
float aspectRatio = windowsSize.x / windowsSize.y;
// float y_scale = (float) ((1f/Math.atan(Math.toRadians(FOV/2f))) * aspectRatio);
// float x_scale = y_scale / aspectRatio;
// float frustrum_length = FAR_PLANE - NEAR_PLANE;
//
// projectionMatrix = new Matrix4f();
// projectionMatrix.m00 = x_scale;
// projectionMatrix.m11 = y_scale;
// projectionMatrix.m22 = -((FAR_PLANE + NEAR_PLANE) / frustrum_length);
// projectionMatrix.m23 = -1;;
// projectionMatrix.m32 = -((2*FAR_PLANE * NEAR_PLANE) / frustrum_length);
// projectionMatrix.m33 = 0;
projectionMatrix = matPerspective(FOV, aspectRatio, NEAR_PLANE, FAR_PLANE);
}
Matrix4f matFrustum(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar) {
Matrix4f tmp = new Matrix4f();
// 0 1 2 3
// 4 5 6 7
// 8 9 10 11
// 12 13 14 15
tmp.m00 = (2.0f * zNear) / (xmax - xmin);
tmp.m11 = (2.0f * zNear) / (ymax - ymin);
tmp.m22 = -(zFar + zNear) / (zFar - zNear);
tmp.m02 = (xmax + xmin) / (xmax - xmin);
tmp.m12 = (ymax + ymin) / (ymax - ymin);
tmp.m32 = -1.0f;
tmp.m23 = -(2.0f * zFar * zNear) / (zFar - zNear);
return tmp;
}
Matrix4f matPerspective(float fovx, float aspect, float zNear, float zFar) {
//TK_DEBUG("drax perspective: fovx=" << fovx << "->" << aspect << " " << zNear << "->" << zFar);
float xmax = zNear * (float)Math.atan(fovx/2.0);
float xmin = -xmax;
float ymin = xmin / aspect;
float ymax = xmax / aspect;
//TK_DEBUG("drax perspective: " << xmin << "->" << xmax << " & " << ymin << "->" << ymax << " " << zNear << "->" << zFar);
return matFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
}
Matrix4f matOrtho(float left, float right, float bottom, float top, float nearVal, float farVal) {
Matrix4f tmp = new Matrix4f();
tmp.m00 = 2.0f / (right - left);
tmp.m11 = 2.0f / (top - bottom);
tmp.m22 = -2.0f / (farVal - nearVal);
tmp.m03 = -1*(right + left) / (right - left);
tmp.m13 = -1*(top + bottom) / (top - bottom);
tmp.m23 = -1*(farVal + nearVal) / (farVal - nearVal);
tmp.m33 = 1;
return tmp;
}
}

View File

@ -75,7 +75,7 @@ public abstract class ShaderProgram {
value.m20, value.m21, value.m22, value.m23,
value.m30, value.m31, value.m32, value.m33
};
GL20.glUniformMatrix4fv(location, false, values);
GL20.glUniformMatrix4fv(location, true, values);
}
private static int loadShader(String file, int type) {

View File

@ -2,11 +2,16 @@ package shaders;
import javax.vecmath.Matrix4f;
import entities.Camera;
import toolbox.Maths;
public class StaticShader extends ShaderProgram {
private static final String VERTEX_FILE = "src/shaders/vertexShader.txt";
private static final String FRAGMENT_FILE = "src/shaders/fragmentShader.txt";
private int location_transformationMatrix;
private int location_projectionMatrix;
private int location_viewMatrix;
public StaticShader() {
super(VERTEX_FILE, FRAGMENT_FILE);
@ -21,9 +26,17 @@ public class StaticShader extends ShaderProgram {
@Override
protected void getAllUniformLocations() {
location_transformationMatrix = super.getUniformLocation("transformationMatrix");
location_projectionMatrix = super.getUniformLocation("projectionMatrix");
location_viewMatrix = super.getUniformLocation("viewMatrix");
}
public void loadTransformationMatrix(Matrix4f value) {
super.loadMatrix(location_transformationMatrix, value);
}
public void loadProjectionMatrix(Matrix4f value) {
super.loadMatrix(location_projectionMatrix, value);
}
public void loadViewMatrix(Camera value) {
super.loadMatrix(location_viewMatrix, Maths.createViewMatrix(value));
}
}

View File

@ -6,10 +6,12 @@ in vec2 textureCoords;
out vec2 pass_textureCoords;
uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
void main(void) {
gl_Position = transformationMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * viewMatrix * transformationMatrix * vec4(position, 1.0);
pass_textureCoords = textureCoords;
}

View File

@ -1,18 +1,49 @@
package toolbox;
import javax.vecmath.Matrix3f;
import javax.vecmath.Matrix4f;
import javax.vecmath.Vector3f;
import entities.Camera;
public class Maths {
public static Matrix4f createTransformationMatrix(Vector3f translation, Vector3f rotation, float scale) {
// Need to rework all of this this is really not optimum ...
Matrix4f matrix = new Matrix4f();
matrix.setIdentity();
matrix.setTranslation(translation);
matrix.rotX(rotation.x);
matrix.rotY(rotation.y);
matrix.rotZ(rotation.z);
matrix.setScale(scale);
Matrix3f rotationMatX = new Matrix3f();
rotationMatX.rotX(rotation.x);
Matrix3f rotationMatY = new Matrix3f();
rotationMatY.rotY(rotation.y);
Matrix3f rotationMatZ = new Matrix3f();
rotationMatZ.rotZ(rotation.z);
rotationMatX.mul(rotationMatY);
rotationMatX.mul(rotationMatZ);
matrix.set(rotationMatX, translation, scale);
// matrix.rotX(rotation.x);
// matrix.rotY(rotation.y);
// matrix.rotZ(rotation.z);
// System.out.println("elementPosition :" + translation + " " + matrix) ;
// matrix.setTranslation(translation);
// matrix.setScale(scale);
//System.out.println("elementPosition :" + translation + " " + matrix) ;
return matrix;
}
public static Matrix4f createViewMatrix(Camera camera) {
// Need to rework all of this this is really not optimum ...
Matrix4f matrix = new Matrix4f();
matrix.setIdentity();
Matrix3f rotationMatX = new Matrix3f();
rotationMatX.rotX(camera.getPitch());
Matrix3f rotationMatY = new Matrix3f();
rotationMatY.rotY(camera.getYaw());
Matrix3f rotationMatZ = new Matrix3f();
rotationMatZ.rotZ(camera.getRoll());
rotationMatX.mul(rotationMatY);
rotationMatX.mul(rotationMatZ);
Vector3f camarePos = camera.getPosition();
matrix.set(rotationMatX, new Vector3f(-camarePos.x,-camarePos.y,-camarePos.z), 1);
return matrix;
}
}