rearch foliage rendering into dedicated pipeline
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-03-27 15:46:18 -04:00
parent 3b0e39d169
commit 6d2b4bf318
11 changed files with 83 additions and 73 deletions

View File

@ -1336,6 +1336,7 @@ Normalized mouse pos lookup function
(03/27/2025)
Disable fluid sim for performance
Increase fall delay
Rearchitect foliage rendering to combat grass pop-in/pop-out

View File

@ -8,6 +8,7 @@ import org.joml.Vector3i;
import electrosphere.engine.Globals;
import electrosphere.entity.EntityUtils;
@Deprecated
/**
* Manages ambient foliage (grass, small plants, etc) that should be shown, typically instanced
*/

View File

@ -35,6 +35,7 @@ import electrosphere.renderer.buffer.ShaderAttribute;
import electrosphere.renderer.texture.Texture;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
@Deprecated
/**
* Contains a set of foliage entities and groups them together.
*/

View File

@ -13,6 +13,7 @@ import electrosphere.util.ds.octree.ChunkTree;
import electrosphere.util.ds.octree.ChunkTree.ChunkTreeNode;
import electrosphere.util.math.GeomUtils;
@Deprecated
/**
* A whole chunk of foliage
*/

View File

@ -8,21 +8,14 @@ import java.util.List;
import java.util.Map;
import java.util.Random;
import org.joml.Matrix4d;
import org.joml.Quaterniond;
import org.joml.Vector3d;
import org.joml.Vector3i;
import electrosphere.client.entity.camera.CameraEntityUtils;
import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.engine.Globals;
import electrosphere.entity.ClientEntityUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.renderer.OpenGLState;
import electrosphere.renderer.RenderPipelineState;
import electrosphere.renderer.actor.instance.TextureInstancedActor;
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
import electrosphere.renderer.buffer.ShaderAttribute;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
@ -468,51 +461,6 @@ public class FoliageCell {
return rVal;
}
/**
* Draws all entities in the foliage cell
*/
protected void draw(){
if(this.modelEntity != null){
Matrix4d modelMatrix = new Matrix4d();
Vector3d cameraCenter = CameraEntityUtils.getCameraCenter(Globals.playerCamera);
RenderPipelineState renderPipelineState = Globals.renderingEngine.getRenderPipelineState();
OpenGLState openGLState = Globals.renderingEngine.getOpenGLState();
Vector3d realPosition = this.getRealPos();
Vector3d cameraModifiedPosition = new Vector3d(realPosition).sub(cameraCenter);
//frustum check entire cell
int size = (int)Math.pow(2,this.lod);
boolean shouldRender = renderPipelineState.getFrustumIntersection().testSphere(
(float)(cameraModifiedPosition.x + size / 2.0),
(float)(cameraModifiedPosition.y + size / 2.0),
(float)(cameraModifiedPosition.z + size / 2.0),
(float)(size)
);
if(shouldRender){
//disable frustum check and instead perform at cell level
boolean currentFrustumCheckState = renderPipelineState.shouldFrustumCheck();
renderPipelineState.setFrustumCheck(false);
Vector3d grassPosition = EntityUtils.getPosition(modelEntity);
Quaterniond grassRotation = EntityUtils.getRotation(modelEntity);
TextureInstancedActor actor = TextureInstancedActor.getTextureInstancedActor(modelEntity);
if(actor != null){
modelMatrix = modelMatrix.identity();
modelMatrix.translate(cameraModifiedPosition);
modelMatrix.rotate(new Quaterniond(grassRotation));
modelMatrix.scale(new Vector3d(EntityUtils.getScale(modelEntity)));
actor.applySpatialData(modelMatrix,grassPosition);
//draw
actor.draw(renderPipelineState, openGLState);
renderPipelineState.setFrustumCheck(currentFrustumCheckState);
}
}
}
}
/**
* Gets the real-space position of the foliage cell
* @return the real-space position

View File

@ -319,26 +319,6 @@ public class FoliageCellManager {
return updated;
}
/**
* Draw all foliage cells
*/
public void draw(){
this.recursivelyDraw(this.chunkTree.getRoot());
}
/**
* Draws all foliage cells recursively
* @param node The current node
*/
private void recursivelyDraw(WorldOctTreeNode<FoliageCell> node){
if(node.getChildren() != null && node.getChildren().size() > 0){
for(int i = 0; i < 8; i++){
this.recursivelyDraw(node.getChildren().get(i));
}
}
node.getData().draw();
}
/**
* Gets the minimum distance from a node to a point
* @param pos the position to check against

View File

@ -19,6 +19,7 @@ import electrosphere.engine.assetmanager.queue.QueuedTexture.QueuedTextureType;
import electrosphere.entity.ClientEntityUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.foliage.AmbientFoliage;
import electrosphere.game.data.foliage.type.FoliageType;
@ -223,6 +224,7 @@ public class FoliageModel {
EntityUtils.getScale(rVal).set(1,1,1);
//add ambient foliage behavior tree
AmbientFoliage.attachAmbientFoliageTree(rVal, 1.0f, foliageType.getGrowthModel().getGrowthRate());
Globals.clientScene.registerEntityToTag(rVal, EntityTags.DRAW_FOLIAGE_PASS);
}
if(toDelete != null){
ClientEntityUtils.destroyEntity(toDelete);

View File

@ -28,5 +28,6 @@ public class EntityTags {
public static final String DRAW_CAST_SHADOW = "drawCastShadow";
public static final String DRAW_VOLUMETIC_DEPTH_PASS = "drawVolumetricDepthPass"; //draw in the volumetic phase of the volumetric pass
public static final String DRAW_VOLUMETIC_SOLIDS_PASS = "drawVolumetricSolidsPass"; //draw in the non-volumetic phase of the volumetric pass
public static final String DRAW_FOLIAGE_PASS = "drawFoliagePass"; //draw in the foliage pass
}

View File

@ -37,6 +37,7 @@ import electrosphere.renderer.framebuffer.Renderbuffer;
import electrosphere.renderer.light.LightManager;
import electrosphere.renderer.pipelines.CompositePipeline;
import electrosphere.renderer.pipelines.FirstPersonItemsPipeline;
import electrosphere.renderer.pipelines.FoliagePipeline;
import electrosphere.renderer.pipelines.ImGuiPipeline;
import electrosphere.renderer.pipelines.MainContentNoOITPipeline;
import electrosphere.renderer.pipelines.MainContentPipeline;
@ -169,6 +170,7 @@ public class RenderingEngine {
ShadowMapPipeline shadowMapPipeline = new ShadowMapPipeline();
VolumeBufferPipeline volumeBufferPipeline = new VolumeBufferPipeline();
NormalsForOutlinePipeline normalsForOutlinePipeline = new NormalsForOutlinePipeline();
FoliagePipeline foliagePipeline = new FoliagePipeline();
OutlineNormalsPipeline outlineNormalsPipeline = new OutlineNormalsPipeline();
CompositePipeline compositePipeline = new CompositePipeline();
PostProcessingPipeline postProcessingPipeline = new PostProcessingPipeline();
@ -672,6 +674,14 @@ public class RenderingEngine {
return this.postProcessingPipeline;
}
/**
* Gets the foliage pipeline
* @return The foliage pipeline
*/
public FoliagePipeline getFoliagePipeline(){
return foliagePipeline;
}
/**
* Gets the current opengl state
* @return

View File

@ -0,0 +1,65 @@
package electrosphere.renderer.pipelines;
import java.util.Set;
import org.joml.Matrix4d;
import org.joml.Quaterniond;
import org.joml.Sphered;
import org.joml.Vector3d;
import electrosphere.client.entity.camera.CameraEntityUtils;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils;
import electrosphere.renderer.OpenGLState;
import electrosphere.renderer.RenderPipelineState;
import electrosphere.renderer.actor.instance.TextureInstancedActor;
/**
* Pipeline for rendering foliage
*/
public class FoliagePipeline implements RenderPipeline {
/**
* Template bounding shere used for checking frustum for this cell
*/
static Sphered boundingSphere = new Sphered(0.5,0.5,0.5,8);
@Override
public void render(OpenGLState openGLState, RenderPipelineState renderPipelineState) {
Set<Entity> foliageEntities = Globals.clientScene.getEntitiesWithTag(EntityTags.DRAW_FOLIAGE_PASS);
if(foliageEntities != null){
for(Entity foliageEntity : foliageEntities){
Matrix4d modelMatrix = new Matrix4d();
Vector3d cameraCenter = CameraEntityUtils.getCameraCenter(Globals.playerCamera);
Vector3d realPosition = EntityUtils.getPosition(foliageEntity);
Vector3d cameraModifiedPosition = new Vector3d(realPosition).sub(cameraCenter);
//frustum check entire cell
boolean shouldRender = renderPipelineState.getFrustumIntersection().testSphere((float)(cameraModifiedPosition.x + boundingSphere.x), (float)(cameraModifiedPosition.y + boundingSphere.y), (float)(cameraModifiedPosition.z + boundingSphere.z), (float)(boundingSphere.r));
if(shouldRender){
//disable frustum check and instead perform at cell level
boolean currentFrustumCheckState = renderPipelineState.shouldFrustumCheck();
renderPipelineState.setFrustumCheck(false);
Vector3d grassPosition = EntityUtils.getPosition(foliageEntity);
Quaterniond grassRotation = EntityUtils.getRotation(foliageEntity);
TextureInstancedActor actor = TextureInstancedActor.getTextureInstancedActor(foliageEntity);
modelMatrix = modelMatrix.identity();
modelMatrix.translate(cameraModifiedPosition);
modelMatrix.rotate(new Quaterniond(grassRotation));
modelMatrix.scale(new Vector3d(EntityUtils.getScale(foliageEntity)));
actor.applySpatialData(modelMatrix,grassPosition);
//draw
actor.draw(renderPipelineState, openGLState);
renderPipelineState.setFrustumCheck(currentFrustumCheckState);
}
}
}
}
}

View File

@ -86,7 +86,7 @@ public class MainContentPipeline implements RenderPipeline {
currentActor.draw(renderPipelineState,openGLState);
}
}
Globals.foliageCellManager.draw();
Globals.renderingEngine.getFoliagePipeline().render(openGLState, renderPipelineState);
for(Entity currentEntity : Globals.clientScene.getEntitiesWithTag(EntityTags.DRAW_INSTANCED)){
Vector3d position = EntityUtils.getPosition(currentEntity);
if(shouldDrawSolidPass(currentEntity)){