290 lines
12 KiB
Java
290 lines
12 KiB
Java
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.client.entity.camera.CameraEntityUtils;
|
|
import electrosphere.engine.Globals;
|
|
import electrosphere.entity.Entity;
|
|
import electrosphere.entity.EntityDataStrings;
|
|
import electrosphere.entity.EntityTags;
|
|
import electrosphere.entity.EntityUtils;
|
|
import electrosphere.entity.state.attach.AttachUtils;
|
|
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.foliageCellManager.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);
|
|
openGLState.glBlend(true);
|
|
openGLState.glBlendFunci(0, GL40.GL_ONE, GL40.GL_ONE);
|
|
openGLState.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);
|
|
|
|
|
|
//
|
|
// Reset State
|
|
//
|
|
Globals.renderingEngine.defaultFramebuffer.bind(openGLState);
|
|
|
|
|
|
|
|
// 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;
|
|
}
|
|
|
|
}
|