Attempted performance tweaks (caching, etc)

This commit is contained in:
satellite 2021-04-04 20:31:14 -04:00
parent 4ced329a47
commit 716ed65f70
5 changed files with 216 additions and 9 deletions

View File

@ -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;

View File

@ -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));

View File

@ -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){

View File

@ -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);
} }

View File

@ -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();