Work on minimizing terrain poly count

This commit is contained in:
austin 2021-11-21 00:13:25 -05:00
parent b2fe119348
commit dda5cb59e5
2 changed files with 489 additions and 1 deletions

View File

@ -93,7 +93,7 @@ public class DrawCell {
if(modelEntity != null){
Globals.entityManager.deregisterEntity(modelEntity);
}
Model terrainModel = ModelUtils.createTerrainModelPrecomputedShader(heightmap, texturemap, program, stride);
Model terrainModel = ModelUtils.createMinimizedTerrainModelPrecomputedShader(heightmap, texturemap, program, stride);
Mesh terrainMesh = terrainModel.meshes.get(0);
terrainMesh.useTextureList = true;
terrainMesh.textureList.add(groundTextureOne);

View File

@ -6,6 +6,8 @@ import electrosphere.renderer.texture.Texture;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.joml.Vector3f;
import org.lwjgl.BufferUtils;
import static org.lwjgl.opengl.GL30.glBindVertexArray;
@ -340,6 +342,492 @@ public class ModelUtils {
return rVal;
}
static float MINIMIZATION_DIFF_MAX = 0.1f;
public static Model createMinimizedTerrainModelPrecomputedShader(float[][] heightfield, float[][] texturemap, ShaderProgram program, int stride){
class QuadToGenerate {
//coords are inclusive
int startX;
int endX;
int startY;
int endY;
float diff;
float min;
float max;
float texture;
boolean homogeneousTexture;
QuadToGenerate(int startX, int startY, int endX, int endY, float diff, float min, float max, boolean homogeneousTexture, float texture){
this.startX = startX;
this.startY = startY;
this.endX = endX;
this.endY = endY;
this.diff = diff;
this.min = min;
this.max = max;
this.texture = texture;
this.homogeneousTexture = homogeneousTexture;
}
}
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;
FloatBuffer textureIndices;
if(stride * actualWidth > width){
int drawWidth = actualWidth + 1;
int drawHeight = actualHeight + 1;
vertices = BufferUtils.createFloatBuffer(drawWidth * drawHeight * 12);
normals = BufferUtils.createFloatBuffer(drawWidth * drawHeight * 12);
faces = BufferUtils.createIntBuffer((drawWidth - 1) * (drawHeight - 1) * 2 * 3);
texture_coords = BufferUtils.createFloatBuffer(drawWidth * drawHeight * 8);
textureIndices = BufferUtils.createFloatBuffer(drawWidth * drawHeight * 16);
} else {
vertices = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 12);
normals = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 12);
faces = BufferUtils.createIntBuffer((actualWidth - 1) * (actualHeight - 1) * 2 * 3);
texture_coords = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 8);
textureIndices = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 16);
}
//merge along y
List<QuadToGenerate> firstPhaseQuads = new LinkedList();
QuadToGenerate quadCurrent = null;
float minVal = 0;
float maxVal = 0;
int textureVal = -1;
for(int x = 0; x < width - 1; x = x + stride){
quadCurrent = null;
for(int y = 0; y < height - 1; y = y + stride){
if(quadCurrent == null){
minVal = 100000000;
maxVal = 0;
textureVal = -1;
//minval
if(heightfield[x][y] < minVal){
minVal = heightfield[x][y];
}
if(heightfield[x+stride][y] < minVal){
minVal = heightfield[x+stride][y];
}
if(heightfield[x][y+stride] < minVal){
minVal = heightfield[x][y+stride];
}
if(heightfield[x+stride][y+stride] < minVal){
minVal = heightfield[x+stride][y+stride];
}
//maxval
if(heightfield[x][y] > maxVal){
maxVal = heightfield[x][y];
}
if(heightfield[x+stride][y] > maxVal){
maxVal = heightfield[x+stride][y];
}
if(heightfield[x][y+stride] > maxVal){
maxVal = heightfield[x][y+stride];
}
if(heightfield[x+stride][y+stride] > maxVal){
maxVal = heightfield[x+stride][y+stride];
}
boolean textureMatch = false;
float texture = -1;
if(x+stride < width - 1 && y+stride < height -1 && texturemap[x][y] == texturemap[x+stride][y] &&
texturemap[x][y] == texturemap[x][y+stride] &&
texturemap[x][y] == texturemap[x+stride][y+stride]){
textureMatch = true;
texture = texturemap[x][y];
} else {
// if(x > 8 && (x+stride < width - 1) && (y+stride < height -1)){
// System.out.println(
// (x+stride < width - 1) + " " +
// (y+stride < height -1) + " " +
// (texturemap[x][y] == texturemap[x+stride][y]) + " " +
// (texturemap[x][y] == texturemap[x][y+stride]) + " " +
// (texturemap[x][y] == texturemap[x+stride][y+stride])
// );
// }
}
if(textureMatch){
quadCurrent = new QuadToGenerate(x,y,x+stride,y+stride,maxVal - minVal,minVal,maxVal,textureMatch,texture);
} else {
firstPhaseQuads.add(new QuadToGenerate(x,y,x+stride,y+stride,maxVal - minVal,minVal,maxVal,textureMatch,texture));
quadCurrent = null;
}
} else {
float newMin = minVal;
float newMax = maxVal;
//min
if(heightfield[x][y+stride] < newMin){
newMin = heightfield[x][y+stride];
}
if(heightfield[x+stride][y+stride] < newMin){
newMin = heightfield[x+stride][y+stride];
}
//max
if(heightfield[x][y+stride] > newMax){
newMax = heightfield[x][y+stride];
}
if(heightfield[x+stride][y+stride] > newMax){
newMax = heightfield[x+stride][y+stride];
}
if(y+stride < height - 1 && x+stride < width - 1){
if(newMax - newMin < MINIMIZATION_DIFF_MAX &&
texturemap[quadCurrent.startX][quadCurrent.startY] == texturemap[x+stride][y] &&
texturemap[quadCurrent.startX][quadCurrent.startY] == texturemap[x][y+stride] &&
texturemap[quadCurrent.startX][quadCurrent.startY] == texturemap[x+stride][y+stride]
){
//add to quad
quadCurrent.endY = y + stride;
quadCurrent.diff = newMax - newMin;
quadCurrent.min = newMax;
quadCurrent.max = newMax;
} else {
//push quad
firstPhaseQuads.add(quadCurrent);
quadCurrent = null;
// System.out.println("Push");
}
} else {
if(newMax - newMin < MINIMIZATION_DIFF_MAX){
//add to quad
quadCurrent.endY = y + stride;
quadCurrent.diff = newMax - newMin;
quadCurrent.min = newMax;
quadCurrent.max = newMax;
} else {
//push quad
firstPhaseQuads.add(quadCurrent);
quadCurrent = null;
// System.out.println("Push");
}
}
}
}
if(quadCurrent != null){
firstPhaseQuads.add(quadCurrent);
}
}
List<QuadToGenerate> finalQuads = new LinkedList();
for(QuadToGenerate current : firstPhaseQuads){
finalQuads.add(current);
}
// System.out.println(finalQuads.size());
//merge along x
// QuadToGenerate currentQuad = null;
// for(QuadToGenerate currentIteration : firstPhaseQuads){
// if(currentQuad == null){
// currentQuad = currentIteration;
// } else {
// if(currentQuad.min < currentIteration.min && currentQuad.max < currentIteration.max){
// float min = currentQuad.min;
// float max = currentIteration.max;
// if(max - min < MINIMIZATION_DIFF_MAX){
// currentQuad.endX = currentIteration.endX;
// currentQuad.max = currentIteration.max;
// } else {
// finalQuads.add(currentQuad);
// currentQuad = currentIteration;
// }
// } else if(currentQuad.min > currentIteration.min && currentQuad.max > currentIteration.max){
// float min = currentIteration.min;
// float max = currentQuad.max;
// if(max - min < MINIMIZATION_DIFF_MAX){
// currentQuad.endX = currentIteration.endX;
// currentQuad.min = currentIteration.min;
// } else {
// finalQuads.add(currentQuad);
// currentQuad = currentIteration;
// }
// } else {
// if(currentQuad.min < currentIteration.min){
// currentQuad.endX = currentIteration.endX;
// } else {
// currentQuad.endX = currentIteration.endX;
// currentQuad.min = currentIteration.min;
// currentQuad.max = currentIteration.max;
// }
// }
// }
// }
// finalQuads.add(currentQuad);
for(QuadToGenerate current : finalQuads){
// System.out.println(current.startX + " " + current.startY + " " + current.endX + " " + current.endY);
}
// System.out.println(finalQuads.size());
// System.exit(0);
int incrementer = 0;
for(QuadToGenerate current : finalQuads){
//deal with vertex
//0,0
vertices.put(current.startX);
vertices.put(heightfield[current.startX][current.startY]);
vertices.put(current.startY);
//1,0
vertices.put(current.endX);
vertices.put(heightfield[current.endX][current.startY]);
vertices.put(current.startY);
//0,1
vertices.put(current.startX);
vertices.put(heightfield[current.startX][current.endY]);
vertices.put(current.endY);
//1,1
vertices.put(current.endX);
vertices.put(heightfield[current.endX][current.endY]);
vertices.put(current.endY);
//deal with normal
Vector3f normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, current.startX, current.startY);
normals.put(normal.x);
normals.put(normal.y);
normals.put(normal.z);
normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, current.endX, current.startY);
normals.put(normal.x);
normals.put(normal.y);
normals.put(normal.z);
normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, current.startX, current.endY);
normals.put(normal.x);
normals.put(normal.y);
normals.put(normal.z);
normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, current.endX, current.endY);
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);
// texture_coords.put(1);
// texture_coords.put(0);
// texture_coords.put(0);
// texture_coords.put(1);
// texture_coords.put(1);
// texture_coords.put(1);
// } 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);
// }
// }
texture_coords.put(0);
texture_coords.put(0);
texture_coords.put(current.endX - current.startX);
texture_coords.put(0);
texture_coords.put(0);
texture_coords.put(current.endY - current.startY);
texture_coords.put(current.endX - current.startX);
texture_coords.put(current.endY - current.startY);
if(current.endX < width - 1 && current.endY < height - 1){
// texturemap[x+stride][y+stride];
for(int i = 0; i < 4 ; i++){
// textureIndices.put(1);
// textureIndices.put(0);
// textureIndices.put(0);
// textureIndices.put(0);
textureIndices.put(texturemap[current.startX][current.startY]);
textureIndices.put(texturemap[current.endX][current.startY]);
textureIndices.put(texturemap[current.startX][current.endY]);
textureIndices.put(texturemap[current.endX][current.endY]);
}
} else {
for(int i = 0; i < 4 ; i++){
textureIndices.put(0);
textureIndices.put(0);
textureIndices.put(0);
textureIndices.put(0);
}
}
//deal with faces
faces.put(incrementer * 4 + 0);
faces.put(incrementer * 4 + 1);
faces.put(incrementer * 4 + 2);
faces.put(incrementer * 4 + 1);
faces.put(incrementer * 4 + 2);
faces.put(incrementer * 4 + 3);
incrementer++;
}
// int numFaces = (actualWidth - 1) * (actualHeight - 1) * 2 * 3;
// for(int x = 0; x < width - 1; x = x + stride){
// for(int y = 0; y < height - 1; y = y + stride){
// //deal with vertex
// //0,0
// vertices.put(x);
// vertices.put(heightfield[x][y]);
// vertices.put(y);
// //1,0
// vertices.put(x + stride);
// vertices.put(heightfield[x+stride][y]);
// vertices.put(y);
// //0,1
// vertices.put(x);
// vertices.put(heightfield[x][y+stride]);
// vertices.put(y + stride);
// //1,1
// vertices.put(x + stride);
// vertices.put(heightfield[x+stride][y+stride]);
// vertices.put(y + stride);
// //deal with normal
// Vector3f normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, x, y);
// normals.put(normal.x);
// normals.put(normal.y);
// normals.put(normal.z);
// normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, x + stride, y);
// normals.put(normal.x);
// normals.put(normal.y);
// normals.put(normal.z);
// normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, x, y + stride);
// normals.put(normal.x);
// normals.put(normal.y);
// normals.put(normal.z);
// normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, x + stride, y + stride);
// 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);
//// texture_coords.put(1);
//// texture_coords.put(0);
//// texture_coords.put(0);
//// texture_coords.put(1);
//// texture_coords.put(1);
//// texture_coords.put(1);
//// } 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);
//// }
//// }
// texture_coords.put(0);
// texture_coords.put(0);
// texture_coords.put(1);
// texture_coords.put(0);
// texture_coords.put(0);
// texture_coords.put(1);
// texture_coords.put(1);
// texture_coords.put(1);
//
// if(x + stride < width - 1 && y + stride < height - 1){
//// texturemap[x+stride][y+stride];
// for(int i = 0; i < 4 ; i++){
//// textureIndices.put(1);
//// textureIndices.put(0);
//// textureIndices.put(0);
//// textureIndices.put(0);
// textureIndices.put(texturemap[x][y]);
// textureIndices.put(texturemap[x+stride][y]);
// textureIndices.put(texturemap[x][y+stride]);
// textureIndices.put(texturemap[x+stride][y+stride]);
// }
// } else {
// for(int i = 0; i < 4 ; i++){
// textureIndices.put(0);
// textureIndices.put(0);
// textureIndices.put(0);
// textureIndices.put(0);
// }
// }
//
//
// //deal with faces
// if(1.0f * x / stride < actualWidth - 1 && 1.0f * y / stride < actualHeight - 1){
// faces.put(incrementer * 4 + 0);
// faces.put(incrementer * 4 + 1);
// faces.put(incrementer * 4 + 2);
// faces.put(incrementer * 4 + 1);
// faces.put(incrementer * 4 + 2);
// faces.put(incrementer * 4 + 3);
// }
// incrementer++;
// }
// }
vertices.flip();
normals.flip();
faces.flip();
texture_coords.flip();
textureIndices.flip();
m.vertexArrayObject = glGenVertexArrays();
glBindVertexArray(m.vertexArrayObject);
//buffer vertices
m.buffer_vertices(vertices, 3);
//buffer normals
m.buffer_normals(normals, 3);
//buffer faces
m.buffer_faces(faces);
//buffer texture coords
m.buffer_texture_coords(texture_coords, 2);
//texture indices
m.bufferCustomFloatAttribArray(textureIndices, 4, 5);
m.shader = program;
glBindVertexArray(0);
m.parent = rVal;
m.hasBones = false;
Material groundMat = new Material();
Globals.assetManager.addTexturePathtoQueue("/Textures/Ground/Dirt1.png");
groundMat.set_diffuse("/Textures/Ground/Dirt1.png");
groundMat.set_specular("/Textures/Ground/Dirt1.png");
m.setMaterial(groundMat);
rVal.meshes.add(m);
return rVal;
}
static Vector3f calculateTerrainNormal(float[][] heightfield, int actualWidth, int actualHeight, int stride, int x, int y){
Vector3f rVal = new Vector3f();
if(x / stride < actualWidth - 1){