From 532a0fa9f212abfa75d6a853cfda684a468fa3b1 Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Wed, 4 Apr 2018 22:59:22 +0200 Subject: [PATCH] Initial work to support SSAO: rendering position and normal maps --- data/shaders/fs_default.glsl | 16 ++------ src/modules/RenderModule.cc | 74 ++++++++++++++++++++++++++++-------- src/modules/RenderModule.h | 4 ++ src/modules/RenderUtils.cc | 71 ++++++++++++++++++++++++++++++---- src/modules/RenderUtils.h | 8 +++- 5 files changed, 136 insertions(+), 37 deletions(-) diff --git a/data/shaders/fs_default.glsl b/data/shaders/fs_default.glsl index 202582a..6603400 100644 --- a/data/shaders/fs_default.glsl +++ b/data/shaders/fs_default.glsl @@ -20,6 +20,8 @@ smooth in vec4 ioFragColor; in vec4 ioFragPosLightSpace; out vec4 outColor; +out vec3 outPosition; +out vec3 outNormal; float ShadowCalculationPCF(vec4 frag_pos_light_space) { vec3 projected_coordinates = frag_pos_light_space.xyz / frag_pos_light_space.w; @@ -88,19 +90,9 @@ void main() { vec4 specular = spec * vec4(0.5); // shadow -// float shadow = ShadowCalculation(ioFragPosLightSpace); float shadow = ShadowCalculationPCF(ioFragPosLightSpace); outColor = ambient + (1.0 - shadow) * (diffuse + specular); -// -// -// vec3 projected_coordinates = ioFragPosLightSpace.xyz / ioFragPosLightSpace.w; -// projected_coordinates = projected_coordinates * 0.5 + 0.5; -// float shadow_map_value = texture(uShadowMap, projected_coordinates.xy).r; -// outColor = shadow_map_value * vec4(1.0, 1.0, 1.0, 1.0); -// -// outColor = vec4(vec3(1.0f - shadow_map_value), 1.0); -// outColor = (shadow) * vec4(1.0, 1.0, 1.0, 1.0); -// outColor = ioFragPosLightSpace / ioFragPosLightSpace.w; -// outColor = ambient + diffuse + specular; + outPosition = ioFragPosition.xyz; + outNormal = ioFragNormal; } diff --git a/src/modules/RenderModule.cc b/src/modules/RenderModule.cc index 91f4682..caee3bf 100644 --- a/src/modules/RenderModule.cc +++ b/src/modules/RenderModule.cc @@ -87,6 +87,8 @@ static void module_serialize ( Serializer* serializer) { SerializeBool(*serializer, "protot.RenderModule.DrawDepth", sRendererSettings.DrawDepth); SerializeBool(*serializer, "protot.RenderModule.DrawLightDepth", sRendererSettings.DrawLightDepth); + SerializeBool(*serializer, "protot.RenderModule.mIsSSAOEnabled", gRenderer->mIsSSAOEnabled); + SerializeBool(*serializer, "protot.RenderModule.Camera.mIsOrthographic", gRenderer->mCamera.mIsOrthographic); SerializeFloat(*serializer, "protot.RenderModule.Camera.mFov", gRenderer->mCamera.mFov); SerializeVec3(*serializer, "protot.RenderModule.Camera.mEye", gRenderer->mCamera.mEye); @@ -374,10 +376,16 @@ void Renderer::Initialize(int width, int height) { // Render Target gLog("Initializing main render target size: %d,%d", width, height); - mRenderTarget.Initialize(width, height, - RenderTarget::EnableColor + int render_target_flags = RenderTarget::EnableColor | RenderTarget::EnableDepthTexture - | RenderTarget::EnableLinearizedDepthTexture); + | RenderTarget::EnableLinearizedDepthTexture; + + if (mIsSSAOEnabled) { + render_target_flags = render_target_flags + | RenderTarget::EnablePositionTexture + | RenderTarget::EnableNormalTexture; + } + mRenderTarget.Initialize(width, height, render_target_flags); mRenderTarget.mVertexArray = &gVertexArray; mRenderTarget.mQuadMesh = &gScreenQuad; @@ -404,8 +412,22 @@ void Renderer::Shutdown() { void Renderer::RenderGl() { mSceneAreaWidth = mSceneAreaWidth < 1 ? 1 : mSceneAreaWidth; mSceneAreaHeight = mSceneAreaHeight < 1 ? 1 : mSceneAreaHeight; - if (mSceneAreaWidth != mRenderTarget.mWidth || mSceneAreaHeight != mRenderTarget.mHeight) { - mRenderTarget.Resize(mSceneAreaWidth, mSceneAreaHeight); + + // TODO: Refactor enabling/disabling buffers for SSAO + int required_render_flags = RenderTarget::EnableColor + | RenderTarget::EnableDepthTexture + | RenderTarget::EnableLinearizedDepthTexture; + + if (mIsSSAOEnabled) { + required_render_flags = required_render_flags + | RenderTarget::EnablePositionTexture + | RenderTarget::EnableNormalTexture; + } + + if (mSceneAreaWidth != mRenderTarget.mWidth + || mSceneAreaHeight != mRenderTarget.mHeight + || mRenderTarget.mFlags != required_render_flags ) { + mRenderTarget.Resize(mSceneAreaWidth, mSceneAreaHeight, required_render_flags); } if (mCamera.mWidth != mSceneAreaWidth @@ -487,7 +509,14 @@ void Renderer::RenderGl() { if (mDefaultProgram.SetMat44("uLightSpaceMatrix", mLight.mLightSpaceMatrix) == -1) { gLog ("Warning: Uniform %s not found!", "uLightSpaceMatrix"); } - + + if (mIsSSAOEnabled) { + GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 }; + glDrawBuffers (3, buffers); + } else { + GLenum buffers[] = { GL_COLOR_ATTACHMENT0}; + glDrawBuffers (1, buffers); + } RenderScene(mDefaultProgram, mCamera); if (mSettings->DrawDepth) { @@ -593,19 +622,32 @@ void Renderer::DrawGui() { ImGui::EndDock(); if (ImGui::BeginDock("Render Settings")) { - ImGui::Text("Scene"); - ImGui::SliderFloat("Moving Factor", &moving_factor, -10.0f, 10.0f); - ImGui::Text("Camera"); mCamera.DrawGui(); - ImGui::Text("Default Texture"); - ImVec2 content_avail = ImGui::GetContentRegionAvail(); - ImGui::Image((void*) mDefaultTexture.mTextureId, - ImVec2(content_avail.x, content_avail.x), - ImVec2(0.0f, 1.0f), - ImVec2(1.0f, 0.0f) - ); + ImGui::Checkbox("Enable SSAO", &mIsSSAOEnabled); + + if (mIsSSAOEnabled) { + ImGui::Text("Position Texture"); + mPositionTextureRef.mTextureIdPtr = &mRenderTarget.mPositionTexture; + mPositionTextureRef.magic = (GLuint)0xbadface; + float aspect = mRenderTarget.mHeight / mRenderTarget.mWidth; + ImVec2 content_avail = ImGui::GetContentRegionAvail(); + ImGui::Image((void*) &mPositionTextureRef, + ImVec2(content_avail.x, content_avail.x * aspect), + ImVec2(0.0f, 1.0f), + ImVec2(1.0f, 0.0f) + ); + + ImGui::Text("Normal Texture"); + mNormalTextureRef.mTextureIdPtr = &mRenderTarget.mNormalTexture; + mNormalTextureRef.magic = (GLuint)0xbadface; + ImGui::Image((void*) &mNormalTextureRef, + ImVec2(content_avail.x, content_avail.x * aspect), + ImVec2(0.0f, 1.0f), + ImVec2(1.0f, 0.0f) + ); + } } ImGui::EndDock(); diff --git a/src/modules/RenderModule.h b/src/modules/RenderModule.h index 4588c47..29d9f5f 100644 --- a/src/modules/RenderModule.h +++ b/src/modules/RenderModule.h @@ -55,6 +55,8 @@ struct Renderer { RendererSettings* mSettings = nullptr; bool mInitialized = false; + bool mIsSSAOEnabled = false; + uint32_t mWidth = 1; uint32_t mHeight = 1; uint32_t mSceneAreaWidth = 1; @@ -72,6 +74,8 @@ struct Renderer { RenderTarget mRenderTarget; GLTextureRef mRenderTextureRef = { (int)0xbadface }; + GLTextureRef mPositionTextureRef = { (int)0xbadface }; + GLTextureRef mNormalTextureRef = { (int)0xbadface }; Renderer() : mInitialized(false), diff --git a/src/modules/RenderUtils.cc b/src/modules/RenderUtils.cc index 466cc55..afe036d 100644 --- a/src/modules/RenderUtils.cc +++ b/src/modules/RenderUtils.cc @@ -153,6 +153,10 @@ GLuint RenderProgram::LinkProgram(GLuint vertex_shader, GLuint fragment_shader) glBindAttribLocation(ProgramID, 2, "inUV"); glBindAttribLocation(ProgramID, 3, "inColor"); + glBindFragDataLocation(ProgramID, 0, "outColor"); + glBindFragDataLocation(ProgramID, 1, "outPosition"); + glBindFragDataLocation(ProgramID, 2, "outNormal"); + glLinkProgram(ProgramID); GLint Result = GL_FALSE; @@ -277,14 +281,29 @@ void RenderTarget::Initialize(int width, int height, int flags) { mFlags = flags; - Resize(width, height); + Resize(width, height, mFlags); } void RenderTarget::Bind() { assert(glIsFramebuffer(mFrameBufferId)); glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferId); - GLenum shadow_map_draw_buffers[] = { GL_COLOR_ATTACHMENT0 }; - glDrawBuffers(1, shadow_map_draw_buffers); + + GLenum buffers[8]; + int num_buffers = 0; + + if (mFlags & EnableColor) { + buffers[num_buffers++] = GL_COLOR_ATTACHMENT0; + } + + if (mFlags & EnablePositionTexture ) { + buffers[num_buffers++] = GL_COLOR_ATTACHMENT2; + } + + if (mFlags & EnableNormalTexture) { + buffers[num_buffers++] = GL_COLOR_ATTACHMENT3; + } + + glDrawBuffers(num_buffers, buffers); } void RenderTarget::Cleanup() { @@ -313,17 +332,30 @@ void RenderTarget::Cleanup() { mLinearizedDepthTexture = -1; } + if (mPositionTexture != -1) { + glDeleteTextures(1, &mPositionTexture); + mPositionTexture = -1; + } + + if (mNormalTexture != -1) { + glDeleteTextures(1, &mNormalTexture); + mNormalTexture = -1; + } + mWidth = -1; mHeight = -1; + mFlags = 0; } -void RenderTarget::Resize(int width, int height) { - if (width == mWidth && height == mHeight) +void RenderTarget::Resize(int width, int height, int flags) { + if (width == mWidth && height == mHeight && flags == mFlags) return; Cleanup(); - gLog("Resizing RenderTarget to %d,%d", width, height); + mFlags = flags; + + gLog("Resizing RenderTarget to %d,%d flags: %d", width, height, flags); mWidth = width; mHeight = height; @@ -360,7 +392,6 @@ void RenderTarget::Resize(int width, int height) { float border_color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, mDepthTexture, 0); if (mFlags & EnableLinearizedDepthTexture) { @@ -383,6 +414,32 @@ void RenderTarget::Resize(int width, int height) { glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthBuffer); } + if (mFlags & EnablePositionTexture) { + glGenTextures(1, &mPositionTexture); + glBindTexture(GL_TEXTURE_2D, mPositionTexture); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, mWidth, mHeight, 0, GL_RGB, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, mPositionTexture, 0); + } + + if (mFlags & EnableNormalTexture) { + glGenTextures(1, &mNormalTexture); + glBindTexture(GL_TEXTURE_2D, mNormalTexture); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, mWidth, mHeight, 0, GL_RGB, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, mNormalTexture, 0); + } + GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (result != GL_FRAMEBUFFER_COMPLETE) { switch (result) { diff --git a/src/modules/RenderUtils.h b/src/modules/RenderUtils.h index 9ca91cb..d56b6da 100644 --- a/src/modules/RenderUtils.h +++ b/src/modules/RenderUtils.h @@ -254,12 +254,16 @@ struct RenderTarget { GLuint mDepthBuffer = -1; GLuint mDepthTexture = -1; GLuint mLinearizedDepthTexture = -1; + GLuint mPositionTexture = -1; + GLuint mNormalTexture = -1; typedef enum { EnableColor = 1, EnableDepth = 2, EnableDepthTexture = 4, - EnableLinearizedDepthTexture = 8 + EnableLinearizedDepthTexture = 8, + EnablePositionTexture = 16, + EnableNormalTexture = 32, } Flags; int mFlags = 0; @@ -274,7 +278,7 @@ struct RenderTarget { void Initialize(int width, int height, int flags); void Bind(); void Cleanup(); - void Resize(int width, int height); + void Resize(int width, int height, int flags); void RenderToLinearizedDepth(const float& near, const float& far, bool is_orthographic); };