clustering terrain draw calls

This commit is contained in:
austin 2025-05-24 23:20:43 -04:00
parent 44ae9909ee
commit 7d04008197
10 changed files with 169 additions and 0 deletions

View File

@ -1972,6 +1972,7 @@ Performance improvements
- AI does not simulate for low-lod server entities
- Nearby entity lookup caching per frame
- Far-away entities do not spawn physics by default
- Clustering terrain draw calls
Lod emitter service checker function
Mesh profiling

View File

@ -47,6 +47,7 @@ public class EntityDataStrings {
Terrain Entity
*/
public static final String TERRAIN_IS_TERRAIN = "terrainEntity";
public static final String BLOCK_ENTITY = "blockEntity";
public static final String CORRESPONDING_DRAW_CELL = "correspondingDrawCell";
/*

View File

@ -113,6 +113,7 @@ public class BlockChunkEntity {
}
}
solidsEnt.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
solidsEnt.putData(EntityDataStrings.BLOCK_ENTITY, true);
rVal.add(solidsEnt);
//
@ -165,6 +166,7 @@ public class BlockChunkEntity {
}
}
transparentEnt.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
transparentEnt.putData(EntityDataStrings.BLOCK_ENTITY, true);
rVal.add(transparentEnt);
@ -189,6 +191,7 @@ public class BlockChunkEntity {
Quaterniond entityRot = EntityUtils.getRotation(entity);
PhysicsUtils.setGeomTransform(realm.getCollisionEngine(), entityPos, entityRot, terrainCollider);
entity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
entity.putData(EntityDataStrings.BLOCK_ENTITY, true);
CommonEntityUtils.setEntityType(entity, EntityType.ENGINE);
}
}

View File

@ -163,4 +163,13 @@ public class TerrainChunk {
return entity.containsKey(EntityDataStrings.TERRAIN_IS_TERRAIN);
}
/**
* Checks if this is a block entity
* @param entity The entity
* @return True if it is a block entity, false otherwise
*/
public static boolean isBlockEntity(Entity entity){
return entity.containsKey(EntityDataStrings.BLOCK_ENTITY);
}
}

View File

@ -139,6 +139,52 @@ public class MainContentPipeline implements RenderPipeline {
}
}
}
for(Entity currentEntity : this.drawTargetAccumulator.getTerrainEntities()){
Vector3d position = EntityUtils.getPosition(currentEntity);
if(
currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW)!=null
){
//fetch actor
Actor currentActor = EntityUtils.getActor(currentEntity);
//calculate camera-modified vector3d
Vector3d cameraCenter = scaleVec.set(cameraCenterVec);
Vector3d cameraModifiedPosition = positionVec.set(position).sub(cameraCenter);
//calculate and apply model transform
modelTransformMatrix = modelTransformMatrix.identity();
modelTransformMatrix.translate(cameraModifiedPosition);
modelTransformMatrix.rotate(EntityUtils.getRotation(currentEntity));
modelTransformMatrix.scale(scaleVec.set(EntityUtils.getScale(currentEntity)));
currentActor.applySpatialData(new Matrix4d(modelTransformMatrix),new Vector3d(position));
//draw
currentActor.draw(renderPipelineState,openGLState);
//tracking
this.terrainChunks++;
}
}
for(Entity currentEntity : this.drawTargetAccumulator.getBlockEntities()){
Vector3d position = EntityUtils.getPosition(currentEntity);
if(
currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW)!=null
){
//fetch actor
Actor currentActor = EntityUtils.getActor(currentEntity);
//calculate camera-modified vector3d
Vector3d cameraCenter = scaleVec.set(cameraCenterVec);
Vector3d cameraModifiedPosition = positionVec.set(position).sub(cameraCenter);
//calculate and apply model transform
modelTransformMatrix = modelTransformMatrix.identity();
modelTransformMatrix.translate(cameraModifiedPosition);
modelTransformMatrix.rotate(EntityUtils.getRotation(currentEntity));
modelTransformMatrix.scale(scaleVec.set(EntityUtils.getScale(currentEntity)));
currentActor.applySpatialData(new Matrix4d(modelTransformMatrix),new Vector3d(position));
//draw
currentActor.draw(renderPipelineState,openGLState);
//tracking
this.terrainChunks++;
}
}
renderPipelineState.setUseBones(true);
Globals.profiler.endCpuSample();
Globals.profiler.beginCpuSample("MainContentPipeline.render - Solids Foliage");

View File

