From 77beb4c3afde5232b3a2454a1518cdeb9da44ba0 Mon Sep 17 00:00:00 2001 From: Malin E Date: Wed, 14 Sep 2022 14:36:33 +0200 Subject: [PATCH] WIP First attempt at a solution --- modules/base/rendering/renderablemodel.cpp | 268 +++++++++++++++++- modules/base/rendering/renderablemodel.h | 19 +- .../base/rendering/screenspaceframebuffer.cpp | 2 +- modules/base/shaders/modelOpacity_fs.glsl | 59 ++++ modules/base/shaders/modelOpacity_vs.glsl | 35 +++ modules/base/shaders/model_fs.glsl | 23 +- modules/base/shaders/model_vs.glsl | 2 +- 7 files changed, 375 insertions(+), 33 deletions(-) create mode 100644 modules/base/shaders/modelOpacity_fs.glsl create mode 100644 modules/base/shaders/modelOpacity_vs.glsl diff --git a/modules/base/rendering/renderablemodel.cpp b/modules/base/rendering/renderablemodel.cpp index 1a6fa4ffdd..c50f092ddf 100644 --- a/modules/base/rendering/renderablemodel.cpp +++ b/modules/base/rendering/renderablemodel.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -39,11 +41,15 @@ #include #include #include +#include #include #include +#include #include #include +#include + namespace { constexpr std::string_view _loggerCat = "RenderableModel"; constexpr std::string_view ProgramName = "ModelProgram"; @@ -62,17 +68,30 @@ namespace { { "Color Adding", ColorAddingBlending } }; + constexpr glm::vec4 PosBufferClearVal = { 1e32, 1e32, 1e32, 1.f }; + + const GLenum ColorAttachmentArray[3] = { + GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, + GL_COLOR_ATTACHMENT2 + }; + constexpr openspace::properties::Property::PropertyInfo EnableAnimationInfo = { "EnableAnimation", "Enable Animation", "Enable or disable the animation for the model if it has any" }; - constexpr std::array UniformNames = { - "opacity", "nLightSources", "lightDirectionsViewSpace", "lightIntensities", + constexpr std::array UniformNames = { + "nLightSources", "lightDirectionsViewSpace", "lightIntensities", "modelViewTransform", "normalTransform", "projectionTransform", "performShading", "ambientIntensity", "diffuseIntensity", - "specularIntensity", "opacityBlending" + "specularIntensity" + }; + + constexpr std::array UniformOpacityNames = { + "opacity", "opacityBlending", "colorTexture", "depthTexture", "positionTexture", + "normalTexture" }; constexpr openspace::properties::Property::PropertyInfo AmbientIntensityInfo = { @@ -486,7 +505,7 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary) } bool RenderableModel::isReady() const { - return _program; + return _program && _screenShader; } void RenderableModel::initialize() { @@ -539,14 +558,198 @@ void RenderableModel::initializeGL() { ghoul::opengl::updateUniformLocations(*_program, _uniformCache, UniformNames); + _screenShader = BaseModule::ProgramObjectManager.request( + "ModelOpacityProgram", + [&]() -> std::unique_ptr { + std::filesystem::path vs = + absPath("${MODULE_BASE}/shaders/modelOpacity_vs.glsl"); + std::filesystem::path fs = + absPath("${MODULE_BASE}/shaders/modelOpacity_fs.glsl"); + + return global::renderEngine->buildRenderProgram("ModelOpacityProgram", vs, fs); + } + ); + ghoul::opengl::updateUniformLocations( + *_screenShader, + _uniformOpacityCache, + UniformOpacityNames + ); + + // Screen quad VAO + const GLfloat quadVertices[] = { + // x y + -1.f, -1.f, + 1.f, 1.f, + -1.f, 1.f, + -1.f, -1.f, + 1.f, -1.f, + 1.f, 1.f, + }; + + glGenVertexArrays(1, &_quadVao); + glBindVertexArray(_quadVao); + + glGenBuffers(1, &_quadVbo); + glBindBuffer(GL_ARRAY_BUFFER, _quadVbo); + + glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr); + glEnableVertexAttribArray(0); + + createFramebuffers(); + _geometry->initialize(); _geometry->calculateBoundingRadius(); } +void RenderableModel::createFramebuffers() { + glm::vec2 resolution = global::windowDelegate->currentDrawBufferResolution(); + + // Generate textures and the frame buffer + glGenTextures(1, &_colorTexture); + glGenTextures(1, &_positionTexture); + glGenTextures(1, &_normalTexture); + glGenTextures(1, &_depthTexture); + glGenFramebuffers(1, &_framebuffer); + + // Create the textures + // Color + glBindTexture(GL_TEXTURE_2D, _colorTexture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA32F, + static_cast(resolution.x), + static_cast(resolution.y), + 0, + GL_RGBA, + GL_FLOAT, + nullptr + ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel(GL_TEXTURE, _colorTexture, -1, "RenderableModel Color"); + } + + + // Position + glBindTexture(GL_TEXTURE_2D, _positionTexture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA32F, + static_cast(resolution.x), + static_cast(resolution.y), + 0, + GL_RGBA, + GL_FLOAT, + nullptr + ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel(GL_TEXTURE, _positionTexture, -1, "RenderableModel Position"); + } + + // Normal + glBindTexture(GL_TEXTURE_2D, _normalTexture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA32F, + static_cast(resolution.x), + static_cast(resolution.y), + 0, + GL_RGBA, + GL_FLOAT, + nullptr + ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel(GL_TEXTURE, _normalTexture, -1, "RenderableModel Normal"); + } + + // Depth + glBindTexture(GL_TEXTURE_2D, _depthTexture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_DEPTH_COMPONENT32F, + static_cast(resolution.x), + static_cast(resolution.y), + 0, + GL_DEPTH_COMPONENT, + GL_FLOAT, + nullptr + ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel(GL_TEXTURE, _depthTexture, -1, "RenderableModel Depth"); + } + + // Create buffers + glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer); + glFramebufferTexture( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + _colorTexture, + 0 + ); + glFramebufferTexture( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT1, + _positionTexture, + 0 + ); + glFramebufferTexture( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT2, + _normalTexture, + 0 + ); + glFramebufferTexture( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + _depthTexture, + 0 + ); + + if (glbinding::Binding::ObjectLabel.isResolved()) { + glObjectLabel(GL_FRAMEBUFFER, _framebuffer, -1, "RenderableModel Opacity"); + } + + // Check status + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LERROR("Framebuffer is not complete!"); + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + void RenderableModel::deinitializeGL() { _geometry->deinitialize(); _geometry.reset(); + glDeleteFramebuffers(1, &_framebuffer); + glDeleteTextures(1, &_colorTexture); + glDeleteTextures(1, &_depthTexture); + glDeleteTextures(1, &_positionTexture); + glDeleteTextures(1, &_normalTexture); + + glDeleteBuffers(1, &_quadVbo); + glDeleteVertexArrays(1, &_quadVao); + std::string program = std::string(ProgramName); if (!_vertexShaderPath.empty()) { program += "|vs=" + _vertexShaderPath; @@ -561,6 +764,8 @@ void RenderableModel::deinitializeGL() { } ); _program = nullptr; + _screenShader = nullptr; + ghoul::opengl::FramebufferObject::deactivate(); } void RenderableModel::render(const RenderData& data, RendererTasks&) { @@ -579,7 +784,7 @@ void RenderableModel::render(const RenderData& data, RendererTasks&) { if (distanceToCamera < maxDistance) { _program->activate(); - _program->setUniform(_uniformCache.opacity, opacity()); + // Model transform and view transform needs to be in double precision const glm::dmat4 modelTransform = @@ -636,7 +841,7 @@ void RenderableModel::render(const RenderData& data, RendererTasks&) { _program->setUniform(_uniformCache.diffuseIntensity, _diffuseIntensity); _program->setUniform(_uniformCache.specularIntensity, _specularIntensity); _program->setUniform(_uniformCache.performShading, _performShading); - _program->setUniform(_uniformCache.opacityBlending, _enableOpacityBlending); + if (_disableFaceCulling) { glDisable(GL_CULL_FACE); @@ -665,18 +870,63 @@ void RenderableModel::render(const RenderData& data, RendererTasks&) { glDisable(GL_DEPTH_TEST); } + // Frame buffer stuff + GLint defaultFBO = ghoul::opengl::FramebufferObject::getActiveObject(); + glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer); + glDrawBuffers(3, ColorAttachmentArray); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClearBufferfv(GL_COLOR, 1, glm::value_ptr(PosBufferClearVal)); + + // Render Pass 1 _geometry->render(*_program); if (_disableFaceCulling) { glEnable(GL_CULL_FACE); } - - global::renderEngine->openglStateCache().resetBlendState(); + _program->deactivate(); if (_disableDepthTest) { glEnable(GL_DEPTH_TEST); } - _program->deactivate(); + // Render pass 2 + glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); + glDisable(GL_DEPTH_TEST); // disable depth test so screen-space quad isn't discarded due to depth test. + + _screenShader->activate(); + + _program->setUniform(_uniformOpacityCache.opacity, opacity()); + _program->setUniform(_uniformOpacityCache.opacityBlending, _enableOpacityBlending); + + // Bind textures + ghoul::opengl::TextureUnit colorTextureUnit; + colorTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _colorTexture); + _program->setUniform(_uniformOpacityCache.modelColorTexture, colorTextureUnit); + /* + ghoul::opengl::TextureUnit positionTextureUnit; + positionTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _positionTexture); + _program->setUniform(_uniformOpacityCache.moedlPositionTexture, positionTextureUnit); + + ghoul::opengl::TextureUnit normalTextureUnit; + normalTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _normalTexture); + _program->setUniform(_uniformOpacityCache.modelNormalTexture, normalTextureUnit); + + ghoul::opengl::TextureUnit depthTextureUnit; + depthTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _depthTexture); + _program->setUniform(_uniformOpacityCache.modelDepthTexture, depthTextureUnit); + + // Draw + glBindVertexArray(_quadVao); + glDrawArrays(GL_TRIANGLES, 0, 6); + _screenShader->deactivate(); + */ + // End + global::renderEngine->openglStateCache().resetBlendState(); + glEnable(GL_DEPTH_TEST); + glActiveTexture(GL_TEXTURE0); } } diff --git a/modules/base/rendering/renderablemodel.h b/modules/base/rendering/renderablemodel.h index 4662690245..d883eef06c 100644 --- a/modules/base/rendering/renderablemodel.h +++ b/modules/base/rendering/renderablemodel.h @@ -40,6 +40,7 @@ #include namespace ghoul::opengl { + class FramebufferObject; class ProgramObject; class Texture; } // namespace ghoul::opengl @@ -104,10 +105,10 @@ private: std::string _vertexShaderPath; std::string _fragmentShaderPath; ghoul::opengl::ProgramObject* _program = nullptr; - UniformCache(opacity, nLightSources, lightDirectionsViewSpace, lightIntensities, + UniformCache(nLightSources, lightDirectionsViewSpace, lightIntensities, modelViewTransform, normalTransform, projectionTransform, performShading, ambientIntensity, diffuseIntensity, - specularIntensity, opacityBlending) _uniformCache; + specularIntensity) _uniformCache; std::vector> _lightSources; @@ -116,6 +117,20 @@ private: std::vector _lightDirectionsViewSpaceBuffer; properties::PropertyOwner _lightSourcePropertyOwner; + + // Frame buffer stuff + GLuint _framebuffer; + GLuint _colorTexture; + GLuint _depthTexture; + GLuint _positionTexture; + GLuint _normalTexture; + GLuint _quadVao; + GLuint _quadVbo; + void createFramebuffers(); + ghoul::opengl::ProgramObject* _screenShader = nullptr; + + UniformCache(opacity, opacityBlending, modelColorTexture, modelDepthTexture, + modelPositionTexture, modelNormalTexture) _uniformOpacityCache; }; } // namespace openspace diff --git a/modules/base/rendering/screenspaceframebuffer.cpp b/modules/base/rendering/screenspaceframebuffer.cpp index 17b7f0d869..0913f877e9 100644 --- a/modules/base/rendering/screenspaceframebuffer.cpp +++ b/modules/base/rendering/screenspaceframebuffer.cpp @@ -108,7 +108,7 @@ void ScreenSpaceFramebuffer::render() { const glm::vec4& size = _size.value(); const float xratio = resolution.x / (size.z - size.x); - const float yratio = resolution.y / (size.w - size.y);; + const float yratio = resolution.y / (size.w - size.y); if (!_renderFunctions.empty()) { GLint viewport[4]; diff --git a/modules/base/shaders/modelOpacity_fs.glsl b/modules/base/shaders/modelOpacity_fs.glsl new file mode 100644 index 0000000000..b45665d31f --- /dev/null +++ b/modules/base/shaders/modelOpacity_fs.glsl @@ -0,0 +1,59 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include "fragment.glsl" +#include "floatoperations.glsl" + +in vec2 vs_st; + +uniform float opacity = 1.0; +uniform bool opacityBlending = false; + +uniform sampler2D colorTexture; +uniform sampler2D depthTexture; +uniform sampler2D positionTexture; +uniform sampler2D normalTexture; + +Fragment getFragment() { + Fragment frag; + + if (opacity == 0.0) { + discard; + } + + if (opacityBlending) { + // frag.color.a = opacity * (frag.color.r + frag.color.g + frag.color.b)/3.0; + frag.color.a = opacity * max(max(frag.color.r, frag.color.g), frag.color.b); + } + else { + frag.color.a = opacity; + } + + frag.color.rgb = texture(colorTexture, vs_st).rgb; + frag.depth = denormalizeFloat(texture(depthTexture, vs_st).x); + frag.gPosition = texture(positionTexture, vs_st); + frag.gNormal = vec4(texture(normalTexture, vs_st).rgb, 0.0); + + return frag; +} diff --git a/modules/base/shaders/modelOpacity_vs.glsl b/modules/base/shaders/modelOpacity_vs.glsl new file mode 100644 index 0000000000..efd3a16703 --- /dev/null +++ b/modules/base/shaders/modelOpacity_vs.glsl @@ -0,0 +1,35 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version __CONTEXT__ + +layout(location = 0) in vec2 in_position; +layout(location = 1) in vec2 in_st; + +out vec2 vs_st; + +void main() { + vs_st = in_st; + gl_Position = vec4(in_position.x, in_position.y, 0.0, 1.0); +} diff --git a/modules/base/shaders/model_fs.glsl b/modules/base/shaders/model_fs.glsl index 76ad9653c3..1cd48498b9 100644 --- a/modules/base/shaders/model_fs.glsl +++ b/modules/base/shaders/model_fs.glsl @@ -39,7 +39,6 @@ uniform bool has_texture_diffuse; uniform bool has_texture_normal; uniform bool has_texture_specular; uniform bool has_color_specular; -uniform bool opacityBlending = false; uniform sampler2D texture_diffuse; uniform sampler2D texture_normal; uniform sampler2D texture_specular; @@ -48,7 +47,6 @@ uniform vec3 color_specular; uniform int nLightSources; uniform vec3 lightDirectionsViewSpace[8]; uniform float lightIntensities[8]; -uniform float opacity = 1.0; Fragment getFragment() { @@ -63,7 +61,7 @@ Fragment getFragment() { // Pink and complementary green in a chessboard pattern frag.color.rgb = mix(vec3(1.0, 0.0, 0.8), vec3(0.0, 1.0, 0.2), chessboard); - frag.color.a = opacity; + frag.color.a = 1.0; frag.depth = vs_screenSpaceDepth; frag.gPosition = vs_positionCameraSpace; frag.gNormal = vec4(vs_normalViewSpace, 0.0); @@ -80,10 +78,6 @@ Fragment getFragment() { diffuseAlbedo = color_diffuse; } - if (opacity == 0.0) { - discard; - } - Fragment frag; if (performShading) { @@ -103,7 +97,7 @@ Fragment getFragment() { // Some of these values could be passed in as uniforms const vec3 lightColorAmbient = vec3(1.0); const vec3 lightColor = vec3(1.0); - + vec3 n; if (has_texture_normal) { vec3 normalAlbedo = texture(texture_normal, vs_st).rgb; @@ -141,18 +135,7 @@ Fragment getFragment() { frag.color.rgb = diffuseAlbedo; } - if (opacityBlending) { - // frag.color.a = opacity * (frag.color.r + frag.color.g + frag.color.b)/3.0; - frag.color.a = opacity * max(max(frag.color.r, frag.color.g), frag.color.b); - } - else { - frag.color.a = opacity; - } - - if (frag.color.a < 0.1) { - discard; - } - + frag.color.a = 1.0; frag.depth = vs_screenSpaceDepth; frag.gPosition = vs_positionCameraSpace; frag.gNormal = vec4(vs_normalViewSpace, 0.0); diff --git a/modules/base/shaders/model_vs.glsl b/modules/base/shaders/model_vs.glsl index 4451a169b8..b73c5c8c79 100644 --- a/modules/base/shaders/model_vs.glsl +++ b/modules/base/shaders/model_vs.glsl @@ -52,7 +52,7 @@ void main() { gl_Position = positionScreenSpace; vs_st = in_st; vs_screenSpaceDepth = positionScreenSpace.w; - + vs_normalViewSpace = normalize(mat3(normalTransform) * (mat3(meshNormalTransform) * in_normal)); // TBN matrix for normal mapping