Merge pull request 'finished game-engine-terrain-generation' (#2) from game-engine-terrain-generation into game-engine

Reviewed-on: Sebastian/Dicewars#2
This commit is contained in:
Sebastian 2023-10-05 14:00:28 +02:00
commit 44514f87e5
14 changed files with 292 additions and 82 deletions

BIN
client/res/hexagon.blend Normal file

Binary file not shown.

BIN
client/res/white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -3,6 +3,7 @@ package core.engine;
import core.engine.entity.Camera;
import core.engine.entity.Entity;
import core.engine.entity.Light;
import core.engine.model.HexagonModel;
import core.engine.model.RawModel;
import core.engine.model.TexturedModel;
import core.engine.renderer.MasterRenderer;
@ -118,24 +119,25 @@ public class Engine {
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
Camera camera = new Camera();
input(camera);
Light light = new Light(new Vector3f(0,0,-20), new Vector3f(1,1,1));
RawModel model = OBJLoader.loadOBJModel("dragon", loader);
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 terrain = new Terrain( loader, new ModelTexture(loader.loadTexture("white")), 16, 32, 7);
//Create Hexagon
HexagonModel hexagonModel = new HexagonModel();
RawModel hexagonRawModel = loader.loadHexagon(hexagonModel);
ModelTexture hexagonTexture = new ModelTexture(loader.loadTexture("white"));
TexturedModel hexagontexturedModel = new TexturedModel(hexagonRawModel, hexagonTexture);
Entity hexagonEntity = new Entity(hexagontexturedModel, new Vector3f(0,1,0), 0,0,0,1);
// Run the rendering loop until the user has attempted to close
// the window or has pressed the ESCAPE key.
MasterRenderer renderer = new MasterRenderer();
input(camera, renderer);
while ( !glfwWindowShouldClose(window) ) {
//entity.increaseRotation(0,1,0);
renderer.processTerrain(terrain);
//renderer.processEntity(entity);
//renderer.processEntity(hexagonEntity);
renderer.render(light, camera);
glfwSwapBuffers(window); // swap the color buffers
// Poll for window events. The key callback above will only be
@ -146,7 +148,7 @@ public class Engine {
loader.cleanUp();
}
private void input(Camera camera) {
private void input(Camera camera, MasterRenderer masterRenderer) {
GLFWScrollCallback glfwScrollCallback = new GLFWScrollCallback() {
@Override
@ -226,6 +228,10 @@ public class Engine {
if(key == GLFW_KEY_S) {
camera.moveBackward();
}
if(key == GLFW_KEY_Y && action == GLFW_PRESS) {
masterRenderer.switchWireframe();
}
}
});

View File

@ -1,5 +1,6 @@
package core.engine;
import core.engine.model.HexagonModel;
import core.engine.model.RawModel;
import core.engine.textures.Texture;
import org.lwjgl.BufferUtils;
@ -29,6 +30,10 @@ public class Loader {
return new RawModel(vaoID, indices.length);
}
public RawModel loadHexagon(HexagonModel hexagonModel) {
return loadToVAO(hexagonModel.getVertices(), hexagonModel.getTextureCoords(), hexagonModel.getNormals(), hexagonModel.getIndices());
}
public int loadTexture(String fileName) {
Texture texture = new Texture("res/" + fileName + ".png");
int textureID = texture.getTextureID();

View File

@ -4,7 +4,7 @@ import utils.vectors.Vector3f;
public class Camera {
private Vector3f position = new Vector3f(50,100,50);
private Vector3f position = new Vector3f(0,37,-1);
private float pitch = 90;
private float yaw = 180;
private float roll;

View File

@ -0,0 +1,88 @@
package core.engine.model;
import utils.vectors.Vector3f;
public class HexagonModel {
private float[] vertices;
private float[] normals;
private float[] textureCoords;
private int[] indices;
public HexagonModel() {
// Vertices (including the center)
vertices = new float[]{
0.0f, 0.0f, 0.0f, // Center
0.0f, 0.0f, 1.0f, // Top Vertex
0.866f, 0.0f, 0.5f, // Upper Right Vertex
0.866f, 0.0f, -0.5f, // Lower Right Vertex
0.0f, 0.0f, -1.0f, // Bottom Vertex
-0.866f, 0.0f, -0.5f, // Lower Left Vertex
-0.866f, 0.0f, 0.5f // Upper Left Vertex
};
// Normals
normals = new float[]{
0, 1, 0, // Center
0, 1, 0, // Top Vertex
0, 1, 0, // Upper Right Vertex
0, 1, 0, // Lower Right Vertex
0, 1, 0, // Bottom Vertex
0, 1, 0, // Lower Left Vertex
0, 1, 0 // Upper Left Vertex
};
// Texture Coordinates
textureCoords = new float[]{
0.5f, 0.5f, // Center
0.5f, 0.0f, // Top Vertex
1.0f, 0.25f, // Upper Right Vertex
1.0f, 0.75f, // Lower Right Vertex
0.5f, 1.0f, // Bottom Vertex
0.0f, 0.75f, // Lower Left Vertex
0.0f, 0.25f // Upper Left Vertex
};
// Indices
indices = new int[]{
0, 1, 2, // Center to Top Vertex to Upper Right Vertex
0, 2, 3, // Center to Upper Right Vertex to Lower Right Vertex
0, 3, 4, // Center to Lower Right Vertex to Bottom Vertex
0, 4, 5, // Center to Bottom Vertex to Lower Left Vertex
0, 5, 6, // Center to Lower Left Vertex to Upper Left Vertex
0, 6, 1 // Center to Upper Left Vertex to Top Vertex
};
}
public float[] getVertices() {
return vertices;
}
public void setVertices(float[] vertices) {
this.vertices = vertices;
}
public float[] getNormals() {
return normals;
}
public void setNormals(float[] normals) {
this.normals = normals;
}
public float[] getTextureCoords() {
return textureCoords;
}
public void setTextureCoords(float[] textureCoords) {
this.textureCoords = textureCoords;
}
public int[] getIndices() {
return indices;
}
public void setIndices(int[] indices) {
this.indices = indices;
}
}

View File

@ -8,6 +8,7 @@ import core.engine.model.TexturedModel;
import core.engine.shader.StaticShader;
import core.engine.shader.TerrainShader;
import core.engine.terrain.Terrain;
import core.engine.terrain.TerrainTile;
import org.lwjgl.opengl.GL11;
import utils.vectors.Matrix4f;
@ -27,9 +28,11 @@ public class MasterRenderer {
private EntityRenderer renderer;
private TerrainRenderer terrainRenderer;
private Map<TexturedModel, List<Entity>> entities = new HashMap<>();
private List<Terrain> terrains = new ArrayList<>();
private List<TerrainTile> terrains = new ArrayList<>();
private Matrix4f projectionMatrix;
private boolean wireframe = false;
public MasterRenderer() {
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glCullFace(GL11.GL_BACK);
@ -62,7 +65,7 @@ public class MasterRenderer {
}
public void processTerrain(Terrain terrain) {
terrains.add(terrain);
terrains.addAll(terrain.getTerrainTiles());
}
public void processEntity(Entity entity) {
@ -97,4 +100,14 @@ public class MasterRenderer {
projectionMatrix.m33 = 0;
}
public void switchWireframe() {
this.wireframe = !this.wireframe;
if(this.wireframe) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
} else {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
}
}

View File

@ -5,6 +5,7 @@ import core.engine.model.RawModel;
import core.engine.model.TexturedModel;
import core.engine.shader.TerrainShader;
import core.engine.terrain.Terrain;
import core.engine.terrain.TerrainTile;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
@ -26,23 +27,24 @@ public class TerrainRenderer {
shader.stop();
}
public void render(List<Terrain> terrains) {
for(Terrain terrain : terrains) {
public void render(List<TerrainTile> terrains) {
for(TerrainTile terrain : terrains) {
prepareTerrain(terrain);
loadModelMatrix(terrain);
GL11.glDrawElements(GL11.GL_TRIANGLES, terrain.getModel().getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
GL11.glDrawElements(GL11.GL_TRIANGLES, terrain.getModel().getRawModel().getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
unbindTexturedModel();
}
}
private void prepareTerrain(Terrain model) {
RawModel rawModel = model.getModel();
private void prepareTerrain(TerrainTile terrainTile) {
RawModel rawModel = terrainTile.getModel().getRawModel();
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());
GL11.glBindTexture(GL11.GL_TEXTURE_2D, terrainTile.getModel().getModelTexture().getTextureID());
shader.loadTerrainColor(terrainTile.getColor());
}
private void unbindTexturedModel() {
@ -52,8 +54,9 @@ public class TerrainRenderer {
GL30.glBindVertexArray(0);
}
private void loadModelMatrix(Terrain terrain) {
Matrix4f transformationMatrix = MatrixGraphicUtils.createTransformationMatrix(new Vector3f(terrain.getX(), 0, terrain.getZ()), 0,0,0,1);
private void loadModelMatrix(TerrainTile terrain) {
Matrix4f transformationMatrix = MatrixGraphicUtils.createTransformationMatrix(terrain.getPosition(), terrain.getRotX(),
terrain.getRotY(), terrain.getRotZ(), terrain.getScale());
shader.loadTransformationMatrix(transformationMatrix);
}
}

View File

@ -4,6 +4,7 @@ import core.engine.entity.Camera;
import core.engine.entity.Light;
import utils.MatrixGraphicUtils;
import utils.vectors.Matrix4f;
import utils.vectors.Vector3f;
public class TerrainShader extends ShaderProgram{
private static final String VERTEX_FILE = "src/main/java/core/engine/shader/terrainVertexShader.glsl";
@ -14,6 +15,7 @@ public class TerrainShader extends ShaderProgram{
private int location_viewMatrix;
private int location_lightPosition;
private int location_lightColor;
private int location_terrainColor;
public TerrainShader() {
super(VERTEX_FILE, FRAGMENT_FILE);
}
@ -25,6 +27,7 @@ public class TerrainShader extends ShaderProgram{
this.location_viewMatrix = super.getUniformLocation("viewMatrix");
this.location_lightColor = super.getUniformLocation("lightColor");
this.location_lightPosition = super.getUniformLocation("lightPosition");
this.location_terrainColor = super.getUniformLocation("terrainColor");
}
@Override
@ -51,4 +54,8 @@ public class TerrainShader extends ShaderProgram{
super.loadVector(location_lightPosition, light.getPosition());
super.loadVector(location_lightColor, light.getColor());
}
public void loadTerrainColor(Vector3f color) {
super.loadVector(location_terrainColor, color);
}
}

View File

@ -8,6 +8,7 @@ out vec4 out_Color;
uniform sampler2D textureSampler;
uniform vec3 lightColor;
uniform vec3 terrainColor;
void main(void) {
vec3 unitNormal = normalize(surfaceNormal);
@ -17,5 +18,5 @@ void main(void) {
float brightness = max(nDotl, 0.2);
vec3 diffusde = brightness * lightColor;
out_Color = vec4(diffusde, 1.0) * texture(textureSampler, pass_textureCoords);
out_Color = /*vec4(diffusde, 1.0) **/ vec4(terrainColor, 1);
}

View File

@ -17,7 +17,7 @@ out vec3 toLightVector;
void main(void) {
vec4 worldPosition = transformationMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * viewMatrix * worldPosition;
pass_textureCoords = textureCoords * 40;
pass_textureCoords = textureCoords;
surfaceNormal = (transformationMatrix * vec4(normal, 0.0)).xyz;
toLightVector = lightPosition - worldPosition.xyz;

View File

@ -1,78 +1,41 @@
package core.engine.terrain;
import core.engine.Loader;
import core.engine.model.HexagonModel;
import core.engine.model.RawModel;
import core.engine.model.TexturedModel;
import core.engine.textures.ModelTexture;
import utils.vectors.Vector3f;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Terrain {
private static final float WIDTH = 100;
private static final float DEPTH = 100;
private static final int VERTEX_COUNT = 128;
private List<TerrainTile> terrainTiles = new ArrayList<>();
private float x;
private float z;
private RawModel model;
private ModelTexture texture;
public Terrain(Loader loader, ModelTexture modelTexture, int rows, int columns, int numberPlayers) {
TerrainGenerator terrainGenerator = new TerrainGenerator();
public Terrain(int gridX, int gridZ, Loader loader, ModelTexture modelTexture) {
this.texture = modelTexture;
this.x = gridX * WIDTH;
this.z = gridZ * DEPTH;
this.model = generateTerrain(loader);
HexagonModel hexagonModel = new HexagonModel();
RawModel rawModel = loader.loadHexagon(hexagonModel);
TexturedModel texturedModel = new TexturedModel(rawModel, modelTexture);
for(int row = 0; row < rows; row++) {
for(int column = 0; column < columns; column++) {
if(row % 2 == 1) {
terrainTiles.add(new TerrainTile(texturedModel, new Vector3f(column * 2* 0.866f, 0, row * 1.5f),0,0,0,1, row, column, terrainGenerator.generateColor(column, row)));
} else {
terrainTiles.add(new TerrainTile(texturedModel, new Vector3f(column *2 * 0.866f - 0.866f, 0, row * 1.5f),0,0,0,1, row, column, terrainGenerator.generateColor(column, row)));
}
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<VERTEX_COUNT;i++){
for(int j=0;j<VERTEX_COUNT;j++){
vertices[vertexPointer*3] = (float)j/((float)VERTEX_COUNT - 1) * WIDTH;
vertices[vertexPointer*3+1] = 0;
vertices[vertexPointer*3+2] = (float)i/((float)VERTEX_COUNT - 1) * DEPTH;
normals[vertexPointer*3] = 0;
normals[vertexPointer*3+1] = 1;
normals[vertexPointer*3+2] = 0;
textureCoords[vertexPointer*2] = (float)j/((float)VERTEX_COUNT - 1);
textureCoords[vertexPointer*2+1] = (float)i/((float)VERTEX_COUNT - 1);
vertexPointer++;
}
}
int pointer = 0;
for(int gz=0;gz<VERTEX_COUNT-1;gz++){
for(int gx=0;gx<VERTEX_COUNT-1;gx++){
int topLeft = (gz*VERTEX_COUNT)+gx;
int topRight = topLeft + 1;
int bottomLeft = ((gz+1)*VERTEX_COUNT)+gx;
int bottomRight = bottomLeft + 1;
indices[pointer++] = topLeft;
indices[pointer++] = bottomLeft;
indices[pointer++] = topRight;
indices[pointer++] = topRight;
indices[pointer++] = bottomLeft;
indices[pointer++] = bottomRight;
}
}
return loader.loadToVAO(vertices, textureCoords, normals, indices);
}
public float getX() {
return x;
}
public float getZ() {
return z;
}
public RawModel getModel() {
return model;
}
public ModelTexture getTexture() {
return texture;
public List<TerrainTile> getTerrainTiles() {
return terrainTiles;
}
}

View File

@ -0,0 +1,37 @@
package core.engine.terrain;
import utils.vectors.Vector3f;
import java.util.Random;
public class TerrainGenerator {
private final Random random = new Random();
private final int seed_red;
private final int seed_blue;
private final int seed_green;
public TerrainGenerator() {
this.seed_red = random.nextInt(1000000000);
this.seed_blue = random.nextInt(1000000000);
this.seed_green = random.nextInt(1000000000);
}
public Vector3f generateColor(int x, int z) {
return new Vector3f(getSmoothNoise(x, z, seed_red), getSmoothNoise(x, z, seed_green), getSmoothNoise(x, z, seed_blue));
}
private float getSmoothNoise(int x, int z, int seed) {
float corners = (getNoise(x -1, z-1, seed) + getNoise(x+1, z-1, seed) +
getNoise(x-1, z+1, seed) + getNoise(x+1, z+1, seed)) / 16f;
float sides = (getNoise(x-1, z, seed) + getNoise(x+1, z, seed) +
getNoise(x, z-1, seed) + getNoise(x, z+1, seed)) / 8f;
float center = getNoise(x, z, seed) / 4f;
return corners + sides + center;
}
private float getNoise(int x, int z, int seed) {
random.setSeed(x * 49632L + z * 325176L + seed);
return random.nextFloat();
}
}

View File

@ -0,0 +1,87 @@
package core.engine.terrain;
import core.engine.Loader;
import core.engine.model.RawModel;
import core.engine.model.TexturedModel;
import core.engine.textures.ModelTexture;
import utils.vectors.Vector3f;
public class TerrainTile {
private TexturedModel model;
private Vector3f position;
private float rotX, rotY, rotZ;
private float scale;
private int row;
private int column;
private Vector3f color;
public TerrainTile(TexturedModel model, Vector3f position, float rotX, float rotY, float rotZ, float scale, int row, int column, Vector3f color) {
this.model = model;
this.position = position;
this.rotX = rotX;
this.rotY = rotY;
this.rotZ = rotZ;
this.scale = scale;
this.row = row;
this.column = column;
this.color = color;
}
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 float getRotX() {
return rotX;
}
public void setRotX(float rotX) {
this.rotX = rotX;
}
public float getRotY() {
return rotY;
}
public void setRotY(float rotY) {
this.rotY = rotY;
}
public float getRotZ() {
return rotZ;
}
public void setRotZ(float rotZ) {
this.rotZ = rotZ;
}
public float getScale() {
return scale;
}
public void setScale(float scale) {
this.scale = scale;
}
public Vector3f getColor() {
return color;
}
public void setColor(Vector3f color) {
this.color = color;
}
}