package electrosphere.renderer.pipelines; import org.joml.Matrix4d; import org.joml.Matrix4f; import org.joml.Quaterniond; import org.joml.Quaternionf; import org.joml.Vector3d; import org.joml.Vector3f; import org.lwjgl.opengl.GL40; import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityTags; import electrosphere.entity.EntityUtils; import electrosphere.entity.types.attach.AttachUtils; import electrosphere.entity.types.camera.CameraEntityUtils; import electrosphere.renderer.OpenGLState; import electrosphere.renderer.RenderPipelineState; import electrosphere.renderer.RenderingEngine; import electrosphere.renderer.RenderPipelineState.SelectedShaderEnum; import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.instance.InstancedActor; import electrosphere.renderer.buffer.ShaderAttribute; /** * The main render pipeline with OIT pass */ public class MainContentPipeline implements RenderPipeline { //First person drawing routine FirstPersonItemsPipeline firstPersonSubPipeline; @Override public void render(OpenGLState openGLState, RenderPipelineState renderPipelineState) { Globals.profiler.beginCpuSample("MainContentPipeline.render"); Matrix4d modelTransformMatrix = new Matrix4d(); //bind screen fbo RenderingEngine.screenFramebuffer.bind(openGLState); openGLState.glDepthTest(true); openGLState.glDepthFunc(GL40.GL_LESS); GL40.glDepthMask(true); openGLState.glViewport(Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY()); /// /// R E N D E R I N G S T U F F /// //Sets the background color. GL40.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); GL40.glClear(GL40.GL_COLOR_BUFFER_BIT | GL40.GL_DEPTH_BUFFER_BIT); // // Set render pipeline state // renderPipelineState.setSelectedShader(SelectedShaderEnum.PRIMARY); renderPipelineState.setUseMeshShader(true); renderPipelineState.setBufferStandardUniforms(true); renderPipelineState.setBufferNonStandardUniforms(false); renderPipelineState.setUseMaterial(true); renderPipelineState.setUseShadowMap(true); renderPipelineState.setUseBones(true); renderPipelineState.setUseLight(true); // // Pass One: Solids // // // D R A W A L L E N T I T I E S // for(Entity currentEntity : Globals.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE)){ Vector3d position = EntityUtils.getPosition(currentEntity); if(shouldDrawSolidPass(currentEntity)){ //fetch actor Actor currentActor = EntityUtils.getActor(currentEntity); //calculate camera-modified vector3f Vector3f cameraModifiedPosition = new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); //calculate and apply model transform modelTransformMatrix.identity(); modelTransformMatrix.translate(cameraModifiedPosition); modelTransformMatrix.rotate(EntityUtils.getRotation(currentEntity)); modelTransformMatrix.scale(new Vector3d(EntityUtils.getScale(currentEntity))); currentActor.applySpatialData(modelTransformMatrix,position); //draw currentActor.draw(renderPipelineState,openGLState); } } Globals.clientFoliageManager.draw(); for(Entity currentEntity : Globals.clientScene.getEntitiesWithTag(EntityTags.DRAW_INSTANCED)){ Vector3d position = EntityUtils.getPosition(currentEntity); if(shouldDrawSolidPass(currentEntity)){ //fetch actor InstancedActor currentActor = InstancedActor.getInstancedActor(currentEntity); //if the shader attribute for model matrix exists, calculate the model matrix and apply if(InstancedActor.getInstanceModelAttribute(currentEntity) != null){ ShaderAttribute modelAttribute = InstancedActor.getInstanceModelAttribute(currentEntity); //calculate model matrix Vector3f cameraModifiedPosition = new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); Quaterniond rotation = EntityUtils.getRotation(currentEntity); // modelTransformMatrix.identity(); modelTransformMatrix.identity().translationRotateScale( cameraModifiedPosition, new Quaternionf((float)rotation.x,(float)rotation.y,(float)rotation.z,(float)rotation.w), new Vector3f(EntityUtils.getScale(currentEntity)) ); //set actor value currentActor.setAttribute(modelAttribute, new Matrix4f(modelTransformMatrix)); //draw currentActor.draw(renderPipelineState, new Vector3d(cameraModifiedPosition)); } else { currentActor.draw(renderPipelineState); } } } //draw all instanced models Globals.clientInstanceManager.draw(renderPipelineState,openGLState); this.firstPersonSubPipeline.render(openGLState, renderPipelineState); // // Pass Two: Transparency Accumulator + Revealage // // glDisable(GL_DEPTH_TEST); GL40.glDepthMask(false); GL40.glEnable(GL40.GL_BLEND); GL40.glBlendFunci(0, GL40.GL_ONE, GL40.GL_ONE); GL40.glBlendFunci(1, GL40.GL_ZERO, GL40.GL_ONE_MINUS_SRC_COLOR); GL40.glBlendEquation(GL40.GL_FUNC_ADD); RenderingEngine.transparencyBuffer.bind(openGLState); GL40.glClearBufferfv(GL40.GL_COLOR,0,RenderingEngine.transparencyAccumulatorClear); GL40.glClearBufferfv(GL40.GL_COLOR,1,RenderingEngine.transparencyRevealageClear); // // Set render pipeline state // renderPipelineState.setUseMeshShader(true); renderPipelineState.setSelectedShader(SelectedShaderEnum.OIT); openGLState.glDepthFunc(GL40.GL_LEQUAL); // //!!!WARNING!!! //Comments on function: //If you're going "gee wilikers I don't know why the back planes of my transparent-labeled aren't showing through the transparency", this is for you //The transparent pass receives the depth buffer of the opaque pass and IS DEPTH MASK CULLED //This means if you draw the transparent object in the depth pass, it will not draw in the transparent pass as it is culled // //!!!WARNING!!! //TLDR OF ABOVE: DO NOT DRAW TRANSPARENT OBJECTS IN OPAQUE PASS // for(Entity currentEntity : Globals.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE)){ Vector3d position = EntityUtils.getPosition(currentEntity); if(shouldDrawTransparentPass(currentEntity)){ //fetch actor Actor currentActor = EntityUtils.getActor(currentEntity); //calculate camera-modified vector3f Vector3f cameraModifiedPosition = new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); //calculate and apply model transform modelTransformMatrix.identity(); modelTransformMatrix.translate(cameraModifiedPosition); modelTransformMatrix.rotate(EntityUtils.getRotation(currentEntity)); modelTransformMatrix.scale(new Vector3d(EntityUtils.getScale(currentEntity))); currentActor.applySpatialData(modelTransformMatrix,position); //draw currentActor.draw(renderPipelineState,openGLState); } } for(Entity currentEntity : Globals.clientScene.getEntitiesWithTag(EntityTags.DRAW_INSTANCED)){ Vector3d position = EntityUtils.getPosition(currentEntity); if(shouldDrawTransparentPass(currentEntity)){ //fetch actor InstancedActor currentActor = InstancedActor.getInstancedActor(currentEntity); //if the shader attribute for model matrix exists, calculate the model matrix and apply if(InstancedActor.getInstanceModelAttribute(currentEntity) != null){ ShaderAttribute modelAttribute = InstancedActor.getInstanceModelAttribute(currentEntity); //calculate model matrix Vector3f cameraModifiedPosition = new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); Quaterniond rotation = EntityUtils.getRotation(currentEntity); // modelTransformMatrix.identity(); modelTransformMatrix.identity().translationRotateScale( cameraModifiedPosition, new Quaternionf((float)rotation.x,(float)rotation.y,(float)rotation.z,(float)rotation.w), new Vector3f(EntityUtils.getScale(currentEntity)) ); //set actor value currentActor.setAttribute(modelAttribute, new Matrix4f(modelTransformMatrix)); //draw currentActor.draw(renderPipelineState, new Vector3d(cameraModifiedPosition)); } else { currentActor.draw(renderPipelineState); } } } //draw all instanced models Globals.clientInstanceManager.draw(renderPipelineState,openGLState); // // Set render pipeline state // renderPipelineState.setSelectedShader(SelectedShaderEnum.PRIMARY); // glBindVertexArray(0); Globals.profiler.endCpuSample(); } /** * Checks if the entity should be drawn * @param entity The entity * @return true if should draw, false otherwise */ static boolean shouldDrawSolidPass(Entity entity){ return ( (boolean)entity.getData(EntityDataStrings.DATA_STRING_DRAW) && entity.getData(EntityDataStrings.DRAW_SOLID_PASS) != null ) && ( !entityBlacklist(entity) ) ; } /** * Checks if the entity should be drawn * @param entity The entity * @return true if should draw, false otherwise */ static boolean shouldDrawTransparentPass(Entity entity){ return ( (boolean)entity.getData(EntityDataStrings.DATA_STRING_DRAW) && entity.getData(EntityDataStrings.DRAW_TRANSPARENT_PASS) != null ) && ( !entityBlacklist(entity) ) ; } /** * Checks whether the entity is on the blacklist for drawing in main pipeline or not * @param entity The entity * @return True if in blacklist, false otherwise */ static boolean entityBlacklist(Entity entity){ return //don't draw first person view in this pipeline ever entity == Globals.firstPersonEntity || //don't draw third person view if camera is first person ( !Globals.controlHandler.cameraIsThirdPerson() && entity == Globals.playerEntity ) || //don't draw items if they're attached to viewmodel ( !Globals.controlHandler.cameraIsThirdPerson() && AttachUtils.hasParent(entity) && Globals.firstPersonEntity != null && AttachUtils.getParent(entity) == Globals.firstPersonEntity ) ; } /** * Get the first person pipeline * @param firstPersonItemsPipeline the first person pipeline */ public void setFirstPersonPipeline(FirstPersonItemsPipeline firstPersonItemsPipeline){ this.firstPersonSubPipeline = firstPersonItemsPipeline; } }