optimize voxel rasterize data passthrough
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2024-11-19 13:01:44 -05:00
parent 4d9047d8cf
commit 8284697812
7 changed files with 427 additions and 264 deletions

View File

@ -1082,6 +1082,7 @@ Fix draw cells not deleting once all children have reported generation
Fix server data cells unloading before ready state Fix server data cells unloading before ready state
Fix terrain chunk generation trying to generate rigid body for no-vertex cell Fix terrain chunk generation trying to generate rigid body for no-vertex cell
Fix server homogenous chunk check on generation with variadic weights Fix server homogenous chunk check on generation with variadic weights
Optimize data passing from voxel rasterizer to model generation

View File

@ -25,7 +25,7 @@ import electrosphere.entity.Entity;
import electrosphere.entity.types.terrain.TerrainChunkData; import electrosphere.entity.types.terrain.TerrainChunkData;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
import electrosphere.net.parser.net.message.TerrainMessage; import electrosphere.net.parser.net.message.TerrainMessage;
import electrosphere.renderer.meshgen.TerrainChunkModelGeneration; import electrosphere.renderer.meshgen.TransvoxelModelGeneration;
import electrosphere.renderer.model.Model; import electrosphere.renderer.model.Model;
import electrosphere.server.terrain.manager.ServerTerrainChunk; import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.server.terrain.manager.ServerTerrainManager; import electrosphere.server.terrain.manager.ServerTerrainManager;
@ -298,7 +298,7 @@ public class ClientTerrainManager {
Globals.profiler.beginCpuSample("ClientTerrainManager.generateTerrainChunkGeometry"); Globals.profiler.beginCpuSample("ClientTerrainManager.generateTerrainChunkGeometry");
lock.acquireUninterruptibly(); lock.acquireUninterruptibly();
for(TerrainChunkGenQueueItem queueItem : terrainChunkGenerationQueue){ for(TerrainChunkGenQueueItem queueItem : terrainChunkGenerationQueue){
Model terrainModel = TerrainChunkModelGeneration.generateTerrainModel(queueItem.getData(), queueItem.getAtlas()); Model terrainModel = TransvoxelModelGeneration.generateTerrainModel(queueItem.getData(), queueItem.getAtlas());
Globals.assetManager.registerModelToSpecificString(terrainModel, queueItem.getPromisedHash()); Globals.assetManager.registerModelToSpecificString(terrainModel, queueItem.getPromisedHash());
if(queueItem.notifyTarget != null){ if(queueItem.notifyTarget != null){
queueItem.notifyTarget.alertToGeneration(); queueItem.notifyTarget.alertToGeneration();

View File

@ -258,30 +258,10 @@ public class CollisionBodyCreation {
*/ */
public static DBody generateBodyFromTerrainData(CollisionEngine collisionEngine, TerrainChunkData data, long categoryBits){ public static DBody generateBodyFromTerrainData(CollisionEngine collisionEngine, TerrainChunkData data, long categoryBits){
DBody body = null; DBody body = null;
int elementCount = data.getFaceElements().size();
float[] vertices = new float[elementCount * 3];
int vertexInserterPos = 0;
int[] indices = new int[elementCount];
int indexInserterPos = 0;
for(int element : data.getFaceElements()){
//add a new vertex
vertices[vertexInserterPos*3+0] = data.getVertices().get(element*3+0);
vertices[vertexInserterPos*3+1] = data.getVertices().get(element*3+1);
vertices[vertexInserterPos*3+2] = data.getVertices().get(element*3+2);
vertexInserterPos = vertexInserterPos + 1;
//push faces -- instead of pushing the element directly, instead use the incrementer because we want to draw a new vertex
//there should be no vertex-sharing between triangles. This keeps the meshes from blurring texture/lighting
indices[indexInserterPos] = indexInserterPos;
indexInserterPos++;
}
//create trimesh //create trimesh
if(vertices.length > 0){ if(data.getFaceElements().length > 0){
DTriMesh triMesh = collisionEngine.createTrimeshGeom(vertices,indices,categoryBits); DTriMesh triMesh = collisionEngine.createTrimeshGeom(data.getVertices(),data.getFaceElements(),categoryBits);
body = collisionEngine.createDBody(triMesh); body = collisionEngine.createDBody(triMesh);
collisionEngine.setKinematic(body); collisionEngine.setKinematic(body);
collisionEngine.setGravityMode(body, false); collisionEngine.setGravityMode(body, false);

View File

@ -20,7 +20,6 @@ import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils; import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.meshgen.TerrainChunkModelGeneration;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration; import electrosphere.renderer.meshgen.TransvoxelModelGeneration;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData; import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.Realm;
@ -65,7 +64,7 @@ public class TerrainChunk {
if(Globals.clientScene.containsEntity(rVal)){ if(Globals.clientScene.containsEntity(rVal)){
String modelPath = ClientTerrainManager.queueTerrainGridGeneration(data, atlas, notifyTarget, toDelete); String modelPath = ClientTerrainManager.queueTerrainGridGeneration(data, atlas, notifyTarget, toDelete);
EntityCreationUtils.makeEntityDrawablePreexistingModel(rVal, modelPath); EntityCreationUtils.makeEntityDrawablePreexistingModel(rVal, modelPath);
if(levelOfDetail == ClientDrawCellManager.FULL_RES_LOD && data.faceElements.size() > 0){ if(levelOfDetail == ClientDrawCellManager.FULL_RES_LOD && data.faceElements.length > 0){
PhysicsEntityUtils.clientAttachTerrainChunkRigidBody(rVal, data); PhysicsEntityUtils.clientAttachTerrainChunkRigidBody(rVal, data);
CollisionObjUtils.clientPositionCharacter(rVal, new Vector3d(EntityUtils.getPosition(rVal)), new Quaterniond()); CollisionObjUtils.clientPositionCharacter(rVal, new Vector3d(EntityUtils.getPosition(rVal)), new Quaterniond());
} else { } else {
@ -112,10 +111,11 @@ public class TerrainChunk {
*/ */
public static Entity serverCreateTerrainChunkEntity(Realm realm, Vector3d position, float[][][] weights, int[][][] values){ public static Entity serverCreateTerrainChunkEntity(Realm realm, Vector3d position, float[][][] weights, int[][][] values){
TerrainChunkData data = TerrainChunkModelGeneration.generateTerrainChunkData(weights, values); TransvoxelChunkData chunkData = new TransvoxelChunkData(weights, values, ClientDrawCellManager.FULL_RES_LOD);
TerrainChunkData data = TransvoxelModelGeneration.generateTerrainChunkData(chunkData);
Entity rVal = EntityCreationUtils.createServerEntity(realm, position); Entity rVal = EntityCreationUtils.createServerEntity(realm, position);
if(data.vertices.size() > 0){ if(data.vertices.length > 0){
PhysicsEntityUtils.serverAttachTerrainChunkRigidBody(rVal, data); PhysicsEntityUtils.serverAttachTerrainChunkRigidBody(rVal, data);
rVal.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true); rVal.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
// ServerEntityUtils.initiallyPositionEntity(realm, rVal, position); // ServerEntityUtils.initiallyPositionEntity(realm, rVal, position);

View File

@ -2,7 +2,6 @@ package electrosphere.entity.types.terrain;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.nio.IntBuffer; import java.nio.IntBuffer;
import java.util.List;
import org.lwjgl.BufferUtils; import org.lwjgl.BufferUtils;
@ -12,17 +11,17 @@ import org.lwjgl.BufferUtils;
public class TerrainChunkData { public class TerrainChunkData {
//the verts //the verts
List<Float> vertices; float[] vertices;
//normals //normals
List<Float> normals; float[] normals;
//faces //faces
List<Integer> faceElements; int[] faceElements;
//UVs //UVs
List<Float> uvs; float[] uvs;
//texture samplers //texture samplers
List<Float> textureSamplers; //what textures in the atlas to sample float[] textureSamplers; //what textures in the atlas to sample
//texture ratio vector //texture ratio vector
List<Float> textureRatioVectors; //HOW MUCH of each texture in the atlas to sample float[] textureRatioVectors; //HOW MUCH of each texture in the atlas to sample
/** /**
* The various buffers of data to send to the gpu * The various buffers of data to send to the gpu
@ -49,7 +48,7 @@ public class TerrainChunkData {
* @param textureSamplers * @param textureSamplers
* @param lod The LOD of the model * @param lod The LOD of the model
*/ */
public TerrainChunkData(List<Float> vertices, List<Float> normals, List<Integer> faceElements, List<Float> uvs, List<Float> textureSamplers, List<Float> textureRatioVectors, int lod){ public TerrainChunkData(float[] vertices, float[] normals, int[] faceElements, float[] uvs, float[] textureSamplers, float[] textureRatioVectors, int lod){
this.vertices = vertices; this.vertices = vertices;
this.normals = normals; this.normals = normals;
this.faceElements = faceElements; this.faceElements = faceElements;
@ -63,50 +62,30 @@ public class TerrainChunkData {
* Allocates and fills the buffers to send to the gpu * Allocates and fills the buffers to send to the gpu
*/ */
public void constructBuffers(){ public void constructBuffers(){
int elementCount = this.getFaceElements().size(); vertexArrayBufferData = BufferUtils.createFloatBuffer(vertices.length);
vertexArrayBufferData = BufferUtils.createFloatBuffer(elementCount * 3); vertexArrayBufferData.put(vertices);
normalArrayBufferData = BufferUtils.createFloatBuffer(elementCount * 3);
textureArrayBufferData = BufferUtils.createFloatBuffer(elementCount * 2);
elementArrayBufferData = BufferUtils.createIntBuffer(elementCount);
int incrementer = 0;
for(int element : this.getFaceElements()){
//for each element, need to push vert, normal, etc
//push current vertex normalArrayBufferData = BufferUtils.createFloatBuffer(normals.length);
vertexArrayBufferData.put(this.getVertices().get(element*3+0)); normalArrayBufferData.put(normals);
vertexArrayBufferData.put(this.getVertices().get(element*3+1));
vertexArrayBufferData.put(this.getVertices().get(element*3+2));
//push current normals textureArrayBufferData = BufferUtils.createFloatBuffer(uvs.length);
normalArrayBufferData.put(this.getNormals().get(element*3+0)); textureArrayBufferData.put(uvs);
normalArrayBufferData.put(this.getNormals().get(element*3+1));
normalArrayBufferData.put(this.getNormals().get(element*3+2));
//push current uvs elementArrayBufferData = BufferUtils.createIntBuffer(faceElements.length);
textureArrayBufferData.put(this.getUVs().get(element*2+0)); elementArrayBufferData.put(faceElements);
textureArrayBufferData.put(this.getUVs().get(element*2+1));
//push faces -- instead of pushing the element directly, instead use the incrementer because we want to draw a new vertex samplerBuffer = BufferUtils.createFloatBuffer(textureSamplers.length);
//there should be no vertex-sharing between triangles. This keeps the meshes from blurring texture/lighting samplerBuffer.put(this.textureSamplers);
elementArrayBufferData.put(incrementer);
incrementer++; ratioBuffer = BufferUtils.createFloatBuffer(textureRatioVectors.length);
} ratioBuffer.put(this.textureRatioVectors);
int vertexCount = this.getTextureSamplers().size() / 3;
samplerBuffer = BufferUtils.createFloatBuffer(vertexCount * 3);
for(float samplerVec : this.getTextureSamplers()){
samplerBuffer.put(samplerVec);
}
ratioBuffer = BufferUtils.createFloatBuffer(vertexCount * 3);
for(float ratioVec : this.getTextureRatioVectors()){
ratioBuffer.put(ratioVec);
}
} }
/** /**
* Gets the vertex data * Gets the vertex data
* @return the vertex data * @return the vertex data
*/ */
public List<Float> getVertices(){ public float[] getVertices(){
return vertices; return vertices;
} }
@ -114,7 +93,7 @@ public class TerrainChunkData {
* Gets the normal data * Gets the normal data
* @return the normal data * @return the normal data
*/ */
public List<Float> getNormals(){ public float[] getNormals(){
return normals; return normals;
} }
@ -122,7 +101,7 @@ public class TerrainChunkData {
* Gets the face element data * Gets the face element data
* @return the face element data * @return the face element data
*/ */
public List<Integer> getFaceElements(){ public int[] getFaceElements(){
return faceElements; return faceElements;
} }
@ -130,7 +109,7 @@ public class TerrainChunkData {
* Gets the uv data * Gets the uv data
* @return the uv data * @return the uv data
*/ */
public List<Float> getUVs(){ public float[] getUVs(){
return uvs; return uvs;
} }
@ -138,7 +117,7 @@ public class TerrainChunkData {
* Gets the texture sampler data * Gets the texture sampler data
* @return the texture sampler data * @return the texture sampler data
*/ */
public List<Float> getTextureSamplers(){ public float[] getTextureSamplers(){
return textureSamplers; return textureSamplers;
} }
@ -146,7 +125,7 @@ public class TerrainChunkData {
* Gets the texture ratio vector data * Gets the texture ratio vector data
* @return the texture ratio vector data * @return the texture ratio vector data
*/ */
public List<Float> getTextureRatioVectors(){ public float[] getTextureRatioVectors(){
return textureRatioVectors; return textureRatioVectors;
} }

View File

@ -2,8 +2,6 @@ package electrosphere.renderer.meshgen;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.nio.IntBuffer; import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -624,147 +622,147 @@ public class TerrainChunkModelGeneration {
return new Vector3f(x,y,z); return new Vector3f(x,y,z);
} }
public static TerrainChunkData generateTerrainChunkData(float[][][] terrainGrid, int[][][] textureGrid){ // public static TerrainChunkData generateTerrainChunkData(float[][][] terrainGrid, int[][][] textureGrid){
// 5 6 // // 5 6
// +-------------+ +-----5-------+ ^ Y // // +-------------+ +-----5-------+ ^ Y
// / | / | / | /| | _ // // / | / | / | /| | _
// / | / | 4 9 6 10 | /\ Z // // / | / | 4 9 6 10 | /\ Z
// 4 +-----+-------+ 7 | +-----+7------+ | | / // // 4 +-----+-------+ 7 | +-----+7------+ | | /
// | 1 +-------+-----+ 2 | +-----1-+-----+ | / // // | 1 +-------+-----+ 2 | +-----1-+-----+ | /
// | / | / 8 0 11 2 | / // // | / | / 8 0 11 2 | /
// | / | / | / | / |/ // // | / | / | / | / |/
// 0 +-------------+ 3 +------3------+ +---------------> X // // 0 +-------------+ 3 +------3------+ +---------------> X
//the current grid cell // //the current grid cell
GridCell currentCell = new GridCell(); // GridCell currentCell = new GridCell();
//the list of all triangles // //the list of all triangles
List<Triangle> triangles = new LinkedList<Triangle>(); // List<Triangle> triangles = new LinkedList<Triangle>();
//the map of vertex to index // //the map of vertex to index
Map<String,Integer> vertMap = new HashMap<String,Integer>(); // Map<String,Integer> vertMap = new HashMap<String,Integer>();
//the list of all verts // //the list of all verts
List<Vector3f> verts = new LinkedList<Vector3f>(); // List<Vector3f> verts = new LinkedList<Vector3f>();
//the list of all normals // //the list of all normals
List<Vector3f> normals = new LinkedList<Vector3f>(); // List<Vector3f> normals = new LinkedList<Vector3f>();
//the list of number of triangles that share a vert // //the list of number of triangles that share a vert
List<Integer> trianglesSharingVert = new LinkedList<Integer>(); // List<Integer> trianglesSharingVert = new LinkedList<Integer>();
//List of texture sampler values // //List of texture sampler values
List<Vector3f> samplerTriangles = new LinkedList<Vector3f>(); // List<Vector3f> samplerTriangles = new LinkedList<Vector3f>();
//List of UVs // //List of UVs
List<Float> UVs = new LinkedList<Float>(); // List<Float> UVs = new LinkedList<Float>();
for(int x = 0; x < terrainGrid.length - 1; x++){ // for(int x = 0; x < terrainGrid.length - 1; x++){
for(int y = 0; y < terrainGrid[0].length - 1; y++){ // for(int y = 0; y < terrainGrid[0].length - 1; y++){
for(int z = 0; z < terrainGrid[0][0].length - 1; z++){ // for(int z = 0; z < terrainGrid[0][0].length - 1; z++){
//push the current cell's values into the gridcell // //push the current cell's values into the gridcell
currentCell.setValues( // currentCell.setValues(
new Vector3f(x+0,y+0,z+0), new Vector3f(x+0,y+0,z+1), new Vector3f(x+1,y+0,z+1), new Vector3f(x+1,y+0,z+0), // new Vector3f(x+0,y+0,z+0), new Vector3f(x+0,y+0,z+1), new Vector3f(x+1,y+0,z+1), new Vector3f(x+1,y+0,z+0),
new Vector3f(x+0,y+1,z+0), new Vector3f(x+0,y+1,z+1), new Vector3f(x+1,y+1,z+1), new Vector3f(x+1,y+1,z+0), // new Vector3f(x+0,y+1,z+0), new Vector3f(x+0,y+1,z+1), new Vector3f(x+1,y+1,z+1), new Vector3f(x+1,y+1,z+0),
terrainGrid[x+0][y+0][z+0], terrainGrid[x+0][y+0][z+1], terrainGrid[x+1][y+0][z+1], terrainGrid[x+1][y+0][z+0], // terrainGrid[x+0][y+0][z+0], terrainGrid[x+0][y+0][z+1], terrainGrid[x+1][y+0][z+1], terrainGrid[x+1][y+0][z+0],
terrainGrid[x+0][y+1][z+0], terrainGrid[x+0][y+1][z+1], terrainGrid[x+1][y+1][z+1], terrainGrid[x+1][y+1][z+0], // terrainGrid[x+0][y+1][z+0], terrainGrid[x+0][y+1][z+1], terrainGrid[x+1][y+1][z+1], terrainGrid[x+1][y+1][z+0],
textureGrid[x+0][y+0][z+0], textureGrid[x+0][y+0][z+1], textureGrid[x+1][y+0][z+1], textureGrid[x+1][y+0][z+0], // textureGrid[x+0][y+0][z+0], textureGrid[x+0][y+0][z+1], textureGrid[x+1][y+0][z+1], textureGrid[x+1][y+0][z+0],
textureGrid[x+0][y+1][z+0], textureGrid[x+0][y+1][z+1], textureGrid[x+1][y+1][z+1], textureGrid[x+1][y+1][z+0] // textureGrid[x+0][y+1][z+0], textureGrid[x+0][y+1][z+1], textureGrid[x+1][y+1][z+1], textureGrid[x+1][y+1][z+0]
); // );
//polygonize the current gridcell // //polygonize the current gridcell
polygonize(currentCell, MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert); // polygonize(currentCell, MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
} // }
} // }
} // }
//all verts in order, flattened as an array of floats instead of vecs // //all verts in order, flattened as an array of floats instead of vecs
List<Float> vertsFlat = new LinkedList<Float>(); // List<Float> vertsFlat = new LinkedList<Float>();
//all normals in order, flattened as an array of floats instead of vecs // //all normals in order, flattened as an array of floats instead of vecs
List<Float> normalsFlat = new LinkedList<Float>(); // List<Float> normalsFlat = new LinkedList<Float>();
//all elements of faces in order // //all elements of faces in order
LinkedList<Integer> elementsFlat = new LinkedList<Integer>(); // LinkedList<Integer> elementsFlat = new LinkedList<Integer>();
//List of texture sampler values // //List of texture sampler values
List<Float> textureSamplers = new LinkedList<Float>(); // List<Float> textureSamplers = new LinkedList<Float>();
//List of texture ratio values // //List of texture ratio values
List<Float> textureRatioData = new LinkedList<Float>(); // List<Float> textureRatioData = new LinkedList<Float>();
//flatten verts + normals // //flatten verts + normals
for(Vector3f vert : verts){ // for(Vector3f vert : verts){
vertsFlat.add(vert.x); // vertsFlat.add(vert.x);
vertsFlat.add(vert.y); // vertsFlat.add(vert.y);
vertsFlat.add(vert.z); // vertsFlat.add(vert.z);
} // }
for(Vector3f normal : normals){ // for(Vector3f normal : normals){
normalsFlat.add(normal.x); // normalsFlat.add(normal.x);
normalsFlat.add(normal.y); // normalsFlat.add(normal.y);
normalsFlat.add(normal.z); // normalsFlat.add(normal.z);
} // }
for(Triangle triangle : triangles){ // for(Triangle triangle : triangles){
elementsFlat.add(triangle.indices[0]); // elementsFlat.add(triangle.indices[0]);
elementsFlat.add(triangle.indices[1]); // elementsFlat.add(triangle.indices[1]);
elementsFlat.add(triangle.indices[2]); // elementsFlat.add(triangle.indices[2]);
} // }
float[] temp = new float[3]; // float[] temp = new float[3];
int i = 0; // int i = 0;
for(Vector3f normal : normals){ // for(Vector3f normal : normals){
Vector3f vert = verts.get(i); // Vector3f vert = verts.get(i);
float absX = Math.abs(normal.x); // float absX = Math.abs(normal.x);
float absY = Math.abs(normal.y); // float absY = Math.abs(normal.y);
float absZ = Math.abs(normal.z); // float absZ = Math.abs(normal.z);
float uvX = vert.z * absX + vert.x * absY + vert.x * absZ; // float uvX = vert.z * absX + vert.x * absY + vert.x * absZ;
float uvY = vert.y * absX + vert.z * absY + vert.y * absZ; // float uvY = vert.y * absX + vert.z * absY + vert.y * absZ;
temp[0] = uvX; // temp[0] = uvX;
temp[1] = uvY; // temp[1] = uvY;
// if(absX >= absZ && absX >= absY){ // // if(absX >= absZ && absX >= absY){
// temp[0] = normal.z / 2.0f + 0.5f + vert.z * (absX / (absX + absZ)) + vert.x * (absZ / (absX + absZ)); // // temp[0] = normal.z / 2.0f + 0.5f + vert.z * (absX / (absX + absZ)) + vert.x * (absZ / (absX + absZ));
// temp[1] = normal.y / 2.0f + 0.5f + vert.x * (absY / (absX + absY)) + vert.y * (absX / (absX + absY)); // // temp[1] = normal.y / 2.0f + 0.5f + vert.x * (absY / (absX + absY)) + vert.y * (absX / (absX + absY));
// } else if(absZ >= absX && absZ >= absY){ // // } else if(absZ >= absX && absZ >= absY){
// temp[0] = normal.x / 2.0f + 0.5f + vert.z * (absX / (absX + absZ)) + vert.x * (absZ / (absX + absZ)); // // temp[0] = normal.x / 2.0f + 0.5f + vert.z * (absX / (absX + absZ)) + vert.x * (absZ / (absX + absZ));
// temp[1] = normal.y / 2.0f + 0.5f + vert.z * (absY / (absZ + absY)) + vert.y * (absZ / (absZ + absY)); // // temp[1] = normal.y / 2.0f + 0.5f + vert.z * (absY / (absZ + absY)) + vert.y * (absZ / (absZ + absY));
// } else if(absY >= absX && absY >= absZ){ // // } else if(absY >= absX && absY >= absZ){
// temp[0] = normal.x / 2.0f + 0.5f + vert.y * (absX / (absX + absY)) + vert.x * (absY / (absX + absY)); // // temp[0] = normal.x / 2.0f + 0.5f + vert.y * (absX / (absX + absY)) + vert.x * (absY / (absX + absY));
// temp[1] = normal.z / 2.0f + 0.5f + vert.y * (absZ / (absZ + absY)) + vert.z * (absY / (absZ + absY)); // // temp[1] = normal.z / 2.0f + 0.5f + vert.y * (absZ / (absZ + absY)) + vert.z * (absY / (absZ + absY));
// } else { // // } else {
// temp[0] = vert.x / 1.5f + vert.z / 1.5f; // // temp[0] = vert.x / 1.5f + vert.z / 1.5f;
// temp[1] = vert.y / 1.5f + vert.z / 1.5f; // // temp[1] = vert.y / 1.5f + vert.z / 1.5f;
// } // // }
i++; // i++;
UVs.add(temp[0]); // UVs.add(temp[0]);
UVs.add(temp[1]); // UVs.add(temp[1]);
} // }
//flatten sampler indices // //flatten sampler indices
for(Vector3f samplerVec : samplerTriangles){ // for(Vector3f samplerVec : samplerTriangles){
textureSamplers.add((float)Globals.voxelTextureAtlas.getVoxelTypeOffset((int)samplerVec.x)); // textureSamplers.add((float)Globals.voxelTextureAtlas.getVoxelTypeOffset((int)samplerVec.x));
textureSamplers.add((float)Globals.voxelTextureAtlas.getVoxelTypeOffset((int)samplerVec.y)); // textureSamplers.add((float)Globals.voxelTextureAtlas.getVoxelTypeOffset((int)samplerVec.y));
textureSamplers.add((float)Globals.voxelTextureAtlas.getVoxelTypeOffset((int)samplerVec.z)); // textureSamplers.add((float)Globals.voxelTextureAtlas.getVoxelTypeOffset((int)samplerVec.z));
} // }
//set ratio dat // //set ratio dat
for(int j = 0; j < triangles.size(); j++){ // for(int j = 0; j < triangles.size(); j++){
//first vertex // //first vertex
textureRatioData.add(1.0f); // textureRatioData.add(1.0f);
textureRatioData.add(0.0f); // textureRatioData.add(0.0f);
textureRatioData.add(0.0f); // textureRatioData.add(0.0f);
//second vertex // //second vertex
textureRatioData.add(0.0f); // textureRatioData.add(0.0f);
textureRatioData.add(1.0f); // textureRatioData.add(1.0f);
textureRatioData.add(0.0f); // textureRatioData.add(0.0f);
//third vertex // //third vertex
textureRatioData.add(0.0f); // textureRatioData.add(0.0f);
textureRatioData.add(0.0f); // textureRatioData.add(0.0f);
textureRatioData.add(1.0f); // textureRatioData.add(1.0f);
} // }
//List<Float> vertices, List<Float> normals, List<Integer> faceElements, List<Float> uvs // //List<Float> vertices, List<Float> normals, List<Integer> faceElements, List<Float> uvs
TerrainChunkData rVal = new TerrainChunkData(vertsFlat, normalsFlat, elementsFlat, UVs, textureSamplers, textureRatioData, 0); // TerrainChunkData rVal = new TerrainChunkData(vertsFlat, normalsFlat, elementsFlat, UVs, textureSamplers, textureRatioData, 0);
return rVal; // return rVal;
} // }
/** /**
* Generates a mesh based on a terrainchunkdata object * Generates a mesh based on a terrainchunkdata object
@ -797,7 +795,7 @@ public class TerrainChunkModelGeneration {
// //
// Buffer data to GPU // Buffer data to GPU
// //
int elementCount = data.getFaceElements().size(); int elementCount = data.getFaceElements().length;
try { try {
//actually buffer vertices //actually buffer vertices
@ -883,6 +881,7 @@ public class TerrainChunkModelGeneration {
* @param atlas The atlas texture for the chunk * @param atlas The atlas texture for the chunk
* @return The model * @return The model
*/ */
@Deprecated
public static Model generateTerrainModel(TerrainChunkData data, VoxelTextureAtlas atlas){ public static Model generateTerrainModel(TerrainChunkData data, VoxelTextureAtlas atlas){
Model rVal = new Model(); Model rVal = new Model();
Mesh m = TerrainChunkModelGeneration.generateTerrainMesh(data); Mesh m = TerrainChunkModelGeneration.generateTerrainMesh(data);

View File

@ -1,15 +1,22 @@
package electrosphere.renderer.meshgen; package electrosphere.renderer.meshgen;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.joml.Vector3f; import org.joml.Vector3f;
import org.lwjgl.opengl.GL40;
import electrosphere.client.terrain.cells.VoxelTextureAtlas;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.types.terrain.TerrainChunkData; import electrosphere.entity.types.terrain.TerrainChunkData;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.model.Material;
import electrosphere.renderer.model.Mesh;
import electrosphere.renderer.model.Model;
import electrosphere.server.terrain.manager.ServerTerrainChunk; import electrosphere.server.terrain.manager.ServerTerrainChunk;
/** /**
@ -17,6 +24,41 @@ import electrosphere.server.terrain.manager.ServerTerrainChunk;
*/ */
public class TransvoxelModelGeneration { public class TransvoxelModelGeneration {
/**
* Number of ints required to store an element
*/
static final int INTS_PER_ELEMENT = 1;
/**
* Number of elements per triangle
*/
static final int ELEMENTS_PER_TRIANGLE = 3;
/**
* Number of floats per vert
*/
static final int FLOATS_PER_VERT = 3;
/**
* Number of vertices per triangle
*/
static final int VERTS_PER_TRIANGLE = ELEMENTS_PER_TRIANGLE;
/**
* Number of floats per UV
*/
static final int FLOATS_PER_UV = 2;
/**
* The number of sampler indices per triangle
*/
static final int SAMPLER_INDICES_PER_TRIANGLE = 3;
/**
* The number of sampler values to store for each vertex
*/
static final int SAMPLER_VALUES_PER_VERT = 3;
//this is the width of the transition cell //this is the width of the transition cell
@ -1045,8 +1087,6 @@ public class TransvoxelModelGeneration {
List<Integer> trianglesSharingVert = new LinkedList<Integer>(); List<Integer> trianglesSharingVert = new LinkedList<Integer>();
//List of texture sampler values //List of texture sampler values
List<Vector3f> samplerTriangles = new LinkedList<Vector3f>(); List<Vector3f> samplerTriangles = new LinkedList<Vector3f>();
//List of UVs
List<Float> UVs = new LinkedList<Float>();
@ -1601,96 +1641,123 @@ public class TransvoxelModelGeneration {
} }
if (verts.size() != normals.size()){
throw new Error("Generated invalid number of elements in lists! " + verts.size() + " " + normals.size());
}
//incrementer
int i = 0;
//all verts in order, flattened as an array of floats instead of vecs
List<Float> vertsFlat = new LinkedList<Float>();
//all normals in order, flattened as an array of floats instead of vecs
List<Float> normalsFlat = new LinkedList<Float>();
//all elements of faces in order //all elements of faces in order
List<Integer> elementsFlat = new LinkedList<Integer>(); int[] elementsFlat = new int[triangles.size() * ELEMENTS_PER_TRIANGLE * INTS_PER_ELEMENT];
//all verts in order, flattened as an array of floats instead of vecs
float[] vertsFlat = new float[triangles.size() * VERTS_PER_TRIANGLE * FLOATS_PER_VERT];
//all normals in order, flattened as an array of floats instead of vecs
float[] normalsFlat = new float[triangles.size() * VERTS_PER_TRIANGLE * FLOATS_PER_VERT];
//List of UVs
float[] UVs = new float[triangles.size() * VERTS_PER_TRIANGLE * FLOATS_PER_UV];
//List of texture sampler values //List of texture sampler values
List<Float> textureSamplers = new LinkedList<Float>(); float[] textureSamplers = new float[samplerTriangles.size() * SAMPLER_INDICES_PER_TRIANGLE];
//List of texture ratio values //List of texture ratio values
List<Float> textureRatioData = new LinkedList<Float>(); float[] textureRatioData = new float[triangles.size() * SAMPLER_INDICES_PER_TRIANGLE * SAMPLER_VALUES_PER_VERT];
float scalingFactor = (float)Math.pow(2,chunkData.levelOfDetail); float scalingFactor = (float)Math.pow(2,chunkData.levelOfDetail);
//flatten verts + normals
for(Vector3f vert : verts){ //store indices
vertsFlat.add(vert.x * scalingFactor); for(int j = 0; j < elementsFlat.length; j++){
vertsFlat.add(vert.y * scalingFactor); //assigning a unique number to each element guarantees there's no vertex sharing between triangles
vertsFlat.add(vert.z * scalingFactor); //we don't want vertex sharing because then the UVs are shared
elementsFlat[j] = j;
} }
for(Vector3f normal : normals){ //flatten verts + normals + uvs
normalsFlat.add(normal.x); i = 0;
normalsFlat.add(normal.y); Vector3f vert = null;
normalsFlat.add(normal.z); Vector3f normal = null;
}
for(Triangle triangle : triangles){ for(Triangle triangle : triangles){
elementsFlat.add(triangle.indices[0]);
elementsFlat.add(triangle.indices[1]);
elementsFlat.add(triangle.indices[2]);
}
float[] temp = new float[3]; //
int i = 0; //point 1 of the triangle
for(Vector3f normal : normals){ vert = verts.get(triangle.indices[0]);
Vector3f vert = verts.get(i); normal = normals.get(triangle.indices[0]);
vertsFlat[i*9+0] = vert.x * scalingFactor;
vertsFlat[i*9+1] = vert.y * scalingFactor;
vertsFlat[i*9+2] = vert.z * scalingFactor;
float absX = Math.abs(normal.x); normalsFlat[i*9+0] = normal.x;
float absY = Math.abs(normal.y); normalsFlat[i*9+1] = normal.y;
float absZ = Math.abs(normal.z); normalsFlat[i*9+2] = normal.z;
float uvX = vert.z * absX + vert.x * absY + vert.x * absZ; UVs[i*6+0] = vert.z * Math.abs(normal.x) + vert.x * Math.abs(normal.y) + vert.x * Math.abs(normal.z);
float uvY = vert.y * absX + vert.z * absY + vert.y * absZ; UVs[i*6+1] = vert.y * Math.abs(normal.x) + vert.z * Math.abs(normal.y) + vert.y * Math.abs(normal.z);
temp[0] = uvX;
temp[1] = uvY;
// if(absX >= absZ && absX >= absY){
// temp[0] = normal.z / 2.0f + 0.5f + vert.z * (absX / (absX + absZ)) + vert.x * (absZ / (absX + absZ)); //
// temp[1] = normal.y / 2.0f + 0.5f + vert.x * (absY / (absX + absY)) + vert.y * (absX / (absX + absY)); //point 2 of the triangle
// } else if(absZ >= absX && absZ >= absY){ vert = verts.get(triangle.indices[1]);
// temp[0] = normal.x / 2.0f + 0.5f + vert.z * (absX / (absX + absZ)) + vert.x * (absZ / (absX + absZ)); normal = normals.get(triangle.indices[1]);
// temp[1] = normal.y / 2.0f + 0.5f + vert.z * (absY / (absZ + absY)) + vert.y * (absZ / (absZ + absY)); vertsFlat[i*9+3] = vert.x * scalingFactor;
// } else if(absY >= absX && absY >= absZ){ vertsFlat[i*9+4] = vert.y * scalingFactor;
// temp[0] = normal.x / 2.0f + 0.5f + vert.y * (absX / (absX + absY)) + vert.x * (absY / (absX + absY)); vertsFlat[i*9+5] = vert.z * scalingFactor;
// temp[1] = normal.z / 2.0f + 0.5f + vert.y * (absZ / (absZ + absY)) + vert.z * (absY / (absZ + absY));
// } else { normalsFlat[i*9+3] = normal.x;
// temp[0] = vert.x / 1.5f + vert.z / 1.5f; normalsFlat[i*9+4] = normal.y;
// temp[1] = vert.y / 1.5f + vert.z / 1.5f; normalsFlat[i*9+5] = normal.z;
// }
UVs[i*6+2] = vert.z * Math.abs(normal.x) + vert.x * Math.abs(normal.y) + vert.x * Math.abs(normal.z);
UVs[i*6+3] = vert.y * Math.abs(normal.x) + vert.z * Math.abs(normal.y) + vert.y * Math.abs(normal.z);
//
//point 3 of the triangle
vert = verts.get(triangle.indices[2]);
normal = normals.get(triangle.indices[2]);
vertsFlat[i*9+6] = vert.x * scalingFactor;
vertsFlat[i*9+7] = vert.y * scalingFactor;
vertsFlat[i*9+8] = vert.z * scalingFactor;
normalsFlat[i*9+6] = normal.x;
normalsFlat[i*9+7] = normal.y;
normalsFlat[i*9+8] = normal.z;
UVs[i*6+4] = vert.z * Math.abs(normal.x) + vert.x * Math.abs(normal.y) + vert.x * Math.abs(normal.z);
UVs[i*6+5] = vert.y * Math.abs(normal.x) + vert.z * Math.abs(normal.y) + vert.y * Math.abs(normal.z);
i++; i++;
UVs.add(temp[0]);
UVs.add(temp[1]);
} }
//flatten sampler indices //flatten sampler indices
i = 0;
for(Vector3f samplerVec : samplerTriangles){ for(Vector3f samplerVec : samplerTriangles){
textureSamplers.add((float)Globals.voxelTextureAtlas.getVoxelTypeOffset((int)samplerVec.x)); textureSamplers[i*3+0] = (float)Globals.voxelTextureAtlas.getVoxelTypeOffset((int)samplerVec.x);
textureSamplers.add((float)Globals.voxelTextureAtlas.getVoxelTypeOffset((int)samplerVec.y)); textureSamplers[i*3+1] = (float)Globals.voxelTextureAtlas.getVoxelTypeOffset((int)samplerVec.y);
textureSamplers.add((float)Globals.voxelTextureAtlas.getVoxelTypeOffset((int)samplerVec.z)); textureSamplers[i*3+2] = (float)Globals.voxelTextureAtlas.getVoxelTypeOffset((int)samplerVec.z);
i++;
}
if(i * 3 < textureSamplers.length){
throw new Error("Did not add all elements! " + samplerTriangles.size() + " " + textureSamplers.length);
} }
//set ratio dat //set ratio dat
for(int j = 0; j < triangles.size(); j++){ for(int j = 0; j < textureRatioData.length / 9; j++){
//first vertex //first vertex
textureRatioData.add(1.0f); textureRatioData[j*9+0] = 1.0f;
textureRatioData.add(0.0f); textureRatioData[j*9+1] = 0.0f;
textureRatioData.add(0.0f); textureRatioData[j*9+2] = 0.0f;
//second vertex //second vertex
textureRatioData.add(0.0f); textureRatioData[j*9+3] = 0.0f;
textureRatioData.add(1.0f); textureRatioData[j*9+4] = 1.0f;
textureRatioData.add(0.0f); textureRatioData[j*9+5] = 0.0f;
//third vertex //third vertex
textureRatioData.add(0.0f); textureRatioData[j*9+6] = 0.0f;
textureRatioData.add(0.0f); textureRatioData[j*9+7] = 0.0f;
textureRatioData.add(1.0f); textureRatioData[j*9+8] = 1.0f;
} }
//List<Float> vertices, List<Float> normals, List<Integer> faceElements, List<Float> uvs //List<Float> vertices, List<Float> normals, List<Integer> faceElements, List<Float> uvs
@ -1699,6 +1766,143 @@ public class TransvoxelModelGeneration {
} }
/**
* Generates a mesh based on a terrainchunkdata object
* @param data The terrain chunk data object
* @return The mesh
*/
protected static Mesh generateTerrainMesh(TerrainChunkData data){
Mesh mesh = new Mesh("terrainChunk");
//
// VAO
//
mesh.generateVAO();
FloatBuffer vertexArrayBufferData = data.getVertexArrayBufferData();
FloatBuffer normalArrayBufferData = data.getNormalArrayBufferData();
FloatBuffer textureArrayBufferData = data.getTextureArrayBufferData();
IntBuffer elementArrayBufferData = data.getElementArrayBufferData();
FloatBuffer samplerBuffer = data.getSamplerBuffer();
FloatBuffer ratioBuffer = data.getRatioBuffer();
//
// Buffer data to GPU
//
int elementCount = data.getFaceElements().length;
try {
//actually buffer vertices
if(vertexArrayBufferData.position() > 0){
vertexArrayBufferData.flip();
mesh.bufferVertices(vertexArrayBufferData, 3);
}
//actually buffer normals
if(normalArrayBufferData.position() > 0){
normalArrayBufferData.flip();
mesh.bufferNormals(normalArrayBufferData, 3);
}
//actually buffer UVs
if(textureArrayBufferData.position() > 0){
textureArrayBufferData.flip();
mesh.bufferTextureCoords(textureArrayBufferData, 2);
}
//buffer element indices
if(elementArrayBufferData.position() > 0){
elementArrayBufferData.flip();
mesh.bufferFaces(elementArrayBufferData, elementCount);
}
} catch (NullPointerException ex){
ex.printStackTrace();
}
//
// SAMPLER INDICES
//
try {
if(samplerBuffer.position() > 0){
samplerBuffer.flip();
mesh.bufferCustomFloatAttribArray(samplerBuffer, 3, SAMPLER_INDEX_ATTRIB_LOC);
}
} catch (NullPointerException ex){
ex.printStackTrace();
}
//
// SAMPLER RATIO DATA
//
try {
if(ratioBuffer.position() > 0){
ratioBuffer.flip();
mesh.bufferCustomFloatAttribArray(ratioBuffer, 3, SAMPLER_RATIO_ATTRIB_LOC);
}
} catch (NullPointerException ex){
ex.printStackTrace();
}
//bounding sphere logic
int distance = ServerTerrainChunk.CHUNK_DIMENSION / 2 * (int)Math.pow(2,data.getLOD());
mesh.updateBoundingSphere(
distance,
distance,
distance,
(float)Math.sqrt(
distance * distance +
distance * distance +
distance * distance
));
GL40.glBindVertexArray(0);
return mesh;
}
/**
* Generates a model based on a terrainchunkdata object
* @param data The terrain chunk data object
* @param atlas The atlas texture for the chunk
* @return The model
*/
public static Model generateTerrainModel(TerrainChunkData data, VoxelTextureAtlas atlas){
Model rVal = new Model();
Mesh m = TransvoxelModelGeneration.generateTerrainMesh(data);
//construct the material for the chunk
Material groundMat = new Material();
groundMat.setTexturePointer(atlas.getSpecular().getTexturePointer());
groundMat.setNormalTexturePointer(atlas.getNormal().getTexturePointer());
m.setMaterial(groundMat);
//shader logic
m.setShader(Globals.terrainShaderProgram);
m.setParent(rVal);
rVal.getMeshes().add(m);
rVal.setBoundingSphere(m.getBoundingSphere());
return rVal;
}