From f9d3541ce82b2cbc5443943e2159a93ec1cb6e19 Mon Sep 17 00:00:00 2001 From: austin Date: Mon, 2 Sep 2024 15:33:56 -0400 Subject: [PATCH] shadow map properly rendering --- assets/Shaders/lightDepth/lightDepth.fs | 2 +- buildNumber.properties | 4 +- .../menu/debug/ImGuiRenderer.java | 45 +++++++++++++ .../menu/debug/ImGuiWindowMacros.java | 5 ++ .../renderer/RenderingEngine.java | 10 ++- .../renderer/framebuffer/Framebuffer.java | 9 ++- .../framebuffer/FramebufferUtils.java | 33 +++------- .../electrosphere/renderer/model/Mesh.java | 7 +- .../pipelines/RenderScreenPipeline.java | 2 +- .../renderer/pipelines/ShadowMapPipeline.java | 66 +++++++++++++++---- .../renderer/shader/ShaderProgram.java | 9 +++ 11 files changed, 146 insertions(+), 46 deletions(-) create mode 100644 src/main/java/electrosphere/menu/debug/ImGuiRenderer.java diff --git a/assets/Shaders/lightDepth/lightDepth.fs b/assets/Shaders/lightDepth/lightDepth.fs index 68241c0b..46b038fa 100644 --- a/assets/Shaders/lightDepth/lightDepth.fs +++ b/assets/Shaders/lightDepth/lightDepth.fs @@ -2,5 +2,5 @@ void main() { - gl_FragDepth = gl_FragCoord.z; + // gl_FragDepth = gl_FragCoord.z; } \ No newline at end of file diff --git a/buildNumber.properties b/buildNumber.properties index 6b777a55..5ecb1621 100644 --- a/buildNumber.properties +++ b/buildNumber.properties @@ -1,3 +1,3 @@ #maven.buildNumber.plugin properties file -#Thu Aug 29 22:01:29 EDT 2024 -buildNumber=305 +#Mon Sep 02 15:21:11 EDT 2024 +buildNumber=315 diff --git a/src/main/java/electrosphere/menu/debug/ImGuiRenderer.java b/src/main/java/electrosphere/menu/debug/ImGuiRenderer.java new file mode 100644 index 00000000..e671f3d3 --- /dev/null +++ b/src/main/java/electrosphere/menu/debug/ImGuiRenderer.java @@ -0,0 +1,45 @@ +package electrosphere.menu.debug; + +import electrosphere.engine.Globals; +import electrosphere.renderer.pipelines.ShadowMapPipeline; +import electrosphere.renderer.ui.imgui.ImGuiWindow; +import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback; +import imgui.ImGui; + +public class ImGuiRenderer { + + //window for viewing information about loggers + protected static ImGuiWindow rendererWindow; + + //stores far plane + private static float[] farPlaneArr = new float[]{1}; + + + /** + * Creates the windows in this file + */ + protected static void createRendererWindows(){ + createRendererWindow(); + } + + /** + * loggers view + */ + protected static void createRendererWindow(){ + rendererWindow = new ImGuiWindow("Renderer"); + rendererWindow.setCallback(new ImGuiWindowCallback() { + @Override + public void exec() { + if(ImGui.collapsingHeader("Shadow Map Pipeline")){ + ShadowMapPipeline shadowMapPipeline = Globals.renderingEngine.getShadowMapPipeline(); + if(ImGui.sliderFloat("Far Plane Distance", farPlaneArr, 1, 100)){ + shadowMapPipeline.setFarPlane(farPlaneArr[0]); + } + } + } + }); + rendererWindow.setOpen(false); + Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(rendererWindow); + } + +} diff --git a/src/main/java/electrosphere/menu/debug/ImGuiWindowMacros.java b/src/main/java/electrosphere/menu/debug/ImGuiWindowMacros.java index f93daf78..e428d311 100644 --- a/src/main/java/electrosphere/menu/debug/ImGuiWindowMacros.java +++ b/src/main/java/electrosphere/menu/debug/ImGuiWindowMacros.java @@ -47,6 +47,7 @@ public class ImGuiWindowMacros { ImGuiAI.createAIDebugWindow(); ImGuiAudio.createAudioDebugMenu(); ImGuiLogger.createLoggersWindows(); + ImGuiRenderer.createRendererWindows(); } /** @@ -161,6 +162,10 @@ public class ImGuiWindowMacros { if(ImGui.button("Loggers")){ ImGuiLogger.loggersWindow.setOpen(true); } + //logger state control + if(ImGui.button("Renderers")){ + ImGuiRenderer.rendererWindow.setOpen(true); + } //close button if(ImGui.button("Close")){ mainDebugWindow.setOpen(false); diff --git a/src/main/java/electrosphere/renderer/RenderingEngine.java b/src/main/java/electrosphere/renderer/RenderingEngine.java index f15253e0..f451128b 100644 --- a/src/main/java/electrosphere/renderer/RenderingEngine.java +++ b/src/main/java/electrosphere/renderer/RenderingEngine.java @@ -340,7 +340,7 @@ public class RenderingEngine { screenTextureDepth = FramebufferUtils.generateScreenTextureDepth(openGLState, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); screenFramebuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, screenTextureColor, screenTextureDepth); defaultFramebuffer.bind(openGLState); - // glBindRenderbuffer(GL_RENDERBUFFER, GL_DEFAULT_RENDERBUFFER); + glBindRenderbuffer(GL_RENDERBUFFER, GL_DEFAULT_RENDERBUFFER); Globals.renderingEngine.checkError(); // @@ -637,6 +637,14 @@ public class RenderingEngine { return renderPipelineState; } + /** + * Gets the shadow map pipeline + * @return The shadow map pipeline + */ + public ShadowMapPipeline getShadowMapPipeline(){ + return this.shadowMapPipeline; + } + /** * Gets the current opengl state * @return diff --git a/src/main/java/electrosphere/renderer/framebuffer/Framebuffer.java b/src/main/java/electrosphere/renderer/framebuffer/Framebuffer.java index a71a5dc9..371b4d1d 100644 --- a/src/main/java/electrosphere/renderer/framebuffer/Framebuffer.java +++ b/src/main/java/electrosphere/renderer/framebuffer/Framebuffer.java @@ -103,6 +103,9 @@ public class Framebuffer { return glCheckNamedFramebufferStatus(framebufferPointer,GL40.GL_FRAMEBUFFER) == 0; } + /** + * Checks the status of the framebuffer + */ public void checkStatus(){ if(this.isError()){ LoggerInterface.loggerRenderer.WARNING("Framebuffer [glError] - " + RenderingEngine.getErrorInEnglish(Globals.renderingEngine.getError())); @@ -226,8 +229,6 @@ public class Framebuffer { * @param texturePointer The depth attachment's pointer */ public void setDepthAttachment(OpenGLState openGLState, Texture depthTexture){ - openGLState.glBindFramebuffer(GL40.GL_FRAMEBUFFER, this.framebufferPointer); - this.depthTexture = depthTexture; if(this.framebufferPointer == Framebuffer.DEFAULT_FRAMEBUFFER_POINTER){ throw new IllegalStateException("Trying to attach image to default frame buffer!"); } @@ -237,7 +238,9 @@ public class Framebuffer { if(!GL40.glIsTexture(depthTexture.getTexturePointer())){ throw new IllegalStateException("Tried to attach incomplete texture to framebuffer!"); } - GL40.glFramebufferTexture2D(GL40.GL_FRAMEBUFFER, GL40.GL_DEPTH_ATTACHMENT, GL40.GL_TEXTURE_2D, depthTexture.getTexturePointer(), 0); + this.depthTexture = depthTexture; + openGLState.glBindFramebuffer(GL40.GL_FRAMEBUFFER, this.framebufferPointer); + GL40.glFramebufferTexture2D(GL40.GL_FRAMEBUFFER, GL40.GL_DEPTH_ATTACHMENT, GL40.GL_TEXTURE_2D, this.depthTexture.getTexturePointer(), 0); Globals.renderingEngine.checkError(); Globals.renderingEngine.defaultFramebuffer.bind(openGLState); } diff --git a/src/main/java/electrosphere/renderer/framebuffer/FramebufferUtils.java b/src/main/java/electrosphere/renderer/framebuffer/FramebufferUtils.java index 6aa7b33c..5f7fd18c 100644 --- a/src/main/java/electrosphere/renderer/framebuffer/FramebufferUtils.java +++ b/src/main/java/electrosphere/renderer/framebuffer/FramebufferUtils.java @@ -2,6 +2,7 @@ package electrosphere.renderer.framebuffer; import electrosphere.engine.Globals; import electrosphere.renderer.OpenGLState; +import electrosphere.renderer.pipelines.ShadowMapPipeline; import electrosphere.renderer.texture.Texture; import java.nio.IntBuffer; @@ -51,6 +52,7 @@ public class FramebufferUtils { //these make sure the texture actually clamps to the borders of the quad texture.setWrap(openGLState, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); texture.setWrap(openGLState, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + texture.setBorderColor(openGLState, new float[]{0,0,0,1}); //guarantees that the texture object has actually been created (calling gen buffers does not guarantee object creation) texture.bind(openGLState); @@ -68,6 +70,7 @@ public class FramebufferUtils { //these make sure the texture actually clamps to the borders of the quad texture.setWrap(openGLState, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); texture.setWrap(openGLState, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + texture.setBorderColor(openGLState, new float[]{0,0,0,1}); //guarantees that the texture object has actually been created (calling gen buffers does not guarantee object creation) texture.bind(openGLState); @@ -86,6 +89,7 @@ public class FramebufferUtils { //these make sure the texture actually clamps to the borders of the quad texture.setWrap(openGLState, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); texture.setWrap(openGLState, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + texture.setBorderColor(openGLState, new float[]{0,0,0,1}); //guarantees that the texture object has actually been created (calling gen buffers does not guarantee object creation) texture.bind(openGLState); @@ -98,35 +102,18 @@ public class FramebufferUtils { public static Framebuffer generateScreenTextureFramebuffer(OpenGLState openGLState, int width, int height, Texture colorTexture, Texture depthTexture){ Framebuffer buffer = new Framebuffer(); - //texture - // int texture = glGenTextures(); - // glBindTexture(GL_TEXTURE_2D,texture); - // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // //these make sure the texture actually clamps to the borders of the quad - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); //bind texture to fbo buffer.setMipMapLevel(0); buffer.attachTexture(openGLState,colorTexture); buffer.setDepthAttachment(openGLState,depthTexture); //check make sure compiled buffer.checkStatus(); + Globals.renderingEngine.defaultFramebuffer.bind(openGLState); return buffer; } public static Framebuffer generateScreenTextureFramebuffer(OpenGLState openGLState, int width, int height, Texture colorTexture){ Framebuffer buffer = new Framebuffer(); - //texture - // int texture = glGenTextures(); - // glBindTexture(GL_TEXTURE_2D,texture); - // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // //these make sure the texture actually clamps to the borders of the quad - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); //bind texture to fbo buffer.setMipMapLevel(0); buffer.attachTexture(openGLState,colorTexture); @@ -161,6 +148,7 @@ public class FramebufferUtils { Globals.renderingEngine.checkError(); //check make sure compiled buffer.checkStatus(); + Globals.renderingEngine.defaultFramebuffer.bind(openGLState); return buffer; } @@ -205,14 +193,10 @@ public class FramebufferUtils { buffer.bind(); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); Globals.renderingEngine.checkError(); - Globals.renderingEngine.checkError(); return buffer; } - static int depthMapWidth = 4096; - static int depthMapHeight = 4096; - public static Framebuffer generateDepthBuffer(OpenGLState openGLState){ Framebuffer buffer = new Framebuffer(); buffer.bind(openGLState); @@ -220,7 +204,7 @@ public class FramebufferUtils { //texture Texture texture = new Texture(); - texture.glTexImage2D(openGLState, depthMapWidth, depthMapHeight, GL_DEPTH_COMPONENT, GL_FLOAT); + texture.glTexImage2D(openGLState, ShadowMapPipeline.SHADOW_MAP_RESOLUTION, ShadowMapPipeline.SHADOW_MAP_RESOLUTION, GL_DEPTH_COMPONENT, GL_FLOAT); texture.setMinFilter(openGLState, GL_NEAREST); texture.setMagFilter(openGLState, GL_NEAREST); texture.setWrap(openGLState, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); @@ -240,6 +224,7 @@ public class FramebufferUtils { //check make sure compiled buffer.checkStatus(); + Globals.renderingEngine.defaultFramebuffer.bind(openGLState); return buffer; } @@ -273,6 +258,7 @@ public class FramebufferUtils { //check make sure compiled buffer.checkStatus(); + Globals.renderingEngine.defaultFramebuffer.bind(openGLState); return buffer; } @@ -316,6 +302,7 @@ public class FramebufferUtils { //check make sure compiled buffer.checkStatus(); + Globals.renderingEngine.defaultFramebuffer.bind(openGLState); return buffer; } diff --git a/src/main/java/electrosphere/renderer/model/Mesh.java b/src/main/java/electrosphere/renderer/model/Mesh.java index 53109e18..9e5c7026 100644 --- a/src/main/java/electrosphere/renderer/model/Mesh.java +++ b/src/main/java/electrosphere/renderer/model/Mesh.java @@ -27,13 +27,13 @@ import org.joml.Vector3f; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL40; import static org.lwjgl.opengl.GL11.GL_FLOAT; import static org.lwjgl.opengl.GL11.GL_INT; import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; import static org.lwjgl.opengl.GL11.GL_TRIANGLES; import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT; -import static org.lwjgl.opengl.GL13.GL_TEXTURE3; import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER; import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER; import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW; @@ -429,11 +429,12 @@ public class Mesh { } if(renderPipelineState.getUseShadowMap()){ - openGLState.glActiveTexture(GL_TEXTURE3); + int shadowMapTextureUnit = 3; + openGLState.glActiveTexture(GL40.GL_TEXTURE0 + shadowMapTextureUnit); Globals.renderingEngine.checkError(); openGLState.glBindTexture(GL_TEXTURE_2D, RenderingEngine.lightBufferDepthTexture.getTexturePointer()); Globals.renderingEngine.checkError(); - openGLState.getActiveShader().setUniform(openGLState, "shadowMap", 3); + openGLState.getActiveShader().setUniform(openGLState, "shadowMap", shadowMapTextureUnit); } diff --git a/src/main/java/electrosphere/renderer/pipelines/RenderScreenPipeline.java b/src/main/java/electrosphere/renderer/pipelines/RenderScreenPipeline.java index 163f45eb..48bba8c1 100644 --- a/src/main/java/electrosphere/renderer/pipelines/RenderScreenPipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/RenderScreenPipeline.java @@ -47,7 +47,7 @@ public class RenderScreenPipeline implements RenderPipeline { openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.screenFramebuffer.getTexture().getTexturePointer()); break; case 1: - openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.lightDepthBuffer.getTexture().getTexturePointer()); + openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.lightDepthBuffer.getDepthTexture().getTexturePointer()); break; case 2: openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.volumeDepthBackfaceTexture.getTexturePointer()); diff --git a/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java b/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java index 498c2c2c..6741b1fb 100644 --- a/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java @@ -16,45 +16,71 @@ import electrosphere.renderer.OpenGLState; import electrosphere.renderer.RenderPipelineState; import electrosphere.renderer.RenderingEngine; import electrosphere.renderer.actor.Actor; +import electrosphere.util.math.MathUtils; /** * Shadow map pipeline */ public class ShadowMapPipeline implements RenderPipeline { + /** + * The resolution of the shadow map + */ + public static final int SHADOW_MAP_RESOLUTION = 4096; + + /** + * The eye of the camera that is used to render the shadow map + */ + Vector3d cameraEye = new Vector3d(-1,10,-5.5); + + /** + * The near plane distance + */ + float nearPlane = 0.1f; + + /** + * The far plane + */ + float farPlane = 25f; + + /** + * Sets whether the far plane should update based on camera location or not + */ + boolean updateFarPlane = true; + @Override public void render(OpenGLState openGLState, RenderPipelineState renderPipelineState) { Globals.profiler.beginCpuSample("ShadowMapPipeline.render"); Matrix4d modelTransformMatrix = new Matrix4d(); //set the viewport to shadow map size - openGLState.glViewport(4096, 4096); + openGLState.glViewport(SHADOW_MAP_RESOLUTION, SHADOW_MAP_RESOLUTION); openGLState.glDepthTest(true); - openGLState.glDepthFunc(GL40.GL_ALWAYS); + openGLState.glDepthFunc(GL40.GL_LEQUAL); openGLState.setActiveShader(renderPipelineState, RenderingEngine.lightDepthShaderProgram); - RenderingEngine.lightDepthBuffer.bind(openGLState); + + GL40.glClearDepth(1.0); GL40.glClear(GL40.GL_DEPTH_BUFFER_BIT); openGLState.glActiveTexture(GL40.GL_TEXTURE0); - float eyeX = -1.0f; - float eyeY = 10.0f; - float eyeZ = -5.5f; - float nearPlane = 0.01f; - float eyeDist = (float)Math.sqrt(eyeX * eyeX + eyeY * eyeY + eyeZ * eyeZ); - float farPlane = eyeDist + 10.0f; + float eyeX = (float)cameraEye.x; + float eyeY = (float)cameraEye.y; + float eyeZ = (float)cameraEye.z; + float eyeDist = (float)cameraEye.length(); + // float farPlane = eyeDist + 10.0f; float sidesMagnitude = (float)Math.sqrt(eyeDist); //set matrices for light render Matrix4f lightProjection = new Matrix4f().setOrtho(-sidesMagnitude, sidesMagnitude, -sidesMagnitude, sidesMagnitude, nearPlane, farPlane);//glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane); Matrix4f lightView = new Matrix4f().setLookAt( new Vector3f(eyeX, eyeY, eyeZ), new Vector3f( 0.0f, 0.0f, 0.0f), - new Vector3f( 0.0f, 1.0f, 0.0f) + MathUtils.getUpVectorf() ); - Globals.lightDepthMatrix = new Matrix4f(lightProjection).mul(lightView); + Globals.lightDepthMatrix = lightProjection.mul(lightView); - GL40.glUniformMatrix4fv(GL40.glGetUniformLocation(openGLState.getActiveShader().getShaderId(), "lightSpaceMatrix"), false, Globals.lightDepthMatrix.get(new float[16])); + openGLState.getActiveShader().setUniform(openGLState, "lightSpaceMatrix", Globals.lightDepthMatrix); // glCullFace(GL_FRONT); @@ -109,5 +135,21 @@ public class ShadowMapPipeline implements RenderPipeline { Globals.profiler.endCpuSample(); } + + /** + * Sets the far plane value + * @param farPlane The far plane value + */ + public void setFarPlane(float farPlane){ + this.farPlane = farPlane; + } + + /** + * Sets whether the far plane should update based on camera location or not + * @param updateFarPlane true if should update, false otherwise + */ + public void setUpdateFarPlane(boolean updateFarPlane){ + this.updateFarPlane = updateFarPlane; + } } diff --git a/src/main/java/electrosphere/renderer/shader/ShaderProgram.java b/src/main/java/electrosphere/renderer/shader/ShaderProgram.java index 9f3b3633..f32317e1 100644 --- a/src/main/java/electrosphere/renderer/shader/ShaderProgram.java +++ b/src/main/java/electrosphere/renderer/shader/ShaderProgram.java @@ -764,6 +764,15 @@ public class ShaderProgram { } } + /** + * Gets the location of a given uniform + * @param uniformName The name of the uniform + * @return The location of the uniform + */ + public int getUniformLocation(String uniformName){ + return GL40.glGetUniformLocation(this.getShaderId(), uniformName); + } + /** * Gets the id of the shader