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;
import electrosphere.game.terrain.TerrainManager;
import electrosphere.renderer.ShaderProgram;
import java.util.Arrays;
/**
@ -26,11 +27,13 @@ public class CellManager {
boolean[][] updateable;
ShaderProgram program;
int drawRadius = 5;
int drawRadius = 1;
int drawStepdownInterval = 2;
int drawStepdownValue = 10;
int drawStepdownValue = 20;
public CellManager(TerrainManager terrainManager, float realX, float realY){
this.terrainManager = terrainManager;
@ -48,6 +51,8 @@ public class CellManager {
}
cellX = transformRealSpaceToCellSpace(realX);
cellY = transformRealSpaceToCellSpace(realY);
program = ShaderProgram.smart_assemble_shader(false, true);
}
public int getCellX(){
@ -98,7 +103,8 @@ public class CellManager {
terrainManager.getAugmentedChunkWidth(),
currentCellX,
currentCellY,
terrainManager.getChunkWidth()
terrainManager.getChunkWidth(),
program
);
}
valid[targetX][targetY] = true;
@ -135,7 +141,10 @@ public class CellManager {
currentCellY < terrainManager.getWorldDiscreteSize()
){
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);
}
drawable[targetX][targetY] = true;
@ -170,7 +179,10 @@ public class CellManager {
currentCellY < terrainManager.getWorldDiscreteSize()
){
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);
}
updateable[targetX][targetY] = false;

View File

@ -5,6 +5,7 @@ import electrosphere.entity.EntityUtil;
import electrosphere.main.Globals;
import electrosphere.renderer.Model;
import electrosphere.renderer.ModelUtils;
import electrosphere.renderer.ShaderProgram;
import electrosphere.util.Utilities;
import org.joml.Vector3f;
@ -23,12 +24,15 @@ public class DrawCell {
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.drawWidth = drawWidth;
this.cellX = cellX;
this.cellY = cellY;
this.cellWidth = cellWidth;
this.program = program;
}
/**
@ -39,7 +43,7 @@ public class DrawCell {
if(modelEntity != null){
Globals.entityManager.deregisterEntity(modelEntity);
}
Model terrainModel = ModelUtils.createTerrainModel(drawArray, stride);
Model terrainModel = ModelUtils.createTerrainModelPrecomputedShader(drawArray, program, stride);
modelEntity = EntityUtil.spawnDrawableEntity(terrainModel);
// System.out.println("New cell @ " + cellX * cellWidth + "," + 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.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
/**
*
@ -27,11 +29,21 @@ public class TerrainManager {
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){
this.worldSizeDiscrete = worldSizeDiscrete;
this.verticalInterpolationRatio = verticalInterpolationRatio;
this.dynamicInterpolationRatio = dynamicInterpolationRatio;
this.elevationMapCache = new HashMap();
this.elevationMapCacheContents = new ArrayList();
}
public void generate(){
@ -63,7 +75,21 @@ public class TerrainManager {
}
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){

View File

@ -364,7 +364,7 @@ public class Main {
static void initPlayer(){
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);
}

View File

@ -162,6 +162,171 @@ public class ModelUtils {
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(){
Model rVal = new Model();
rVal.meshes = new ArrayList();