@ -164,6 +164,46 @@ public class ShadowMapPipeline implements RenderPipeline {
}
}
}
for(Entity currentEntity : this.drawTargetAccumulator.getTerrainEntities()){
Vector3d position = EntityUtils.getPosition(currentEntity);
if(
currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW)!=null
){
//fetch actor
Actor currentActor = EntityUtils.getActor(currentEntity);
//calculate camera-modified vector3d
Vector3d cameraCenter = scaleVec.set(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
Vector3d cameraModifiedPosition = posVec.set(position).sub(cameraCenter);
//calculate and apply model transform
modelTransformMatrix = modelTransformMatrix.identity();
modelTransformMatrix.translate(cameraModifiedPosition);
modelTransformMatrix.rotate(EntityUtils.getRotation(currentEntity));
modelTransformMatrix.scale(scaleVec.set(EntityUtils.getScale(currentEntity)));
currentActor.applySpatialData(new Matrix4d(modelTransformMatrix),new Vector3d(position));
//draw
currentActor.draw(renderPipelineState,openGLState);
}
}
for(Entity currentEntity : this.drawTargetAccumulator.getBlockEntities()){
Vector3d position = EntityUtils.getPosition(currentEntity);
if(
currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW)!=null
){
//fetch actor
Actor currentActor = EntityUtils.getActor(currentEntity);
//calculate camera-modified vector3d
Vector3d cameraCenter = scaleVec.set(CameraEntityUtils.getCameraCenter(Globals.clientState.playerCamera));
Vector3d cameraModifiedPosition = posVec.set(position).sub(cameraCenter);
//calculate and apply model transform
modelTransformMatrix = modelTransformMatrix.identity();
modelTransformMatrix.translate(cameraModifiedPosition);
modelTransformMatrix.rotate(EntityUtils.getRotation(currentEntity));
modelTransformMatrix.scale(scaleVec.set(EntityUtils.getScale(currentEntity)));
currentActor.applySpatialData(new Matrix4d(modelTransformMatrix),new Vector3d(position));
//draw
currentActor.draw(renderPipelineState,openGLState);
}
}

View File

@ -3,12 +3,15 @@ package electrosphere.renderer.target;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.joml.Matrix4d;
import org.joml.Vector3d;
import electrosphere.entity.Entity;
/**
* Accumulates non-spatially identical draw calls to batch to gpu
*/
@ -19,6 +22,16 @@ public class DrawTargetAccumulator {
*/
private Map<String,ModelAccumulatorData> modelPathAccumulatorMap = new HashMap<String,ModelAccumulatorData>();
/**
* Groups terrain entities
*/
private List<Entity> terrainEntities = new LinkedList<Entity>();
/**
* Groups block entities
*/
private List<Entity> blockEntities = new LinkedList<Entity>();
/**
* Adds a call to draw a given model
@ -37,6 +50,22 @@ public class DrawTargetAccumulator {
}
}
/**
* Adds a terrain entity
* @param entity The entity
*/
public void addTerrainCall(Entity entity){
this.terrainEntities.add(entity);
}
/**
* Adds a block entity
* @param entity The entity
*/
public void addBlockCall(Entity entity){
this.blockEntities.add(entity);
}
/**
* Gets the calls to make
* @return The calls to make
@ -52,6 +81,24 @@ public class DrawTargetAccumulator {
for(ModelAccumulatorData data : modelPathAccumulatorMap.values()){
data.count = 0;
}
this.terrainEntities.clear();
this.blockEntities.clear();
}
/**
* Gets the list of terrain entities
* @return The list of terrain entities
*/
public List<Entity> getTerrainEntities(){
return this.terrainEntities;
}
/**
* Gets the list of block entities
* @return The list of block entities
*/
public List<Entity> getBlockEntities(){
return this.blockEntities;
}
/**

View File

@ -12,6 +12,7 @@ import electrosphere.entity.DrawableUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.terrain.TerrainChunk;
import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.pipelines.MainContentPipeline;
import electrosphere.renderer.pipelines.NormalsForOutlinePipeline;
@ -112,6 +113,26 @@ public class DrawTargetEvaluator {
normalAccumulator.addCall(currentActor.getModelPath(), position, modelTransformMatrix);
}
}
} else if(TerrainChunk.isBlockEntity(currentEntity)){
if(MainContentPipeline.shouldDrawSolidPass(currentEntity)){
mainAccumulator.addBlockCall(currentEntity);
}
if(dist < ShadowMapPipeline.DRAW_CUTOFF_DIST && shadowList.contains(currentEntity)){
shadowAccumulator.addBlockCall(currentEntity);
}
if(dist < NormalsForOutlinePipeline.DRAW_CUTOFF_DIST && NormalsForOutlinePipeline.shouldDraw(currentEntity)){
normalAccumulator.addBlockCall(currentEntity);
}
} else if(TerrainChunk.isTerrainEntity(currentEntity)) {
if(MainContentPipeline.shouldDrawSolidPass(currentEntity)){
mainAccumulator.addTerrainCall(currentEntity);
}
if(dist < ShadowMapPipeline.DRAW_CUTOFF_DIST && shadowList.contains(currentEntity)){
shadowAccumulator.addTerrainCall(currentEntity);
}
if(dist < NormalsForOutlinePipeline.DRAW_CUTOFF_DIST && NormalsForOutlinePipeline.shouldDraw(currentEntity)){
normalAccumulator.addTerrainCall(currentEntity);
}
} else {
if(MainContentPipeline.shouldDrawSolidPass(currentEntity)){
mainQueue.add(currentEntity);

View File

@ -103,6 +103,7 @@ public class PhysicsDataCell {
this.blockData = BlockMeshgen.rasterize(this.blockChunk);
BlockChunkEntity.serverCreateBlockChunkEntity(localBlockPhysicsEntity, this.blockData);
localBlockPhysicsEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
localBlockPhysicsEntity.putData(EntityDataStrings.BLOCK_ENTITY, true);
}
/**