diff --git a/client/res/grass.png b/client/res/grass.png new file mode 100644 index 0000000..cb64011 Binary files /dev/null and b/client/res/grass.png differ diff --git a/client/src/main/java/core/engine/Engine.java b/client/src/main/java/core/engine/Engine.java index 933ef76..932066c 100644 --- a/client/src/main/java/core/engine/Engine.java +++ b/client/src/main/java/core/engine/Engine.java @@ -5,7 +5,8 @@ import core.engine.entity.Entity; import core.engine.entity.Light; import core.engine.model.RawModel; import core.engine.model.TexturedModel; -import core.engine.shader.StaticShader; +import core.engine.renderer.MasterRenderer; +import core.engine.terrain.Terrain; import core.engine.textures.ModelTexture; import org.lwjgl.Version; import org.lwjgl.glfw.GLFWErrorCallback; @@ -21,7 +22,6 @@ import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks; import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.glfw.GLFW.glfwSwapBuffers; import static org.lwjgl.opengl.GL11.glClearColor; -import static org.lwjgl.opengl.GL11C.*; import static org.lwjgl.system.MemoryStack.stackPush; import static org.lwjgl.system.MemoryUtil.NULL; @@ -142,12 +142,19 @@ public class Engine { ModelTexture modelTexture = new ModelTexture(loader.loadTexture("white")); TexturedModel texturedModel = new TexturedModel(model, modelTexture); Entity entity = new Entity(texturedModel, new Vector3f(0,0,-50), 0,0,0,1); + + //Generate Simple, Flat Terrain + Terrain terrain = new Terrain(0,0, loader, new ModelTexture(loader.loadTexture("grass"))); + Terrain terrain1 = new Terrain(1,0, loader, new ModelTexture(loader.loadTexture("grass"))); + // Run the rendering loop until the user has attempted to close // the window or has pressed the ESCAPE key. MasterRenderer renderer = new MasterRenderer(); while ( !glfwWindowShouldClose(window) ) { - entity.increaseRotation(0,1,0); - renderer.processEntity(entity); + //entity.increaseRotation(0,1,0); + renderer.processTerrain(terrain1); + renderer.processTerrain(terrain); + //renderer.processEntity(entity); renderer.render(light, camera); glfwSwapBuffers(window); // swap the color buffers diff --git a/client/src/main/java/core/engine/MasterRenderer.java b/client/src/main/java/core/engine/MasterRenderer.java deleted file mode 100644 index 4bcd065..0000000 --- a/client/src/main/java/core/engine/MasterRenderer.java +++ /dev/null @@ -1,45 +0,0 @@ -package core.engine; - -import core.engine.entity.Camera; -import core.engine.entity.Entity; -import core.engine.entity.Light; -import core.engine.model.TexturedModel; -import core.engine.shader.StaticShader; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class MasterRenderer { - - private StaticShader shader = new StaticShader(); - private Renderer renderer = new Renderer(shader); - private Map> entities = new HashMap<>(); - - public void render(Light light, Camera camera) { - renderer.prepare(); - shader.start(); - shader.loadLight(light); - shader.loadViewMatrix(camera); - renderer.render(entities); - shader.stop(); - entities.clear(); - } - - public void processEntity(Entity entity) { - TexturedModel entityModel = entity.getModel(); - List batch = entities.get(entityModel); - if(batch != null) { - batch.add(entity); - } else { - List newBatch = new ArrayList<>(); - newBatch.add(entity); - entities.put(entityModel, newBatch); - } - } - - public void cleanUp() { - shader.cleanUp(); - } -} diff --git a/client/src/main/java/core/engine/entity/Camera.java b/client/src/main/java/core/engine/entity/Camera.java index 0c11402..3647f87 100644 --- a/client/src/main/java/core/engine/entity/Camera.java +++ b/client/src/main/java/core/engine/entity/Camera.java @@ -4,9 +4,9 @@ import utils.vectors.Vector3f; public class Camera { - private Vector3f position = new Vector3f(0,0,0); + private Vector3f position = new Vector3f(0,10,0); private float pitch; - private float yaw; + private float yaw = 180; private float roll; public void moveLeft() { diff --git a/client/src/main/java/core/engine/Renderer.java b/client/src/main/java/core/engine/renderer/EntityRenderer.java similarity index 66% rename from client/src/main/java/core/engine/Renderer.java rename to client/src/main/java/core/engine/renderer/EntityRenderer.java index 2091359..2bbc6e1 100644 --- a/client/src/main/java/core/engine/Renderer.java +++ b/client/src/main/java/core/engine/renderer/EntityRenderer.java @@ -1,4 +1,4 @@ -package core.engine; +package core.engine.renderer; import core.engine.entity.Entity; import core.engine.model.RawModel; @@ -17,28 +17,22 @@ import java.util.Map; import static org.lwjgl.opengl.GL11C.*; -public class Renderer { +public class EntityRenderer { private static final float FOV = 70; private static final float NEAR_PLEANE = 0.1f; private static final float FAR_PLANE = 1000; - private Matrix4f projectionMatrix; + private StaticShader shader; - public Renderer(StaticShader shader) { + public EntityRenderer(StaticShader shader, Matrix4f projectionMatrix) { this.shader = shader; - GL11.glEnable(GL11.GL_CULL_FACE); - GL11.glCullFace(GL11.GL_BACK); - createProjectionMatrix(); + shader.start(); shader.loadProjectionMatrix(projectionMatrix); shader.stop(); } - public void prepare() { - GL11.glEnable(GL11.GL_DEPTH_TEST); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer - GL11.glClearColor(5,195,221,1); - } + public void render(Map> entities) { for(TexturedModel model: entities.keySet()) { @@ -75,19 +69,5 @@ public class Renderer { shader.loadTransformationMatrix(transformationMatrix); } - private void createProjectionMatrix() { - float aspectRatio = (float) Engine.WINDOW_WIDTH / (float) Engine.WINDOW_HEIGHT; - float y_scale = (float) ((1f / Math.tan(Math.toRadians(FOV / 2f))) * aspectRatio); - float x_scale = y_scale / aspectRatio; - float frustum_length = FAR_PLANE - NEAR_PLEANE; - projectionMatrix = new Matrix4f(); - projectionMatrix.m00 = x_scale; - projectionMatrix.m11 = y_scale; - projectionMatrix.m22 = -((FAR_PLANE + NEAR_PLEANE) / frustum_length); - projectionMatrix.m23 = -1; - projectionMatrix.m32 = -((2 * NEAR_PLEANE * FAR_PLANE) / frustum_length); - projectionMatrix.m33 = 0; - - } } diff --git a/client/src/main/java/core/engine/renderer/MasterRenderer.java b/client/src/main/java/core/engine/renderer/MasterRenderer.java new file mode 100644 index 0000000..849271e --- /dev/null +++ b/client/src/main/java/core/engine/renderer/MasterRenderer.java @@ -0,0 +1,100 @@ +package core.engine.renderer; + +import core.engine.Engine; +import core.engine.entity.Camera; +import core.engine.entity.Entity; +import core.engine.entity.Light; +import core.engine.model.TexturedModel; +import core.engine.shader.StaticShader; +import core.engine.shader.TerrainShader; +import core.engine.terrain.Terrain; +import org.lwjgl.opengl.GL11; +import utils.vectors.Matrix4f; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.lwjgl.opengl.GL11C.*; + +public class MasterRenderer { + private static final float FOV = 70; + private static final float NEAR_PLEANE = 0.1f; + private static final float FAR_PLANE = 1000; + private StaticShader shader = new StaticShader(); + private TerrainShader terrainShader = new TerrainShader(); + private EntityRenderer renderer; + private TerrainRenderer terrainRenderer; + private Map> entities = new HashMap<>(); + private List terrains = new ArrayList<>(); + private Matrix4f projectionMatrix; + + public MasterRenderer() { + GL11.glEnable(GL11.GL_CULL_FACE); + GL11.glCullFace(GL11.GL_BACK); + createProjectionMatrix(); + renderer = new EntityRenderer(shader, projectionMatrix); + terrainRenderer = new TerrainRenderer(terrainShader, projectionMatrix); + + } + + public void prepare() { + GL11.glEnable(GL11.GL_DEPTH_TEST); + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); + GL11.glClearColor(0.49f, 89f, 0.98f, 1); + } + + public void render(Light light, Camera camera) { + prepare(); + shader.start(); + shader.loadLight(light); + shader.loadViewMatrix(camera); + renderer.render(entities); + shader.stop(); + terrainShader.start(); + terrainShader.loadLight(light); + terrainShader.loadViewMatrix(camera); + terrainRenderer.render(terrains); + terrainShader.stop(); + terrains.clear(); + entities.clear(); + } + + public void processTerrain(Terrain terrain) { + terrains.add(terrain); + } + + public void processEntity(Entity entity) { + TexturedModel entityModel = entity.getModel(); + List batch = entities.get(entityModel); + if(batch != null) { + batch.add(entity); + } else { + List newBatch = new ArrayList<>(); + newBatch.add(entity); + entities.put(entityModel, newBatch); + } + } + + public void cleanUp() { + shader.cleanUp(); + terrainShader.cleanUp(); + } + + private void createProjectionMatrix() { + float aspectRatio = (float) Engine.WINDOW_WIDTH / (float) Engine.WINDOW_HEIGHT; + float y_scale = (float) ((1f / Math.tan(Math.toRadians(FOV / 2f))) * aspectRatio); + float x_scale = y_scale / aspectRatio; + float frustum_length = FAR_PLANE - NEAR_PLEANE; + + projectionMatrix = new Matrix4f(); + projectionMatrix.m00 = x_scale; + projectionMatrix.m11 = y_scale; + projectionMatrix.m22 = -((FAR_PLANE + NEAR_PLEANE) / frustum_length); + projectionMatrix.m23 = -1; + projectionMatrix.m32 = -((2 * NEAR_PLEANE * FAR_PLANE) / frustum_length); + projectionMatrix.m33 = 0; + + } +} diff --git a/client/src/main/java/core/engine/renderer/TerrainRenderer.java b/client/src/main/java/core/engine/renderer/TerrainRenderer.java new file mode 100644 index 0000000..688bf0d --- /dev/null +++ b/client/src/main/java/core/engine/renderer/TerrainRenderer.java @@ -0,0 +1,59 @@ +package core.engine.renderer; + +import core.engine.entity.Entity; +import core.engine.model.RawModel; +import core.engine.model.TexturedModel; +import core.engine.shader.TerrainShader; +import core.engine.terrain.Terrain; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL30; +import utils.MatrixGraphicUtils; +import utils.vectors.Matrix4f; +import utils.vectors.Vector3f; + +import java.util.List; + +public class TerrainRenderer { + + private TerrainShader shader; + + public TerrainRenderer(TerrainShader shader, Matrix4f projectionMatrix) { + this.shader = shader; + shader.start(); + shader.loadProjectionMatrix(projectionMatrix); + shader.stop(); + } + + public void render(List terrains) { + for(Terrain terrain : terrains) { + prepareTerrain(terrain); + loadModelMatrix(terrain); + GL11.glDrawElements(GL11.GL_TRIANGLES, terrain.getModel().getVertexCount(), GL11.GL_UNSIGNED_INT, 0); + unbindTexturedModel(); + } + } + + private void prepareTerrain(Terrain model) { + RawModel rawModel = model.getModel(); + GL30.glBindVertexArray(rawModel.getVaoID()); + GL20.glEnableVertexAttribArray(0); + GL20.glEnableVertexAttribArray(1); + GL20.glEnableVertexAttribArray(2); + GL13.glActiveTexture(GL13.GL_TEXTURE0); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, model.getTexture().getTextureID()); + } + + private void unbindTexturedModel() { + GL20.glDisableVertexAttribArray(0); + GL20.glDisableVertexAttribArray(1); + GL20.glDisableVertexAttribArray(2); + GL30.glBindVertexArray(0); + } + + private void loadModelMatrix(Terrain terrain) { + Matrix4f transformationMatrix = MatrixGraphicUtils.createTransformationMatrix(new Vector3f(terrain.getX(), 0, terrain.getZ()), 0,0,0,1); + shader.loadTransformationMatrix(transformationMatrix); + } +} diff --git a/client/src/main/java/core/engine/shader/TerrainShader.java b/client/src/main/java/core/engine/shader/TerrainShader.java new file mode 100644 index 0000000..2c09a51 --- /dev/null +++ b/client/src/main/java/core/engine/shader/TerrainShader.java @@ -0,0 +1,54 @@ +package core.engine.shader; + +import core.engine.entity.Camera; +import core.engine.entity.Light; +import utils.MatrixGraphicUtils; +import utils.vectors.Matrix4f; + +public class TerrainShader extends ShaderProgram{ + private static final String VERTEX_FILE = "src/main/java/core/engine/shader/terrainVertexShader.glsl"; + private static final String FRAGMENT_FILE = "src/main/java/core/engine/shader/terrainFragmentShader.glsl"; + + private int location_transformationMatrix; + private int location_projectionMatrix; + private int location_viewMatrix; + private int location_lightPosition; + private int location_lightColor; + public TerrainShader() { + super(VERTEX_FILE, FRAGMENT_FILE); + } + + @Override + protected void getAllUniformLocations() { + this.location_transformationMatrix = super.getUniformLocation("transformationMatrix"); + this.location_projectionMatrix = super.getUniformLocation("projectionMatrix"); + this.location_viewMatrix = super.getUniformLocation("viewMatrix"); + this.location_lightColor = super.getUniformLocation("lightColor"); + this.location_lightPosition = super.getUniformLocation("lightPosition"); + } + + @Override + protected void bindAttributes() { + super.bindAttribute(0, "position"); + super.bindAttribute(1, "textureCoords"); + super.bindAttribute(2, "normal"); + } + + public void loadTransformationMatrix(Matrix4f matrix) { + super.loadMatrix(location_transformationMatrix, matrix); + } + + public void loadProjectionMatrix(Matrix4f matrix) { + super.loadMatrix(location_projectionMatrix, matrix); + } + + public void loadViewMatrix(Camera camera) { + Matrix4f viewMatrix = MatrixGraphicUtils.createViewMatrix(camera); + super.loadMatrix(location_viewMatrix, viewMatrix); + } + + public void loadLight(Light light) { + super.loadVector(location_lightPosition, light.getPosition()); + super.loadVector(location_lightColor, light.getColor()); + } +} diff --git a/client/src/main/java/core/engine/shader/terrainFragmentShader.glsl b/client/src/main/java/core/engine/shader/terrainFragmentShader.glsl new file mode 100644 index 0000000..bd7f6d4 --- /dev/null +++ b/client/src/main/java/core/engine/shader/terrainFragmentShader.glsl @@ -0,0 +1,21 @@ +#version 400 core + +in vec2 pass_textureCoords; +in vec3 surfaceNormal; +in vec3 toLightVector; + +out vec4 out_Color; + +uniform sampler2D textureSampler; +uniform vec3 lightColor; + +void main(void) { + vec3 unitNormal = normalize(surfaceNormal); + vec3 unitToLightVector = normalize(toLightVector); + + float nDotl = dot(unitNormal, unitToLightVector); + float brightness = max(nDotl, 0.2); + vec3 diffusde = brightness * lightColor; + + out_Color = vec4(diffusde, 1.0) * texture(textureSampler, pass_textureCoords); +} \ No newline at end of file diff --git a/client/src/main/java/core/engine/shader/terrainVertexShader.glsl b/client/src/main/java/core/engine/shader/terrainVertexShader.glsl new file mode 100644 index 0000000..36b0d54 --- /dev/null +++ b/client/src/main/java/core/engine/shader/terrainVertexShader.glsl @@ -0,0 +1,24 @@ +#version 400 core + +in vec3 position; +in vec2 textureCoords; +in vec3 normal; + +uniform mat4 transformationMatrix; +uniform mat4 projectionMatrix; +uniform mat4 viewMatrix; +uniform vec3 lightPosition; + + +out vec2 pass_textureCoords; +out vec3 surfaceNormal; +out vec3 toLightVector; + +void main(void) { + vec4 worldPosition = transformationMatrix * vec4(position, 1.0); + gl_Position = projectionMatrix * viewMatrix * worldPosition; + pass_textureCoords = textureCoords * 40; + + surfaceNormal = (transformationMatrix * vec4(normal, 0.0)).xyz; + toLightVector = lightPosition - worldPosition.xyz; +} \ No newline at end of file diff --git a/client/src/main/java/core/engine/terrain/Terrain.java b/client/src/main/java/core/engine/terrain/Terrain.java new file mode 100644 index 0000000..eb60164 --- /dev/null +++ b/client/src/main/java/core/engine/terrain/Terrain.java @@ -0,0 +1,77 @@ +package core.engine.terrain; + +import core.engine.Loader; +import core.engine.model.RawModel; +import core.engine.textures.ModelTexture; + +public class Terrain { + + private static final float SIZE = 800; + private static final int VERTEX_COUNT = 128; + + private float x; + private float z; + private RawModel model; + private ModelTexture texture; + + public Terrain(int gridX, int gridZ, Loader loader, ModelTexture modelTexture) { + this.texture = modelTexture; + this.x = gridX * SIZE; + this.z = gridZ * SIZE; + this.model = generateTerrain(loader); + } + + private RawModel generateTerrain(Loader loader){ + int count = VERTEX_COUNT * VERTEX_COUNT; + float[] vertices = new float[count * 3]; + float[] normals = new float[count * 3]; + float[] textureCoords = new float[count*2]; + int[] indices = new int[6*(VERTEX_COUNT-1)*(VERTEX_COUNT-1)]; + int vertexPointer = 0; + for(int i=0;i