Attempted performance tweaks (caching, etc)
This commit is contained in:
parent
4ced329a47
commit
716ed65f70
@ -1,6 +1,7 @@
|
|||||||
package electrosphere.game.cell;
|
package electrosphere.game.cell;
|
||||||
|
|
||||||
import electrosphere.game.terrain.TerrainManager;
|
import electrosphere.game.terrain.TerrainManager;
|
||||||
|
import electrosphere.renderer.ShaderProgram;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -26,11 +27,13 @@ public class CellManager {
|
|||||||
boolean[][] updateable;
|
boolean[][] updateable;
|
||||||
|
|
||||||
|
|
||||||
|
ShaderProgram program;
|
||||||
|
|
||||||
|
|
||||||
int drawRadius = 5;
|
|
||||||
|
int drawRadius = 1;
|
||||||
int drawStepdownInterval = 2;
|
int drawStepdownInterval = 2;
|
||||||
int drawStepdownValue = 10;
|
int drawStepdownValue = 20;
|
||||||
|
|
||||||
public CellManager(TerrainManager terrainManager, float realX, float realY){
|
public CellManager(TerrainManager terrainManager, float realX, float realY){
|
||||||
this.terrainManager = terrainManager;
|
this.terrainManager = terrainManager;
|
||||||
@ -48,6 +51,8 @@ public class CellManager {
|
|||||||
}
|
}
|
||||||
cellX = transformRealSpaceToCellSpace(realX);
|
cellX = transformRealSpaceToCellSpace(realX);
|
||||||
cellY = transformRealSpaceToCellSpace(realY);
|
cellY = transformRealSpaceToCellSpace(realY);
|
||||||
|
|
||||||
|
program = ShaderProgram.smart_assemble_shader(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCellX(){
|
public int getCellX(){
|
||||||
@ -98,7 +103,8 @@ public class CellManager {
|
|||||||
terrainManager.getAugmentedChunkWidth(),
|
terrainManager.getAugmentedChunkWidth(),
|
||||||
currentCellX,
|
currentCellX,
|
||||||
currentCellY,
|
currentCellY,
|
||||||
terrainManager.getChunkWidth()
|
terrainManager.getChunkWidth(),
|
||||||
|
program
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
valid[targetX][targetY] = true;
|
valid[targetX][targetY] = true;
|
||||||
@ -135,7 +141,10 @@ public class CellManager {
|
|||||||
currentCellY < terrainManager.getWorldDiscreteSize()
|
currentCellY < terrainManager.getWorldDiscreteSize()
|
||||||
){
|
){
|
||||||
int dist = Math.abs(targetX - drawRadius) * Math.abs(targetY - drawRadius);
|
int dist = Math.abs(targetX - drawRadius) * Math.abs(targetY - drawRadius);
|
||||||
int stride = 20;//Math.max(100, dist / drawStepdownInterval * drawStepdownValue);
|
int stride = Math.min(100, Math.max(3, dist / drawStepdownInterval * drawStepdownValue));
|
||||||
|
while(terrainManager.getChunkWidth() % stride != 0){
|
||||||
|
stride = stride + 1;
|
||||||
|
}
|
||||||
cells[targetX][targetY].generateDrawableEntity(stride);
|
cells[targetX][targetY].generateDrawableEntity(stride);
|
||||||
}
|
}
|
||||||
drawable[targetX][targetY] = true;
|
drawable[targetX][targetY] = true;
|
||||||
@ -170,7 +179,10 @@ public class CellManager {
|
|||||||
currentCellY < terrainManager.getWorldDiscreteSize()
|
currentCellY < terrainManager.getWorldDiscreteSize()
|
||||||
){
|
){
|
||||||
int dist = Math.abs(targetX - drawRadius) * Math.abs(targetY - drawRadius);
|
int dist = Math.abs(targetX - drawRadius) * Math.abs(targetY - drawRadius);
|
||||||
int stride = 20;//Math.max(100, dist / drawStepdownInterval * drawStepdownValue);
|
int stride = Math.min(100, Math.max(1, dist / drawStepdownInterval * drawStepdownValue));
|
||||||
|
while(terrainManager.getChunkWidth() % stride != 0){
|
||||||
|
stride = stride + 1;
|
||||||
|
}
|
||||||
cells[targetX][targetY].generateDrawableEntity(stride);
|
cells[targetX][targetY].generateDrawableEntity(stride);
|
||||||
}
|
}
|
||||||
updateable[targetX][targetY] = false;
|
updateable[targetX][targetY] = false;
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import electrosphere.entity.EntityUtil;
|
|||||||
import electrosphere.main.Globals;
|
import electrosphere.main.Globals;
|
||||||
import electrosphere.renderer.Model;
|
import electrosphere.renderer.Model;
|
||||||
import electrosphere.renderer.ModelUtils;
|
import electrosphere.renderer.ModelUtils;
|
||||||
|
import electrosphere.renderer.ShaderProgram;
|
||||||
import electrosphere.util.Utilities;
|
import electrosphere.util.Utilities;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
@ -23,12 +24,15 @@ public class DrawCell {
|
|||||||
|
|
||||||
Entity modelEntity;
|
Entity modelEntity;
|
||||||
|
|
||||||
public DrawCell(float[][] drawArray, int drawWidth, int cellX, int cellY, int cellWidth){
|
ShaderProgram program;
|
||||||
|
|
||||||
|
public DrawCell(float[][] drawArray, int drawWidth, int cellX, int cellY, int cellWidth, ShaderProgram program){
|
||||||
this.drawArray = drawArray;
|
this.drawArray = drawArray;
|
||||||
this.drawWidth = drawWidth;
|
this.drawWidth = drawWidth;
|
||||||
this.cellX = cellX;
|
this.cellX = cellX;
|
||||||
this.cellY = cellY;
|
this.cellY = cellY;
|
||||||
this.cellWidth = cellWidth;
|
this.cellWidth = cellWidth;
|
||||||
|
this.program = program;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,7 +43,7 @@ public class DrawCell {
|
|||||||
if(modelEntity != null){
|
if(modelEntity != null){
|
||||||
Globals.entityManager.deregisterEntity(modelEntity);
|
Globals.entityManager.deregisterEntity(modelEntity);
|
||||||
}
|
}
|
||||||
Model terrainModel = ModelUtils.createTerrainModel(drawArray, stride);
|
Model terrainModel = ModelUtils.createTerrainModelPrecomputedShader(drawArray, program, stride);
|
||||||
modelEntity = EntityUtil.spawnDrawableEntity(terrainModel);
|
modelEntity = EntityUtil.spawnDrawableEntity(terrainModel);
|
||||||
// System.out.println("New cell @ " + cellX * cellWidth + "," + cellY * cellWidth);
|
// System.out.println("New cell @ " + cellX * cellWidth + "," + cellY * cellWidth);
|
||||||
EntityUtil.getEntityPosition(modelEntity).set(new Vector3f(cellX * cellWidth, 0, cellY * cellWidth));
|
EntityUtil.getEntityPosition(modelEntity).set(new Vector3f(cellX * cellWidth, 0, cellY * cellWidth));
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import electrosphere.util.Utilities;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -27,11 +29,21 @@ public class TerrainManager {
|
|||||||
TerrainModel model;
|
TerrainModel model;
|
||||||
|
|
||||||
|
|
||||||
|
//Basic idea is we associate string that contains chunk x&y with elevation
|
||||||
|
//While we incur a penalty with converting ints -> string, think this will
|
||||||
|
//offset regenerating the array every time we want a new one
|
||||||
|
int cacheSize = 50;
|
||||||
|
HashMap<String, float[][]> elevationMapCache;
|
||||||
|
ArrayList<String> elevationMapCacheContents;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public TerrainManager(int worldSizeDiscrete, int verticalInterpolationRatio, int dynamicInterpolationRatio){
|
public TerrainManager(int worldSizeDiscrete, int verticalInterpolationRatio, int dynamicInterpolationRatio){
|
||||||
this.worldSizeDiscrete = worldSizeDiscrete;
|
this.worldSizeDiscrete = worldSizeDiscrete;
|
||||||
this.verticalInterpolationRatio = verticalInterpolationRatio;
|
this.verticalInterpolationRatio = verticalInterpolationRatio;
|
||||||
this.dynamicInterpolationRatio = dynamicInterpolationRatio;
|
this.dynamicInterpolationRatio = dynamicInterpolationRatio;
|
||||||
|
this.elevationMapCache = new HashMap();
|
||||||
|
this.elevationMapCacheContents = new ArrayList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generate(){
|
public void generate(){
|
||||||
@ -63,7 +75,21 @@ public class TerrainManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public float[][] getAugmentedTerrainAtChunk(int x, int y){
|
public float[][] getAugmentedTerrainAtChunk(int x, int y){
|
||||||
return model.getAugmentedElevationForChunk(x, y);
|
String targetChunkName = x + "-" + y;
|
||||||
|
if(elevationMapCache.containsKey(targetChunkName)){
|
||||||
|
elevationMapCacheContents.remove(targetChunkName);
|
||||||
|
elevationMapCacheContents.add(0, targetChunkName);
|
||||||
|
return elevationMapCache.get(targetChunkName);
|
||||||
|
} else {
|
||||||
|
float[][] targetChunk = model.getAugmentedElevationForChunk(x, y);
|
||||||
|
if(elevationMapCacheContents.size() > cacheSize){
|
||||||
|
String oldChunk = elevationMapCacheContents.remove(elevationMapCacheContents.size() - 1);
|
||||||
|
elevationMapCache.remove(oldChunk);
|
||||||
|
}
|
||||||
|
elevationMapCache.put(targetChunkName, targetChunk);
|
||||||
|
elevationMapCacheContents.add(targetChunkName);
|
||||||
|
return targetChunk;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getHeightAtPosition(float x, float y){
|
public float getHeightAtPosition(float x, float y){
|
||||||
|
|||||||
@ -364,7 +364,7 @@ public class Main {
|
|||||||
|
|
||||||
static void initPlayer(){
|
static void initPlayer(){
|
||||||
Globals.player = new Entity();
|
Globals.player = new Entity();
|
||||||
Globals.player.putData("position", new Vector3f(playerStartRealX,1900f,playerStartRealY));
|
Globals.player.putData("position", new Vector3f(playerStartRealX,2200f,playerStartRealY));
|
||||||
|
|
||||||
Globals.cellManager.setCellX(GL_S);
|
Globals.cellManager.setCellX(GL_S);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -162,6 +162,171 @@ public class ModelUtils {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Model createTerrainModelPrecomputedShader(float[][] heightfield, ShaderProgram program, int stride){
|
||||||
|
Model rVal = new Model();
|
||||||
|
rVal.meshes = new ArrayList();
|
||||||
|
Mesh m = new Mesh();
|
||||||
|
int width = heightfield.length;
|
||||||
|
int height = heightfield[0].length;
|
||||||
|
|
||||||
|
int actualWidth = (int)Math.ceil(1.0f * width / (1.0f * stride));
|
||||||
|
int actualHeight = (int)Math.ceil(1.0f * height / (1.0f * stride));
|
||||||
|
|
||||||
|
// System.out.println(actualWidth + " " + actualHeight);
|
||||||
|
|
||||||
|
// System.out.println((actualWidth - 1) * (actualHeight - 1));
|
||||||
|
|
||||||
|
FloatBuffer vertices;
|
||||||
|
FloatBuffer normals;
|
||||||
|
IntBuffer faces;
|
||||||
|
FloatBuffer texture_coords;
|
||||||
|
if(stride * actualWidth > width){
|
||||||
|
int drawWidth = actualWidth + 1;
|
||||||
|
int drawHeight = actualHeight + 1;
|
||||||
|
vertices = BufferUtils.createFloatBuffer(drawWidth * drawHeight * 3);
|
||||||
|
normals = BufferUtils.createFloatBuffer(drawWidth * drawHeight * 3);
|
||||||
|
faces = BufferUtils.createIntBuffer((drawWidth - 1) * (drawHeight - 1) * 2 * 3);
|
||||||
|
texture_coords = BufferUtils.createFloatBuffer(drawWidth * drawHeight * 2);
|
||||||
|
} else {
|
||||||
|
vertices = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 3);
|
||||||
|
normals = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 3);
|
||||||
|
faces = BufferUtils.createIntBuffer((actualWidth - 1) * (actualHeight - 1) * 2 * 3);
|
||||||
|
texture_coords = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int x = 0; x < width; x = x + stride){
|
||||||
|
for(int y = 0; y < height; y = y + stride){
|
||||||
|
//deal with vertex
|
||||||
|
vertices.put(x);
|
||||||
|
vertices.put(heightfield[x][y]);
|
||||||
|
vertices.put(y);
|
||||||
|
//deal with normal
|
||||||
|
if(x / stride < actualWidth - 1){
|
||||||
|
if(y / stride < actualHeight - 1){
|
||||||
|
float hL;
|
||||||
|
if(x > 0){
|
||||||
|
hL = heightfield[x-1][y];
|
||||||
|
} else {
|
||||||
|
hL = heightfield[x][y];
|
||||||
|
}
|
||||||
|
float hR = heightfield[x+1][y];
|
||||||
|
float hD = heightfield[x][y+1];
|
||||||
|
float hU;
|
||||||
|
if(y > 0){
|
||||||
|
hU = heightfield[x][y-1];
|
||||||
|
} else {
|
||||||
|
hU = heightfield[x][y];
|
||||||
|
}
|
||||||
|
Vector3f Normal = new Vector3f(hL - hR, 2.0f, hD - hU);
|
||||||
|
Normal.normalize();
|
||||||
|
normals.put(Normal.x);
|
||||||
|
normals.put(Normal.y);
|
||||||
|
normals.put(Normal.z);
|
||||||
|
} else {
|
||||||
|
float hL;
|
||||||
|
if(x > 0){
|
||||||
|
hL = heightfield[x-1][y];
|
||||||
|
} else {
|
||||||
|
hL = heightfield[x][y];
|
||||||
|
}
|
||||||
|
float hR = heightfield[x+1][y];
|
||||||
|
float hD = heightfield[x][y];
|
||||||
|
float hU = heightfield[x][y-1];
|
||||||
|
Vector3f Normal = new Vector3f(hL - hR, 2.0f, hD - hU);
|
||||||
|
Normal.normalize();
|
||||||
|
normals.put(Normal.x);
|
||||||
|
normals.put(Normal.y);
|
||||||
|
normals.put(Normal.z);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(y / stride < actualHeight - 1){
|
||||||
|
float hL = heightfield[x-1][y];
|
||||||
|
float hR = heightfield[x][y];
|
||||||
|
float hD = heightfield[x][y+1];
|
||||||
|
float hU;
|
||||||
|
if(y > 0){
|
||||||
|
hU = heightfield[x][y-1];
|
||||||
|
} else {
|
||||||
|
hU = heightfield[x][y];
|
||||||
|
}
|
||||||
|
Vector3f Normal = new Vector3f(hL - hR, 2.0f, hD - hU);
|
||||||
|
Normal.normalize();
|
||||||
|
normals.put(Normal.x);
|
||||||
|
normals.put(Normal.y);
|
||||||
|
normals.put(Normal.z);
|
||||||
|
} else {
|
||||||
|
float hL = heightfield[x-1][y];
|
||||||
|
float hR = heightfield[x][y];
|
||||||
|
float hD = heightfield[x][y];
|
||||||
|
float hU = heightfield[x][y-1];
|
||||||
|
Vector3f Normal = new Vector3f(hL - hR, 2.0f, hD - hU);
|
||||||
|
Normal.normalize();
|
||||||
|
normals.put(Normal.x);
|
||||||
|
normals.put(Normal.y);
|
||||||
|
normals.put(Normal.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//deal with texture coordinates
|
||||||
|
if(x / stride % 2 == 0){
|
||||||
|
if(y / stride % 2 == 0){
|
||||||
|
texture_coords.put(0);
|
||||||
|
texture_coords.put(0);
|
||||||
|
} else {
|
||||||
|
texture_coords.put(0);
|
||||||
|
texture_coords.put(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(y / stride % 2 == 0){
|
||||||
|
texture_coords.put(1);
|
||||||
|
texture_coords.put(0);
|
||||||
|
} else {
|
||||||
|
texture_coords.put(1);
|
||||||
|
texture_coords.put(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//deal with faces
|
||||||
|
if(1.0f * x / stride < actualWidth - 1 && 1.0f * y / stride < actualHeight - 1){
|
||||||
|
faces.put((x / stride + 0) * actualHeight + (y / stride + 0));
|
||||||
|
faces.put((x / stride + 0) * actualHeight + (y / stride + 1));
|
||||||
|
faces.put((x / stride + 1) * actualHeight + (y / stride + 0));
|
||||||
|
faces.put((x / stride + 1) * actualHeight + (y / stride + 0));
|
||||||
|
faces.put((x / stride + 0) * actualHeight + (y / stride + 1));
|
||||||
|
faces.put((x / stride + 1) * actualHeight + (y / stride + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vertices.flip();
|
||||||
|
normals.flip();
|
||||||
|
faces.flip();
|
||||||
|
texture_coords.flip();
|
||||||
|
|
||||||
|
m.vertexArrayObject = glGenVertexArrays();
|
||||||
|
glBindVertexArray(m.vertexArrayObject);
|
||||||
|
//buffer vertices
|
||||||
|
m.buffer_vertices(vertices);
|
||||||
|
//buffer normals
|
||||||
|
m.buffer_normals(normals);
|
||||||
|
//buffer faces
|
||||||
|
m.buffer_faces(faces);
|
||||||
|
//buffer texture coords
|
||||||
|
m.buffer_texture_coords(texture_coords);
|
||||||
|
m.shader = program;
|
||||||
|
glBindVertexArray(0);
|
||||||
|
m.parent = rVal;
|
||||||
|
|
||||||
|
Material groundMat = new Material();
|
||||||
|
Texture groundTex = new Texture("Textures/Ground/Dirt1.png");
|
||||||
|
groundMat.set_diffuse(groundTex);
|
||||||
|
groundMat.set_specular(groundTex);
|
||||||
|
m.set_material(groundMat);
|
||||||
|
|
||||||
|
rVal.meshes.add(m);
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Model createUnitCube(){
|
public static Model createUnitCube(){
|
||||||
Model rVal = new Model();
|
Model rVal = new Model();
|
||||||
rVal.meshes = new ArrayList();
|
rVal.meshes = new ArrayList();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user