diff --git a/assets/Models/creatures/person2/person2_1.glb b/assets/Models/creatures/person2/person2_1.glb index fabb090e..c46cb12e 100644 Binary files a/assets/Models/creatures/person2/person2_1.glb and b/assets/Models/creatures/person2/person2_1.glb differ diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index e67f51b4..e6401a9f 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -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 diff --git a/src/main/java/electrosphere/entity/EntityDataStrings.java b/src/main/java/electrosphere/entity/EntityDataStrings.java index 3e272c2a..2dfa8e77 100644 --- a/src/main/java/electrosphere/entity/EntityDataStrings.java +++ b/src/main/java/electrosphere/entity/EntityDataStrings.java @@ -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"; /* diff --git a/src/main/java/electrosphere/entity/types/terrain/BlockChunkEntity.java b/src/main/java/electrosphere/entity/types/terrain/BlockChunkEntity.java index c0c95c26..1e0006bb 100644 --- a/src/main/java/electrosphere/entity/types/terrain/BlockChunkEntity.java +++ b/src/main/java/electrosphere/entity/types/terrain/BlockChunkEntity.java @@ -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); } } diff --git a/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java b/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java index 70383231..5fa74966 100644 --- a/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java +++ b/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java @@ -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); + } + } diff --git a/src/main/java/electrosphere/renderer/pipelines/MainContentPipeline.java b/src/main/java/electrosphere/renderer/pipelines/MainContentPipeline.java index 8b0e157d..bfce538f 100644 --- a/src/main/java/electrosphere/renderer/pipelines/MainContentPipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/MainContentPipeline.java @@ -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"); diff --git a/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java b/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java index a475b796..8df52c7e 100644 --- a/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java @@ -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); + } + } diff --git a/src/main/java/electrosphere/renderer/target/DrawTargetAccumulator.java b/src/main/java/electrosphere/renderer/target/DrawTargetAccumulator.java index 18d18aac..df6c41ed 100644 --- a/src/main/java/electrosphere/renderer/target/DrawTargetAccumulator.java +++ b/src/main/java/electrosphere/renderer/target/DrawTargetAccumulator.java @@ -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 modelPathAccumulatorMap = new HashMap(); + /** + * Groups terrain entities + */ + private List terrainEntities = new LinkedList(); + + /** + * Groups block entities + */ + private List blockEntities = new LinkedList(); + /** * 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 getTerrainEntities(){ + return this.terrainEntities; + } + + /** + * Gets the list of block entities + * @return The list of block entities + */ + public List getBlockEntities(){ + return this.blockEntities; } /** diff --git a/src/main/java/electrosphere/renderer/target/DrawTargetEvaluator.java b/src/main/java/electrosphere/renderer/target/DrawTargetEvaluator.java index ec855591..ce4c3ea3 100644 --- a/src/main/java/electrosphere/renderer/target/DrawTargetEvaluator.java +++ b/src/main/java/electrosphere/renderer/target/DrawTargetEvaluator.java @@ -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); diff --git a/src/main/java/electrosphere/server/datacell/physics/PhysicsDataCell.java b/src/main/java/electrosphere/server/datacell/physics/PhysicsDataCell.java index c2a31e98..d5d3432c 100644 --- a/src/main/java/electrosphere/server/datacell/physics/PhysicsDataCell.java +++ b/src/main/java/electrosphere/server/datacell/physics/PhysicsDataCell.java @@ -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); } /**