From 59781583584fcaa931dbc6a1491cba0e0797a6d6 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 11 Apr 2018 17:21:44 +0200 Subject: [PATCH 01/81] Updated debugAmbientOcclussionPass script to tablet app --- .../utilities/render/ambientOcclusionPass.qml | 75 +++++++---- .../render/debugAmbientOcclusionPass.js | 126 ++++++++++++++---- 2 files changed, 151 insertions(+), 50 deletions(-) diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index 08334cf2aa..b661f992f1 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -7,40 +7,60 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.5 +import QtQuick 2.7 import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.3 + +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls + import "configSlider" import "../lib/plotperf" -Column { - spacing: 8 +Rectangle { + HifiConstants { id: hifi;} + id: render; + anchors.margins: hifi.dimensions.contentMargin.x + + color: hifi.colors.baseGray; + Column { id: surfaceGeometry spacing: 10 + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: hifi.dimensions.contentMargin.x - Column{ - Repeater { - model: [ - "Radius:radius:2.0:false", - "Level:obscuranceLevel:1.0:false", - "Num Taps:numSamples:32:true", - "Taps Spiral:numSpiralTurns:10.0:false", - "Falloff Bias:falloffBias:0.2:false", - "Edge Sharpness:edgeSharpness:1.0:false", - "Blur Radius:blurRadius:10.0:false", - ] - ConfigSlider { - label: qsTr(modelData.split(":")[0]) - integral: (modelData.split(":")[3] == 'true') - config: Render.getConfig("RenderMainView.AmbientOcclusion") - property: modelData.split(":")[1] - max: modelData.split(":")[2] - min: 0.0 - } + Repeater { + model: [ + "Radius:radius:2.0:false", + "Level:obscuranceLevel:1.0:false", + "Num Taps:numSamples:32:true", + "Taps Spiral:numSpiralTurns:10.0:false", + "Falloff Bias:falloffBias:0.2:false", + "Edge Sharpness:edgeSharpness:1.0:false", + "Blur Radius:blurRadius:10.0:false", + ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: (modelData.split(":")[3] == 'true') + config: Render.getConfig("RenderMainView.AmbientOcclusion") + property: modelData.split(":")[1] + max: modelData.split(":")[2] + min: 0.0 + width: 280 + height:38 } } + Row{ + spacing: 10 + anchors.left: parent.left + anchors.right: parent.right + Column { + spacing: 10 + Repeater { model: [ "resolutionLevel:resolutionLevel", @@ -48,19 +68,24 @@ Column { "fetchMipsEnabled:fetchMipsEnabled", "borderingEnabled:borderingEnabled" ] - CheckBox { + HifiControls.CheckBox { + boxSize: 20 text: qsTr(modelData.split(":")[0]) checked: Render.getConfig("RenderMainView.AmbientOcclusion")[modelData.split(":")[1]] onCheckedChanged: { Render.getConfig("RenderMainView.AmbientOcclusion")[modelData.split(":")[1]] = checked } } } } + Column { + spacing: 10 + Repeater { model: [ "debugEnabled:showCursorPixel" ] - CheckBox { + HifiControls.CheckBox { + boxSize: 20 text: qsTr(modelData.split(":")[0]) checked: Render.getConfig("RenderMainView.DebugAmbientOcclusion")[modelData.split(":")[1]] onCheckedChanged: { Render.getConfig("RenderMainView.DebugAmbientOcclusion")[modelData.split(":")[1]] = checked } @@ -70,6 +95,8 @@ Column { } PlotPerf { + anchors.left: parent.left + anchors.right: parent.right title: "Timing" height: 50 object: Render.getConfig("RenderMainView.AmbientOcclusion") diff --git a/scripts/developer/utilities/render/debugAmbientOcclusionPass.js b/scripts/developer/utilities/render/debugAmbientOcclusionPass.js index f70b3a5cc9..776fc1b600 100644 --- a/scripts/developer/utilities/render/debugAmbientOcclusionPass.js +++ b/scripts/developer/utilities/render/debugAmbientOcclusionPass.js @@ -1,38 +1,112 @@ // -// debugSurfaceGeometryPass.js +// debugAmbientOcclusionPass.js +// developer/utilities/render // -// Created by Sam Gateau on 6/6/2016 -// Copyright 2016 High Fidelity, Inc. +// Olivier Prat, created on 11/04/2018. +// Copyright 2017 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// Set up the qml ui -var qml = Script.resolvePath('ambientOcclusionPass.qml'); -var window = new OverlayWindow({ - title: 'Ambient Occlusion Pass', - source: qml, - width: 400, height: 300, -}); -window.setPosition(Window.innerWidth - 420, 50 + 550 + 50); -window.closed.connect(function() { Script.stop(); }); +(function() { + "use strict"; + var TABLET_BUTTON_NAME = "SSAO"; + var QMLAPP_URL = Script.resolvePath("./ambientOcclusionPass.qml"); + var ICON_URL = Script.resolvePath("../../../system/assets/images/ssao-i.svg"); + var ACTIVE_ICON_URL = Script.resolvePath("../../../system/assets/images/ssao-a.svg"); -var moveDebugCursor = false; -Controller.mousePressEvent.connect(function (e) { - if (e.isMiddleButton) { - moveDebugCursor = true; - setDebugCursor(e.x, e.y); + Script.include([ + Script.resolvePath("../../../system/libraries/stringHelpers.js"), + ]); + + var onScreen = false; + + function onClicked() { + if (onScreen) { + tablet.gotoHomeScreen(); + } else { + tablet.loadQMLSource(QMLAPP_URL); + } } -}); -Controller.mouseReleaseEvent.connect(function() { moveDebugCursor = false; }); -Controller.mouseMoveEvent.connect(function (e) { if (moveDebugCursor) setDebugCursor(e.x, e.y); }); + + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var button = tablet.addButton({ + text: TABLET_BUTTON_NAME, + icon: ICON_URL, + activeIcon: ACTIVE_ICON_URL + }); + + var hasEventBridge = false; + + function wireEventBridge(on) { + if (!tablet) { + print("Warning in wireEventBridge(): 'tablet' undefined!"); + return; + } + if (on) { + if (!hasEventBridge) { + tablet.fromQml.connect(fromQml); + hasEventBridge = true; + } + } else { + if (hasEventBridge) { + tablet.fromQml.disconnect(fromQml); + hasEventBridge = false; + } + } + } + + function onScreenChanged(type, url) { + if (url === QMLAPP_URL) { + onScreen = true; + } else { + onScreen = false; + } + + button.editProperties({isActive: onScreen}); + wireEventBridge(onScreen); + } + + function fromQml(message) { + } + + button.clicked.connect(onClicked); + tablet.screenChanged.connect(onScreenChanged); + + Script.scriptEnding.connect(function () { + if (onScreen) { + tablet.gotoHomeScreen(); + } + button.clicked.disconnect(onClicked); + tablet.screenChanged.disconnect(onScreenChanged); + tablet.removeButton(button); + }); + + + /* + var moveDebugCursor = false; + Controller.mousePressEvent.connect(function (e) { + if (e.isMiddleButton) { + moveDebugCursor = true; + setDebugCursor(e.x, e.y); + } + }); + Controller.mouseReleaseEvent.connect(function() { moveDebugCursor = false; }); + Controller.mouseMoveEvent.connect(function (e) { if (moveDebugCursor) setDebugCursor(e.x, e.y); }); -function setDebugCursor(x, y) { - nx = (x / Window.innerWidth); - ny = 1.0 - ((y) / (Window.innerHeight - 32)); + function setDebugCursor(x, y) { + nx = (x / Window.innerWidth); + ny = 1.0 - ((y) / (Window.innerHeight - 32)); + + Render.getConfig("RenderMainView").getConfig("DebugAmbientOcclusion").debugCursorTexcoord = { x: nx, y: ny }; + } + */ + + function cleanup() { + } + Script.scriptEnding.connect(cleanup); +}()); - Render.getConfig("RenderMainView").getConfig("DebugAmbientOcclusion").debugCursorTexcoord = { x: nx, y: ny }; -} From 644ef33730914c7c50e7dfbd5c3e93b89850b704 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 12 Apr 2018 17:58:05 +0200 Subject: [PATCH 02/81] First draft at batch generateTextureMipsWithPipeline --- .../gpu-gl-common/src/gpu/gl/GLBackend.cpp | 16 ++++- .../gpu-gl-common/src/gpu/gl/GLBackend.h | 9 ++- .../src/gpu/gl/GLBackendTexture.cpp | 62 ++++++++++++++++--- libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp | 7 +-- libraries/gpu-gl/src/gpu/gl41/GL41Backend.h | 4 +- libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp | 37 +++++------ libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 2 +- libraries/gpu/src/gpu/Batch.cpp | 9 +++ libraries/gpu/src/gpu/Batch.h | 7 ++- libraries/gpu/src/gpu/Context.cpp | 12 ++++ libraries/gpu/src/gpu/Context.h | 2 + libraries/render-utils/src/ssao.slh | 1 + 12 files changed, 124 insertions(+), 44 deletions(-) diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index 9bb02d678d..0858e36f65 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -62,7 +62,8 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::gl::GLBackend::do_setFramebufferSwapChain), (&::gpu::gl::GLBackend::do_clearFramebuffer), (&::gpu::gl::GLBackend::do_blit), - (&::gpu::gl::GLBackend::do_generateTextureMips), + (&::gpu::gl::GLBackend::do_generateTextureMips), + (&::gpu::gl::GLBackend::do_generateTextureMipsWithPipeline), (&::gpu::gl::GLBackend::do_advance), @@ -133,10 +134,23 @@ GLBackend::GLBackend() { GLBackend::~GLBackend() { + if (_mipGenerationFramebufferId) { + glDeleteFramebuffers(1, &_mipGenerationFramebufferId); + _mipGenerationFramebufferId = 0; + } killInput(); killTransform(); } +void GLBackend::do_draw(const Batch& batch, size_t paramOffset) { + Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; + uint32 numVertices = batch._params[paramOffset + 1]._uint; + uint32 startVertex = batch._params[paramOffset + 0]._uint; + + draw(mode, numVertices, startVertex); +} + void GLBackend::renderPassTransfer(const Batch& batch) { const size_t numCommands = batch.getCommands().size(); const Batch::Commands::value_type* command = batch.getCommands().data(); diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index 6355137a19..0d62e7490f 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -108,7 +108,7 @@ public: // Draw Stage - virtual void do_draw(const Batch& batch, size_t paramOffset) = 0; + virtual void do_draw(const Batch& batch, size_t paramOffset); virtual void do_drawIndexed(const Batch& batch, size_t paramOffset) = 0; virtual void do_drawInstanced(const Batch& batch, size_t paramOffset) = 0; virtual void do_drawIndexedInstanced(const Batch& batch, size_t paramOffset) = 0; @@ -120,7 +120,8 @@ public: virtual void do_setInputBuffer(const Batch& batch, size_t paramOffset) final; virtual void do_setIndexBuffer(const Batch& batch, size_t paramOffset) final; virtual void do_setIndirectBuffer(const Batch& batch, size_t paramOffset) final; - virtual void do_generateTextureMips(const Batch& batch, size_t paramOffset) final; + virtual void do_generateTextureMips(const Batch& batch, size_t paramOffset) final; + virtual void do_generateTextureMipsWithPipeline(const Batch& batch, size_t paramOffset) final; // Transform Stage virtual void do_setModelTransform(const Batch& batch, size_t paramOffset) final; @@ -234,6 +235,8 @@ public: protected: + virtual void draw(GLenum mode, uint32 numVertices, uint32 startVertex) = 0; + void recycle() const override; // FIXME instead of a single flag, create a features struct similar to @@ -492,6 +495,8 @@ protected: } _textureManagement; virtual void initTextureManagementStage() {} + GLuint _mipGenerationFramebufferId{ 0 }; + typedef void (GLBackend::*CommandCall)(const Batch&, size_t); static CommandCall _commandCalls[Batch::NUM_COMMANDS]; friend class GLState; diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp index ca4e328612..674fdacf0f 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp @@ -66,16 +66,58 @@ GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePointer) { } void GLBackend::do_generateTextureMips(const Batch& batch, size_t paramOffset) { - TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); - if (!resourceTexture) { - return; - } + TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); + if (!resourceTexture) { + return; + } - // DO not transfer the texture, this call is expected for rendering texture - GLTexture* object = syncGPUObject(resourceTexture); - if (!object) { - return; - } + // DO not transfer the texture, this call is expected for rendering texture + GLTexture* object = syncGPUObject(resourceTexture); + if (!object) { + return; + } - object->generateMips(); + object->generateMips(); +} + +void GLBackend::do_generateTextureMipsWithPipeline(const Batch& batch, size_t paramOffset) { + TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); + if (!resourceTexture) { + return; + } + + // Do not transfer the texture, this call is expected for rendering texture + GLTexture* object = syncGPUObject(resourceTexture); + if (!object) { + return; + } + + auto numMips = batch._params[paramOffset + 1]._int; + if (numMips < 0) { + numMips = resourceTexture->getNumMips(); + } else { + numMips = std::min(numMips, (int)resourceTexture->getNumMips()); + } + + if (_mipGenerationFramebufferId == 0) { + glGenFramebuffers(1, &_mipGenerationFramebufferId); + Q_ASSERT(_mipGenerationFramebufferId > 0); + } + + glBindFramebuffer(GL_FRAMEBUFFER, _mipGenerationFramebufferId); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER_EXT, 0); + + for (int level = 1; level < numMips; level++) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, object->_id, level); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, level - 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level - 1); + + const auto mipDimensions = resourceTexture->evalMipDimensions(level); + glViewport(0, 0, mipDimensions.x, mipDimensions.y); + draw(GL_TRIANGLE_STRIP, 4, 0); + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, numMips-1); + + resetOutputStage(); } diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp index 88cf89ad99..d4376632ca 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp @@ -20,12 +20,7 @@ using namespace gpu::gl41; const std::string GL41Backend::GL41_VERSION { "GL41" }; -void GL41Backend::do_draw(const Batch& batch, size_t paramOffset) { - Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; - GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; - uint32 numVertices = batch._params[paramOffset + 1]._uint; - uint32 startVertex = batch._params[paramOffset + 0]._uint; - +void GL41Backend::draw(GLenum mode, uint32 numVertices, uint32 startVertex) { if (isStereo()) { #ifdef GPU_STEREO_DRAWCALL_INSTANCED glDrawArraysInstanced(mode, startVertex, numVertices, 2); diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index 3c59781f78..408766f566 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -133,6 +133,9 @@ public: }; protected: + + void draw(GLenum mode, uint32 numVertices, uint32 startVertex) override; + GLuint getFramebufferID(const FramebufferPointer& framebuffer) override; GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override; @@ -146,7 +149,6 @@ protected: GLQuery* syncGPUObject(const Query& query) override; // Draw Stage - void do_draw(const Batch& batch, size_t paramOffset) override; void do_drawIndexed(const Batch& batch, size_t paramOffset) override; void do_drawInstanced(const Batch& batch, size_t paramOffset) override; void do_drawIndexedInstanced(const Batch& batch, size_t paramOffset) override; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp index c119e27d5b..9a08bbf173 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp @@ -24,33 +24,28 @@ void GL45Backend::recycle() const { Parent::recycle(); } -void GL45Backend::do_draw(const Batch& batch, size_t paramOffset) { - Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; - GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; - uint32 numVertices = batch._params[paramOffset + 1]._uint; - uint32 startVertex = batch._params[paramOffset + 0]._uint; - - if (isStereo()) { +void GL45Backend::draw(GLenum mode, uint32 numVertices, uint32 startVertex) { + if (isStereo()) { #ifdef GPU_STEREO_DRAWCALL_INSTANCED - glDrawArraysInstanced(mode, startVertex, numVertices, 2); + glDrawArraysInstanced(mode, startVertex, numVertices, 2); #else - setupStereoSide(0); - glDrawArrays(mode, startVertex, numVertices); - setupStereoSide(1); - glDrawArrays(mode, startVertex, numVertices); + setupStereoSide(0); + glDrawArrays(mode, startVertex, numVertices); + setupStereoSide(1); + glDrawArrays(mode, startVertex, numVertices); #endif - _stats._DSNumTriangles += 2 * numVertices / 3; - _stats._DSNumDrawcalls += 2; + _stats._DSNumTriangles += 2 * numVertices / 3; + _stats._DSNumDrawcalls += 2; - } else { - glDrawArrays(mode, startVertex, numVertices); - _stats._DSNumTriangles += numVertices / 3; - _stats._DSNumDrawcalls++; - } - _stats._DSNumAPIDrawcalls++; + } else { + glDrawArrays(mode, startVertex, numVertices); + _stats._DSNumTriangles += numVertices / 3; + _stats._DSNumDrawcalls++; + } + _stats._DSNumAPIDrawcalls++; - (void) CHECK_GL_ERROR(); + (void)CHECK_GL_ERROR(); } void GL45Backend::do_drawIndexed(const Batch& batch, size_t paramOffset) { diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index c23a83eaf9..1683861c89 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -231,6 +231,7 @@ public: protected: + void draw(GLenum mode, uint32 numVertices, uint32 startVertex) override; void recycle() const override; GLuint getFramebufferID(const FramebufferPointer& framebuffer) override; @@ -246,7 +247,6 @@ protected: // Draw Stage - void do_draw(const Batch& batch, size_t paramOffset) override; void do_drawIndexed(const Batch& batch, size_t paramOffset) override; void do_drawInstanced(const Batch& batch, size_t paramOffset) override; void do_drawIndexedInstanced(const Batch& batch, size_t paramOffset) override; diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index db4941c163..0c49901091 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -425,6 +425,15 @@ void Batch::generateTextureMips(const TexturePointer& texture) { _params.emplace_back(_textures.cache(texture)); } +void Batch::generateTextureMipsWithPipeline(const TexturePointer& texture, int numMips) { + setResourceTexture(0, texture); + + ADD_COMMAND(generateTextureMipsWithPipeline); + + _params.emplace_back(_textures.cache(texture)); + _params.emplace_back(numMips); +} + void Batch::beginQuery(const QueryPointer& query) { ADD_COMMAND(beginQuery); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 96b234295d..90a30f4e5e 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -211,7 +211,9 @@ public: void blit(const FramebufferPointer& src, const Vec4i& srcRect, const FramebufferPointer& dst, const Vec4i& dstRect); // Generate the mips for a texture - void generateTextureMips(const TexturePointer& texture); + void generateTextureMips(const TexturePointer& texture); + // Generate the mips for a texture using the current pipeline + void generateTextureMipsWithPipeline(const TexturePointer& texture, int numMips = -1); // Query Section void beginQuery(const QueryPointer& query); @@ -310,7 +312,8 @@ public: COMMAND_setFramebufferSwapChain, COMMAND_clearFramebuffer, COMMAND_blit, - COMMAND_generateTextureMips, + COMMAND_generateTextureMips, + COMMAND_generateTextureMipsWithPipeline, COMMAND_advance, diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index e1b68c88ca..657829214f 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -14,6 +14,7 @@ #include "Frame.h" #include "GPULogging.h" +#include "StandardShaderLib.h" using namespace gpu; @@ -317,3 +318,14 @@ Size Context::getTexturePendingGPUTransferMemSize() { Size Context::getTextureResourcePopulatedGPUMemSize() { return Backend::textureResourcePopulatedGPUMemSize.getValue(); } + +PipelinePointer Context::createMipGenerationPipeline(const ShaderPointer& ps, const gpu::Shader::BindingSet& slotBindings) { + auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); + static gpu::StatePointer state(new gpu::State()); + + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + gpu::Shader::makeProgram(*program, slotBindings); + + // Good to go add the brand new pipeline + return gpu::Pipeline::create(program, state); +} diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 2df7de2331..63713832e7 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -220,6 +220,8 @@ public: // Same as above but grabbed at every end of a frame void getFrameStats(ContextStats& stats) const; + static PipelinePointer createMipGenerationPipeline(const ShaderPointer& pixelShader, const gpu::Shader::BindingSet& slotBindings = gpu::Shader::BindingSet()); + double getFrameTimerGPUAverage() const; double getFrameTimerBatchAverage() const; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index c9b27bc2c8..c0039265fa 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -313,6 +313,7 @@ float evalAO(in vec3 C, in vec3 n_C, in vec3 Q) { // the source occlusion texture uniform sampler2D occlusionMap; + vec2 fetchOcclusionDepthRaw(ivec2 coords, out vec3 raw) { raw = texelFetch(occlusionMap, coords, 0).xyz; return unpackOcclusionDepth(raw); From 7e78e79685e9c61ac954aabdca3ba87f5d19b5c5 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 18 Apr 2018 17:20:16 +0200 Subject: [PATCH 03/81] Created median shader for AO depth mip creation but generateMipWithPipeline not working --- .../src/gpu/gl/GLBackendTexture.cpp | 2 +- libraries/gpu/src/gpu/Batch.h | 2 +- .../src/AmbientOcclusionEffect.cpp | 32 +++++++++++++---- .../render-utils/src/AmbientOcclusionEffect.h | 14 ++++---- .../render-utils/src/mip_depth_median.slf | 35 +++++++++++++++++++ 5 files changed, 70 insertions(+), 15 deletions(-) create mode 100644 libraries/render-utils/src/mip_depth_median.slf diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp index 674fdacf0f..410c52a1f6 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp @@ -105,7 +105,7 @@ void GLBackend::do_generateTextureMipsWithPipeline(const Batch& batch, size_t pa } glBindFramebuffer(GL_FRAMEBUFFER, _mipGenerationFramebufferId); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER_EXT, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); for (int level = 1; level < numMips; level++) { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, object->_id, level); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 90a30f4e5e..06b1bd860e 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -213,7 +213,7 @@ public: // Generate the mips for a texture void generateTextureMips(const TexturePointer& texture); // Generate the mips for a texture using the current pipeline - void generateTextureMipsWithPipeline(const TexturePointer& texture, int numMips = -1); + void generateTextureMipsWithPipeline(const TexturePointer& destTexture, int numMips = -1); // Query Section void beginQuery(const QueryPointer& query); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index c526f16b75..7176135a0a 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -34,6 +34,12 @@ #include "ssao_makeHorizontalBlur_frag.h" #include "ssao_makeVerticalBlur_frag.h" +#include "mip_depth_median_frag.h" + +gpu::PipelinePointer AmbientOcclusionEffect::_occlusionPipeline; +gpu::PipelinePointer AmbientOcclusionEffect::_hBlurPipeline; +gpu::PipelinePointer AmbientOcclusionEffect::_vBlurPipeline; +gpu::PipelinePointer AmbientOcclusionEffect::_mipCreationPipeline; AmbientOcclusionFramebuffer::AmbientOcclusionFramebuffer() { } @@ -333,6 +339,15 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { return _vBlurPipeline; } +const gpu::PipelinePointer& AmbientOcclusionEffect::getMipCreationPipeline() { + if (!_mipCreationPipeline) { + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("depthTexture"), 0)); + _mipCreationPipeline = gpu::Context::createMipGenerationPipeline(mip_depth_median_frag::getShader(), slotBindings); + } + return _mipCreationPipeline; +} + void AmbientOcclusionEffect::updateGaussianDistribution() { auto coefs = _parametersBuffer.edit()._gaussianCoefs; GaussianDistribution::evalSampling(coefs, Parameters::GAUSSIAN_COEFS_LENGTH, _parametersBuffer->getBlurRadius(), _parametersBuffer->getBlurDeviation()); @@ -384,9 +399,11 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto occlusionPipeline = getOcclusionPipeline(); auto firstHBlurPipeline = getHBlurPipeline(); auto lastVBlurPipeline = getVBlurPipeline(); + auto mipCreationPipeline = getMipCreationPipeline(); gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) { - batch.enableStereo(false); + PROFILE_RANGE_BATCH(batch, "AmbientOcclusion"); + batch.enableStereo(false); _gpuTimer->begin(batch); @@ -395,16 +412,18 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.resetViewTransform(); Transform model; - model.setTranslation(glm::vec3(sMin, tMin, 0.0f)); + + // We need this with the mips levels + batch.setModelTransform(model); + batch.setPipeline(mipCreationPipeline); + batch.generateTextureMipsWithPipeline(_framebuffer->getLinearDepthTexture()); + + model.setTranslation(glm::vec3(sMin, tMin, 0.0f)); model.setScale(glm::vec3(sWidth, tHeight, 1.0f)); batch.setModelTransform(model); batch.setUniformBuffer(AmbientOcclusionEffect_FrameTransformSlot, frameTransform->getFrameTransformBuffer()); batch.setUniformBuffer(AmbientOcclusionEffect_ParamsSlot, _parametersBuffer); - - - // We need this with the mips levels - batch.generateTextureMips(_framebuffer->getLinearDepthTexture()); // Occlusion pass batch.setFramebuffer(occlusionFBO); @@ -413,7 +432,6 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, _framebuffer->getLinearDepthTexture()); batch.draw(gpu::TRIANGLE_STRIP, 4); - if (_parametersBuffer->getBlurRadius() > 0) { // Blur 1st pass batch.setFramebuffer(occlusionBlurredFBO); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 3643e608ed..99cf4b034c 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -159,13 +159,15 @@ private: ParametersBuffer _parametersBuffer; - const gpu::PipelinePointer& getOcclusionPipeline(); - const gpu::PipelinePointer& getHBlurPipeline(); // first - const gpu::PipelinePointer& getVBlurPipeline(); // second + static const gpu::PipelinePointer& getOcclusionPipeline(); + static const gpu::PipelinePointer& getHBlurPipeline(); // first + static const gpu::PipelinePointer& getVBlurPipeline(); // second + static const gpu::PipelinePointer& getMipCreationPipeline(); - gpu::PipelinePointer _occlusionPipeline; - gpu::PipelinePointer _hBlurPipeline; - gpu::PipelinePointer _vBlurPipeline; + static gpu::PipelinePointer _occlusionPipeline; + static gpu::PipelinePointer _hBlurPipeline; + static gpu::PipelinePointer _vBlurPipeline; + static gpu::PipelinePointer _mipCreationPipeline; AmbientOcclusionFramebufferPointer _framebuffer; diff --git a/libraries/render-utils/src/mip_depth_median.slf b/libraries/render-utils/src/mip_depth_median.slf new file mode 100644 index 0000000000..08813ebb5f --- /dev/null +++ b/libraries/render-utils/src/mip_depth_median.slf @@ -0,0 +1,35 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// mip_depth_median.frag +// fragment shader +// +// Created by Olivier Prat on 4/18/18. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +uniform sampler2D depthTexture; + +in vec2 varTexCoord0; +out vec4 outFragColor; + +void main(void) { + vec4 depths = textureGather(depthTexture, varTexCoord0); + + // Order the depths from minimum to maximum + depths.xy = depths.x > depths.y ? depths.yx : depths.xy; + depths.xz = depths.x > depths.z ? depths.zx : depths.xz; + depths.xw = depths.x > depths.w ? depths.wx : depths.xw; + + depths.yz = depths.y > depths.z ? depths.zy : depths.yz; + depths.yw = depths.y > depths.w ? depths.wy : depths.yw; + + depths.zw = depths.z > depths.w ? depths.wz : depths.zw; + + float median = (depths.y + depths.z) / 2.0; + outFragColor = vec4(vec3(median), 1.0); +} From 0316df4faeb871e3273ab81ed56b052a73515a22 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 19 Apr 2018 15:03:39 +0200 Subject: [PATCH 04/81] Working generateMipWithPipeline command in batch --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 7176135a0a..edd848cfc7 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -413,10 +413,12 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte Transform model; - // We need this with the mips levels + // We need this with the mips levels + batch.pushProfileRange("Depth mip creation"); batch.setModelTransform(model); batch.setPipeline(mipCreationPipeline); batch.generateTextureMipsWithPipeline(_framebuffer->getLinearDepthTexture()); + batch.popProfileRange(); model.setTranslation(glm::vec3(sMin, tMin, 0.0f)); model.setScale(glm::vec3(sWidth, tHeight, 1.0f)); @@ -433,7 +435,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.draw(gpu::TRIANGLE_STRIP, 4); if (_parametersBuffer->getBlurRadius() > 0) { - // Blur 1st pass + PROFILE_RANGE_BATCH(batch, "Blur"); + // Blur 1st pass batch.setFramebuffer(occlusionBlurredFBO); batch.setPipeline(firstHBlurPipeline); batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, occlusionFBO->getRenderBuffer(0)); From 5dcb7f622a2761c16ea40a6eecaa28b5c872da91 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 19 Apr 2018 17:34:11 +0200 Subject: [PATCH 05/81] Fixed corrupted glViewport after call to generateMipWithPipeline --- libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp index 410c52a1f6..48ef49186f 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp @@ -118,6 +118,11 @@ void GLBackend::do_generateTextureMipsWithPipeline(const Batch& batch, size_t pa } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, numMips-1); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); resetOutputStage(); + // Restore viewport + ivec4& vp = _transform._viewport; + glViewport(vp.x, vp.y, vp.z, vp.w); } From 5e9355235ccbd4e6a832dc8354e37e27aa48e490 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 19 Apr 2018 17:34:28 +0200 Subject: [PATCH 06/81] First step for HBAO. Not working of course --- libraries/render-utils/src/ssao.slh | 147 ++++++++++++++---- .../render-utils/src/ssao_debugOcclusion.slf | 8 +- .../render-utils/src/ssao_makeOcclusion.slf | 70 ++++----- 3 files changed, 151 insertions(+), 74 deletions(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index c0039265fa..262d6a77a2 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -11,11 +11,13 @@ <@if not SSAO_SLH@> <@def SSAO_SLH@> +#define SSAO_USE_HORIZON_BASED 1 + <@func declarePackOcclusionDepth()@> const float FAR_PLANE_Z = -300.0; -float CSZToDephtKey(float z) { +float CSZToDepthKey(float z) { return clamp(z * (1.0 / FAR_PLANE_Z), 0.0, 1.0); } vec3 packOcclusionDepth(float occlusion, float depth) { @@ -156,24 +158,25 @@ float evalDiskRadius(float Zeye, vec2 imageSize) { return ssDiskRadius; } -const float TWO_PI = 6.28; +const float PI = 3.1415926; +const float TWO_PI = 6.2831852; -vec3 getUnitTapLocation(int sampleNumber, float spinAngle){ +vec3 getUnitTapLocation(int sampleNumber, float spiralTurns, float spinAngle, float angleRange){ // Radius relative to ssR float alpha = float(sampleNumber + 0.5) * getInvNumSamples(); - float angle = alpha * (getNumSpiralTurns() * TWO_PI) + spinAngle; + float angle = alpha * (spiralTurns * angleRange) + spinAngle; return vec3(cos(angle), sin(angle), alpha); } -vec3 getTapLocation(int sampleNumber, float spinAngle, float outerRadius) { - vec3 tap = getUnitTapLocation(sampleNumber, spinAngle); +vec3 getTapLocationSSAO(int sampleNumber, float spinAngle, float outerRadius) { + vec3 tap = getUnitTapLocation(sampleNumber, getNumSpiralTurns(), spinAngle, TWO_PI); tap.xy *= tap.z; tap *= outerRadius; return tap; } -vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius, vec2 pixelPos, vec2 imageSize) { - vec3 tap = getTapLocation(sampleNumber, spinAngle, outerRadius); +vec3 getTapLocationClampedSSAO(int sampleNumber, float spinAngle, float outerRadius, vec2 pixelPos, vec2 imageSize) { + vec3 tap = getTapLocationSSAO(sampleNumber, spinAngle, outerRadius); vec2 tapPos = pixelPos + tap.xy; if (!(isBorderingEnabled() > 0.0)) { @@ -196,24 +199,7 @@ vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius, tapPos.y -= (imageSize.y - tapPos.y); redoTap = true; } -/* - if ((tapPos.x < 0.5)) { - tapPos.x = 0.5; - redoTap = true; - } else if ((tapPos.x > imageSize.x - 0.5)) { - tapPos.x = imageSize.x - 0.5; - redoTap = true; - } - if ((tapPos.y < 0.5)) { - tapPos.y = 0.5; - redoTap = true; - } else if ((tapPos.y > imageSize.y - 0.5)) { - tapPos.y = imageSize.y - 0.5; - redoTap = true; - } -*/ - if (redoTap) { tap.xy = tapPos - pixelPos; tap.z = length(tap.xy); @@ -228,14 +214,17 @@ vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius, <@func declareFetchDepthPyramidMap()@> - // the depth pyramid texture uniform sampler2D pyramidMap; -float getZEye(ivec2 pixel, int level) { +float getZEyeAtPixel(ivec2 pixel, int level) { return -texelFetch(pyramidMap, pixel, level).x; } +float getZEyeAtUV(vec2 texCoord, int level) { + return -texture(pyramidMap, texCoord, level).x; +} + const int LOG_MAX_OFFSET = 3; const int MAX_MIP_LEVEL = 5; int evalMipFromRadius(float radius) { @@ -243,7 +232,6 @@ int evalMipFromRadius(float radius) { return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); } - vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { ivec2 ssP = ivec2(tap.xy) + ssC; ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y); @@ -292,10 +280,18 @@ vec3 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { <@func declareEvalObscurance()@> -float evalAO(in vec3 C, in vec3 n_C, in vec3 Q) { - vec3 v = Q - C; +vec3 fastAcos(vec3 x) { + // [Eberly2014] GPGPU Programming for Games and Science + vec3 absX = abs(x); + vec3 res = absX * (-0.156583) + vec3(PI / 2.0); + res *= sqrt(vec3(1.0) - absX); + return mix(res, vec3(PI) - res, greaterThanEqual(x, vec3(0))); +} + +float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 tapPosition) { + vec3 v = tapPosition - centerPosition; float vv = dot(v, v); - float vn = dot(v, n_C); + float vn = dot(v, centerNormal); // Fall off function as recommended in SAO paper const float epsilon = 0.01; @@ -303,6 +299,95 @@ float evalAO(in vec3 C, in vec3 n_C, in vec3 Q) { return f * f * f * max((vn - getFalloffBias()) / (epsilon + vv), 0.0); } +vec2 searchHorizons(int side, float centerDepth, vec2 centerPixelUV, vec2 imageSize, vec2 deltaTap, float ssDiskRadius, vec3 fragNormalES) { + vec2 searchVec = deltaTap * ssDiskRadius; + vec2 absSearchVec = abs(searchVec); + vec2 horizons = vec2(-PI/2.0, -PI/2.0); + vec3 centerPoint = vec3(centerPixelUV, centerDepth); + int stepIndex; + vec2 tapPixelUV; + + if (absSearchVec.x > absSearchVec.y) { + int stepCount = int(ceil(absSearchVec.x)); + + // Positive search for h2 + tapPixelUV = centerPixelUV; + deltaTap = (searchVec / searchVec.x) / imageSize; + stepIndex = stepCount; + while (stepIndex>0 && tapPixelUV.x < 1.0) { + tapPixelUV += deltaTap; + // Don't clamp for the moment + + float tapDepth = getZEyeAtUV(tapPixelUV, 0); + vec3 deltaVec = vec3(tapPixelUV, tapDepth) - centerPoint; + + horizons.y = max(horizons.y, normalize(deltaVec).z); + --stepIndex; + } + + // Negative search for h1 + tapPixelUV = centerPixelUV; + stepIndex = stepCount; + while (stepIndex>0 && tapPixelUV.x > 0.0) { + tapPixelUV -= deltaTap; + // Don't clamp for the moment + + float tapDepth = getZEyeAtUV(tapPixelUV, 0); + vec3 deltaVec = vec3(tapPixelUV, tapDepth) - centerPoint; + + horizons.x = max(horizons.x, normalize(deltaVec).z); + --stepIndex; + } + } else { + int stepCount = int(ceil(absSearchVec.y)); + + // Positive search for h2 + tapPixelUV = centerPixelUV; + deltaTap = (searchVec / searchVec.y) / imageSize; + stepIndex = stepCount; + while (stepIndex>0 && tapPixelUV.y < 1.0) { + tapPixelUV += deltaTap; + // Don't clamp for the moment + + float tapDepth = getZEyeAtUV(tapPixelUV, 0); + vec3 deltaVec = vec3(tapPixelUV, tapDepth) - centerPoint; + + horizons.y = max(horizons.y, normalize(deltaVec).z); + --stepIndex; + } + + // Negative search for h1 + tapPixelUV = centerPixelUV; + stepIndex = stepCount; + while (stepIndex>0 && tapPixelUV.y > 0.0) { + tapPixelUV -= deltaTap; + // Don't clamp for the moment + + float tapDepth = getZEyeAtUV(tapPixelUV, 0); + vec3 deltaVec = vec3(tapPixelUV, tapDepth) - centerPoint; + + horizons.x = max(horizons.x, normalize(deltaVec).z); + --stepIndex; + } + } + + vec3 angles = acos(vec3(horizons, fragNormalES.z))-PI/2.0; + angles.x = -angles.x; + // Clamp to limit horizon defined by normal plane + horizons.xy = angles.zz + max(angles.xy - angles.zz, vec2(-PI/2.0, PI/2.0)); + return horizons; +} + +float integrateArc(float h1, float h2) { + vec2 cosh = cos(vec2(h1, h2)); + return 2.0 - cosh.x - cosh.y; +} + +float evalVisibilityHBAO(int side, float centerDepth, vec2 centerPixelUV, vec2 imageSize, vec2 deltaTap, float ssDiskRadius, vec3 fragNormalES) { + vec2 horizonAngles = searchHorizons(side, centerDepth, centerPixelUV, imageSize, deltaTap, ssDiskRadius, fragNormalES); + return integrateArc(horizonAngles.x, horizonAngles.y); +} + <@endfunc@> <@func declareBlurPass(axis)@> diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf index 6af457db67..1ba99f0aa9 100644 --- a/libraries/render-utils/src/ssao_debugOcclusion.slf +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -50,7 +50,7 @@ void main(void) { ivec2 ssC = ivec2(cursorPixelPos); // Fetch the z under the pixel (stereo or not) - float Zeye = getZEye(ssC, 0); + float Zeye = getZEyeAtPixel(ssC, 0); // Stereo side info ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel()); @@ -84,7 +84,7 @@ void main(void) { bool keep = false; for (int i = 0; i < getNumSamples(); ++i) { - vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, cursorPixelPos, imageSize); + vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, ssDiskRadius, cursorPixelPos, imageSize); // The occluding point in camera space vec2 fragToTap = vec2(ssC) + tap.xy - fragCoord.xy; @@ -97,7 +97,7 @@ void main(void) { vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); - sum += float(tap.z > 0.0) * evalAO(Cp, Cn, Q); + sum += float(tap.z > 0.0) * evalVisibilitySSAO(Cp, Cn, Q); } @@ -114,7 +114,7 @@ void main(void) { } !> - outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); + outFragColor = vec4(packOcclusionDepth(A, CSZToDepthKey(Cp.z)), 1.0); if ((dot(fragToCursor,fragToCursor) < (100.0 * keepTapRadius * keepTapRadius) )) { // outFragColor = vec4(vec3(A), 1.0); diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 4c808342c5..3919b3e1d1 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -24,63 +24,55 @@ void main(void) { // Pixel being shaded vec2 fragCoord = gl_FragCoord.xy; - ivec2 ssC = ivec2(fragCoord.xy); + ivec2 centerPixelPos = ivec2(fragCoord.xy); // Fetch the z under the pixel (stereo or not) - float Zeye = getZEye(ssC, 0); + float Zeye = getZEyeAtPixel(centerPixelPos, 0); // Stereo side info - ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel()); + ivec4 side = getStereoSideInfo(centerPixelPos.x, getResolutionLevel()); - // From now on, ssC is the pixel pos in the side - ssC.x -= side.y; - vec2 fragPos = (vec2(ssC) + vec2(0.5)) / imageSize; + // From now on, centerPixelPos is the pixel pos in the side + centerPixelPos.x -= side.y; + vec2 fragUVPos = (vec2(centerPixelPos) + vec2(0.5)) / imageSize; // The position and normal of the pixel fragment in Eye space - vec3 Cp = evalEyePositionFromZeye(side.x, Zeye, fragPos); - vec3 Cn = evalEyeNormal(Cp); + vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); + vec3 fragNormalES = evalEyeNormal(fragPositionES); // Choose the screen-space sample radius - float ssDiskRadius = evalDiskRadius(Cp.z, imageSize); - + float ssDiskRadius = evalDiskRadius(fragPositionES.z, imageSize); +#if SSAO_USE_HORIZON_BASED + ssDiskRadius = min(ssDiskRadius, 3.0); +#endif // Let's make noise - float randomPatternRotationAngle = getAngleDithering(ssC); - //vec3 wCp = (getViewInverse() * vec4(Cp, 1.0)).xyz; - //float randomPatternRotationAngle = getAngleDitheringWorldPos(wCp); + float randomPatternRotationAngle = getAngleDithering(centerPixelPos); - // Accumulate the Obscurance for each samples - float sum = 0.0; + // Accumulate the visibility for each samples + float visibilitySum = 0.0; for (int i = 0; i < getNumSamples(); ++i) { - vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, ssC, imageSize); - - vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize); - - vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); - - sum += float(tap.z > 0.0) * evalAO(Cp, Cn, Q); +#if SSAO_USE_HORIZON_BASED + vec3 deltaTap = getUnitTapLocation(i, 1, randomPatternRotationAngle, PI); + visibilitySum += evalVisibilityHBAO(side.x, Zeye, fragUVPos, imageSize, deltaTap.xy, ssDiskRadius, fragNormalES); +#else + vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, ssDiskRadius, centerPixelPos, imageSize); + vec3 tapUVZ = fetchTap(side, centerPixelPos, tap, imageSize); + vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); + visibilitySum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES); +#endif } - float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples()); + float occlusion = max(0.0, 1.0 - visibilitySum * getObscuranceScaling() * 5.0 * getInvNumSamples()); // KEEP IT for Debugging // Bilateral box-filter over a quad for free, respecting depth edges // (the difference that this makes is subtle) - if (abs(dFdx(Cp.z)) < 0.02) { - A -= dFdx(A) * ((ssC.x & 1) - 0.5); +/* if (abs(dFdx(fragPositionES.z)) < 0.02) { + occlusion -= dFdx(occlusion) * ((centerPixelPos.x & 1) - 0.5); } - if (abs(dFdy(Cp.z)) < 0.02) { - A -= dFdy(A) * ((ssC.y & 1) - 0.5); - } - - - outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); - - /* { - vec3 tap = getTapLocationClamped(2, randomPatternRotationAngle, ssDiskRadius, ssC, imageSize); - vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize); - vec2 fetchUV = vec2(tapUVZ.x + side.w * 0.5 * (side.x - tapUVZ.x), tapUVZ.y); - vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); - outFragColor = vec4(fetchUV, 0.0, 1.0); + if (abs(dFdy(fragPositionES.z)) < 0.02) { + occlusion -= dFdy(occlusion) * ((centerPixelPos.y & 1) - 0.5); }*/ - + + outFragColor = vec4(packOcclusionDepth(occlusion, CSZToDepthKey(fragPositionES.z)), 1.0); } From 3497c93e9a36daf5fcfc89888949e70c0fc94295 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 19 Apr 2018 18:02:31 +0200 Subject: [PATCH 07/81] Updated ambient occlusion debug script to be a tablet app --- .../utilities/render/ambientOcclusionPass.qml | 21 ++---- .../render/debugAmbientOcclusionPass.js | 67 ++++++++----------- 2 files changed, 32 insertions(+), 56 deletions(-) diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index b661f992f1..179fc8341c 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -19,16 +19,16 @@ import "../lib/plotperf" Rectangle { HifiConstants { id: hifi;} - id: render; + id: root; anchors.margins: hifi.dimensions.contentMargin.x color: hifi.colors.baseGray; - + Column { id: surfaceGeometry - spacing: 10 + spacing: 8 anchors.left: parent.left - anchors.right: parent.right + anchors.right: parent.right anchors.margins: hifi.dimensions.contentMargin.x Repeater { @@ -48,19 +48,13 @@ Rectangle { property: modelData.split(":")[1] max: modelData.split(":")[2] min: 0.0 - width: 280 height:38 } } - Row{ + Row { spacing: 10 - anchors.left: parent.left - anchors.right: parent.right - Column { - spacing: 10 - Repeater { model: [ "resolutionLevel:resolutionLevel", @@ -76,10 +70,7 @@ Rectangle { } } } - Column { - spacing: 10 - Repeater { model: [ "debugEnabled:showCursorPixel" @@ -95,8 +86,6 @@ Rectangle { } PlotPerf { - anchors.left: parent.left - anchors.right: parent.right title: "Timing" height: 50 object: Render.getConfig("RenderMainView.AmbientOcclusion") diff --git a/scripts/developer/utilities/render/debugAmbientOcclusionPass.js b/scripts/developer/utilities/render/debugAmbientOcclusionPass.js index 776fc1b600..409473511e 100644 --- a/scripts/developer/utilities/render/debugAmbientOcclusionPass.js +++ b/scripts/developer/utilities/render/debugAmbientOcclusionPass.js @@ -1,30 +1,25 @@ +"use strict"; + // // debugAmbientOcclusionPass.js -// developer/utilities/render +// tablet-sample-app // -// Olivier Prat, created on 11/04/2018. -// Copyright 2017 High Fidelity, Inc. +// Created by Olivier Prat on April 19 2018. +// Copyright 2018 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // (function() { - "use strict"; - - var TABLET_BUTTON_NAME = "SSAO"; + var TABLET_BUTTON_NAME = "AO"; var QMLAPP_URL = Script.resolvePath("./ambientOcclusionPass.qml"); - var ICON_URL = Script.resolvePath("../../../system/assets/images/ssao-i.svg"); - var ACTIVE_ICON_URL = Script.resolvePath("../../../system/assets/images/ssao-a.svg"); - Script.include([ - Script.resolvePath("../../../system/libraries/stringHelpers.js"), - ]); - - var onScreen = false; + + var onLuciScreen = false; function onClicked() { - if (onScreen) { + if (onLuciScreen) { tablet.gotoHomeScreen(); } else { tablet.loadQMLSource(QMLAPP_URL); @@ -33,9 +28,8 @@ var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ - text: TABLET_BUTTON_NAME, - icon: ICON_URL, - activeIcon: ACTIVE_ICON_URL + text: TABLET_BUTTON_NAME, + sortOrder: 1 }); var hasEventBridge = false; @@ -60,13 +54,13 @@ function onScreenChanged(type, url) { if (url === QMLAPP_URL) { - onScreen = true; + onLuciScreen = true; } else { - onScreen = false; + onLuciScreen = false; } - button.editProperties({isActive: onScreen}); - wireEventBridge(onScreen); + button.editProperties({isActive: onLuciScreen}); + wireEventBridge(onLuciScreen); } function fromQml(message) { @@ -74,18 +68,7 @@ button.clicked.connect(onClicked); tablet.screenChanged.connect(onScreenChanged); - - Script.scriptEnding.connect(function () { - if (onScreen) { - tablet.gotoHomeScreen(); - } - button.clicked.disconnect(onClicked); - tablet.screenChanged.disconnect(onScreenChanged); - tablet.removeButton(button); - }); - - /* var moveDebugCursor = false; Controller.mousePressEvent.connect(function (e) { if (e.isMiddleButton) { @@ -97,16 +80,20 @@ Controller.mouseMoveEvent.connect(function (e) { if (moveDebugCursor) setDebugCursor(e.x, e.y); }); + Script.scriptEnding.connect(function () { + if (onLuciScreen) { + tablet.gotoHomeScreen(); + } + button.clicked.disconnect(onClicked); + tablet.screenChanged.disconnect(onScreenChanged); + tablet.removeButton(button); + }); + function setDebugCursor(x, y) { - nx = (x / Window.innerWidth); - ny = 1.0 - ((y) / (Window.innerHeight - 32)); + nx = ((x + 0.5) / Window.innerWidth); + ny = 1.0 - ((y + 0.5) / (Window.innerHeight)); - Render.getConfig("RenderMainView").getConfig("DebugAmbientOcclusion").debugCursorTexcoord = { x: nx, y: ny }; + Render.getConfig("RenderMainView").getConfig("DebugAmbientOcclusion").debugCursorTexcoord = { x: nx, y: ny }; } - */ - function cleanup() { - } - Script.scriptEnding.connect(cleanup); }()); - From c167a711290bbe0f5e123f2d50a7649356ee1941 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 6 Sep 2018 13:56:58 +0200 Subject: [PATCH 08/81] Switched back to normal SSAO and fixed broken ambient occlusion Luci visualization --- libraries/render-utils/src/DebugDeferredBuffer.cpp | 4 +--- libraries/render-utils/src/ssao.slh | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 0e61b36280..848c10597a 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -220,9 +220,7 @@ static const std::string DEFAULT_DEBUG_SCATTERING_SHADER{ static const std::string DEFAULT_AMBIENT_OCCLUSION_SHADER{ "vec4 getFragmentColor() {" - " return vec4(vec3(texture(obscuranceMap, uv).x), 1.0);" - // When drawing color " return vec4(vec3(texture(debugTexture0, uv).xyz), 1.0);" - // when drawing normal" return vec4(normalize(texture(debugTexture0, uv).xyz * 2.0 - vec3(1.0)), 1.0);" + " return vec4(vec3(texture(debugTexture0, uv).x), 1.0);" " }" }; static const std::string DEFAULT_AMBIENT_OCCLUSION_BLURRED_SHADER{ diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 89aa220e72..da8466ccdb 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -11,7 +11,7 @@ <@if not SSAO_SLH@> <@def SSAO_SLH@> -#define SSAO_USE_HORIZON_BASED 1 +#define SSAO_USE_HORIZON_BASED 0 <@include render-utils/ShaderConstants.h@> From 7a736043a6bdad0ede2dbfdfbd4a9cb3c5b3eaa4 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 6 Sep 2018 17:08:10 +0200 Subject: [PATCH 09/81] Small changes --- .../render-utils/src/AmbientOcclusionEffect.cpp | 12 +----------- libraries/render-utils/src/ssao.slh | 2 +- libraries/render-utils/src/ssao_makeOcclusion.slf | 2 +- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index e8eb291e2c..1bc7ec2c22 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -186,7 +186,7 @@ void AmbientOcclusionEffect::configure(const Config& config) { if (config.obscuranceLevel != _parametersBuffer->getObscuranceLevel()) { auto& current = _parametersBuffer.edit().radiusInfo; - current.w = config.obscuranceLevel; + current.w = config.obscuranceLevel * 10.0; } if (config.falloffBias != _parametersBuffer->getFalloffBias()) { @@ -343,12 +343,6 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto framebufferSize = _framebuffer->getSourceFrameSize(); - float sMin = occlusionViewport.x / (float)framebufferSize.x; - float sWidth = occlusionViewport.z / (float)framebufferSize.x; - float tMin = occlusionViewport.y / (float)framebufferSize.y; - float tHeight = occlusionViewport.w / (float)framebufferSize.y; - - auto occlusionPipeline = getOcclusionPipeline(); auto firstHBlurPipeline = getHBlurPipeline(); auto lastVBlurPipeline = getVBlurPipeline(); @@ -373,10 +367,6 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.generateTextureMipsWithPipeline(_framebuffer->getLinearDepthTexture()); batch.popProfileRange(); - model.setTranslation(glm::vec3(sMin, tMin, 0.0f)); - model.setScale(glm::vec3(sWidth, tHeight, 1.0f)); - batch.setModelTransform(model); - batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _parametersBuffer); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index da8466ccdb..7b2aa66d0d 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -412,7 +412,7 @@ vec2 fetchOcclusionDepth(ivec2 coords) { const int RADIUS_SCALE = 1; const float BLUR_WEIGHT_OFFSET = 0.05; -const float BLUR_EDGE_SCALE = 2000.0; +const float BLUR_EDGE_SCALE = 5000.0; vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 ssC, float key) { ivec2 tapOffset = <$axis$> * (r * RADIUS_SCALE); diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 0a92ba7fbe..9b9380640b 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -64,7 +64,7 @@ void main(void) { #endif } - float occlusion = max(0.0, 1.0 - visibilitySum * getObscuranceScaling() * 5.0 * getInvNumSamples()); + float occlusion = clamp(1.0 - visibilitySum * getObscuranceScaling() * getInvNumSamples(), 0.0, 1.0); // KEEP IT for Debugging // Bilateral box-filter over a quad for free, respecting depth edges From fec59e8b957a8e601d03b4566a423399c168690f Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 7 Sep 2018 16:12:03 +0200 Subject: [PATCH 10/81] WIP HBAO --- .../src/AmbientOcclusionEffect.cpp | 15 +- libraries/render-utils/src/ssao.slh | 193 ++++++++++-------- .../render-utils/src/ssao_makeOcclusion.slf | 17 +- 3 files changed, 136 insertions(+), 89 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 1bc7ec2c22..12b8c62556 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -30,6 +30,9 @@ #include "DependencyManager.h" #include "ViewFrustum.h" +// Should match value in ssao_makeOcclusion.slf +#define SSAO_USE_HORIZON_BASED 1 + gpu::PipelinePointer AmbientOcclusionEffect::_occlusionPipeline; gpu::PipelinePointer AmbientOcclusionEffect::_hBlurPipeline; gpu::PipelinePointer AmbientOcclusionEffect::_vBlurPipeline; @@ -346,7 +349,9 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto occlusionPipeline = getOcclusionPipeline(); auto firstHBlurPipeline = getHBlurPipeline(); auto lastVBlurPipeline = getVBlurPipeline(); - auto mipCreationPipeline = getMipCreationPipeline(); +#if SSAO_USE_HORIZON_BASED + auto mipCreationPipeline = getMipCreationPipeline(); +#endif gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) { PROFILE_RANGE_BATCH(batch, "AmbientOcclusion"); @@ -363,8 +368,12 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte // We need this with the mips levels batch.pushProfileRange("Depth mip creation"); batch.setModelTransform(model); - batch.setPipeline(mipCreationPipeline); - batch.generateTextureMipsWithPipeline(_framebuffer->getLinearDepthTexture()); +#if SSAO_USE_HORIZON_BASED + batch.setPipeline(mipCreationPipeline); + batch.generateTextureMipsWithPipeline(_framebuffer->getLinearDepthTexture()); +#else + batch.generateTextureMips(_framebuffer->getLinearDepthTexture()); +#endif batch.popProfileRange(); batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 7b2aa66d0d..13594c68f3 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -11,8 +11,6 @@ <@if not SSAO_SLH@> <@def SSAO_SLH@> -#define SSAO_USE_HORIZON_BASED 0 - <@include render-utils/ShaderConstants.h@> <@func declarePackOcclusionDepth()@> @@ -253,23 +251,15 @@ vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { vec3 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { int mipLevel = evalMipFromRadius(tap.z * doFetchMips()); - ivec2 ssP = ivec2(tap.xy) + ssC; - ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y); + vec2 ssP = tap.xy + vec2(ssC); // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. // Manually clamp to the texture size because texelFetch bypasses the texture unit - // ivec2 mipSize = textureSize(pyramidMap, mipLevel); - ivec2 mipSize = max(ivec2(imageSize) >> mipLevel, ivec2(1)); - - ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), mipSize - ivec2(1)); - vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize; vec2 fetchUV = vec2(tapUV.x + side.w * 0.5 * (side.x - tapUV.x), tapUV.y); - // vec2 tapUV = (vec2(mipP) + vec2(0.5)) / vec2(mipSize); vec3 P; P.xy = tapUV; - // P.z = -texelFetch(pyramidMap, mipP, mipLevel).x; P.z = -textureLod(pyramidMap, fetchUV, float(mipLevel)).x; return P; @@ -295,88 +285,126 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t float vv = dot(v, v); float vn = dot(v, centerNormal); - // Fall off function as recommended in SAO paper + // Fall off function as recommended in SSAO paper const float epsilon = 0.01; float f = max(getRadius2() - vv, 0.0); return f * f * f * max((vn - getFalloffBias()) / (epsilon + vv), 0.0); } -vec2 searchHorizons(int side, float centerDepth, vec2 centerPixelUV, vec2 imageSize, vec2 deltaTap, float ssDiskRadius, vec3 fragNormalES) { +<@func updateHorizon(horizon, deltaPixelTap)@> + { + int stepIndex; + vec2 tapPixelPos = vec2(0); + float radius = 0.0; + + for (stepIndex=stepCount ; stepIndex>0 ; stepIndex--) { + tapPixelPos += deltaPixelTap; + radius += deltaRadius; + + vec3 tap = vec3(tapPixelPos, radius); + vec3 tapUVZ = fetchTap(side, centerPixelPos, tap, imageSize); + vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); + vec3 deltaVec = normalize(tapPositionES - fragPositionES); + + <$horizon$> = max(<$horizon$>, dot(deltaVec, fragNormalES)); + } + } +<@endfunc@> + +<@func searchBresenhamHorizon(deltaPixelCoord)@> + { + float epsilon = 1e-8; + vec2 deltaPixelTap = searchVec / absSearchVec.<$deltaPixelCoord$>; + vec2 absDeltaPixelTap = abs(deltaPixelTap); + bvec2 nullDelta = absDeltaPixelTap < epsilon; + + pixelDelta1 = mix(pixelDelta1, vec2(1.0), pixelDelta1 < epsilon && nullDelta); + pixelDelta2 = mix(pixelDelta2, vec2(1.0), pixelDelta2 < epsilon && nullDelta); + + pixelDelta1 = ceil(pixelDelta1 / absDeltaPixelTap); + pixelDelta2 = ceil(pixelDelta2 / absDeltaPixelTap); + + int maxStepCount = max(0, int(ceil(absSearchVec.<$deltaPixelCoord$>))); + float deltaRadius = ssDiskRadius / maxStepCount; + int stepCount; + + // Forward search for h1 + stepCount = clamp(int(min(pixelDelta1.x, pixelDelta1.y)), 0, maxStepCount); + <$updateHorizon(horizons.x, deltaPixelTap)$> + + // Backward search for h2 + stepCount = clamp(int(min(pixelDelta2.x, pixelDelta2.y)), 0, maxStepCount); + <$updateHorizon(horizons.y, -deltaPixelTap)$> + } +<@endfunc@> + +vec2 clampSearchVec(vec2 imageSize, vec2 centerPixelPos, vec2 searchVec) { + vec2 clampdSearchVec = searchVec; + vec2 endPixel = centerPixelPos + clampdSearchVec; + + if (endPixel.x < 0) { + clampdSearchVec = clampdSearchVec * ((0-centerPixelPos.x) / clampdSearchVec.x); + endPixel = centerPixelPos + clampdSearchVec; + } + if (endPixel.x >= imageSize.x) { + clampdSearchVec = clampdSearchVec * ((imageSize.x-1-centerPixelPos.x) / clampdSearchVec.x); + endPixel = centerPixelPos + clampdSearchVec; + } + if (endPixel.y < 0) { + clampdSearchVec = clampdSearchVec * ((0-centerPixelPos.y) / clampdSearchVec.y); + endPixel = centerPixelPos + clampdSearchVec; + } + if (endPixel.y >= imageSize.y) { + clampdSearchVec = clampdSearchVec * ((imageSize.y-1-centerPixelPos.y) / clampdSearchVec.y); + } + + return clampdSearchVec; +} + +vec2 searchHorizons(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 deltaTap, float ssDiskRadius, + vec3 fragPositionES, vec3 fragNormalES) { vec2 searchVec = deltaTap * ssDiskRadius; - vec2 absSearchVec = abs(searchVec); - vec2 horizons = vec2(-PI/2.0, -PI/2.0); - vec3 centerPoint = vec3(centerPixelUV, centerDepth); - int stepIndex; - vec2 tapPixelUV; + vec2 horizons = vec2(0.0); + // Forward search for h1 + vec2 clampedSearchVec = clampSearchVec(imageSize, vec2(centerPixelPos), searchVec); + int stepCount = int(floor(length(clampedSearchVec)+0.5)); + if (stepCount>0) { + vec2 deltaPixelTap = clampedSearchVec / float(stepCount); + float deltaRadius = length(deltaPixelTap); + <$updateHorizon(horizons.x, deltaPixelTap)$> + } + // Backward search for h2 + clampedSearchVec = clampSearchVec(imageSize, vec2(centerPixelPos), -searchVec); + stepCount = int(floor(length(clampedSearchVec)+0.5)); + if (stepCount>0) { + vec2 deltaPixelTap = clampedSearchVec / float(stepCount); + float deltaRadius = length(deltaPixelTap); + <$updateHorizon(horizons.y, deltaPixelTap)$> + } + +// +// absSearchVec.y) { - int stepCount = int(ceil(absSearchVec.x)); - - // Positive search for h2 - tapPixelUV = centerPixelUV; - deltaTap = (searchVec / searchVec.x) / imageSize; - stepIndex = stepCount; - while (stepIndex>0 && tapPixelUV.x < 1.0) { - tapPixelUV += deltaTap; - // Don't clamp for the moment - - float tapDepth = getZEyeAtUV(tapPixelUV, 0); - vec3 deltaVec = vec3(tapPixelUV, tapDepth) - centerPoint; - - horizons.y = max(horizons.y, normalize(deltaVec).z); - --stepIndex; - } - - // Negative search for h1 - tapPixelUV = centerPixelUV; - stepIndex = stepCount; - while (stepIndex>0 && tapPixelUV.x > 0.0) { - tapPixelUV -= deltaTap; - // Don't clamp for the moment - - float tapDepth = getZEyeAtUV(tapPixelUV, 0); - vec3 deltaVec = vec3(tapPixelUV, tapDepth) - centerPoint; - - horizons.x = max(horizons.x, normalize(deltaVec).z); - --stepIndex; - } + <$searchBresenhamHorizon(x)$> } else { - int stepCount = int(ceil(absSearchVec.y)); - - // Positive search for h2 - tapPixelUV = centerPixelUV; - deltaTap = (searchVec / searchVec.y) / imageSize; - stepIndex = stepCount; - while (stepIndex>0 && tapPixelUV.y < 1.0) { - tapPixelUV += deltaTap; - // Don't clamp for the moment - - float tapDepth = getZEyeAtUV(tapPixelUV, 0); - vec3 deltaVec = vec3(tapPixelUV, tapDepth) - centerPoint; - - horizons.y = max(horizons.y, normalize(deltaVec).z); - --stepIndex; - } - - // Negative search for h1 - tapPixelUV = centerPixelUV; - stepIndex = stepCount; - while (stepIndex>0 && tapPixelUV.y > 0.0) { - tapPixelUV -= deltaTap; - // Don't clamp for the moment - - float tapDepth = getZEyeAtUV(tapPixelUV, 0); - vec3 deltaVec = vec3(tapPixelUV, tapDepth) - centerPoint; - - horizons.x = max(horizons.x, normalize(deltaVec).z); - --stepIndex; - } + <$searchBresenhamHorizon(y)$> } - vec3 angles = acos(vec3(horizons, fragNormalES.z))-PI/2.0; + vec3 angles = acos(vec3(horizons, fragNormalES.z)) - PI/2.0; angles.x = -angles.x; // Clamp to limit horizon defined by normal plane horizons.xy = angles.zz + max(angles.xy - angles.zz, vec2(-PI/2.0, PI/2.0)); + */ + +// +// !> +// + return horizons; } @@ -385,9 +413,10 @@ float integrateArc(float h1, float h2) { return 2.0 - cosh.x - cosh.y; } -float evalVisibilityHBAO(int side, float centerDepth, vec2 centerPixelUV, vec2 imageSize, vec2 deltaTap, float ssDiskRadius, vec3 fragNormalES) { - vec2 horizonAngles = searchHorizons(side, centerDepth, centerPixelUV, imageSize, deltaTap, ssDiskRadius, fragNormalES); - return integrateArc(horizonAngles.x, horizonAngles.y); +float evalVisibilityHBAO(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 deltaTap, float ssDiskRadius, + vec3 fragPositionES, vec3 fragNormalES) { + vec2 horizonAngles = searchHorizons(side, centerPixelPos, imageSize, deltaTap, ssDiskRadius, fragPositionES, fragNormalES); + return min(1.0, integrateArc(horizonAngles.x, horizonAngles.y) * 0.5); } <@endfunc@> diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 9b9380640b..c5d680e0d8 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -19,6 +19,8 @@ <$declarePackOcclusionDepth()$> +#define SSAO_USE_HORIZON_BASED 1 + layout(location=0) out vec4 outFragColor; void main(void) { @@ -52,10 +54,11 @@ void main(void) { // Accumulate the visibility for each samples float visibilitySum = 0.0; - for (int i = 0; i < getNumSamples(); ++i) { + int numSamples = 1; // TEMPO OP getNumSamples() + for (int i = 0; i < numSamples; ++i) { #if SSAO_USE_HORIZON_BASED - vec3 deltaTap = getUnitTapLocation(i, 1, randomPatternRotationAngle, PI); - visibilitySum += evalVisibilityHBAO(side.x, Zeye, fragUVPos, imageSize, deltaTap.xy, ssDiskRadius, fragNormalES); + vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); + visibilitySum += evalVisibilityHBAO(side, centerPixelPos, imageSize, deltaTap.xy, ssDiskRadius, fragPositionES, fragNormalES); #else vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, ssDiskRadius, centerPixelPos, imageSize); vec3 tapUVZ = fetchTap(side, centerPixelPos, tap, imageSize); @@ -64,7 +67,12 @@ void main(void) { #endif } - float occlusion = clamp(1.0 - visibilitySum * getObscuranceScaling() * getInvNumSamples(), 0.0, 1.0); +#if SSAO_USE_HORIZON_BASED + visibilitySum = 1.0 - visibilitySum * getInvNumSamples(); +#else + visibilitySum = visibilitySum * getInvNumSamples(); +#endif + float occlusion = clamp(1.0 - visibilitySum * getObscuranceScaling(), 0.0, 1.0); // KEEP IT for Debugging // Bilateral box-filter over a quad for free, respecting depth edges @@ -77,4 +85,5 @@ void main(void) { }*/ outFragColor = vec4(packOcclusionDepth(occlusion, CSZToDepthKey(fragPositionES.z)), 1.0); + } From fd9d05bdbfe9e239d59ad60a08cfd2fde44a561e Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 11 Sep 2018 15:30:18 +0200 Subject: [PATCH 11/81] First 'working' version of HBAO --- libraries/render-utils/src/ssao.slh | 9 ++------- libraries/render-utils/src/ssao_makeOcclusion.slf | 7 +------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 5c70174f8a..8e1cb27346 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -408,15 +408,10 @@ vec2 searchHorizons(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 delta return horizons; } -float integrateArc(float h1, float h2) { - vec2 cosh = cos(vec2(h1, h2)); - return 2.0 - cosh.x - cosh.y; -} - float evalVisibilityHBAO(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 deltaTap, float ssDiskRadius, vec3 fragPositionES, vec3 fragNormalES) { - vec2 horizonAngles = searchHorizons(side, centerPixelPos, imageSize, deltaTap, ssDiskRadius, fragPositionES, fragNormalES); - return min(1.0, integrateArc(horizonAngles.x, horizonAngles.y) * 0.5); + vec2 horizons = searchHorizons(side, centerPixelPos, imageSize, deltaTap, ssDiskRadius, fragPositionES, fragNormalES); + return (horizons.x + horizons.y) * 0.5; } <@endfunc@> diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index c5d680e0d8..89f2aadfab 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -54,7 +54,7 @@ void main(void) { // Accumulate the visibility for each samples float visibilitySum = 0.0; - int numSamples = 1; // TEMPO OP getNumSamples() + int numSamples = int(getNumSamples()); for (int i = 0; i < numSamples; ++i) { #if SSAO_USE_HORIZON_BASED vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); @@ -67,11 +67,7 @@ void main(void) { #endif } -#if SSAO_USE_HORIZON_BASED - visibilitySum = 1.0 - visibilitySum * getInvNumSamples(); -#else visibilitySum = visibilitySum * getInvNumSamples(); -#endif float occlusion = clamp(1.0 - visibilitySum * getObscuranceScaling(), 0.0, 1.0); // KEEP IT for Debugging @@ -85,5 +81,4 @@ void main(void) { }*/ outFragColor = vec4(packOcclusionDepth(occlusion, CSZToDepthKey(fragPositionES.z)), 1.0); - } From 6c0309402f761a8f704e53b44a124e23f636c509 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 11 Sep 2018 16:14:54 +0200 Subject: [PATCH 12/81] Some fixes for HBAO. Need performance improvements --- .../render-utils/src/AmbientOcclusionEffect.cpp | 7 +++++-- libraries/render-utils/src/ssao.slh | 13 +++++++++---- libraries/render-utils/src/ssao_makeOcclusion.slf | 4 +--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 12b8c62556..0cc5220abf 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -184,12 +184,15 @@ void AmbientOcclusionEffect::configure(const Config& config) { auto& current = _parametersBuffer.edit().radiusInfo; current.x = radius; current.y = radius * radius; - current.z = (float)(1.0 / pow((double)radius, RADIUS_POWER)); + current.z = 10.0f; +#if !SSAO_USE_HORIZON_BASED + current.z *= (float)(1.0 / pow((double)radius, RADIUS_POWER)); +#endif } if (config.obscuranceLevel != _parametersBuffer->getObscuranceLevel()) { auto& current = _parametersBuffer.edit().radiusInfo; - current.w = config.obscuranceLevel * 10.0; + current.w = config.obscuranceLevel; } if (config.falloffBias != _parametersBuffer->getFalloffBias()) { diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 8e1cb27346..b4dd7e6b6c 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -305,8 +305,11 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t vec3 tapUVZ = fetchTap(side, centerPixelPos, tap, imageSize); vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); vec3 deltaVec = normalize(tapPositionES - fragPositionES); + float rawHorizon = dot(deltaVec, fragNormalES); - <$horizon$> = max(<$horizon$>, dot(deltaVec, fragNormalES)); + rawHorizon *= 1.0 - radius / ssDiskRadius; + + <$horizon$> = max(<$horizon$>, rawHorizon); } } <@endfunc@> @@ -368,7 +371,8 @@ vec2 searchHorizons(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 delta // Forward search for h1 vec2 clampedSearchVec = clampSearchVec(imageSize, vec2(centerPixelPos), searchVec); - int stepCount = int(floor(length(clampedSearchVec)+0.5)); + vec2 absClampedSearchVec = abs(clampedSearchVec); + int stepCount = int(max(absClampedSearchVec.x, absClampedSearchVec.y)); if (stepCount>0) { vec2 deltaPixelTap = clampedSearchVec / float(stepCount); float deltaRadius = length(deltaPixelTap); @@ -376,7 +380,8 @@ vec2 searchHorizons(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 delta } // Backward search for h2 clampedSearchVec = clampSearchVec(imageSize, vec2(centerPixelPos), -searchVec); - stepCount = int(floor(length(clampedSearchVec)+0.5)); + absClampedSearchVec = abs(clampedSearchVec); + stepCount = int(max(absClampedSearchVec.x, absClampedSearchVec.y)); if (stepCount>0) { vec2 deltaPixelTap = clampedSearchVec / float(stepCount); float deltaRadius = length(deltaPixelTap); @@ -411,7 +416,7 @@ vec2 searchHorizons(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 delta float evalVisibilityHBAO(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 deltaTap, float ssDiskRadius, vec3 fragPositionES, vec3 fragNormalES) { vec2 horizons = searchHorizons(side, centerPixelPos, imageSize, deltaTap, ssDiskRadius, fragPositionES, fragNormalES); - return (horizons.x + horizons.y) * 0.5; + return (horizons.x + horizons.y) * 0.5 / PI; } <@endfunc@> diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 89f2aadfab..e2c8a5ffa6 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -46,9 +46,7 @@ void main(void) { // Choose the screen-space sample radius float ssDiskRadius = evalDiskRadius(fragPositionES.z, imageSize); -#if SSAO_USE_HORIZON_BASED - ssDiskRadius = min(ssDiskRadius, 3.0); -#endif + // Let's make noise float randomPatternRotationAngle = getAngleDithering(centerPixelPos); From 45b4881edc75ff4d30cc006b7a5331a1fc5b7936 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 12 Sep 2018 17:59:57 +0200 Subject: [PATCH 13/81] Bilateral blur --- .../src/AmbientOcclusionEffect.cpp | 145 +++++++++++++----- .../render-utils/src/AmbientOcclusionEffect.h | 64 +++++--- .../render-utils/src/SurfaceGeometryPass.cpp | 5 +- .../src/render-utils/ShaderConstants.h | 2 + .../render-utils/ssao_makeHorizontalBlur.slp | 2 +- .../render-utils/ssao_makeVerticalBlur.slp | 2 +- libraries/render-utils/src/ssao.slh | 75 +++++---- libraries/render-utils/src/ssao_blur.slv | 42 +++++ .../src/ssao_makeHorizontalBlur.slf | 3 +- .../render-utils/src/ssao_makeOcclusion.slf | 6 +- .../src/ssao_makeVerticalBlur.slf | 4 +- 11 files changed, 251 insertions(+), 99 deletions(-) create mode 100644 libraries/render-utils/src/ssao_blur.slv diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 0cc5220abf..8d28fae760 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -41,7 +41,7 @@ gpu::PipelinePointer AmbientOcclusionEffect::_mipCreationPipeline; AmbientOcclusionFramebuffer::AmbientOcclusionFramebuffer() { } -void AmbientOcclusionFramebuffer::updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer) { +bool AmbientOcclusionFramebuffer::updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer) { //If the depth buffer or size changed, we need to delete our FBOs bool reset = false; if ((_linearDepthTexture != linearDepthBuffer)) { @@ -59,6 +59,8 @@ void AmbientOcclusionFramebuffer::updateLinearDepth(const gpu::TexturePointer& l if (reset) { clear(); } + + return reset; } void AmbientOcclusionFramebuffer::clear() { @@ -170,6 +172,41 @@ public: } }; +AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : + render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false), +#if SSAO_USE_HORIZON_BASED + radius{ 0.1f }, +#else + radius{ 0.5f }, +#endif + perspectiveScale{ 1.0f }, + obscuranceLevel{ 0.5f }, + falloffBias{ 0.01f }, + edgeSharpness{ 1.0f }, + blurDeviation{ 2.5f }, + numSpiralTurns{ 7.0f }, +#if SSAO_USE_HORIZON_BASED + numSamples{ 1 }, +#else + numSamples{ 16 }, +#endif + resolutionLevel{ 1 }, + blurRadius{ 4 }, + ditheringEnabled{ true }, + borderingEnabled{ true }, + fetchMipsEnabled{ true } { + +} + +AmbientOcclusionEffect::AOParameters::AOParameters() : +resolutionInfo{ -1.0f, 0.0f, 1.0f, 0.0f }, +radiusInfo{ 0.5f, 0.5f * 0.5f, 1.0f / (0.25f * 0.25f * 0.25f), 1.0f }, +ditheringInfo{ 0.0f, 0.0f, 0.01f, 1.0f }, +sampleInfo{ 11.0f, 1.0f / 11.0f, 7.0f, 1.0f }, +blurInfo{ 1.0f, 3.0f, 2.0f, 0.0f } { + +} + AmbientOcclusionEffect::AmbientOcclusionEffect() { } @@ -177,11 +214,12 @@ void AmbientOcclusionEffect::configure(const Config& config) { DependencyManager::get()->setAmbientOcclusionEnabled(config.enabled); bool shouldUpdateGaussian = false; + bool shouldUpdateBlurs = false; const double RADIUS_POWER = 6.0; const auto& radius = config.radius; - if (radius != _parametersBuffer->getRadius()) { - auto& current = _parametersBuffer.edit().radiusInfo; + if (radius != _aoParametersBuffer->getRadius()) { + auto& current = _aoParametersBuffer.edit().radiusInfo; current.x = radius; current.y = radius * radius; current.z = 10.0f; @@ -190,74 +228,97 @@ void AmbientOcclusionEffect::configure(const Config& config) { #endif } - if (config.obscuranceLevel != _parametersBuffer->getObscuranceLevel()) { - auto& current = _parametersBuffer.edit().radiusInfo; + if (config.obscuranceLevel != _aoParametersBuffer->getObscuranceLevel()) { + auto& current = _aoParametersBuffer.edit().radiusInfo; current.w = config.obscuranceLevel; } - if (config.falloffBias != _parametersBuffer->getFalloffBias()) { - auto& current = _parametersBuffer.edit().ditheringInfo; + if (config.falloffBias != _aoParametersBuffer->getFalloffBias()) { + auto& current = _aoParametersBuffer.edit().ditheringInfo; current.z = config.falloffBias; } - if (config.edgeSharpness != _parametersBuffer->getEdgeSharpness()) { - auto& current = _parametersBuffer.edit().blurInfo; + if (config.edgeSharpness != _aoParametersBuffer->getEdgeSharpness()) { + auto& current = _aoParametersBuffer.edit().blurInfo; current.x = config.edgeSharpness; } - if (config.blurDeviation != _parametersBuffer->getBlurDeviation()) { - auto& current = _parametersBuffer.edit().blurInfo; + if (config.blurDeviation != _aoParametersBuffer->getBlurDeviation()) { + auto& current = _aoParametersBuffer.edit().blurInfo; current.z = config.blurDeviation; shouldUpdateGaussian = true; } - if (config.numSpiralTurns != _parametersBuffer->getNumSpiralTurns()) { - auto& current = _parametersBuffer.edit().sampleInfo; + if (config.numSpiralTurns != _aoParametersBuffer->getNumSpiralTurns()) { + auto& current = _aoParametersBuffer.edit().sampleInfo; current.z = config.numSpiralTurns; } - if (config.numSamples != _parametersBuffer->getNumSamples()) { - auto& current = _parametersBuffer.edit().sampleInfo; + if (config.numSamples != _aoParametersBuffer->getNumSamples()) { + auto& current = _aoParametersBuffer.edit().sampleInfo; current.x = config.numSamples; current.y = 1.0f / config.numSamples; } - if (config.fetchMipsEnabled != _parametersBuffer->isFetchMipsEnabled()) { - auto& current = _parametersBuffer.edit().sampleInfo; + if (config.fetchMipsEnabled != _aoParametersBuffer->isFetchMipsEnabled()) { + auto& current = _aoParametersBuffer.edit().sampleInfo; current.w = (float)config.fetchMipsEnabled; } if (!_framebuffer) { _framebuffer = std::make_shared(); + shouldUpdateBlurs = true; } - if (config.perspectiveScale != _parametersBuffer->getPerspectiveScale()) { - _parametersBuffer.edit().resolutionInfo.z = config.perspectiveScale; + if (config.perspectiveScale != _aoParametersBuffer->getPerspectiveScale()) { + _aoParametersBuffer.edit().resolutionInfo.z = config.perspectiveScale; } - if (config.resolutionLevel != _parametersBuffer->getResolutionLevel()) { - auto& current = _parametersBuffer.edit().resolutionInfo; + + if (config.resolutionLevel != _aoParametersBuffer->getResolutionLevel()) { + auto& current = _aoParametersBuffer.edit().resolutionInfo; current.x = (float) config.resolutionLevel; + shouldUpdateBlurs = true; } - if (config.blurRadius != _parametersBuffer->getBlurRadius()) { - auto& current = _parametersBuffer.edit().blurInfo; + if (config.blurRadius != _aoParametersBuffer->getBlurRadius()) { + auto& current = _aoParametersBuffer.edit().blurInfo; current.y = (float)config.blurRadius; shouldUpdateGaussian = true; } - if (config.ditheringEnabled != _parametersBuffer->isDitheringEnabled()) { - auto& current = _parametersBuffer.edit().ditheringInfo; + if (config.ditheringEnabled != _aoParametersBuffer->isDitheringEnabled()) { + auto& current = _aoParametersBuffer.edit().ditheringInfo; current.x = (float)config.ditheringEnabled; } - if (config.borderingEnabled != _parametersBuffer->isBorderingEnabled()) { - auto& current = _parametersBuffer.edit().ditheringInfo; + if (config.borderingEnabled != _aoParametersBuffer->isBorderingEnabled()) { + auto& current = _aoParametersBuffer.edit().ditheringInfo; current.w = (float)config.borderingEnabled; } if (shouldUpdateGaussian) { updateGaussianDistribution(); } + + if (shouldUpdateBlurs) { + updateBlurParameters(); + } +} + +void AmbientOcclusionEffect::updateBlurParameters() { + const auto resolutionLevel = _aoParametersBuffer->getResolutionLevel(); + const auto resolutionScale = 1 << resolutionLevel; + auto& vblur = _vblurParametersBuffer.edit(); + auto& hblur = _hblurParametersBuffer.edit(); + auto frameSize = _framebuffer->getSourceFrameSize(); + + hblur.scaleHeight.x = 1.0f / (frameSize.x * resolutionScale); + hblur.scaleHeight.y = 1.0f / frameSize.x; + hblur.scaleHeight.z = frameSize.y / resolutionScale; + + vblur.scaleHeight.x = 1.0f / (frameSize.y * resolutionScale); + vblur.scaleHeight.y = 1.0f / frameSize.y; + vblur.scaleHeight.z = frameSize.y; } const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { @@ -309,8 +370,8 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getMipCreationPipeline() { } void AmbientOcclusionEffect::updateGaussianDistribution() { - auto coefs = _parametersBuffer.edit()._gaussianCoefs; - GaussianDistribution::evalSampling(coefs, Parameters::GAUSSIAN_COEFS_LENGTH, _parametersBuffer->getBlurRadius(), _parametersBuffer->getBlurDeviation()); + auto coefs = _aoParametersBuffer.edit()._gaussianCoefs; + GaussianDistribution::evalSampling(coefs, AOParameters::GAUSSIAN_COEFS_LENGTH, _aoParametersBuffer->getBlurRadius(), _aoParametersBuffer->getBlurDeviation()); } void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { @@ -325,6 +386,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); auto sourceViewport = args->_viewport; auto occlusionViewport = sourceViewport; + auto firstBlurViewport = sourceViewport; if (!_gpuTimer) { _gpuTimer = std::make_shared < gpu::RangeTimer>(__FUNCTION__); @@ -334,18 +396,21 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte _framebuffer = std::make_shared(); } - if (_parametersBuffer->getResolutionLevel() > 0) { - linearDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); - occlusionViewport = occlusionViewport >> _parametersBuffer->getResolutionLevel(); + const auto resolutionScale = powf(0.5f, _aoParametersBuffer->getResolutionLevel()); + if (_aoParametersBuffer->getResolutionLevel() > 0) { + occlusionViewport = occlusionViewport >> _aoParametersBuffer->getResolutionLevel(); + firstBlurViewport.w = firstBlurViewport.w >> _aoParametersBuffer->getResolutionLevel(); } - _framebuffer->updateLinearDepth(linearDepthTexture); + if (_framebuffer->updateLinearDepth(linearDepthTexture)) { + updateBlurParameters(); + } auto occlusionFBO = _framebuffer->getOcclusionFramebuffer(); auto occlusionBlurredFBO = _framebuffer->getOcclusionBlurredFramebuffer(); outputs.edit0() = _framebuffer; - outputs.edit1() = _parametersBuffer; + outputs.edit1() = _aoParametersBuffer; auto framebufferSize = _framebuffer->getSourceFrameSize(); @@ -380,7 +445,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.popProfileRange(); batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _parametersBuffer); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); // Occlusion pass batch.setFramebuffer(occlusionFBO); @@ -389,16 +454,24 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setResourceTexture(render_utils::slot::texture::SsaoPyramid, _framebuffer->getLinearDepthTexture()); batch.draw(gpu::TRIANGLE_STRIP, 4); - if (_parametersBuffer->getBlurRadius() > 0) { + /* TEMPO OP if (_aoParametersBuffer->getBlurRadius() > 0)*/ { PROFILE_RANGE_BATCH(batch, "Blur"); // Blur 1st pass + model.setScale(resolutionScale); + batch.setModelTransform(model); + batch.setViewportTransform(firstBlurViewport); batch.setFramebuffer(occlusionBlurredFBO); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _hblurParametersBuffer); batch.setPipeline(firstHBlurPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionFBO->getRenderBuffer(0)); batch.draw(gpu::TRIANGLE_STRIP, 4); // Blur 2nd pass + model.setScale(glm::vec3(1.0f, resolutionScale, 1.0f)); + batch.setModelTransform(model); + batch.setViewportTransform(sourceViewport); batch.setFramebuffer(occlusionFBO); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _vblurParametersBuffer); batch.setPipeline(lastVBlurPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionBlurredFBO->getRenderBuffer(0)); batch.draw(gpu::TRIANGLE_STRIP, 4); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index f96830a8f2..b44569eb89 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -32,7 +32,7 @@ public: gpu::TexturePointer getOcclusionBlurredTexture(); // Update the source framebuffer size which will drive the allocation of all the other resources. - void updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer); + bool updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer); gpu::TexturePointer getLinearDepthTexture(); const glm::ivec2& getSourceFrameSize() const { return _frameSize; } @@ -71,7 +71,7 @@ class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent { Q_PROPERTY(int blurRadius MEMBER blurRadius WRITE setBlurRadius) public: - AmbientOcclusionEffectConfig() : render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false) {} + AmbientOcclusionEffectConfig(); const int MAX_RESOLUTION_LEVEL = 4; const int MAX_BLUR_RADIUS = 6; @@ -86,19 +86,19 @@ public: void setResolutionLevel(int level) { resolutionLevel = std::max(0, std::min(level, MAX_RESOLUTION_LEVEL)); emit dirty(); } void setBlurRadius(int radius) { blurRadius = std::max(0, std::min(MAX_BLUR_RADIUS, radius)); emit dirty(); } - float radius{ 0.5f }; - float perspectiveScale{ 1.0f }; - float obscuranceLevel{ 0.5f }; // intensify or dim down the obscurance effect - float falloffBias{ 0.01f }; - float edgeSharpness{ 1.0f }; - float blurDeviation{ 2.5f }; - float numSpiralTurns{ 7.0f }; // defining an angle span to distribute the samples ray directions - int numSamples{ 16 }; - int resolutionLevel{ 1 }; - int blurRadius{ 4 }; // 0 means no blurring - bool ditheringEnabled{ true }; // randomize the distribution of taps per pixel, should always be true - bool borderingEnabled{ true }; // avoid evaluating information from non existing pixels out of the frame, should always be true - bool fetchMipsEnabled{ true }; // fetch taps in sub mips to otpimize cache, should always be true + float radius; + float perspectiveScale; + float obscuranceLevel; // intensify or dim down the obscurance effect + float falloffBias; + float edgeSharpness; + float blurDeviation; + float numSpiralTurns; // defining an angle span to distribute the samples ray directions + int numSamples; + int resolutionLevel; + int blurRadius; // 0 means no blurring + bool ditheringEnabled; // randomize the distribution of taps per pixel, should always be true + bool borderingEnabled; // avoid evaluating information from non existing pixels out of the frame, should always be true + bool fetchMipsEnabled; // fetch taps in sub mips to otpimize cache, should always be true signals: void dirty(); @@ -118,23 +118,23 @@ public: // Class describing the uniform buffer with all the parameters common to the AO shaders - class Parameters { + class AOParameters { public: // Resolution info - glm::vec4 resolutionInfo { -1.0f, 0.0f, 1.0f, 0.0f }; + glm::vec4 resolutionInfo; // radius info is { R, R^2, 1 / R^6, ObscuranceScale} - glm::vec4 radiusInfo{ 0.5f, 0.5f * 0.5f, 1.0f / (0.25f * 0.25f * 0.25f), 1.0f }; + glm::vec4 radiusInfo; // Dithering info - glm::vec4 ditheringInfo { 0.0f, 0.0f, 0.01f, 1.0f }; + glm::vec4 ditheringInfo; // Sampling info - glm::vec4 sampleInfo { 11.0f, 1.0f/11.0f, 7.0f, 1.0f }; + glm::vec4 sampleInfo; // Blurring info - glm::vec4 blurInfo { 1.0f, 3.0f, 2.0f, 0.0f }; + glm::vec4 blurInfo; // gaussian distribution coefficients first is the sampling radius (max is 6) const static int GAUSSIAN_COEFS_LENGTH = 8; float _gaussianCoefs[GAUSSIAN_COEFS_LENGTH]; - Parameters() {} + AOParameters(); int getResolutionLevel() const { return resolutionInfo.x; } float getRadius() const { return radiusInfo.x; } @@ -152,12 +152,26 @@ public: bool isDitheringEnabled() const { return ditheringInfo.x; } bool isBorderingEnabled() const { return ditheringInfo.w; } }; - using ParametersBuffer = gpu::StructBuffer; + using AOParametersBuffer = gpu::StructBuffer; private: + + // Class describing the uniform buffer with all the parameters common to the bilateral blur shaders + class BlurParameters { + public: + glm::vec4 scaleHeight{ 0.0f }; + + BlurParameters() {} + }; + using BlurParametersBuffer = gpu::StructBuffer; + + void updateGaussianDistribution(); + void updateBlurParameters(); - ParametersBuffer _parametersBuffer; + AOParametersBuffer _aoParametersBuffer; + BlurParametersBuffer _vblurParametersBuffer; + BlurParametersBuffer _hblurParametersBuffer; static const gpu::PipelinePointer& getOcclusionPipeline(); static const gpu::PipelinePointer& getHBlurPipeline(); // first @@ -195,7 +209,7 @@ signals: class DebugAmbientOcclusion { public: - using Inputs = render::VaryingSet4; + using Inputs = render::VaryingSet4; using Config = DebugAmbientOcclusionConfig; using JobModel = render::Job::ModelI; diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index d32cba43db..b0f19862ce 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -64,14 +64,15 @@ void LinearDepthFramebuffer::allocate() { auto height = _frameSize.y; // For Linear Depth: - _linearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), width, height, gpu::Texture::SINGLE_MIP, + const uint16_t LINEAR_DEPTH_MAX_MIP_LEVEL = 5; + _linearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), width, height, LINEAR_DEPTH_MAX_MIP_LEVEL, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)); _linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("linearDepth")); _linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture); _linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat()); // For Downsampling: - const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = 5; + const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = LINEAR_DEPTH_MAX_MIP_LEVEL; _halfLinearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), _halfFrameSize.x, _halfFrameSize.y, HALF_LINEAR_DEPTH_MAX_MIP_LEVEL, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)); diff --git a/libraries/render-utils/src/render-utils/ShaderConstants.h b/libraries/render-utils/src/render-utils/ShaderConstants.h index 330df6a2af..3aeb3a73c8 100644 --- a/libraries/render-utils/src/render-utils/ShaderConstants.h +++ b/libraries/render-utils/src/render-utils/ShaderConstants.h @@ -86,6 +86,7 @@ // Ambient occlusion #define RENDER_UTILS_BUFFER_SSAO_PARAMS 2 #define RENDER_UTILS_BUFFER_SSAO_DEBUG_PARAMS 3 +#define RENDER_UTILS_BUFFER_SSAO_BLUR_PARAMS 4 #define RENDER_UTILS_TEXTURE_SSAO_PYRAMID 1 #define RENDER_UTILS_TEXTURE_SSAO_OCCLUSION 0 @@ -153,6 +154,7 @@ enum Buffer { SsscParams = RENDER_UTILS_BUFFER_SSSC_PARAMS, SsaoParams = RENDER_UTILS_BUFFER_SSAO_PARAMS, SsaoDebugParams = RENDER_UTILS_BUFFER_SSAO_DEBUG_PARAMS, + SsaoBlurParams = RENDER_UTILS_BUFFER_SSAO_BLUR_PARAMS, LightIndex = RENDER_UTILS_BUFFER_LIGHT_INDEX, TaaParams = RENDER_UTILS_BUFFER_TAA_PARAMS, HighlightParams = RENDER_UTILS_BUFFER_HIGHLIGHT_PARAMS, diff --git a/libraries/render-utils/src/render-utils/ssao_makeHorizontalBlur.slp b/libraries/render-utils/src/render-utils/ssao_makeHorizontalBlur.slp index d4d8ec4b01..49fd3dba93 100644 --- a/libraries/render-utils/src/render-utils/ssao_makeHorizontalBlur.slp +++ b/libraries/render-utils/src/render-utils/ssao_makeHorizontalBlur.slp @@ -1 +1 @@ -VERTEX gpu::vertex::DrawViewportQuadTransformTexcoord +VERTEX ssao_blur diff --git a/libraries/render-utils/src/render-utils/ssao_makeVerticalBlur.slp b/libraries/render-utils/src/render-utils/ssao_makeVerticalBlur.slp index d4d8ec4b01..49fd3dba93 100644 --- a/libraries/render-utils/src/render-utils/ssao_makeVerticalBlur.slp +++ b/libraries/render-utils/src/render-utils/ssao_makeVerticalBlur.slp @@ -1 +1 @@ -VERTEX gpu::vertex::DrawViewportQuadTransformTexcoord +VERTEX ssao_blur diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index b4dd7e6b6c..d974a83104 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -425,73 +425,90 @@ float evalVisibilityHBAO(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 <$declarePackOcclusionDepth()$> <$declareAmbientOcclusion()$> +<$declareFetchDepthPyramidMap()$> // the source occlusion texture layout(binding=RENDER_UTILS_TEXTURE_SSAO_OCCLUSION) uniform sampler2D occlusionMap; +struct BlurParams { + vec4 scaleHeight; +}; -vec2 fetchOcclusionDepthRaw(ivec2 coords, out vec3 raw) { - raw = texelFetch(occlusionMap, coords, 0).xyz; - return unpackOcclusionDepth(raw); +layout(binding=RENDER_UTILS_BUFFER_SSAO_BLUR_PARAMS) uniform blurParamsBuffer { + BlurParams blurParams; +}; + +float getOcclusionBlurScale() { + return blurParams.scaleHeight.x; } -vec2 fetchOcclusionDepth(ivec2 coords) { - return unpackOcclusionDepth(texelFetch(occlusionMap, coords, 0).xyz); +float getDepthBlurScale() { + return blurParams.scaleHeight.y; +} + +int getBlurImageHeight() { + return int(blurParams.scaleHeight.z); +} + +float fetchOcclusion(vec2 coords) { + vec3 raw = texture(occlusionMap, coords, 0).xyz; + return raw.x; } -const int RADIUS_SCALE = 1; const float BLUR_WEIGHT_OFFSET = 0.05; -const float BLUR_EDGE_SCALE = 5000.0; +const float BLUR_EDGE_SCALE = 100.0; -vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 ssC, float key) { - ivec2 tapOffset = <$axis$> * (r * RADIUS_SCALE); - ivec2 ssP = (ssC + tapOffset); +vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float key) { + ivec2 tapOffset = <$axis$> * r; + ivec2 tapPixelCoord = destPixelCoord + tapOffset; - if ((ssP.x < side.y || ssP.x >= side.z + side.y) || (ssP.y < 0 || ssP.y >= int(getWidthHeight(getResolutionLevel()).y))) { + if ((tapPixelCoord.x < side.y || tapPixelCoord.x >= side.z + side.y) || (tapPixelCoord.y < 0 || tapPixelCoord.y >= getBlurImageHeight())) { return vec2(0.0); } - vec2 tapOZ = fetchOcclusionDepth(ssC + tapOffset); + vec2 tapTexCoord = scaledTexCoord + tapOffset * getOcclusionBlurScale(); + float tapOcclusion = fetchOcclusion(tapTexCoord); + + tapTexCoord = fullTexCoord + tapOffset * getDepthBlurScale(); + float tapDepth = getZEyeAtUV(tapTexCoord, 0); // spatial domain: offset gaussian tap float weight = BLUR_WEIGHT_OFFSET + getBlurCoef(abs(r)); // range domain (the "bilateral" weight). As depth difference increases, decrease weight. - weight *= max(0.0, 1.0 - (getBlurEdgeSharpness() * BLUR_EDGE_SCALE) * abs(tapOZ.y - key)); + weight *= max(0.0, 1.0 - (getBlurEdgeSharpness() * BLUR_EDGE_SCALE) * abs(tapDepth - key)); - return vec2(tapOZ.x * weight, weight); + return vec2(tapOcclusion * weight, weight); } -vec3 getBlurredOcclusion(vec2 coord) { - ivec2 ssC = ivec2(coord); - +vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord) { // Stereo side info - ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel()); + ivec4 side = getStereoSideInfo(destPixelCoord.x, 0); - vec3 rawSample; - vec2 occlusionDepth = fetchOcclusionDepthRaw(ssC, rawSample); - float key = occlusionDepth.y; + float pixelDepth = getZEyeAtUV(fullTexCoord, 0); + vec2 weightedSums = vec2(0.0); - // Central pixel contribution - float mainWeight = getBlurCoef(0); - vec2 weightedSums = vec2(occlusionDepth.x * mainWeight, mainWeight); - // Accumulate weighted contributions along the bluring axis in the [-radius, radius] range int blurRadius = getBlurRadius(); // negative side first for (int r = -blurRadius; r <= -1; ++r) { - weightedSums += evalTapWeightedValue(side.xyz, r, ssC, key); + weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, pixelDepth); } + + // Central pixel contribution + float mainWeight = getBlurCoef(0); + float pixelOcclusion = fetchOcclusion(scaledTexCoord); + weightedSums += vec2(pixelOcclusion * mainWeight, mainWeight); + // then positive side for (int r = 1; r <= blurRadius; ++r) { - weightedSums += evalTapWeightedValue(side.xyz, r, ssC, key); + weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, pixelDepth); } // Final normalization const float epsilon = 0.0001; float result = weightedSums.x / (weightedSums.y + epsilon); - rawSample.x = result; - return rawSample; + return vec3(result); } <@endfunc@> diff --git a/libraries/render-utils/src/ssao_blur.slv b/libraries/render-utils/src/ssao_blur.slv new file mode 100644 index 0000000000..aafd9adbf4 --- /dev/null +++ b/libraries/render-utils/src/ssao_blur.slv @@ -0,0 +1,42 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// ssao_blur.vert +// +// Draw the unit quad [-1,-1 -> 1,1] filling in +// Simply draw a Triangle_strip of 2 triangles, no input buffers or index buffer needed +// +// Created by Olivier Prat on 9/12/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include gpu/Transform.slh@> + +<$declareStandardTransform()$> + +layout(location=0) out vec4 varTexCoord0; + +void main(void) { + const vec4 UNIT_QUAD[4] = vec4[4]( + vec4(-1.0, -1.0, 0.0, 1.0), + vec4(1.0, -1.0, 0.0, 1.0), + vec4(-1.0, 1.0, 0.0, 1.0), + vec4(1.0, 1.0, 0.0, 1.0) + ); + vec4 pos = UNIT_QUAD[gl_VertexID]; + + // standard transform but applied to the Texcoord + vec2 fullTexCoord = (pos.xy + 1.0) * 0.5; + vec4 tc = vec4(fullTexCoord, pos.zw); + + TransformObject obj = getTransformObject(); + <$transformModelToWorldPos(obj, tc, tc)$> + + gl_Position = pos; + varTexCoord0.xy = tc.xy; + varTexCoord0.zw = fullTexCoord.xy; +} diff --git a/libraries/render-utils/src/ssao_makeHorizontalBlur.slf b/libraries/render-utils/src/ssao_makeHorizontalBlur.slf index 94dbb2b00c..2d02ed02f0 100644 --- a/libraries/render-utils/src/ssao_makeHorizontalBlur.slf +++ b/libraries/render-utils/src/ssao_makeHorizontalBlur.slf @@ -16,9 +16,10 @@ const ivec2 horizontal = ivec2(1,0); <$declareBlurPass(horizontal)$> +layout(location=0) in vec4 varTexCoord0; layout(location=0) out vec4 outFragColor; void main(void) { - outFragColor = vec4(getBlurredOcclusion(gl_FragCoord.xy), 1.0); + outFragColor = vec4(getBlurredOcclusion(ivec2(gl_FragCoord.xy), varTexCoord0.xy, varTexCoord0.zw), 1.0); } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index e2c8a5ffa6..ba01241ce7 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -30,9 +30,6 @@ void main(void) { vec2 fragCoord = gl_FragCoord.xy; ivec2 centerPixelPos = ivec2(fragCoord.xy); - // Fetch the z under the pixel (stereo or not) - float Zeye = getZEyeAtPixel(centerPixelPos, 0); - // Stereo side info ivec4 side = getStereoSideInfo(centerPixelPos.x, getResolutionLevel()); @@ -40,6 +37,9 @@ void main(void) { centerPixelPos.x -= side.y; vec2 fragUVPos = (vec2(centerPixelPos) + vec2(0.5)) / imageSize; + // Fetch the z under the pixel (stereo or not) + float Zeye = getZEyeAtUV(fragUVPos, 0); + // The position and normal of the pixel fragment in Eye space vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); vec3 fragNormalES = evalEyeNormal(fragPositionES); diff --git a/libraries/render-utils/src/ssao_makeVerticalBlur.slf b/libraries/render-utils/src/ssao_makeVerticalBlur.slf index 0b9b5c7eaf..1ef6666424 100644 --- a/libraries/render-utils/src/ssao_makeVerticalBlur.slf +++ b/libraries/render-utils/src/ssao_makeVerticalBlur.slf @@ -15,9 +15,11 @@ const ivec2 vertical = ivec2(0,1); <$declareBlurPass(vertical)$> +layout(location=0) in vec4 varTexCoord0; + layout(location=0) out vec4 outFragColor; void main(void) { - float occlusion = getBlurredOcclusion(gl_FragCoord.xy).x; + float occlusion = getBlurredOcclusion(ivec2(gl_FragCoord.xy), varTexCoord0.xy, varTexCoord0.zw).x; outFragColor = vec4(occlusion, 0.0, 0.0, occlusion); } From 8006d7c0522ac787f7f242a8715e195ce71e01d3 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 13 Sep 2018 15:33:44 +0200 Subject: [PATCH 14/81] Blur is now at occlusion resolution and added some bias to prevent AO on silhouettes --- .../src/AmbientOcclusionEffect.cpp | 14 +++++++++---- .../render-utils/src/AmbientOcclusionEffect.h | 4 ++++ libraries/render-utils/src/ssao.slh | 20 +++++++++++-------- .../utilities/render/ambientOcclusionPass.qml | 3 ++- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 8d28fae760..fe9f4fc46b 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -182,6 +182,7 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : perspectiveScale{ 1.0f }, obscuranceLevel{ 0.5f }, falloffBias{ 0.01f }, + silhouetteRadius{ 0.3f }, edgeSharpness{ 1.0f }, blurDeviation{ 2.5f }, numSpiralTurns{ 7.0f }, @@ -296,6 +297,11 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.w = (float)config.borderingEnabled; } + if (config.silhouetteRadius != _aoParametersBuffer->getSilhouetteRadius()) { + auto& current = _aoParametersBuffer.edit().ditheringInfo; + current.y = (float)config.silhouetteRadius; + } + if (shouldUpdateGaussian) { updateGaussianDistribution(); } @@ -312,12 +318,12 @@ void AmbientOcclusionEffect::updateBlurParameters() { auto& hblur = _hblurParametersBuffer.edit(); auto frameSize = _framebuffer->getSourceFrameSize(); - hblur.scaleHeight.x = 1.0f / (frameSize.x * resolutionScale); - hblur.scaleHeight.y = 1.0f / frameSize.x; + hblur.scaleHeight.x = 1.0f / frameSize.x; + hblur.scaleHeight.y = float(resolutionScale) / frameSize.x; hblur.scaleHeight.z = frameSize.y / resolutionScale; - vblur.scaleHeight.x = 1.0f / (frameSize.y * resolutionScale); - vblur.scaleHeight.y = 1.0f / frameSize.y; + vblur.scaleHeight.x = 1.0f / frameSize.y; + vblur.scaleHeight.y = float(resolutionScale) / frameSize.y; vblur.scaleHeight.z = frameSize.y; } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index b44569eb89..48752ba3b6 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -63,6 +63,7 @@ class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent { Q_PROPERTY(float radius MEMBER radius WRITE setRadius) Q_PROPERTY(float obscuranceLevel MEMBER obscuranceLevel WRITE setObscuranceLevel) Q_PROPERTY(float falloffBias MEMBER falloffBias WRITE setFalloffBias) + Q_PROPERTY(float silhouetteRadius MEMBER silhouetteRadius WRITE setSilhouetteRadius) Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness WRITE setEdgeSharpness) Q_PROPERTY(float blurDeviation MEMBER blurDeviation WRITE setBlurDeviation) Q_PROPERTY(float numSpiralTurns MEMBER numSpiralTurns WRITE setNumSpiralTurns) @@ -79,6 +80,7 @@ public: void setRadius(float newRadius) { radius = std::max(0.01f, newRadius); emit dirty(); } void setObscuranceLevel(float level) { obscuranceLevel = std::max(0.01f, level); emit dirty(); } void setFalloffBias(float bias) { falloffBias = std::max(0.0f, std::min(bias, 0.2f)); emit dirty(); } + void setSilhouetteRadius(float value) { silhouetteRadius = std::max(0.0f, value); emit dirty(); } void setEdgeSharpness(float sharpness) { edgeSharpness = std::max(0.0f, (float)sharpness); emit dirty(); } void setBlurDeviation(float deviation) { blurDeviation = std::max(0.0f, deviation); emit dirty(); } void setNumSpiralTurns(float turns) { numSpiralTurns = std::max(0.0f, (float)turns); emit dirty(); } @@ -90,6 +92,7 @@ public: float perspectiveScale; float obscuranceLevel; // intensify or dim down the obscurance effect float falloffBias; + float silhouetteRadius; float edgeSharpness; float blurDeviation; float numSpiralTurns; // defining an angle span to distribute the samples ray directions @@ -143,6 +146,7 @@ public: float getFalloffBias() const { return (float)ditheringInfo.z; } float getEdgeSharpness() const { return (float)blurInfo.x; } float getBlurDeviation() const { return blurInfo.z; } + float getSilhouetteRadius() const { return ditheringInfo.y; } float getNumSpiralTurns() const { return sampleInfo.z; } int getNumSamples() const { return (int)sampleInfo.x; } diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index d974a83104..71ad578485 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -67,6 +67,7 @@ float getRadius2() { float getInvRadius6() { return params._radiusInfo.z; } + float getObscuranceScaling() { return params._radiusInfo.z * params._radiusInfo.w; } @@ -74,7 +75,7 @@ float getObscuranceScaling() { float isDitheringEnabled() { return params._ditheringInfo.x; } -float getFrameDithering() { +float getSilhouetteRadius() { return params._ditheringInfo.y; } float isBorderingEnabled() { @@ -139,12 +140,12 @@ float getAngleDitheringWorldPos(in vec3 pixelWorldPos) { ivec3 pixelPos = ivec3(worldPosFract * 256.0); - return isDitheringEnabled() * float(((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) + (3 * pixelPos.y ^ pixelPos.z + pixelPos.x * pixelPos.z)) * 10) + getFrameDithering(); + return isDitheringEnabled() * float(((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) + (3 * pixelPos.y ^ pixelPos.z + pixelPos.x * pixelPos.z)) * 10); } float getAngleDithering(in ivec2 pixelPos) { // Hash function used in the AlchemyAO paper - return isDitheringEnabled() * float((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10) + getFrameDithering(); + return isDitheringEnabled() * float((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10); } float evalDiskRadius(float Zeye, vec2 imageSize) { @@ -304,10 +305,13 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t vec3 tap = vec3(tapPixelPos, radius); vec3 tapUVZ = fetchTap(side, centerPixelPos, tap, imageSize); vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); - vec3 deltaVec = normalize(tapPositionES - fragPositionES); - float rawHorizon = dot(deltaVec, fragNormalES); + vec3 deltaVec = tapPositionES - fragPositionES; + float deltaVecHeight = dot(deltaVec, fragNormalES); + float rawHorizon = dot(normalize(deltaVec), fragNormalES); + float falloff = max(0.0, 1.0 - deltaVecHeight / getSilhouetteRadius()); - rawHorizon *= 1.0 - radius / ssDiskRadius; + rawHorizon = rawHorizon < getFalloffBias() ? 0.0f : rawHorizon; + rawHorizon *= falloff * falloff; <$horizon$> = max(<$horizon$>, rawHorizon); } @@ -455,8 +459,8 @@ float fetchOcclusion(vec2 coords) { return raw.x; } -const float BLUR_WEIGHT_OFFSET = 0.05; -const float BLUR_EDGE_SCALE = 100.0; +const float BLUR_WEIGHT_OFFSET = 0.01; +const float BLUR_EDGE_SCALE = 10.0; vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float key) { ivec2 tapOffset = <$axis$> * r; diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index 179fc8341c..1e5a46f115 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -38,7 +38,8 @@ Rectangle { "Num Taps:numSamples:32:true", "Taps Spiral:numSpiralTurns:10.0:false", "Falloff Bias:falloffBias:0.2:false", - "Edge Sharpness:edgeSharpness:1.0:false", + "Silhouette Radius:silhouetteRadius:1.0:false", + "Blur Edge Sharpness:edgeSharpness:1.0:false", "Blur Radius:blurRadius:10.0:false", ] ConfigSlider { From 6b8f47c75a6e644d650140e1fd16660ac1b7d7c9 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 13 Sep 2018 18:39:02 +0200 Subject: [PATCH 15/81] Added some tweaking parameters to try to limit silhouette AO --- .../src/AmbientOcclusionEffect.cpp | 27 ++-- .../render-utils/src/AmbientOcclusionEffect.h | 20 +-- libraries/render-utils/src/ssao.slh | 144 ++++++++---------- .../render-utils/src/ssao_makeOcclusion.slf | 4 + .../utilities/render/ambientOcclusionPass.qml | 6 +- 5 files changed, 97 insertions(+), 104 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index fe9f4fc46b..381f015f9e 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -181,8 +181,12 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : #endif perspectiveScale{ 1.0f }, obscuranceLevel{ 0.5f }, - falloffBias{ 0.01f }, - silhouetteRadius{ 0.3f }, +#if SSAO_USE_HORIZON_BASED + falloffAngle{ 0.1f }, +#else + falloffAngle{ 0.01f }, +#endif + falloffDistance{ 0.3f }, edgeSharpness{ 1.0f }, blurDeviation{ 2.5f }, numSpiralTurns{ 7.0f }, @@ -234,9 +238,9 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.w = config.obscuranceLevel; } - if (config.falloffBias != _aoParametersBuffer->getFalloffBias()) { + if (config.falloffAngle != _aoParametersBuffer->getFalloffAngle()) { auto& current = _aoParametersBuffer.edit().ditheringInfo; - current.z = config.falloffBias; + current.z = config.falloffAngle; } if (config.edgeSharpness != _aoParametersBuffer->getEdgeSharpness()) { @@ -297,9 +301,9 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.w = (float)config.borderingEnabled; } - if (config.silhouetteRadius != _aoParametersBuffer->getSilhouetteRadius()) { + if (config.falloffDistance != _aoParametersBuffer->getFalloffDistance()) { auto& current = _aoParametersBuffer.edit().ditheringInfo; - current.y = (float)config.silhouetteRadius; + current.y = (float)config.falloffDistance; } if (shouldUpdateGaussian) { @@ -450,6 +454,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #endif batch.popProfileRange(); + batch.pushProfileRange("Occlusion"); batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); @@ -459,10 +464,11 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setPipeline(occlusionPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoPyramid, _framebuffer->getLinearDepthTexture()); batch.draw(gpu::TRIANGLE_STRIP, 4); + batch.popProfileRange(); - /* TEMPO OP if (_aoParametersBuffer->getBlurRadius() > 0)*/ { - PROFILE_RANGE_BATCH(batch, "Blur"); - // Blur 1st pass + { + PROFILE_RANGE_BATCH(batch, "Bilateral Blur"); + // Blur 1st pass model.setScale(resolutionScale); batch.setModelTransform(model); batch.setViewportTransform(firstBlurViewport); @@ -482,8 +488,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionBlurredFBO->getRenderBuffer(0)); batch.draw(gpu::TRIANGLE_STRIP, 4); } - - + batch.setResourceTexture(render_utils::slot::texture::SsaoPyramid, nullptr); batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, nullptr); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 48752ba3b6..ad56aff399 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -62,8 +62,8 @@ class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent { Q_PROPERTY(bool fetchMipsEnabled MEMBER fetchMipsEnabled NOTIFY dirty) Q_PROPERTY(float radius MEMBER radius WRITE setRadius) Q_PROPERTY(float obscuranceLevel MEMBER obscuranceLevel WRITE setObscuranceLevel) - Q_PROPERTY(float falloffBias MEMBER falloffBias WRITE setFalloffBias) - Q_PROPERTY(float silhouetteRadius MEMBER silhouetteRadius WRITE setSilhouetteRadius) + Q_PROPERTY(float falloffAngle MEMBER falloffAngle WRITE setFalloffAngle) + Q_PROPERTY(float falloffDistance MEMBER falloffDistance WRITE setFalloffDistance) Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness WRITE setEdgeSharpness) Q_PROPERTY(float blurDeviation MEMBER blurDeviation WRITE setBlurDeviation) Q_PROPERTY(float numSpiralTurns MEMBER numSpiralTurns WRITE setNumSpiralTurns) @@ -75,12 +75,12 @@ public: AmbientOcclusionEffectConfig(); const int MAX_RESOLUTION_LEVEL = 4; - const int MAX_BLUR_RADIUS = 6; + const int MAX_BLUR_RADIUS = 15; void setRadius(float newRadius) { radius = std::max(0.01f, newRadius); emit dirty(); } void setObscuranceLevel(float level) { obscuranceLevel = std::max(0.01f, level); emit dirty(); } - void setFalloffBias(float bias) { falloffBias = std::max(0.0f, std::min(bias, 0.2f)); emit dirty(); } - void setSilhouetteRadius(float value) { silhouetteRadius = std::max(0.0f, value); emit dirty(); } + void setFalloffAngle(float bias) { falloffAngle = std::max(0.0f, std::min(bias, 0.2f)); emit dirty(); } + void setFalloffDistance(float value) { falloffDistance = std::max(0.0f, value); emit dirty(); } void setEdgeSharpness(float sharpness) { edgeSharpness = std::max(0.0f, (float)sharpness); emit dirty(); } void setBlurDeviation(float deviation) { blurDeviation = std::max(0.0f, deviation); emit dirty(); } void setNumSpiralTurns(float turns) { numSpiralTurns = std::max(0.0f, (float)turns); emit dirty(); } @@ -91,8 +91,8 @@ public: float radius; float perspectiveScale; float obscuranceLevel; // intensify or dim down the obscurance effect - float falloffBias; - float silhouetteRadius; + float falloffAngle; + float falloffDistance; float edgeSharpness; float blurDeviation; float numSpiralTurns; // defining an angle span to distribute the samples ray directions @@ -134,7 +134,7 @@ public: // Blurring info glm::vec4 blurInfo; // gaussian distribution coefficients first is the sampling radius (max is 6) - const static int GAUSSIAN_COEFS_LENGTH = 8; + const static int GAUSSIAN_COEFS_LENGTH = 16; float _gaussianCoefs[GAUSSIAN_COEFS_LENGTH]; AOParameters(); @@ -143,10 +143,10 @@ public: float getRadius() const { return radiusInfo.x; } float getPerspectiveScale() const { return resolutionInfo.z; } float getObscuranceLevel() const { return radiusInfo.w; } - float getFalloffBias() const { return (float)ditheringInfo.z; } + float getFalloffAngle() const { return (float)ditheringInfo.z; } + float getFalloffDistance() const { return ditheringInfo.y; } float getEdgeSharpness() const { return (float)blurInfo.x; } float getBlurDeviation() const { return blurInfo.z; } - float getSilhouetteRadius() const { return ditheringInfo.y; } float getNumSpiralTurns() const { return sampleInfo.z; } int getNumSamples() const { return (int)sampleInfo.x; } diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 71ad578485..b74cb740a8 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -41,7 +41,7 @@ struct AmbientOcclusionParams { vec4 _ditheringInfo; vec4 _sampleInfo; vec4 _blurInfo; - float _gaussianCoefs[8]; + float _gaussianCoefs[16]; }; layout(binding=RENDER_UTILS_BUFFER_SSAO_PARAMS) uniform ambientOcclusionParamsBuffer { @@ -75,14 +75,14 @@ float getObscuranceScaling() { float isDitheringEnabled() { return params._ditheringInfo.x; } -float getSilhouetteRadius() { +float getFalloffDistance() { return params._ditheringInfo.y; } float isBorderingEnabled() { return params._ditheringInfo.w; } -float getFalloffBias() { +float getFalloffAngle() { return params._ditheringInfo.z; } @@ -226,7 +226,7 @@ float getZEyeAtUV(vec2 texCoord, int level) { return -texture(pyramidMap, texCoord, level).x; } -const int LOG_MAX_OFFSET = 3; +const int LOG_MAX_OFFSET = 1; const int MAX_MIP_LEVEL = 5; int evalMipFromRadius(float radius) { // mipLevel = floor(log(ssR / MAX_OFFSET)); @@ -249,7 +249,7 @@ vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { return P; } -vec3 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { +vec4 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { int mipLevel = evalMipFromRadius(tap.z * float(doFetchMips())); vec2 ssP = tap.xy + vec2(ssC); @@ -259,15 +259,13 @@ vec3 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize; vec2 fetchUV = vec2(tapUV.x + side.w * 0.5 * (side.x - tapUV.x), tapUV.y); - vec3 P; + vec4 P; P.xy = tapUV; - P.z = -textureLod(pyramidMap, fetchUV, float(mipLevel)).x; - + P.w = float(mipLevel); + P.z = -textureLod(pyramidMap, fetchUV, P.w).x; return P; } - - <@endfunc@> @@ -289,59 +287,63 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t // Fall off function as recommended in SSAO paper const float epsilon = 0.01; float f = max(getRadius2() - vv, 0.0); - return f * f * f * max((vn - getFalloffBias()) / (epsilon + vv), 0.0); + return f * f * f * max((vn - getFalloffAngle()) / (epsilon + vv), 0.0); } +float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES, float normalizedRadius) { + vec3 deltaVec = tapPositionES - fragPositionES; + float distance = abs(deltaVec.z); + float rawHorizon = dot(normalize(deltaVec), fragNormalES); + + rawHorizon = (rawHorizon - getFalloffAngle()) / (1.0 - getFalloffAngle()); + rawHorizon *= 1.0 - normalizedRadius * normalizedRadius; + rawHorizon *= 1.0 - smoothstep(getFalloffDistance()/2, getFalloffDistance(), distance); + + return rawHorizon; +} + +<@func computeHorizon()@> + vec3 tap = vec3(tapPixelPos, radius); + vec4 tapUVZ_mip = fetchTap(side, centerPixelPos, tap, imageSize); + vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ_mip.z, tapUVZ_mip.xy); + float rawHorizon = computeHorizonFromTap(tapPositionES, fragPositionES, fragNormalES, radius / searchRadius); + + <$horizon$> = max(<$horizon$>, rawHorizon); +<@endfunc@> + +#define SSAO_LINEAR_SAMPLING 0 + <@func updateHorizon(horizon, deltaPixelTap)@> { - int stepIndex; vec2 tapPixelPos = vec2(0); - float radius = 0.0; - for (stepIndex=stepCount ; stepIndex>0 ; stepIndex--) { - tapPixelPos += deltaPixelTap; +#if !SSAO_LINEAR_SAMPLING + float radius = deltaRadius; + float mipLevel = evalMipFromRadius(radius * float(doFetchMips())); + + while (radius; + + <$computeHorizon()$> + + if (tapUVZ_mip.w != mipLevel) { + mipLevel = tapUVZ_mip.w; + deltaRadius *= 2; + <$deltaPixelTap$> *= 2; + } + radius += deltaRadius; + } +#else + float radius = 0.0; + int stepIndex; + + for (stepIndex=0 ; stepIndex; radius += deltaRadius; - vec3 tap = vec3(tapPixelPos, radius); - vec3 tapUVZ = fetchTap(side, centerPixelPos, tap, imageSize); - vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); - vec3 deltaVec = tapPositionES - fragPositionES; - float deltaVecHeight = dot(deltaVec, fragNormalES); - float rawHorizon = dot(normalize(deltaVec), fragNormalES); - float falloff = max(0.0, 1.0 - deltaVecHeight / getSilhouetteRadius()); - - rawHorizon = rawHorizon < getFalloffBias() ? 0.0f : rawHorizon; - rawHorizon *= falloff * falloff; - - <$horizon$> = max(<$horizon$>, rawHorizon); + <$computeHorizon()$> } - } -<@endfunc@> - -<@func searchBresenhamHorizon(deltaPixelCoord)@> - { - float epsilon = 1e-8; - vec2 deltaPixelTap = searchVec / absSearchVec.<$deltaPixelCoord$>; - vec2 absDeltaPixelTap = abs(deltaPixelTap); - bvec2 nullDelta = absDeltaPixelTap < epsilon; - - pixelDelta1 = mix(pixelDelta1, vec2(1.0), pixelDelta1 < epsilon && nullDelta); - pixelDelta2 = mix(pixelDelta2, vec2(1.0), pixelDelta2 < epsilon && nullDelta); - - pixelDelta1 = ceil(pixelDelta1 / absDeltaPixelTap); - pixelDelta2 = ceil(pixelDelta2 / absDeltaPixelTap); - - int maxStepCount = max(0, int(ceil(absSearchVec.<$deltaPixelCoord$>))); - float deltaRadius = ssDiskRadius / maxStepCount; - int stepCount; - - // Forward search for h1 - stepCount = clamp(int(min(pixelDelta1.x, pixelDelta1.y)), 0, maxStepCount); - <$updateHorizon(horizons.x, deltaPixelTap)$> - - // Backward search for h2 - stepCount = clamp(int(min(pixelDelta2.x, pixelDelta2.y)), 0, maxStepCount); - <$updateHorizon(horizons.y, -deltaPixelTap)$> +#endif } <@endfunc@> @@ -379,7 +381,8 @@ vec2 searchHorizons(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 delta int stepCount = int(max(absClampedSearchVec.x, absClampedSearchVec.y)); if (stepCount>0) { vec2 deltaPixelTap = clampedSearchVec / float(stepCount); - float deltaRadius = length(deltaPixelTap); + float searchRadius = length(clampedSearchVec); + float deltaRadius = searchRadius / float(stepCount); <$updateHorizon(horizons.x, deltaPixelTap)$> } // Backward search for h2 @@ -388,32 +391,11 @@ vec2 searchHorizons(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 delta stepCount = int(max(absClampedSearchVec.x, absClampedSearchVec.y)); if (stepCount>0) { vec2 deltaPixelTap = clampedSearchVec / float(stepCount); - float deltaRadius = length(deltaPixelTap); + float searchRadius = length(clampedSearchVec); + float deltaRadius = searchRadius / float(stepCount); <$updateHorizon(horizons.y, deltaPixelTap)$> } -// -// absSearchVec.y) { - <$searchBresenhamHorizon(x)$> - } else { - <$searchBresenhamHorizon(y)$> - } - - vec3 angles = acos(vec3(horizons, fragNormalES.z)) - PI/2.0; - angles.x = -angles.x; - // Clamp to limit horizon defined by normal plane - horizons.xy = angles.zz + max(angles.xy - angles.zz, vec2(-PI/2.0, PI/2.0)); - */ - -// -// !> -// - return horizons; } @@ -460,7 +442,7 @@ float fetchOcclusion(vec2 coords) { } const float BLUR_WEIGHT_OFFSET = 0.01; -const float BLUR_EDGE_SCALE = 10.0; +const float BLUR_EDGE_SCALE = 300.0; vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float key) { ivec2 tapOffset = <$axis$> * r; @@ -479,7 +461,9 @@ vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTe float weight = BLUR_WEIGHT_OFFSET + getBlurCoef(abs(r)); // range domain (the "bilateral" weight). As depth difference increases, decrease weight. - weight *= max(0.0, 1.0 - (getBlurEdgeSharpness() * BLUR_EDGE_SCALE) * abs(tapDepth - key)); +// weight *= max(0.0, 1.0 - (getBlurEdgeSharpness() * BLUR_EDGE_SCALE) * abs(tapDepth - key)); + float zDistance = tapDepth - key; + weight *= exp(-(getBlurEdgeSharpness() * BLUR_EDGE_SCALE) * zDistance * zDistance); return vec2(tapOcclusion * weight, weight); } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index ba01241ce7..fc974a7baa 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -20,6 +20,7 @@ <$declarePackOcclusionDepth()$> #define SSAO_USE_HORIZON_BASED 1 +#define SSAO_HBAO_MAX_RADIUS 100.0 layout(location=0) out vec4 outFragColor; @@ -46,6 +47,9 @@ void main(void) { // Choose the screen-space sample radius float ssDiskRadius = evalDiskRadius(fragPositionES.z, imageSize); +#if SSAO_USE_HORIZON_BASED + ssDiskRadius = min(ssDiskRadius, SSAO_HBAO_MAX_RADIUS); +#endif // Let's make noise float randomPatternRotationAngle = getAngleDithering(centerPixelPos); diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index 1e5a46f115..ca00849706 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -37,10 +37,10 @@ Rectangle { "Level:obscuranceLevel:1.0:false", "Num Taps:numSamples:32:true", "Taps Spiral:numSpiralTurns:10.0:false", - "Falloff Bias:falloffBias:0.2:false", - "Silhouette Radius:silhouetteRadius:1.0:false", + "Falloff Angle:falloffAngle:0.2:false", + "Falloff Distance:falloffDistance:2.0:false", "Blur Edge Sharpness:edgeSharpness:1.0:false", - "Blur Radius:blurRadius:10.0:false", + "Blur Radius:blurRadius:15.0:false", ] ConfigSlider { label: qsTr(modelData.split(":")[0]) From ad5064b045e88509797310d15b0c574e455240e7 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 17 Sep 2018 14:33:48 +0200 Subject: [PATCH 16/81] Removed falloff distance from shader --- .../render-utils/src/AmbientOcclusionEffect.h | 2 +- libraries/render-utils/src/ssao.slh | 14 +++++++------- libraries/render-utils/src/ssao_makeOcclusion.slf | 3 +-- .../utilities/render/ambientOcclusionPass.qml | 2 +- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index ad56aff399..81ceee9bf6 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -79,7 +79,7 @@ public: void setRadius(float newRadius) { radius = std::max(0.01f, newRadius); emit dirty(); } void setObscuranceLevel(float level) { obscuranceLevel = std::max(0.01f, level); emit dirty(); } - void setFalloffAngle(float bias) { falloffAngle = std::max(0.0f, std::min(bias, 0.2f)); emit dirty(); } + void setFalloffAngle(float bias) { falloffAngle = std::max(0.0f, std::min(bias, 1.0f)); emit dirty(); } void setFalloffDistance(float value) { falloffDistance = std::max(0.0f, value); emit dirty(); } void setEdgeSharpness(float sharpness) { edgeSharpness = std::max(0.0f, (float)sharpness); emit dirty(); } void setBlurDeviation(float deviation) { blurDeviation = std::max(0.0f, deviation); emit dirty(); } diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index b74cb740a8..88d8f08e7a 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -290,14 +290,14 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t return f * f * f * max((vn - getFalloffAngle()) / (epsilon + vv), 0.0); } -float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES, float normalizedRadius) { +float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES) { vec3 deltaVec = tapPositionES - fragPositionES; - float distance = abs(deltaVec.z); + float distanceSquared = dot(deltaVec, deltaVec); float rawHorizon = dot(normalize(deltaVec), fragNormalES); + float radiusFalloff = distanceSquared / getRadius2(); - rawHorizon = (rawHorizon - getFalloffAngle()) / (1.0 - getFalloffAngle()); - rawHorizon *= 1.0 - normalizedRadius * normalizedRadius; - rawHorizon *= 1.0 - smoothstep(getFalloffDistance()/2, getFalloffDistance(), distance); + rawHorizon = max(0.0, (rawHorizon - getFalloffAngle()) / (1.0 - getFalloffAngle())); + rawHorizon *= 1.0 - radiusFalloff; return rawHorizon; } @@ -306,12 +306,12 @@ float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNo vec3 tap = vec3(tapPixelPos, radius); vec4 tapUVZ_mip = fetchTap(side, centerPixelPos, tap, imageSize); vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ_mip.z, tapUVZ_mip.xy); - float rawHorizon = computeHorizonFromTap(tapPositionES, fragPositionES, fragNormalES, radius / searchRadius); + float rawHorizon = computeHorizonFromTap(tapPositionES, fragPositionES, fragNormalES); <$horizon$> = max(<$horizon$>, rawHorizon); <@endfunc@> -#define SSAO_LINEAR_SAMPLING 0 +#define SSAO_LINEAR_SAMPLING 1 <@func updateHorizon(horizon, deltaPixelTap)@> { diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index fc974a7baa..c81644ce58 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -69,8 +69,7 @@ void main(void) { #endif } - visibilitySum = visibilitySum * getInvNumSamples(); - float occlusion = clamp(1.0 - visibilitySum * getObscuranceScaling(), 0.0, 1.0); + float occlusion = clamp(1.0 - visibilitySum * getObscuranceScaling() * getInvNumSamples(), 0.0, 1.0); // KEEP IT for Debugging // Bilateral box-filter over a quad for free, respecting depth edges diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index ca00849706..0416443139 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -37,7 +37,7 @@ Rectangle { "Level:obscuranceLevel:1.0:false", "Num Taps:numSamples:32:true", "Taps Spiral:numSpiralTurns:10.0:false", - "Falloff Angle:falloffAngle:0.2:false", + "Falloff Angle:falloffAngle:0.5:false", "Falloff Distance:falloffDistance:2.0:false", "Blur Edge Sharpness:edgeSharpness:1.0:false", "Blur Radius:blurRadius:15.0:false", From d9e2c8df69d8ac703033aebad1aa39450988ae1a Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 17 Sep 2018 15:06:00 +0200 Subject: [PATCH 17/81] Fixed uniform buffer slot index in DebugAmbientOcclusion --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 7 ++++--- libraries/render-utils/src/ssao.slh | 11 ++++------- libraries/render-utils/src/ssao_makeOcclusion.slf | 3 ++- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 381f015f9e..44a5cca9b7 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -78,12 +78,13 @@ void AmbientOcclusionFramebuffer::allocate() { auto width = _frameSize.x; auto height = _frameSize.y; + auto format = gpu::Element::COLOR_RGBA_32; - _occlusionTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)); + _occlusionTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)); _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); - _occlusionBlurredTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)); + _occlusionBlurredTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)); _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusionBlurred")); _occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture); } @@ -582,7 +583,7 @@ void DebugAmbientOcclusion::run(const render::RenderContextPointer& renderContex batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, ambientOcclusionUniforms); - batch.setUniformBuffer(2, _parametersBuffer); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoDebugParams, _parametersBuffer); batch.setPipeline(debugPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoPyramid, linearDepthTexture); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 88d8f08e7a..cea4caa8e7 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -297,7 +297,7 @@ float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNo float radiusFalloff = distanceSquared / getRadius2(); rawHorizon = max(0.0, (rawHorizon - getFalloffAngle()) / (1.0 - getFalloffAngle())); - rawHorizon *= 1.0 - radiusFalloff; + rawHorizon *= max(0.0, 1.0 - radiusFalloff); return rawHorizon; } @@ -315,6 +315,9 @@ float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNo <@func updateHorizon(horizon, deltaPixelTap)@> { + vec2 deltaPixelTap = clampedSearchVec / float(stepCount); + float searchRadius = length(clampedSearchVec); + float deltaRadius = searchRadius / float(stepCount); vec2 tapPixelPos = vec2(0); #if !SSAO_LINEAR_SAMPLING @@ -380,9 +383,6 @@ vec2 searchHorizons(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 delta vec2 absClampedSearchVec = abs(clampedSearchVec); int stepCount = int(max(absClampedSearchVec.x, absClampedSearchVec.y)); if (stepCount>0) { - vec2 deltaPixelTap = clampedSearchVec / float(stepCount); - float searchRadius = length(clampedSearchVec); - float deltaRadius = searchRadius / float(stepCount); <$updateHorizon(horizons.x, deltaPixelTap)$> } // Backward search for h2 @@ -390,9 +390,6 @@ vec2 searchHorizons(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 delta absClampedSearchVec = abs(clampedSearchVec); stepCount = int(max(absClampedSearchVec.x, absClampedSearchVec.y)); if (stepCount>0) { - vec2 deltaPixelTap = clampedSearchVec / float(stepCount); - float searchRadius = length(clampedSearchVec); - float deltaRadius = searchRadius / float(stepCount); <$updateHorizon(horizons.y, deltaPixelTap)$> } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index c81644ce58..ee22590679 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -81,5 +81,6 @@ void main(void) { occlusion -= dFdy(occlusion) * ((centerPixelPos.y & 1) - 0.5); }*/ - outFragColor = vec4(packOcclusionDepth(occlusion, CSZToDepthKey(fragPositionES.z)), 1.0); + //outFragColor = vec4(packOcclusionDepth(occlusion, CSZToDepthKey(fragPositionES.z)), 1.0); + outFragColor = vec4(vec3(occlusion), 1.0); } From d0eef1b8d06769153ff9f327dba4fcf345845f4c Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 17 Sep 2018 16:12:54 +0200 Subject: [PATCH 18/81] Some cleanup --- .../src/AmbientOcclusionEffect.cpp | 4 +- libraries/render-utils/src/ssao.slh | 114 +++++++++--------- 2 files changed, 60 insertions(+), 58 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 44a5cca9b7..70f36521d8 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -80,11 +80,11 @@ void AmbientOcclusionFramebuffer::allocate() { auto height = _frameSize.y; auto format = gpu::Element::COLOR_RGBA_32; - _occlusionTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)); + _occlusionTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT, gpu::Sampler::WRAP_CLAMP)); _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); - _occlusionBlurredTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)); + _occlusionBlurredTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT, gpu::Sampler::WRAP_CLAMP)); _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusionBlurred")); _occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture); } diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index cea4caa8e7..8f27f1f445 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -293,66 +293,29 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES) { vec3 deltaVec = tapPositionES - fragPositionES; float distanceSquared = dot(deltaVec, deltaVec); - float rawHorizon = dot(normalize(deltaVec), fragNormalES); - float radiusFalloff = distanceSquared / getRadius2(); + float horizon = dot(normalize(deltaVec), fragNormalES); + float radiusFalloff = max(0.0, 1.0 - (distanceSquared / getRadius2())); - rawHorizon = max(0.0, (rawHorizon - getFalloffAngle()) / (1.0 - getFalloffAngle())); - rawHorizon *= max(0.0, 1.0 - radiusFalloff); + horizon = max(0.0, (horizon - getFalloffAngle()) / (1.0 - getFalloffAngle())); + horizon *= radiusFalloff; - return rawHorizon; + return horizon; } <@func computeHorizon()@> vec3 tap = vec3(tapPixelPos, radius); vec4 tapUVZ_mip = fetchTap(side, centerPixelPos, tap, imageSize); vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ_mip.z, tapUVZ_mip.xy); - float rawHorizon = computeHorizonFromTap(tapPositionES, fragPositionES, fragNormalES); + float tapCosHorizonAngle = computeHorizonFromTap(tapPositionES, fragPositionES, fragNormalES); - <$horizon$> = max(<$horizon$>, rawHorizon); + cosHorizonAngle = max(cosHorizonAngle, tapCosHorizonAngle); <@endfunc@> #define SSAO_LINEAR_SAMPLING 1 -<@func updateHorizon(horizon, deltaPixelTap)@> - { - vec2 deltaPixelTap = clampedSearchVec / float(stepCount); - float searchRadius = length(clampedSearchVec); - float deltaRadius = searchRadius / float(stepCount); - vec2 tapPixelPos = vec2(0); - -#if !SSAO_LINEAR_SAMPLING - float radius = deltaRadius; - float mipLevel = evalMipFromRadius(radius * float(doFetchMips())); - - while (radius; - - <$computeHorizon()$> - - if (tapUVZ_mip.w != mipLevel) { - mipLevel = tapUVZ_mip.w; - deltaRadius *= 2; - <$deltaPixelTap$> *= 2; - } - radius += deltaRadius; - } -#else - float radius = 0.0; - int stepIndex; - - for (stepIndex=0 ; stepIndex; - radius += deltaRadius; - - <$computeHorizon()$> - } -#endif - } -<@endfunc@> - vec2 clampSearchVec(vec2 imageSize, vec2 centerPixelPos, vec2 searchVec) { vec2 clampdSearchVec = searchVec; - vec2 endPixel = centerPixelPos + clampdSearchVec; +/* TEMPO OP vec2 endPixel = centerPixelPos + clampdSearchVec; if (endPixel.x < 0) { clampdSearchVec = clampdSearchVec * ((0-centerPixelPos.x) / clampdSearchVec.x); @@ -368,11 +331,55 @@ vec2 clampSearchVec(vec2 imageSize, vec2 centerPixelPos, vec2 searchVec) { } if (endPixel.y >= imageSize.y) { clampdSearchVec = clampdSearchVec * ((imageSize.y-1-centerPixelPos.y) / clampdSearchVec.y); - } + }*/ return clampdSearchVec; } +float computeHorizon(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 deltaTap, float ssDiskRadius, + vec3 fragPositionES, vec3 fragNormalES, vec2 clampedSearchVec) { + vec2 absClampedSearchVec = abs(clampedSearchVec); + int stepCount = int(max(absClampedSearchVec.x, absClampedSearchVec.y)); + float cosHorizonAngle = 0.0; + + if (stepCount>0) { + vec2 deltaPixelTap = clampedSearchVec / float(stepCount); + float searchRadius = length(clampedSearchVec); + float deltaRadius = searchRadius / float(stepCount); + vec2 tapPixelPos = vec2(0); + +#if !SSAO_LINEAR_SAMPLING + float radius = deltaRadius; + float mipLevel = evalMipFromRadius(radius * float(doFetchMips())); + + while (radius + + if (tapUVZ_mip.w != mipLevel) { + mipLevel = tapUVZ_mip.w; + deltaRadius *= 2; + deltaPixelTap *= 2; + } + radius += deltaRadius; + } +#else + float radius = 0.0; + int stepIndex; + + for (stepIndex=0 ; stepIndex + } +#endif + } + + return cosHorizonAngle; +} + vec2 searchHorizons(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 deltaTap, float ssDiskRadius, vec3 fragPositionES, vec3 fragNormalES) { vec2 searchVec = deltaTap * ssDiskRadius; @@ -380,18 +387,13 @@ vec2 searchHorizons(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 delta // Forward search for h1 vec2 clampedSearchVec = clampSearchVec(imageSize, vec2(centerPixelPos), searchVec); - vec2 absClampedSearchVec = abs(clampedSearchVec); - int stepCount = int(max(absClampedSearchVec.x, absClampedSearchVec.y)); - if (stepCount>0) { - <$updateHorizon(horizons.x, deltaPixelTap)$> - } + horizons.x = computeHorizon(side, centerPixelPos, imageSize, deltaTap, ssDiskRadius, + fragPositionES, fragNormalES, clampedSearchVec); + // Backward search for h2 clampedSearchVec = clampSearchVec(imageSize, vec2(centerPixelPos), -searchVec); - absClampedSearchVec = abs(clampedSearchVec); - stepCount = int(max(absClampedSearchVec.x, absClampedSearchVec.y)); - if (stepCount>0) { - <$updateHorizon(horizons.y, deltaPixelTap)$> - } + horizons.y = computeHorizon(side, centerPixelPos, imageSize, deltaTap, ssDiskRadius, + fragPositionES, fragNormalES, clampedSearchVec); return horizons; } From 0f467ceeb955da267e20c9b3fba4e78e8b8ce361 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 17 Sep 2018 17:19:07 +0200 Subject: [PATCH 19/81] Border clamping for linear depth texture --- .../render-utils/src/SurfaceGeometryPass.cpp | 4 +- libraries/render-utils/src/ssao.slh | 146 +++++++++--------- .../render-utils/src/ssao_makeOcclusion.slf | 41 ++--- 3 files changed, 93 insertions(+), 98 deletions(-) diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index b0f19862ce..f22b8351d4 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -66,7 +66,7 @@ void LinearDepthFramebuffer::allocate() { // For Linear Depth: const uint16_t LINEAR_DEPTH_MAX_MIP_LEVEL = 5; _linearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), width, height, LINEAR_DEPTH_MAX_MIP_LEVEL, - gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)); + gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT, gpu::Sampler::WRAP_CLAMP)); _linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("linearDepth")); _linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture); _linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat()); @@ -74,7 +74,7 @@ void LinearDepthFramebuffer::allocate() { // For Downsampling: const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = LINEAR_DEPTH_MAX_MIP_LEVEL; _halfLinearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), _halfFrameSize.x, _halfFrameSize.y, HALF_LINEAR_DEPTH_MAX_MIP_LEVEL, - gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)); + gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT, gpu::Sampler::WRAP_CLAMP)); _halfNormalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _halfFrameSize.x, _halfFrameSize.y, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 8f27f1f445..b441d7ca8c 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -148,15 +148,15 @@ float getAngleDithering(in ivec2 pixelPos) { return isDitheringEnabled() * float((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10); } -float evalDiskRadius(float Zeye, vec2 imageSize) { +float evalDiskRadius(float Zeye, vec2 sideImageSize) { // Choose the screen-space sample radius // proportional to the projected area of the sphere - float ssDiskRadius = -( getProjScale(getResolutionLevel()) * getRadius() / Zeye ) * getPerspectiveScale(); + float diskPixelRadius = -( getProjScale(getResolutionLevel()) * getRadius() / Zeye ) * getPerspectiveScale(); // clamp the disk to fit in the image otherwise too many unknown - ssDiskRadius = min(ssDiskRadius, imageSize.y * 0.5); + diskPixelRadius = min(diskPixelRadius, sideImageSize.y * 0.5); - return ssDiskRadius; + return diskPixelRadius; } const float PI = 3.1415926; @@ -176,7 +176,7 @@ vec3 getTapLocationSSAO(int sampleNumber, float spinAngle, float outerRadius) { return tap; } -vec3 getTapLocationClampedSSAO(int sampleNumber, float spinAngle, float outerRadius, vec2 pixelPos, vec2 imageSize) { +vec3 getTapLocationClampedSSAO(int sampleNumber, float spinAngle, float outerRadius, vec2 pixelPos, vec2 sideImageSize) { vec3 tap = getTapLocationSSAO(sampleNumber, spinAngle, outerRadius); vec2 tapPos = pixelPos + tap.xy; @@ -188,16 +188,16 @@ vec3 getTapLocationClampedSSAO(int sampleNumber, float spinAngle, float outerRad if ((tapPos.x < 0.5)) { tapPos.x = -tapPos.x; redoTap = true; - } else if ((tapPos.x > imageSize.x - 0.5)) { - tapPos.x -= (imageSize.x - tapPos.x); + } else if ((tapPos.x > sideImageSize.x - 0.5)) { + tapPos.x -= (sideImageSize.x - tapPos.x); redoTap = true; } if ((tapPos.y < 0.5)) { tapPos.y = -tapPos.y; redoTap = true; - } else if ((tapPos.y > imageSize.y - 0.5)) { - tapPos.y -= (imageSize.y - tapPos.y); + } else if ((tapPos.y > sideImageSize.y - 0.5)) { + tapPos.y -= (sideImageSize.y - tapPos.y); redoTap = true; } @@ -233,12 +233,12 @@ int evalMipFromRadius(float radius) { return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); } -vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { +vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 sideImageSize) { ivec2 ssP = ivec2(tap.xy) + ssC; ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y); - vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize; + vec2 tapUV = (vec2(ssP) + vec2(0.5)) / sideImageSize; vec2 fetchUV = vec2(tapUV.x + float(side.w) * 0.5 * (float(side.x) - tapUV.x), tapUV.y); @@ -249,14 +249,14 @@ vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { return P; } -vec4 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { +vec4 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 sideImageSize) { int mipLevel = evalMipFromRadius(tap.z * float(doFetchMips())); vec2 ssP = tap.xy + vec2(ssC); // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. // Manually clamp to the texture size because texelFetch bypasses the texture unit - vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize; + vec2 tapUV = (vec2(ssP) + vec2(0.5)) / sideImageSize; vec2 fetchUV = vec2(tapUV.x + side.w * 0.5 * (side.x - tapUV.x), tapUV.y); vec4 P; @@ -302,53 +302,67 @@ float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNo return horizon; } -<@func computeHorizon()@> - vec3 tap = vec3(tapPixelPos, radius); - vec4 tapUVZ_mip = fetchTap(side, centerPixelPos, tap, imageSize); - vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ_mip.z, tapUVZ_mip.xy); - float tapCosHorizonAngle = computeHorizonFromTap(tapPositionES, fragPositionES, fragNormalES); +vec2 clampSearchVector(vec2 sideImageSize, vec2 shadedPixelPos, vec2 searchVec) { + vec2 clampedSearchVec = searchVec; + vec2 endPixel = shadedPixelPos + clampedSearchVec; - cosHorizonAngle = max(cosHorizonAngle, tapCosHorizonAngle); + if (endPixel.x < 0) { + clampedSearchVec *= ((0-shadedPixelPos.x) / clampedSearchVec.x); + endPixel = shadedPixelPos + clampedSearchVec; + } + if (endPixel.x > (sideImageSize.x-1)) { + clampedSearchVec *= ((sideImageSize.x-1-shadedPixelPos.x) / clampedSearchVec.x); + endPixel = shadedPixelPos + clampedSearchVec; + } + if (endPixel.y < 0) { + clampedSearchVec *= ((0-shadedPixelPos.y) / clampedSearchVec.y); + endPixel = shadedPixelPos + clampedSearchVec; + } + if (endPixel.y > (sideImageSize.y-1)) { + clampedSearchVec *= ((sideImageSize.y-1-shadedPixelPos.y) / clampedSearchVec.y); + } + + return clampedSearchVec; +} + +<@func computeHorizon()@> + if (tapPixelPos.x>=0 && tapPixelPos.y>=0 && tapPixelPos.x #define SSAO_LINEAR_SAMPLING 1 -vec2 clampSearchVec(vec2 imageSize, vec2 centerPixelPos, vec2 searchVec) { - vec2 clampdSearchVec = searchVec; -/* TEMPO OP vec2 endPixel = centerPixelPos + clampdSearchVec; - - if (endPixel.x < 0) { - clampdSearchVec = clampdSearchVec * ((0-centerPixelPos.x) / clampdSearchVec.x); - endPixel = centerPixelPos + clampdSearchVec; - } - if (endPixel.x >= imageSize.x) { - clampdSearchVec = clampdSearchVec * ((imageSize.x-1-centerPixelPos.x) / clampdSearchVec.x); - endPixel = centerPixelPos + clampdSearchVec; - } - if (endPixel.y < 0) { - clampdSearchVec = clampdSearchVec * ((0-centerPixelPos.y) / clampdSearchVec.y); - endPixel = centerPixelPos + clampdSearchVec; - } - if (endPixel.y >= imageSize.y) { - clampdSearchVec = clampdSearchVec * ((imageSize.y-1-centerPixelPos.y) / clampdSearchVec.y); - }*/ - - return clampdSearchVec; -} - -float computeHorizon(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 deltaTap, float ssDiskRadius, - vec3 fragPositionES, vec3 fragNormalES, vec2 clampedSearchVec) { - vec2 absClampedSearchVec = abs(clampedSearchVec); - int stepCount = int(max(absClampedSearchVec.x, absClampedSearchVec.y)); +float computeHorizon(ivec4 side, ivec2 shadedPixelPos, vec2 sideImageSize, vec2 deltaTap, + vec3 fragPositionES, vec3 fragNormalES, vec2 searchVec) { + vec2 absSearchVec = abs(searchVec); + int stepCount = int(max(absSearchVec.x, absSearchVec.y)); float cosHorizonAngle = 0.0; if (stepCount>0) { - vec2 deltaPixelTap = clampedSearchVec / float(stepCount); - float searchRadius = length(clampedSearchVec); + vec2 deltaPixelTap = searchVec / float(stepCount); + float searchRadius = length(searchVec); float deltaRadius = searchRadius / float(stepCount); vec2 tapPixelPos = vec2(0); -#if !SSAO_LINEAR_SAMPLING +#if SSAO_LINEAR_SAMPLING + float radius = 0.0; + int stepIndex; + + for (stepIndex=0 ; stepIndex + } +#else float radius = deltaRadius; float mipLevel = evalMipFromRadius(radius * float(doFetchMips())); @@ -364,44 +378,24 @@ float computeHorizon(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 delt } radius += deltaRadius; } -#else - float radius = 0.0; - int stepIndex; - - for (stepIndex=0 ; stepIndex - } #endif } return cosHorizonAngle; } -vec2 searchHorizons(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 deltaTap, float ssDiskRadius, - vec3 fragPositionES, vec3 fragNormalES) { - vec2 searchVec = deltaTap * ssDiskRadius; - vec2 horizons = vec2(0.0); +float evalVisibilityHBAO(ivec4 side, ivec2 shadedPixelPos, vec2 sideImageSize, vec2 deltaTap, float diskPixelRadius, + vec3 fragPositionES, vec3 fragNormalES) { + vec2 searchVec = deltaTap * diskPixelRadius; + float obscurance; // Forward search for h1 - vec2 clampedSearchVec = clampSearchVec(imageSize, vec2(centerPixelPos), searchVec); - horizons.x = computeHorizon(side, centerPixelPos, imageSize, deltaTap, ssDiskRadius, - fragPositionES, fragNormalES, clampedSearchVec); + obscurance = computeHorizon(side, shadedPixelPos, sideImageSize, deltaTap, fragPositionES, fragNormalES, searchVec); // Backward search for h2 - clampedSearchVec = clampSearchVec(imageSize, vec2(centerPixelPos), -searchVec); - horizons.y = computeHorizon(side, centerPixelPos, imageSize, deltaTap, ssDiskRadius, - fragPositionES, fragNormalES, clampedSearchVec); + obscurance += computeHorizon(side, shadedPixelPos, sideImageSize, deltaTap, fragPositionES, fragNormalES, -searchVec); - return horizons; -} - -float evalVisibilityHBAO(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 deltaTap, float ssDiskRadius, - vec3 fragPositionES, vec3 fragNormalES) { - vec2 horizons = searchHorizons(side, centerPixelPos, imageSize, deltaTap, ssDiskRadius, fragPositionES, fragNormalES); - return (horizons.x + horizons.y) * 0.5 / PI; + return obscurance * 0.5 / PI; } <@endfunc@> diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index ee22590679..1a31950b7f 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -25,62 +25,63 @@ layout(location=0) out vec4 outFragColor; void main(void) { - vec2 imageSize = getSideImageSize(getResolutionLevel()); + vec2 sideImageSize = getSideImageSize(getResolutionLevel()); // Pixel being shaded vec2 fragCoord = gl_FragCoord.xy; - ivec2 centerPixelPos = ivec2(fragCoord.xy); + ivec2 shadedPixelPos = ivec2(fragCoord.xy); // Stereo side info - ivec4 side = getStereoSideInfo(centerPixelPos.x, getResolutionLevel()); + ivec4 side = getStereoSideInfo(shadedPixelPos.x, getResolutionLevel()); - // From now on, centerPixelPos is the pixel pos in the side - centerPixelPos.x -= side.y; - vec2 fragUVPos = (vec2(centerPixelPos) + vec2(0.5)) / imageSize; + // From now on, shadedPixelPos is the pixel pos in the side + shadedPixelPos.x -= side.y; + vec2 shadedUVPos = (vec2(shadedPixelPos) + vec2(0.5)) / sideImageSize; // Fetch the z under the pixel (stereo or not) - float Zeye = getZEyeAtUV(fragUVPos, 0); + float Zeye = getZEyeAtUV(shadedUVPos, 0); // The position and normal of the pixel fragment in Eye space - vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); + vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, shadedUVPos); vec3 fragNormalES = evalEyeNormal(fragPositionES); // Choose the screen-space sample radius - float ssDiskRadius = evalDiskRadius(fragPositionES.z, imageSize); + float diskPixelRadius = evalDiskRadius(fragPositionES.z, sideImageSize); #if SSAO_USE_HORIZON_BASED - ssDiskRadius = min(ssDiskRadius, SSAO_HBAO_MAX_RADIUS); + diskPixelRadius = min(diskPixelRadius, SSAO_HBAO_MAX_RADIUS); #endif // Let's make noise - float randomPatternRotationAngle = getAngleDithering(centerPixelPos); + float randomPatternRotationAngle = getAngleDithering(shadedPixelPos); - // Accumulate the visibility for each samples - float visibilitySum = 0.0; + // Accumulate the obscurance for each samples + float obscuranceSum = 0.0; int numSamples = int(getNumSamples()); for (int i = 0; i < numSamples; ++i) { #if SSAO_USE_HORIZON_BASED vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); - visibilitySum += evalVisibilityHBAO(side, centerPixelPos, imageSize, deltaTap.xy, ssDiskRadius, fragPositionES, fragNormalES); + obscuranceSum += evalVisibilityHBAO(side, shadedPixelPos, sideImageSize, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); #else - vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, ssDiskRadius, centerPixelPos, imageSize); - vec3 tapUVZ = fetchTap(side, centerPixelPos, tap, imageSize); + vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, shadedPixelPos, sideImageSize); + vec3 tapUVZ = fetchTap(side, shadedPixelPos, tap, sideImageSize); vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); - visibilitySum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES); + obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES); #endif } - float occlusion = clamp(1.0 - visibilitySum * getObscuranceScaling() * getInvNumSamples(), 0.0, 1.0); + float occlusion = clamp(1.0 - obscuranceSum * getObscuranceScaling() * getInvNumSamples(), 0.0, 1.0); // KEEP IT for Debugging // Bilateral box-filter over a quad for free, respecting depth edges // (the difference that this makes is subtle) /* if (abs(dFdx(fragPositionES.z)) < 0.02) { - occlusion -= dFdx(occlusion) * ((centerPixelPos.x & 1) - 0.5); + occlusion -= dFdx(occlusion) * ((shadedPixelPos.x & 1) - 0.5); } if (abs(dFdy(fragPositionES.z)) < 0.02) { - occlusion -= dFdy(occlusion) * ((centerPixelPos.y & 1) - 0.5); + occlusion -= dFdy(occlusion) * ((shadedPixelPos.y & 1) - 0.5); }*/ //outFragColor = vec4(packOcclusionDepth(occlusion, CSZToDepthKey(fragPositionES.z)), 1.0); outFragColor = vec4(vec3(occlusion), 1.0); + } From c27f3dcafe5d367eff97ad67ac15fa44ec792c92 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 18 Sep 2018 08:45:04 +0200 Subject: [PATCH 20/81] Some cleanup, still trying to solve the problem --- .../src/AmbientOcclusionEffect.cpp | 2 +- .../render-utils/src/DebugDeferredBuffer.cpp | 2 +- .../render-utils/src/DebugDeferredBuffer.h | 4 +- libraries/render-utils/src/ssao.slh | 70 ++++++------------- .../render-utils/src/ssao_makeOcclusion.slf | 7 +- ...ip_depth_median.slf => ssao_mip_depth.slf} | 13 ++-- scripts/developer/utilities/render/luci.js | 8 +-- 7 files changed, 43 insertions(+), 63 deletions(-) rename libraries/render-utils/src/{mip_depth_median.slf => ssao_mip_depth.slf} (77%) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 70f36521d8..8e50eeb7c9 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -375,7 +375,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { const gpu::PipelinePointer& AmbientOcclusionEffect::getMipCreationPipeline() { if (!_mipCreationPipeline) { - _mipCreationPipeline = gpu::Context::createMipGenerationPipeline(gpu::Shader::createPixel(shader::render_utils::fragment::mip_depth_median)); + _mipCreationPipeline = gpu::Context::createMipGenerationPipeline(gpu::Shader::createPixel(shader::render_utils::fragment::ssao_mip_depth)); } return _mipCreationPipeline; } diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 848c10597a..4a8fad7c6d 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -384,7 +384,7 @@ void DebugDeferredBuffer::configure(const Config& config) { auto& parameters = _parameters.edit(); _mode = (Mode)config.mode; - _size = config.size; + _size = glm::vec4{config.debugCursorTexcoord.x*2.0f - 1.0f, -1.0f, 1.0f, 1.0f}; parameters._shadowCascadeIndex = glm::clamp(_mode - Mode::ShadowCascade0Mode, 0, (int)SHADOW_CASCADE_MAX_COUNT - 1); } diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index 9daa8fd530..0fc006b452 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -25,14 +25,14 @@ class DebugDeferredBufferConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(bool enabled MEMBER enabled) Q_PROPERTY(int mode MEMBER mode WRITE setMode) - Q_PROPERTY(glm::vec4 size MEMBER size NOTIFY dirty) + Q_PROPERTY(glm::vec2 debugCursorTexcoord MEMBER debugCursorTexcoord NOTIFY dirty) public: DebugDeferredBufferConfig() : render::Job::Config(false) {} void setMode(int newMode); int mode{ 0 }; - glm::vec4 size{ 0.0f, -1.0f, 1.0f, 1.0f }; + glm::vec2 debugCursorTexcoord{ 0.5f, 0.5f }; signals: void dirty(); }; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index b441d7ca8c..ab728553f1 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -249,14 +249,12 @@ vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 sideImageSize) { return P; } -vec4 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 sideImageSize) { - int mipLevel = evalMipFromRadius(tap.z * float(doFetchMips())); - - vec2 ssP = tap.xy + vec2(ssC); +vec4 fetchTap(ivec4 side, vec2 tapPixelPos, float tapRadius, vec2 sideImageSize) { + int mipLevel = evalMipFromRadius(tapRadius * float(doFetchMips())); // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. // Manually clamp to the texture size because texelFetch bypasses the texture unit - vec2 tapUV = (vec2(ssP) + vec2(0.5)) / sideImageSize; + vec2 tapUV = (tapPixelPos + vec2(0.5)) / sideImageSize; vec2 fetchUV = vec2(tapUV.x + side.w * 0.5 * (side.x - tapUV.x), tapUV.y); vec4 P; @@ -293,44 +291,21 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES) { vec3 deltaVec = tapPositionES - fragPositionES; float distanceSquared = dot(deltaVec, deltaVec); - float horizon = dot(normalize(deltaVec), fragNormalES); + float cosHorizonAngle = dot(normalize(deltaVec), fragNormalES); float radiusFalloff = max(0.0, 1.0 - (distanceSquared / getRadius2())); - horizon = max(0.0, (horizon - getFalloffAngle()) / (1.0 - getFalloffAngle())); - horizon *= radiusFalloff; + cosHorizonAngle = max(0.0, (cosHorizonAngle - getFalloffAngle()) / (1.0 - getFalloffAngle())); + cosHorizonAngle *= radiusFalloff; - return horizon; -} - -vec2 clampSearchVector(vec2 sideImageSize, vec2 shadedPixelPos, vec2 searchVec) { - vec2 clampedSearchVec = searchVec; - vec2 endPixel = shadedPixelPos + clampedSearchVec; - - if (endPixel.x < 0) { - clampedSearchVec *= ((0-shadedPixelPos.x) / clampedSearchVec.x); - endPixel = shadedPixelPos + clampedSearchVec; - } - if (endPixel.x > (sideImageSize.x-1)) { - clampedSearchVec *= ((sideImageSize.x-1-shadedPixelPos.x) / clampedSearchVec.x); - endPixel = shadedPixelPos + clampedSearchVec; - } - if (endPixel.y < 0) { - clampedSearchVec *= ((0-shadedPixelPos.y) / clampedSearchVec.y); - endPixel = shadedPixelPos + clampedSearchVec; - } - if (endPixel.y > (sideImageSize.y-1)) { - clampedSearchVec *= ((sideImageSize.y-1-shadedPixelPos.y) / clampedSearchVec.y); - } - - return clampedSearchVec; + return cosHorizonAngle; } <@func computeHorizon()@> - if (tapPixelPos.x>=0 && tapPixelPos.y>=0 && tapPixelPos.x=sideImageSize.x && tapPixelPos.y>=sideImageSize.y) { break; } - vec3 tap = vec3(tapPixelPos, radius); - vec4 tapUVZ_mip = fetchTap(side, shadedPixelPos, tap, sideImageSize); + vec4 tapUVZ_mip = fetchTap(side, tapPixelPos, radius, sideImageSize); vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ_mip.z, tapUVZ_mip.xy); float tapCosHorizonAngle = computeHorizonFromTap(tapPositionES, fragPositionES, fragNormalES); @@ -338,26 +313,25 @@ vec2 clampSearchVector(vec2 sideImageSize, vec2 shadedPixelPos, vec2 searchVec) <@endfunc@> -#define SSAO_LINEAR_SAMPLING 1 +#define SSAO_LINEAR_SEARCH_HORIZON 1 -float computeHorizon(ivec4 side, ivec2 shadedPixelPos, vec2 sideImageSize, vec2 deltaTap, - vec3 fragPositionES, vec3 fragNormalES, vec2 searchVec) { +float computeHorizon(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, vec2 deltaTap, + vec3 fragPositionES, vec3 fragNormalES, vec2 searchVec, float searchRadius) { vec2 absSearchVec = abs(searchVec); - int stepCount = int(max(absSearchVec.x, absSearchVec.y)); + int stepCount = int(ceil(max(absSearchVec.x, absSearchVec.y))); float cosHorizonAngle = 0.0; if (stepCount>0) { vec2 deltaPixelTap = searchVec / float(stepCount); - float searchRadius = length(searchVec); float deltaRadius = searchRadius / float(stepCount); - vec2 tapPixelPos = vec2(0); + vec2 tapPixelOffset = vec2(0); -#if SSAO_LINEAR_SAMPLING +#if SSAO_LINEAR_SEARCH_HORIZON float radius = 0.0; int stepIndex; for (stepIndex=0 ; stepIndex @@ -366,8 +340,8 @@ float computeHorizon(ivec4 side, ivec2 shadedPixelPos, vec2 sideImageSize, vec2 float radius = deltaRadius; float mipLevel = evalMipFromRadius(radius * float(doFetchMips())); - while (radius @@ -384,16 +358,16 @@ float computeHorizon(ivec4 side, ivec2 shadedPixelPos, vec2 sideImageSize, vec2 return cosHorizonAngle; } -float evalVisibilityHBAO(ivec4 side, ivec2 shadedPixelPos, vec2 sideImageSize, vec2 deltaTap, float diskPixelRadius, +float evalVisibilityHBAO(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, vec2 deltaTap, float diskPixelRadius, vec3 fragPositionES, vec3 fragNormalES) { vec2 searchVec = deltaTap * diskPixelRadius; float obscurance; // Forward search for h1 - obscurance = computeHorizon(side, shadedPixelPos, sideImageSize, deltaTap, fragPositionES, fragNormalES, searchVec); + obscurance = computeHorizon(side, shadedPixelPos, sideImageSize, deltaTap, fragPositionES, fragNormalES, searchVec, diskPixelRadius); // Backward search for h2 - obscurance += computeHorizon(side, shadedPixelPos, sideImageSize, deltaTap, fragPositionES, fragNormalES, -searchVec); + obscurance += computeHorizon(side, shadedPixelPos, sideImageSize, deltaTap, fragPositionES, fragNormalES, -searchVec, diskPixelRadius); return obscurance * 0.5 / PI; } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 1a31950b7f..a28b06cea1 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -60,10 +60,13 @@ void main(void) { for (int i = 0; i < numSamples; ++i) { #if SSAO_USE_HORIZON_BASED vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); - obscuranceSum += evalVisibilityHBAO(side, shadedPixelPos, sideImageSize, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); + // TEMPO OP + deltaTap.xy = vec2(1,0); + obscuranceSum += evalVisibilityHBAO(side, vec2(shadedPixelPos), sideImageSize, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); #else vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, shadedPixelPos, sideImageSize); - vec3 tapUVZ = fetchTap(side, shadedPixelPos, tap, sideImageSize); + vec2 tapPixelPos = vec2(shadedPixelPos) + tap.xy; + vec3 tapUVZ = fetchTap(side, tapPixelPos, tap.z, sideImageSize); vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES); #endif diff --git a/libraries/render-utils/src/mip_depth_median.slf b/libraries/render-utils/src/ssao_mip_depth.slf similarity index 77% rename from libraries/render-utils/src/mip_depth_median.slf rename to libraries/render-utils/src/ssao_mip_depth.slf index 489573b519..6a72af704c 100644 --- a/libraries/render-utils/src/mip_depth_median.slf +++ b/libraries/render-utils/src/ssao_mip_depth.slf @@ -2,7 +2,7 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// mip_depth_median.frag +// ssao_mip_depth.frag // fragment shader // // Created by Olivier Prat on 4/18/18. @@ -22,7 +22,7 @@ void main(void) { vec4 depths = textureGather(depthTexture, varTexCoord0); // Order the depths from minimum to maximum - depths.xy = depths.x > depths.y ? depths.yx : depths.xy; +/* depths.xy = depths.x > depths.y ? depths.yx : depths.xy; depths.xz = depths.x > depths.z ? depths.zx : depths.xz; depths.xw = depths.x > depths.w ? depths.wx : depths.xw; @@ -31,6 +31,11 @@ void main(void) { depths.zw = depths.z > depths.w ? depths.wz : depths.zw; - float median = (depths.y + depths.z) / 2.0; - outFragColor = vec4(vec3(median), 1.0); + float outZ = (depths.y + depths.z) / 2.0;*/ + + float outZ = min(depths.x, depths.y); + outZ = min(outZ, depths.z); + outZ = min(outZ, depths.w); + + outFragColor = vec4(vec3(outZ), 1.0); } diff --git a/scripts/developer/utilities/render/luci.js b/scripts/developer/utilities/render/luci.js index 005d96780a..5ad2733dcd 100644 --- a/scripts/developer/utilities/render/luci.js +++ b/scripts/developer/utilities/render/luci.js @@ -78,13 +78,11 @@ Controller.mouseReleaseEvent.connect(function() { moveDebugCursor = false; }); Controller.mouseMoveEvent.connect(function (e) { if (moveDebugCursor) setDebugCursor(e.x, e.y); }); - - function setDebugCursor(x, y) { - nx = (x / Window.innerWidth); - ny = 1.0 - ((y) / (Window.innerHeight - 32)); + nx = ((x + 0.5) / Window.innerWidth); + ny = 1.0 - ((y + 0.5) / (Window.innerHeight)); - Render.getConfig("RenderMainView").getConfig("Antialiasing").debugCursorTexcoord = { x: nx, y: ny }; + Render.getConfig("RenderMainView").getConfig("DebugDeferredBuffer").debugCursorTexcoord = { x: nx, y: ny }; } From acc6d0b79eb6b4d26d4b8c5a44e6bd874e25cb83 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 18 Sep 2018 10:22:35 +0200 Subject: [PATCH 21/81] Fixed wrong AO with far objects! --- .../render-utils/src/SurfaceGeometryPass.cpp | 4 +-- libraries/render-utils/src/ssao.slh | 12 ++++---- .../render-utils/src/ssao_makeOcclusion.slf | 28 +++++++++---------- libraries/render-utils/src/ssao_mip_depth.slf | 9 ++---- 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index f22b8351d4..d2bff5b322 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -66,7 +66,7 @@ void LinearDepthFramebuffer::allocate() { // For Linear Depth: const uint16_t LINEAR_DEPTH_MAX_MIP_LEVEL = 5; _linearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), width, height, LINEAR_DEPTH_MAX_MIP_LEVEL, - gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT, gpu::Sampler::WRAP_CLAMP)); + gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP)); _linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("linearDepth")); _linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture); _linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat()); @@ -74,7 +74,7 @@ void LinearDepthFramebuffer::allocate() { // For Downsampling: const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = LINEAR_DEPTH_MAX_MIP_LEVEL; _halfLinearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), _halfFrameSize.x, _halfFrameSize.y, HALF_LINEAR_DEPTH_MAX_MIP_LEVEL, - gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT, gpu::Sampler::WRAP_CLAMP)); + gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP)); _halfNormalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _halfFrameSize.x, _halfFrameSize.y, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index ab728553f1..051f685e2d 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -226,7 +226,7 @@ float getZEyeAtUV(vec2 texCoord, int level) { return -texture(pyramidMap, texCoord, level).x; } -const int LOG_MAX_OFFSET = 1; +const int LOG_MAX_OFFSET = 2; const int MAX_MIP_LEVEL = 5; int evalMipFromRadius(float radius) { // mipLevel = floor(log(ssR / MAX_OFFSET)); @@ -289,10 +289,12 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t } float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES) { + const float epsilon = 0.01; + vec3 deltaVec = tapPositionES - fragPositionES; - float distanceSquared = dot(deltaVec, deltaVec); - float cosHorizonAngle = dot(normalize(deltaVec), fragNormalES); - float radiusFalloff = max(0.0, 1.0 - (distanceSquared / getRadius2())); + float distance = length(deltaVec); + float cosHorizonAngle = dot(deltaVec, fragNormalES) / (distance + epsilon); + float radiusFalloff = max(0.0, 1.0 - (distance*distance / getRadius2())); cosHorizonAngle = max(0.0, (cosHorizonAngle - getFalloffAngle()) / (1.0 - getFalloffAngle())); cosHorizonAngle *= radiusFalloff; @@ -313,7 +315,7 @@ float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNo <@endfunc@> -#define SSAO_LINEAR_SEARCH_HORIZON 1 +#define SSAO_LINEAR_SEARCH_HORIZON 0 float computeHorizon(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, vec2 deltaTap, vec3 fragPositionES, vec3 fragNormalES, vec2 searchVec, float searchRadius) { diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index a28b06cea1..94e87c75e0 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -29,20 +29,20 @@ void main(void) { // Pixel being shaded vec2 fragCoord = gl_FragCoord.xy; - ivec2 shadedPixelPos = ivec2(fragCoord.xy); + ivec2 fragPixelPos = ivec2(fragCoord.xy); // Stereo side info - ivec4 side = getStereoSideInfo(shadedPixelPos.x, getResolutionLevel()); + ivec4 side = getStereoSideInfo(fragPixelPos.x, getResolutionLevel()); - // From now on, shadedPixelPos is the pixel pos in the side - shadedPixelPos.x -= side.y; - vec2 shadedUVPos = (vec2(shadedPixelPos) + vec2(0.5)) / sideImageSize; + // From now on, fragPixelPos is the pixel pos in the side + fragPixelPos.x -= side.y; + vec2 fragUVPos = (vec2(fragPixelPos) + vec2(0.5)) / sideImageSize; // Fetch the z under the pixel (stereo or not) - float Zeye = getZEyeAtUV(shadedUVPos, 0); + float Zeye = getZEyeAtUV(fragUVPos, 0); // The position and normal of the pixel fragment in Eye space - vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, shadedUVPos); + vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); vec3 fragNormalES = evalEyeNormal(fragPositionES); // Choose the screen-space sample radius @@ -52,7 +52,7 @@ void main(void) { #endif // Let's make noise - float randomPatternRotationAngle = getAngleDithering(shadedPixelPos); + float randomPatternRotationAngle = getAngleDithering(fragPixelPos); // Accumulate the obscurance for each samples float obscuranceSum = 0.0; @@ -60,12 +60,10 @@ void main(void) { for (int i = 0; i < numSamples; ++i) { #if SSAO_USE_HORIZON_BASED vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); - // TEMPO OP - deltaTap.xy = vec2(1,0); - obscuranceSum += evalVisibilityHBAO(side, vec2(shadedPixelPos), sideImageSize, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); + obscuranceSum += evalVisibilityHBAO(side, vec2(fragPixelPos), sideImageSize, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); #else - vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, shadedPixelPos, sideImageSize); - vec2 tapPixelPos = vec2(shadedPixelPos) + tap.xy; + vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, fragPixelPos, sideImageSize); + vec2 tapPixelPos = vec2(fragPixelPos) + tap.xy; vec3 tapUVZ = fetchTap(side, tapPixelPos, tap.z, sideImageSize); vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES); @@ -78,10 +76,10 @@ void main(void) { // Bilateral box-filter over a quad for free, respecting depth edges // (the difference that this makes is subtle) /* if (abs(dFdx(fragPositionES.z)) < 0.02) { - occlusion -= dFdx(occlusion) * ((shadedPixelPos.x & 1) - 0.5); + occlusion -= dFdx(occlusion) * ((fragPixelPos.x & 1) - 0.5); } if (abs(dFdy(fragPositionES.z)) < 0.02) { - occlusion -= dFdy(occlusion) * ((shadedPixelPos.y & 1) - 0.5); + occlusion -= dFdy(occlusion) * ((fragPixelPos.y & 1) - 0.5); }*/ //outFragColor = vec4(packOcclusionDepth(occlusion, CSZToDepthKey(fragPositionES.z)), 1.0); diff --git a/libraries/render-utils/src/ssao_mip_depth.slf b/libraries/render-utils/src/ssao_mip_depth.slf index 6a72af704c..49f3d5254f 100644 --- a/libraries/render-utils/src/ssao_mip_depth.slf +++ b/libraries/render-utils/src/ssao_mip_depth.slf @@ -22,7 +22,7 @@ void main(void) { vec4 depths = textureGather(depthTexture, varTexCoord0); // Order the depths from minimum to maximum -/* depths.xy = depths.x > depths.y ? depths.yx : depths.xy; + depths.xy = depths.x > depths.y ? depths.yx : depths.xy; depths.xz = depths.x > depths.z ? depths.zx : depths.xz; depths.xw = depths.x > depths.w ? depths.wx : depths.xw; @@ -31,11 +31,8 @@ void main(void) { depths.zw = depths.z > depths.w ? depths.wz : depths.zw; - float outZ = (depths.y + depths.z) / 2.0;*/ - - float outZ = min(depths.x, depths.y); - outZ = min(outZ, depths.z); - outZ = min(outZ, depths.w); + // Take the median depth + float outZ = (depths.y + depths.z) / 2.0; outFragColor = vec4(vec3(outZ), 1.0); } From a2abf33669d944983cf997e7c713db14b1cbe515 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 18 Sep 2018 11:45:58 +0200 Subject: [PATCH 22/81] Removed falloff distance as we're directly using the radius --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 11 +++-------- libraries/render-utils/src/AmbientOcclusionEffect.h | 4 ---- libraries/render-utils/src/ssao.slh | 8 ++++---- .../utilities/render/ambientOcclusionPass.qml | 1 - 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 8e50eeb7c9..cca9997cf6 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -176,18 +176,17 @@ public: AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false), #if SSAO_USE_HORIZON_BASED - radius{ 0.1f }, + radius{ 0.3f }, #else radius{ 0.5f }, #endif perspectiveScale{ 1.0f }, obscuranceLevel{ 0.5f }, #if SSAO_USE_HORIZON_BASED - falloffAngle{ 0.1f }, + falloffAngle{ 0.2f }, #else falloffAngle{ 0.01f }, #endif - falloffDistance{ 0.3f }, edgeSharpness{ 1.0f }, blurDeviation{ 2.5f }, numSpiralTurns{ 7.0f }, @@ -242,6 +241,7 @@ void AmbientOcclusionEffect::configure(const Config& config) { if (config.falloffAngle != _aoParametersBuffer->getFalloffAngle()) { auto& current = _aoParametersBuffer.edit().ditheringInfo; current.z = config.falloffAngle; + current.y = 1.0f / (1.0f - config.falloffAngle); } if (config.edgeSharpness != _aoParametersBuffer->getEdgeSharpness()) { @@ -302,11 +302,6 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.w = (float)config.borderingEnabled; } - if (config.falloffDistance != _aoParametersBuffer->getFalloffDistance()) { - auto& current = _aoParametersBuffer.edit().ditheringInfo; - current.y = (float)config.falloffDistance; - } - if (shouldUpdateGaussian) { updateGaussianDistribution(); } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 81ceee9bf6..4021768995 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -63,7 +63,6 @@ class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent { Q_PROPERTY(float radius MEMBER radius WRITE setRadius) Q_PROPERTY(float obscuranceLevel MEMBER obscuranceLevel WRITE setObscuranceLevel) Q_PROPERTY(float falloffAngle MEMBER falloffAngle WRITE setFalloffAngle) - Q_PROPERTY(float falloffDistance MEMBER falloffDistance WRITE setFalloffDistance) Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness WRITE setEdgeSharpness) Q_PROPERTY(float blurDeviation MEMBER blurDeviation WRITE setBlurDeviation) Q_PROPERTY(float numSpiralTurns MEMBER numSpiralTurns WRITE setNumSpiralTurns) @@ -80,7 +79,6 @@ public: void setRadius(float newRadius) { radius = std::max(0.01f, newRadius); emit dirty(); } void setObscuranceLevel(float level) { obscuranceLevel = std::max(0.01f, level); emit dirty(); } void setFalloffAngle(float bias) { falloffAngle = std::max(0.0f, std::min(bias, 1.0f)); emit dirty(); } - void setFalloffDistance(float value) { falloffDistance = std::max(0.0f, value); emit dirty(); } void setEdgeSharpness(float sharpness) { edgeSharpness = std::max(0.0f, (float)sharpness); emit dirty(); } void setBlurDeviation(float deviation) { blurDeviation = std::max(0.0f, deviation); emit dirty(); } void setNumSpiralTurns(float turns) { numSpiralTurns = std::max(0.0f, (float)turns); emit dirty(); } @@ -92,7 +90,6 @@ public: float perspectiveScale; float obscuranceLevel; // intensify or dim down the obscurance effect float falloffAngle; - float falloffDistance; float edgeSharpness; float blurDeviation; float numSpiralTurns; // defining an angle span to distribute the samples ray directions @@ -144,7 +141,6 @@ public: float getPerspectiveScale() const { return resolutionInfo.z; } float getObscuranceLevel() const { return radiusInfo.w; } float getFalloffAngle() const { return (float)ditheringInfo.z; } - float getFalloffDistance() const { return ditheringInfo.y; } float getEdgeSharpness() const { return (float)blurInfo.x; } float getBlurDeviation() const { return blurInfo.z; } diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 051f685e2d..99d45647ee 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -75,9 +75,6 @@ float getObscuranceScaling() { float isDitheringEnabled() { return params._ditheringInfo.x; } -float getFalloffDistance() { - return params._ditheringInfo.y; -} float isBorderingEnabled() { return params._ditheringInfo.w; } @@ -85,6 +82,9 @@ float isBorderingEnabled() { float getFalloffAngle() { return params._ditheringInfo.z; } +float getFalloffAngleScale() { + return params._ditheringInfo.y; +} float getNumSamples() { return params._sampleInfo.x; @@ -296,7 +296,7 @@ float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNo float cosHorizonAngle = dot(deltaVec, fragNormalES) / (distance + epsilon); float radiusFalloff = max(0.0, 1.0 - (distance*distance / getRadius2())); - cosHorizonAngle = max(0.0, (cosHorizonAngle - getFalloffAngle()) / (1.0 - getFalloffAngle())); + cosHorizonAngle = max(0.0, (cosHorizonAngle - getFalloffAngle()) * getFalloffAngleScale()); cosHorizonAngle *= radiusFalloff; return cosHorizonAngle; diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index 0416443139..f92b469626 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -38,7 +38,6 @@ Rectangle { "Num Taps:numSamples:32:true", "Taps Spiral:numSpiralTurns:10.0:false", "Falloff Angle:falloffAngle:0.5:false", - "Falloff Distance:falloffDistance:2.0:false", "Blur Edge Sharpness:edgeSharpness:1.0:false", "Blur Radius:blurRadius:15.0:false", ] From f7379dfcc97f77e57655ddc1f2d8c96efb99955e Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 18 Sep 2018 11:54:39 +0200 Subject: [PATCH 23/81] Switched AO buffer to single R8 component --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 2 +- libraries/render-utils/src/ssao.slh | 5 +++-- libraries/render-utils/src/ssao_debugOcclusion.slf | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index cca9997cf6..dc08b9f28b 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -78,7 +78,7 @@ void AmbientOcclusionFramebuffer::allocate() { auto width = _frameSize.x; auto height = _frameSize.y; - auto format = gpu::Element::COLOR_RGBA_32; + auto format = gpu::Element::COLOR_R_8; _occlusionTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT, gpu::Sampler::WRAP_CLAMP)); _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 99d45647ee..5c03afc53c 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -229,7 +229,6 @@ float getZEyeAtUV(vec2 texCoord, int level) { const int LOG_MAX_OFFSET = 2; const int MAX_MIP_LEVEL = 5; int evalMipFromRadius(float radius) { - // mipLevel = floor(log(ssR / MAX_OFFSET)); return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); } @@ -293,12 +292,14 @@ float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNo vec3 deltaVec = tapPositionES - fragPositionES; float distance = length(deltaVec); - float cosHorizonAngle = dot(deltaVec, fragNormalES) / (distance + epsilon); + float cosHorizonAngle = 0.0; float radiusFalloff = max(0.0, 1.0 - (distance*distance / getRadius2())); + cosHorizonAngle = dot(deltaVec, fragNormalES) / (distance + epsilon); cosHorizonAngle = max(0.0, (cosHorizonAngle - getFalloffAngle()) * getFalloffAngleScale()); cosHorizonAngle *= radiusFalloff; + return cosHorizonAngle; } diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf index 92e5a28a0b..10069582aa 100644 --- a/libraries/render-utils/src/ssao_debugOcclusion.slf +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -82,7 +82,7 @@ void main(void) { // Accumulate the Obscurance for each samples float sum = 0.0; float keepTapRadius = 1.0; - int keepedMip = -1; + int keptMip = -1; bool keep = false; int sampleCount = int(getNumSamples()); for (int i = 0; i < sampleCount; ++i) { @@ -92,7 +92,7 @@ void main(void) { vec2 fragToTap = vec2(ssC) + tap.xy - fragCoord.xy; if (dot(fragToTap,fragToTap) < keepTapRadius) { keep = true; - keepedMip = evalMipFromRadius(tap.z * float(doFetchMips())); + keptMip = evalMipFromRadius(tap.z * float(doFetchMips())); } vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize); @@ -127,6 +127,6 @@ void main(void) { if (!keep) { outFragColor = vec4(0.1); } else { - outFragColor.rgb = colorWheel(float(keepedMip)/float(MAX_MIP_LEVEL)); + outFragColor.rgb = colorWheel(float(keptMip)/float(MAX_MIP_LEVEL)); } } From fb7a8bdd4dc1baf40944bde4622c51fdb839195d Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 18 Sep 2018 12:13:49 +0200 Subject: [PATCH 24/81] Mip depth sampling in HBAO now works --- .../render-utils/src/SurfaceGeometryPass.cpp | 6 ++++-- libraries/render-utils/src/ssao.slh | 7 ++++--- libraries/render-utils/src/ssao_mip_depth.slf | 15 ++------------- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index d2bff5b322..6f455c2dbb 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -65,8 +65,10 @@ void LinearDepthFramebuffer::allocate() { // For Linear Depth: const uint16_t LINEAR_DEPTH_MAX_MIP_LEVEL = 5; + // Point sampling of the depth is need for the AmbientOcclusionEffect in HBAO, as well as the clamp to edge + const auto depthSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP); _linearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), width, height, LINEAR_DEPTH_MAX_MIP_LEVEL, - gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP)); + depthSampler); _linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("linearDepth")); _linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture); _linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat()); @@ -74,7 +76,7 @@ void LinearDepthFramebuffer::allocate() { // For Downsampling: const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = LINEAR_DEPTH_MAX_MIP_LEVEL; _halfLinearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), _halfFrameSize.x, _halfFrameSize.y, HALF_LINEAR_DEPTH_MAX_MIP_LEVEL, - gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP)); + depthSampler); _halfNormalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _halfFrameSize.x, _halfFrameSize.y, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 5c03afc53c..d9915f6de9 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -226,7 +226,7 @@ float getZEyeAtUV(vec2 texCoord, int level) { return -texture(pyramidMap, texCoord, level).x; } -const int LOG_MAX_OFFSET = 2; +const int LOG_MAX_OFFSET = 1; const int MAX_MIP_LEVEL = 5; int evalMipFromRadius(float radius) { return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); @@ -316,7 +316,7 @@ float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNo <@endfunc@> -#define SSAO_LINEAR_SEARCH_HORIZON 0 +#define HBAO_HORIZON_SEARCH_CONSTANT_STEP 0 float computeHorizon(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, vec2 deltaTap, vec3 fragPositionES, vec3 fragNormalES, vec2 searchVec, float searchRadius) { @@ -329,7 +329,7 @@ float computeHorizon(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, vec2 d float deltaRadius = searchRadius / float(stepCount); vec2 tapPixelOffset = vec2(0); -#if SSAO_LINEAR_SEARCH_HORIZON +#if HBAO_HORIZON_SEARCH_CONSTANT_STEP float radius = 0.0; int stepIndex; @@ -339,6 +339,7 @@ float computeHorizon(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, vec2 d <$computeHorizon()$> } +// Step is adapted to Mip level #else float radius = deltaRadius; float mipLevel = evalMipFromRadius(radius * float(doFetchMips())); diff --git a/libraries/render-utils/src/ssao_mip_depth.slf b/libraries/render-utils/src/ssao_mip_depth.slf index 49f3d5254f..c028ba3ec9 100644 --- a/libraries/render-utils/src/ssao_mip_depth.slf +++ b/libraries/render-utils/src/ssao_mip_depth.slf @@ -20,19 +20,8 @@ out vec4 outFragColor; void main(void) { vec4 depths = textureGather(depthTexture, varTexCoord0); - - // Order the depths from minimum to maximum - depths.xy = depths.x > depths.y ? depths.yx : depths.xy; - depths.xz = depths.x > depths.z ? depths.zx : depths.xz; - depths.xw = depths.x > depths.w ? depths.wx : depths.xw; - - depths.yz = depths.y > depths.z ? depths.zy : depths.yz; - depths.yw = depths.y > depths.w ? depths.wy : depths.yw; - - depths.zw = depths.z > depths.w ? depths.wz : depths.zw; - - // Take the median depth - float outZ = (depths.y + depths.z) / 2.0; + // Keep the minimum depth + float outZ = min(depths.w, min(depths.z, min(depths.x, depths.y))); outFragColor = vec4(vec3(outZ), 1.0); } From 60418b36d76da9f02db7b3236e90271e662b32aa Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 18 Sep 2018 15:18:06 +0200 Subject: [PATCH 25/81] Preparing for halton taps --- .../src/AmbientOcclusionEffect.cpp | 23 +++++++++-------- .../render-utils/src/SurfaceGeometryPass.cpp | 11 ++++---- .../render-utils/src/SurfaceGeometryPass.h | 7 +++--- .../src/render-utils/ShaderConstants.h | 4 +-- libraries/render-utils/src/ssao.slh | 25 +++++++++---------- .../surfaceGeometry_downsampleDepthNormal.slf | 2 -- 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index dc08b9f28b..140833abec 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -183,7 +183,7 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : perspectiveScale{ 1.0f }, obscuranceLevel{ 0.5f }, #if SSAO_USE_HORIZON_BASED - falloffAngle{ 0.2f }, + falloffAngle{ 0.3f }, #else falloffAngle{ 0.01f }, #endif @@ -390,6 +390,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte const auto& linearDepthFramebuffer = inputs.get2(); auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); + auto occlusionDepthTexture = linearDepthTexture; auto sourceViewport = args->_viewport; auto occlusionViewport = sourceViewport; auto firstBlurViewport = sourceViewport; @@ -406,6 +407,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte if (_aoParametersBuffer->getResolutionLevel() > 0) { occlusionViewport = occlusionViewport >> _aoParametersBuffer->getResolutionLevel(); firstBlurViewport.w = firstBlurViewport.w >> _aoParametersBuffer->getResolutionLevel(); + occlusionDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); } if (_framebuffer->updateLinearDepth(linearDepthTexture)) { @@ -444,21 +446,20 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setModelTransform(model); #if SSAO_USE_HORIZON_BASED batch.setPipeline(mipCreationPipeline); - batch.generateTextureMipsWithPipeline(_framebuffer->getLinearDepthTexture()); + batch.generateTextureMipsWithPipeline(occlusionDepthTexture); #else - batch.generateTextureMips(_framebuffer->getLinearDepthTexture()); + batch.generateTextureMips(occlusionDepthTexture); #endif batch.popProfileRange(); + // Occlusion pass batch.pushProfileRange("Occlusion"); batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); - - // Occlusion pass + batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); batch.setFramebuffer(occlusionFBO); batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(1.0f)); batch.setPipeline(occlusionPipeline); - batch.setResourceTexture(render_utils::slot::texture::SsaoPyramid, _framebuffer->getLinearDepthTexture()); + batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, occlusionDepthTexture); batch.draw(gpu::TRIANGLE_STRIP, 4); batch.popProfileRange(); @@ -469,6 +470,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setModelTransform(model); batch.setViewportTransform(firstBlurViewport); batch.setFramebuffer(occlusionBlurredFBO); + // Use full resolution depth and normal for bilateral upscaling and blur + batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _hblurParametersBuffer); batch.setPipeline(firstHBlurPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionFBO->getRenderBuffer(0)); @@ -485,7 +488,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.draw(gpu::TRIANGLE_STRIP, 4); } - batch.setResourceTexture(render_utils::slot::texture::SsaoPyramid, nullptr); + batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, nullptr); batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, nullptr); _gpuTimer->end(batch); @@ -581,11 +584,11 @@ void DebugAmbientOcclusion::run(const render::RenderContextPointer& renderContex batch.setUniformBuffer(render_utils::slot::buffer::SsaoDebugParams, _parametersBuffer); batch.setPipeline(debugPipeline); - batch.setResourceTexture(render_utils::slot::texture::SsaoPyramid, linearDepthTexture); + batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); batch.draw(gpu::TRIANGLE_STRIP, 4); - batch.setResourceTexture(render_utils::slot::texture::SsaoPyramid, nullptr); + batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, nullptr); }); } diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index 6f455c2dbb..bf90aa3b22 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -28,10 +28,10 @@ namespace ru { LinearDepthFramebuffer::LinearDepthFramebuffer() { } -void LinearDepthFramebuffer::updatePrimaryDepth(const gpu::TexturePointer& depthBuffer) { +void LinearDepthFramebuffer::update(const gpu::TexturePointer& depthBuffer) { //If the depth buffer or size changed, we need to delete our FBOs bool reset = false; - if ((_primaryDepthTexture != depthBuffer)) { + if (_primaryDepthTexture != depthBuffer) { _primaryDepthTexture = depthBuffer; reset = true; } @@ -144,11 +144,12 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con if (!_linearDepthFramebuffer) { _linearDepthFramebuffer = std::make_shared(); } - _linearDepthFramebuffer->updatePrimaryDepth(deferredFramebuffer->getPrimaryDepthTexture()); auto depthBuffer = deferredFramebuffer->getPrimaryDepthTexture(); auto normalTexture = deferredFramebuffer->getDeferredNormalTexture(); + _linearDepthFramebuffer->update(depthBuffer); + auto linearDepthFBO = _linearDepthFramebuffer->getLinearDepthFramebuffer(); auto linearDepthTexture = _linearDepthFramebuffer->getLinearDepthTexture(); @@ -247,7 +248,7 @@ const gpu::PipelinePointer& LinearDepthPass::getDownsamplePipeline(const render: SurfaceGeometryFramebuffer::SurfaceGeometryFramebuffer() { } -void SurfaceGeometryFramebuffer::updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer) { +void SurfaceGeometryFramebuffer::update(const gpu::TexturePointer& linearDepthBuffer) { //If the depth buffer or size changed, we need to delete our FBOs bool reset = false; if ((_linearDepthTexture != linearDepthBuffer)) { @@ -414,7 +415,7 @@ void SurfaceGeometryPass::run(const render::RenderContextPointer& renderContext, if (!_surfaceGeometryFramebuffer) { _surfaceGeometryFramebuffer = std::make_shared(); } - _surfaceGeometryFramebuffer->updateLinearDepth(linearDepthTexture); + _surfaceGeometryFramebuffer->update(linearDepthTexture); auto curvatureFramebuffer = _surfaceGeometryFramebuffer->getCurvatureFramebuffer(); auto curvatureTexture = _surfaceGeometryFramebuffer->getCurvatureTexture(); diff --git a/libraries/render-utils/src/SurfaceGeometryPass.h b/libraries/render-utils/src/SurfaceGeometryPass.h index 367f599f67..1d8f77e67d 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.h +++ b/libraries/render-utils/src/SurfaceGeometryPass.h @@ -34,11 +34,10 @@ public: gpu::TexturePointer getHalfNormalTexture(); // Update the depth buffer which will drive the allocation of all the other resources according to its size. - void updatePrimaryDepth(const gpu::TexturePointer& depthBuffer); - gpu::TexturePointer getPrimaryDepthTexture(); + void update(const gpu::TexturePointer& depthBuffer); const glm::ivec2& getDepthFrameSize() const { return _frameSize; } - void setResolutionLevel(int level); + void setResolutionLevel(int level) { _resolutionLevel = std::max(0, level); } int getResolutionLevel() const { return _resolutionLevel; } protected: @@ -107,7 +106,7 @@ public: gpu::TexturePointer getBlurringTexture(); // Update the source framebuffer size which will drive the allocation of all the other resources. - void updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer); + void update(const gpu::TexturePointer& linearDepthBuffer); gpu::TexturePointer getLinearDepthTexture(); const glm::ivec2& getSourceFrameSize() const { return _frameSize; } diff --git a/libraries/render-utils/src/render-utils/ShaderConstants.h b/libraries/render-utils/src/render-utils/ShaderConstants.h index 3aeb3a73c8..c6bdfb759c 100644 --- a/libraries/render-utils/src/render-utils/ShaderConstants.h +++ b/libraries/render-utils/src/render-utils/ShaderConstants.h @@ -87,7 +87,7 @@ #define RENDER_UTILS_BUFFER_SSAO_PARAMS 2 #define RENDER_UTILS_BUFFER_SSAO_DEBUG_PARAMS 3 #define RENDER_UTILS_BUFFER_SSAO_BLUR_PARAMS 4 -#define RENDER_UTILS_TEXTURE_SSAO_PYRAMID 1 +#define RENDER_UTILS_TEXTURE_SSAO_DEPTH 1 #define RENDER_UTILS_TEXTURE_SSAO_OCCLUSION 0 // Temporal anti-aliasing @@ -193,7 +193,7 @@ enum Texture { TaaDepth = RENDER_UTILS_TEXTURE_TAA_DEPTH, TaaNext = RENDER_UTILS_TEXTURE_TAA_NEXT, SsaoOcclusion = RENDER_UTILS_TEXTURE_SSAO_OCCLUSION, - SsaoPyramid = RENDER_UTILS_TEXTURE_SSAO_PYRAMID, + SsaoDepth = RENDER_UTILS_TEXTURE_SSAO_DEPTH, HighlightSceneDepth = RENDER_UTILS_TEXTURE_HIGHLIGHT_SCENE_DEPTH, HighlightDepth = RENDER_UTILS_TEXTURE_HIGHLIGHT_DEPTH, SurfaceGeometryDepth = RENDER_UTILS_TEXTURE_SG_DEPTH, diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index d9915f6de9..8a2b1ba0e2 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -216,14 +216,14 @@ vec3 getTapLocationClampedSSAO(int sampleNumber, float spinAngle, float outerRad <@func declareFetchDepthPyramidMap()@> // the depth pyramid texture -layout(binding=RENDER_UTILS_TEXTURE_SSAO_PYRAMID) uniform sampler2D pyramidMap; +layout(binding=RENDER_UTILS_TEXTURE_SSAO_DEPTH) uniform sampler2D depthPyramidTex; float getZEyeAtPixel(ivec2 pixel, int level) { - return -texelFetch(pyramidMap, pixel, level).x; + return -texelFetch(depthPyramidTex, pixel, level).x; } float getZEyeAtUV(vec2 texCoord, int level) { - return -texture(pyramidMap, texCoord, level).x; + return -texture(depthPyramidTex, texCoord, level).x; } const int LOG_MAX_OFFSET = 1; @@ -243,7 +243,7 @@ vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 sideImageSize) { vec3 P; P.xy = tapUV; - P.z = -texture(pyramidMap, fetchUV).x; + P.z = -texture(depthPyramidTex, fetchUV).x; return P; } @@ -259,7 +259,7 @@ vec4 fetchTap(ivec4 side, vec2 tapPixelPos, float tapRadius, vec2 sideImageSize) vec4 P; P.xy = tapUV; P.w = float(mipLevel); - P.z = -textureLod(pyramidMap, fetchUV, P.w).x; + P.z = -textureLod(depthPyramidTex, fetchUV, P.w).x; return P; } @@ -413,9 +413,9 @@ float fetchOcclusion(vec2 coords) { } const float BLUR_WEIGHT_OFFSET = 0.01; -const float BLUR_EDGE_SCALE = 300.0; +const float BLUR_EDGE_DISTANCE_SCALE = 300.0; -vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float key) { +vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float fragDepth, vec3 fragNormal) { ivec2 tapOffset = <$axis$> * r; ivec2 tapPixelCoord = destPixelCoord + tapOffset; @@ -432,9 +432,8 @@ vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTe float weight = BLUR_WEIGHT_OFFSET + getBlurCoef(abs(r)); // range domain (the "bilateral" weight). As depth difference increases, decrease weight. -// weight *= max(0.0, 1.0 - (getBlurEdgeSharpness() * BLUR_EDGE_SCALE) * abs(tapDepth - key)); - float zDistance = tapDepth - key; - weight *= exp(-(getBlurEdgeSharpness() * BLUR_EDGE_SCALE) * zDistance * zDistance); + float zDistance = tapDepth - fragDepth; + weight *= exp(-getBlurEdgeSharpness() * (zDistance * zDistance * BLUR_EDGE_DISTANCE_SCALE)); return vec2(tapOcclusion * weight, weight); } @@ -443,14 +442,14 @@ vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTex // Stereo side info ivec4 side = getStereoSideInfo(destPixelCoord.x, 0); - float pixelDepth = getZEyeAtUV(fullTexCoord, 0); + float fragDepth = getZEyeAtUV(fullTexCoord, 0); vec2 weightedSums = vec2(0.0); // Accumulate weighted contributions along the bluring axis in the [-radius, radius] range int blurRadius = getBlurRadius(); // negative side first for (int r = -blurRadius; r <= -1; ++r) { - weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, pixelDepth); + weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth); } // Central pixel contribution @@ -460,7 +459,7 @@ vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTex // then positive side for (int r = 1; r <= blurRadius; ++r) { - weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, pixelDepth); + weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth); } // Final normalization diff --git a/libraries/render-utils/src/surfaceGeometry_downsampleDepthNormal.slf b/libraries/render-utils/src/surfaceGeometry_downsampleDepthNormal.slf index 34e78ea4ff..9f82f9138a 100644 --- a/libraries/render-utils/src/surfaceGeometry_downsampleDepthNormal.slf +++ b/libraries/render-utils/src/surfaceGeometry_downsampleDepthNormal.slf @@ -26,9 +26,7 @@ layout(location=1) out vec4 outNormal; void main(void) { // Gather 2 by 2 quads from texture and downsample - // Try different filters for Z vec4 Zeyes = textureGather(linearDepthMap, varTexCoord0, 0); - // float Zeye = texture(linearDepthMap, varTexCoord0).x; vec4 rawNormalsX = textureGather(normalMap, varTexCoord0, 0); vec4 rawNormalsY = textureGather(normalMap, varTexCoord0, 1); From 9141be91244ff37683f24e048e5d2fc6318014c6 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 18 Sep 2018 15:29:27 +0200 Subject: [PATCH 26/81] Shader compile fix --- .../src/AmbientOcclusionEffect.cpp | 2 +- libraries/render-utils/src/ssao.slh | 22 +++---------------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 140833abec..66e59ddad0 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -42,7 +42,7 @@ AmbientOcclusionFramebuffer::AmbientOcclusionFramebuffer() { } bool AmbientOcclusionFramebuffer::updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer) { - //If the depth buffer or size changed, we need to delete our FBOs + // If the depth buffer or size changed, we need to delete our FBOs bool reset = false; if ((_linearDepthTexture != linearDepthBuffer)) { _linearDepthTexture = linearDepthBuffer; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 8a2b1ba0e2..63dadc9bec 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -226,28 +226,12 @@ float getZEyeAtUV(vec2 texCoord, int level) { return -texture(depthPyramidTex, texCoord, level).x; } -const int LOG_MAX_OFFSET = 1; -const int MAX_MIP_LEVEL = 5; int evalMipFromRadius(float radius) { + const int LOG_MAX_OFFSET = 1; + const int MAX_MIP_LEVEL = 5; return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); } -vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 sideImageSize) { - ivec2 ssP = ivec2(tap.xy) + ssC; - ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y); - - - vec2 tapUV = (vec2(ssP) + vec2(0.5)) / sideImageSize; - - vec2 fetchUV = vec2(tapUV.x + float(side.w) * 0.5 * (float(side.x) - tapUV.x), tapUV.y); - - vec3 P; - P.xy = tapUV; - P.z = -texture(depthPyramidTex, fetchUV).x; - - return P; -} - vec4 fetchTap(ivec4 side, vec2 tapPixelPos, float tapRadius, vec2 sideImageSize) { int mipLevel = evalMipFromRadius(tapRadius * float(doFetchMips())); @@ -415,7 +399,7 @@ float fetchOcclusion(vec2 coords) { const float BLUR_WEIGHT_OFFSET = 0.01; const float BLUR_EDGE_DISTANCE_SCALE = 300.0; -vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float fragDepth, vec3 fragNormal) { +vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float fragDepth) { ivec2 tapOffset = <$axis$> * r; ivec2 tapPixelCoord = destPixelCoord + tapOffset; From 3d096d064438ff3eac10cbd89bf6b90673913dc9 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 18 Sep 2018 16:10:39 +0200 Subject: [PATCH 27/81] Added shared header --- .../src/AmbientOcclusionEffect.cpp | 44 ++++++++---------- .../render-utils/src/AmbientOcclusionEffect.h | 46 +++++++------------ libraries/render-utils/src/ssao.slh | 12 +---- .../src/ssao_makeHorizontalBlur.slf | 2 + .../render-utils/src/ssao_makeOcclusion.slf | 1 - .../src/ssao_makeVerticalBlur.slf | 2 + libraries/render-utils/src/ssao_shared.h | 44 ++++++++++++++++++ 7 files changed, 87 insertions(+), 64 deletions(-) create mode 100644 libraries/render-utils/src/ssao_shared.h diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 66e59ddad0..0a7a15ecbd 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -30,9 +30,6 @@ #include "DependencyManager.h" #include "ViewFrustum.h" -// Should match value in ssao_makeOcclusion.slf -#define SSAO_USE_HORIZON_BASED 1 - gpu::PipelinePointer AmbientOcclusionEffect::_occlusionPipeline; gpu::PipelinePointer AmbientOcclusionEffect::_hBlurPipeline; gpu::PipelinePointer AmbientOcclusionEffect::_vBlurPipeline; @@ -203,13 +200,12 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : } -AmbientOcclusionEffect::AOParameters::AOParameters() : -resolutionInfo{ -1.0f, 0.0f, 1.0f, 0.0f }, -radiusInfo{ 0.5f, 0.5f * 0.5f, 1.0f / (0.25f * 0.25f * 0.25f), 1.0f }, -ditheringInfo{ 0.0f, 0.0f, 0.01f, 1.0f }, -sampleInfo{ 11.0f, 1.0f / 11.0f, 7.0f, 1.0f }, -blurInfo{ 1.0f, 3.0f, 2.0f, 0.0f } { - +AmbientOcclusionEffect::AOParameters::AOParameters() { + _resolutionInfo = { -1.0f, 0.0f, 1.0f, 0.0f }; + _radiusInfo = { 0.5f, 0.5f * 0.5f, 1.0f / (0.25f * 0.25f * 0.25f), 1.0f }; + _ditheringInfo = { 0.0f, 0.0f, 0.01f, 1.0f }; + _sampleInfo = { 11.0f, 1.0f / 11.0f, 7.0f, 1.0f }; + _blurInfo = { 1.0f, 3.0f, 2.0f, 0.0f }; } AmbientOcclusionEffect::AmbientOcclusionEffect() { @@ -224,7 +220,7 @@ void AmbientOcclusionEffect::configure(const Config& config) { const double RADIUS_POWER = 6.0; const auto& radius = config.radius; if (radius != _aoParametersBuffer->getRadius()) { - auto& current = _aoParametersBuffer.edit().radiusInfo; + auto& current = _aoParametersBuffer.edit()._radiusInfo; current.x = radius; current.y = radius * radius; current.z = 10.0f; @@ -234,40 +230,40 @@ void AmbientOcclusionEffect::configure(const Config& config) { } if (config.obscuranceLevel != _aoParametersBuffer->getObscuranceLevel()) { - auto& current = _aoParametersBuffer.edit().radiusInfo; + auto& current = _aoParametersBuffer.edit()._radiusInfo; current.w = config.obscuranceLevel; } if (config.falloffAngle != _aoParametersBuffer->getFalloffAngle()) { - auto& current = _aoParametersBuffer.edit().ditheringInfo; + auto& current = _aoParametersBuffer.edit()._ditheringInfo; current.z = config.falloffAngle; current.y = 1.0f / (1.0f - config.falloffAngle); } if (config.edgeSharpness != _aoParametersBuffer->getEdgeSharpness()) { - auto& current = _aoParametersBuffer.edit().blurInfo; + auto& current = _aoParametersBuffer.edit()._blurInfo; current.x = config.edgeSharpness; } if (config.blurDeviation != _aoParametersBuffer->getBlurDeviation()) { - auto& current = _aoParametersBuffer.edit().blurInfo; + auto& current = _aoParametersBuffer.edit()._blurInfo; current.z = config.blurDeviation; shouldUpdateGaussian = true; } if (config.numSpiralTurns != _aoParametersBuffer->getNumSpiralTurns()) { - auto& current = _aoParametersBuffer.edit().sampleInfo; + auto& current = _aoParametersBuffer.edit()._sampleInfo; current.z = config.numSpiralTurns; } if (config.numSamples != _aoParametersBuffer->getNumSamples()) { - auto& current = _aoParametersBuffer.edit().sampleInfo; + auto& current = _aoParametersBuffer.edit()._sampleInfo; current.x = config.numSamples; current.y = 1.0f / config.numSamples; } if (config.fetchMipsEnabled != _aoParametersBuffer->isFetchMipsEnabled()) { - auto& current = _aoParametersBuffer.edit().sampleInfo; + auto& current = _aoParametersBuffer.edit()._sampleInfo; current.w = (float)config.fetchMipsEnabled; } @@ -277,28 +273,28 @@ void AmbientOcclusionEffect::configure(const Config& config) { } if (config.perspectiveScale != _aoParametersBuffer->getPerspectiveScale()) { - _aoParametersBuffer.edit().resolutionInfo.z = config.perspectiveScale; + _aoParametersBuffer.edit()._resolutionInfo.z = config.perspectiveScale; } if (config.resolutionLevel != _aoParametersBuffer->getResolutionLevel()) { - auto& current = _aoParametersBuffer.edit().resolutionInfo; + auto& current = _aoParametersBuffer.edit()._resolutionInfo; current.x = (float) config.resolutionLevel; shouldUpdateBlurs = true; } if (config.blurRadius != _aoParametersBuffer->getBlurRadius()) { - auto& current = _aoParametersBuffer.edit().blurInfo; + auto& current = _aoParametersBuffer.edit()._blurInfo; current.y = (float)config.blurRadius; shouldUpdateGaussian = true; } if (config.ditheringEnabled != _aoParametersBuffer->isDitheringEnabled()) { - auto& current = _aoParametersBuffer.edit().ditheringInfo; + auto& current = _aoParametersBuffer.edit()._ditheringInfo; current.x = (float)config.ditheringEnabled; } if (config.borderingEnabled != _aoParametersBuffer->isBorderingEnabled()) { - auto& current = _aoParametersBuffer.edit().ditheringInfo; + auto& current = _aoParametersBuffer.edit()._ditheringInfo; current.w = (float)config.borderingEnabled; } @@ -377,7 +373,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getMipCreationPipeline() { void AmbientOcclusionEffect::updateGaussianDistribution() { auto coefs = _aoParametersBuffer.edit()._gaussianCoefs; - GaussianDistribution::evalSampling(coefs, AOParameters::GAUSSIAN_COEFS_LENGTH, _aoParametersBuffer->getBlurRadius(), _aoParametersBuffer->getBlurDeviation()); + GaussianDistribution::evalSampling(coefs, SSAO_BLUR_GAUSSIAN_COEFS_COUNT, _aoParametersBuffer->getBlurRadius(), _aoParametersBuffer->getBlurDeviation()); } void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 4021768995..86754d494b 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -115,42 +115,30 @@ public: void configure(const Config& config); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); - + +#include "ssao_shared.h" // Class describing the uniform buffer with all the parameters common to the AO shaders - class AOParameters { + class AOParameters : public AmbientOcclusionParams { public: - // Resolution info - glm::vec4 resolutionInfo; - // radius info is { R, R^2, 1 / R^6, ObscuranceScale} - glm::vec4 radiusInfo; - // Dithering info - glm::vec4 ditheringInfo; - // Sampling info - glm::vec4 sampleInfo; - // Blurring info - glm::vec4 blurInfo; - // gaussian distribution coefficients first is the sampling radius (max is 6) - const static int GAUSSIAN_COEFS_LENGTH = 16; - float _gaussianCoefs[GAUSSIAN_COEFS_LENGTH]; - + AOParameters(); - int getResolutionLevel() const { return resolutionInfo.x; } - float getRadius() const { return radiusInfo.x; } - float getPerspectiveScale() const { return resolutionInfo.z; } - float getObscuranceLevel() const { return radiusInfo.w; } - float getFalloffAngle() const { return (float)ditheringInfo.z; } - float getEdgeSharpness() const { return (float)blurInfo.x; } - float getBlurDeviation() const { return blurInfo.z; } + int getResolutionLevel() const { return _resolutionInfo.x; } + float getRadius() const { return _radiusInfo.x; } + float getPerspectiveScale() const { return _resolutionInfo.z; } + float getObscuranceLevel() const { return _radiusInfo.w; } + float getFalloffAngle() const { return (float)_ditheringInfo.z; } + float getEdgeSharpness() const { return (float)_blurInfo.x; } + float getBlurDeviation() const { return _blurInfo.z; } - float getNumSpiralTurns() const { return sampleInfo.z; } - int getNumSamples() const { return (int)sampleInfo.x; } - bool isFetchMipsEnabled() const { return sampleInfo.w; } + float getNumSpiralTurns() const { return _sampleInfo.z; } + int getNumSamples() const { return (int)_sampleInfo.x; } + bool isFetchMipsEnabled() const { return _sampleInfo.w; } - int getBlurRadius() const { return (int)blurInfo.y; } - bool isDitheringEnabled() const { return ditheringInfo.x; } - bool isBorderingEnabled() const { return ditheringInfo.w; } + int getBlurRadius() const { return (int)_blurInfo.y; } + bool isDitheringEnabled() const { return _ditheringInfo.x; } + bool isBorderingEnabled() const { return _ditheringInfo.w; } }; using AOParametersBuffer = gpu::StructBuffer; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 63dadc9bec..38b7999924 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -12,6 +12,7 @@ <@def SSAO_SLH@> <@include render-utils/ShaderConstants.h@> +<@include ssao_shared.h@> <@func declarePackOcclusionDepth()@> @@ -35,15 +36,6 @@ vec2 unpackOcclusionDepth(vec3 raw) { <@include DeferredTransform.slh@> <$declareDeferredFrameTransform()$> -struct AmbientOcclusionParams { - vec4 _resolutionInfo; - vec4 _radiusInfo; - vec4 _ditheringInfo; - vec4 _sampleInfo; - vec4 _blurInfo; - float _gaussianCoefs[16]; -}; - layout(binding=RENDER_UTILS_BUFFER_SSAO_PARAMS) uniform ambientOcclusionParamsBuffer { AmbientOcclusionParams params; }; @@ -456,4 +448,4 @@ vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTex <@endfunc@> -<@endif@> \ No newline at end of file +<@endif@> diff --git a/libraries/render-utils/src/ssao_makeHorizontalBlur.slf b/libraries/render-utils/src/ssao_makeHorizontalBlur.slf index 2d02ed02f0..fc90052eed 100644 --- a/libraries/render-utils/src/ssao_makeHorizontalBlur.slf +++ b/libraries/render-utils/src/ssao_makeHorizontalBlur.slf @@ -13,6 +13,8 @@ <@include ssao.slh@> +// Hack comment + const ivec2 horizontal = ivec2(1,0); <$declareBlurPass(horizontal)$> diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 94e87c75e0..8c8832634c 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -19,7 +19,6 @@ <$declarePackOcclusionDepth()$> -#define SSAO_USE_HORIZON_BASED 1 #define SSAO_HBAO_MAX_RADIUS 100.0 layout(location=0) out vec4 outFragColor; diff --git a/libraries/render-utils/src/ssao_makeVerticalBlur.slf b/libraries/render-utils/src/ssao_makeVerticalBlur.slf index 1ef6666424..69b92000de 100644 --- a/libraries/render-utils/src/ssao_makeVerticalBlur.slf +++ b/libraries/render-utils/src/ssao_makeVerticalBlur.slf @@ -12,6 +12,8 @@ // <@include ssao.slh@> +// Hack comment + const ivec2 vertical = ivec2(0,1); <$declareBlurPass(vertical)$> diff --git a/libraries/render-utils/src/ssao_shared.h b/libraries/render-utils/src/ssao_shared.h new file mode 100644 index 0000000000..6b71c20c43 --- /dev/null +++ b/libraries/render-utils/src/ssao_shared.h @@ -0,0 +1,44 @@ +// + +// <@if not RENDER_UTILS_SSAO_SHARED_H@> +// <@def RENDER_UTILS_SSAO_SHARED_H@> + +// Hack comment to absorb the extra '//' scribe prepends + +#ifndef RENDER_UTILS_SSAO_SHARED_H +#define RENDER_UTILS_SSAO_SHARED_H + +#define SSAO_USE_HORIZON_BASED 1 +#define SSAO_BLUR_GAUSSIAN_COEFS_COUNT 16 + +// glsl / C++ compatible source as interface for Shadows +#ifdef __cplusplus +# define SSAO_VEC4 glm::vec4 +#else +# define SSAO_VEC4 vec4 +#endif + +struct AmbientOcclusionParams { + SSAO_VEC4 _resolutionInfo; + SSAO_VEC4 _radiusInfo; + SSAO_VEC4 _ditheringInfo; + SSAO_VEC4 _sampleInfo; + SSAO_VEC4 _blurInfo; + float _gaussianCoefs[SSAO_BLUR_GAUSSIAN_COEFS_COUNT]; +}; + +#endif // RENDER_UTILS_SHADER_CONSTANTS_H + +// <@if 1@> +// Trigger Scribe include +// <@endif@> + +// <@endif@> + +// Hack Comment \ No newline at end of file From 03814e7653fd8106d4209fb5abd8d67ab42902d1 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 18 Sep 2018 18:33:28 +0200 Subject: [PATCH 28/81] Preparing for split rendering of HBAO directions --- .../src/AmbientOcclusionEffect.cpp | 68 +++++++++++++++++-- .../render-utils/src/AmbientOcclusionEffect.h | 4 ++ .../src/render-utils/ShaderConstants.h | 2 + libraries/render-utils/src/ssao.slh | 14 +++- .../render-utils/src/ssao_makeOcclusion.slf | 3 +- libraries/render-utils/src/ssao_shared.h | 16 ++++- 6 files changed, 99 insertions(+), 8 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 0a7a15ecbd..c1101ad395 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -260,6 +260,23 @@ void AmbientOcclusionEffect::configure(const Config& config) { auto& current = _aoParametersBuffer.edit()._sampleInfo; current.x = config.numSamples; current.y = 1.0f / config.numSamples; + + // Regenerate halton sequence + const int B = config.numSamples + 1; + const float invB = 1.0f / (float)B; + + for (int i = 0; i < _randomSamples.size(); i++) { + int index = i+1; // Indices start at 1, not 0 + float f = 1.0f; + float r = 0.0f; + + while (index > 0) { + f = f * invB; + r = r + f * (float)(index % B); + index = index / B; + } + _randomSamples[i] = r; + } } if (config.fetchMipsEnabled != _aoParametersBuffer->isFetchMipsEnabled()) { @@ -280,6 +297,13 @@ void AmbientOcclusionEffect::configure(const Config& config) { auto& current = _aoParametersBuffer.edit()._resolutionInfo; current.x = (float) config.resolutionLevel; shouldUpdateBlurs = true; + + _aoFrameParametersBuffer[0].edit()._pixelOffsets = { 0, 0, 0, 0 }; +#if SSAO_USE_QUAD_SPLIT + _aoFrameParametersBuffer[1].edit()._pixelOffsets = { 1, 0, 0, 0 }; + _aoFrameParametersBuffer[2].edit()._pixelOffsets = { 1, 1, 0, 0 }; + _aoFrameParametersBuffer[3].edit()._pixelOffsets = { 0, 1, 0, 0 }; +#endif } if (config.blurRadius != _aoParametersBuffer->getBlurRadius()) { @@ -425,21 +449,29 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto mipCreationPipeline = getMipCreationPipeline(); #endif + // Update sample rotation + const int SSAO_RANDOM_SAMPLE_COUNT = int(_randomSamples.size() / SSAO_SPLIT_COUNT); + for (int splitId=0 ; splitId < SSAO_SPLIT_COUNT ; splitId++) { + auto& sample = _aoFrameParametersBuffer[splitId].edit(); + sample._angleInfo.x = _randomSamples[_frameId + SSAO_RANDOM_SAMPLE_COUNT * splitId] * M_PI; + } + _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; + gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) { PROFILE_RANGE_BATCH(batch, "AmbientOcclusion"); batch.enableStereo(false); _gpuTimer->begin(batch); - batch.setViewportTransform(occlusionViewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); Transform model; + batch.setProjectionTransform(glm::mat4()); + batch.setModelTransform(model); // We need this with the mips levels batch.pushProfileRange("Depth mip creation"); - batch.setModelTransform(model); #if SSAO_USE_HORIZON_BASED batch.setPipeline(mipCreationPipeline); batch.generateTextureMipsWithPipeline(occlusionDepthTexture); @@ -450,13 +482,42 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte // Occlusion pass batch.pushProfileRange("Occlusion"); + batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); batch.setFramebuffer(occlusionFBO); batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(1.0f)); batch.setPipeline(occlusionPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, occlusionDepthTexture); + +#if SSAO_USE_QUAD_SPLIT + { + auto splitViewport = occlusionViewport >> SSAO_USE_QUAD_SPLIT; + + batch.setViewportTransform(splitViewport); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + splitViewport.x += splitViewport.z; + batch.setViewportTransform(splitViewport); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[1]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + splitViewport.y += splitViewport.w; + batch.setViewportTransform(splitViewport); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[2]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + splitViewport.x = 0; + batch.setViewportTransform(splitViewport); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[3]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + } +#else + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); batch.draw(gpu::TRIANGLE_STRIP, 4); +#endif + batch.popProfileRange(); { @@ -552,7 +613,6 @@ void DebugAmbientOcclusion::run(const render::RenderContextPointer& renderContex linearDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); occlusionViewport = occlusionViewport >> ambientOcclusionUniforms->getResolutionLevel(); } - auto framebufferSize = glm::ivec2(linearDepthTexture->getDimensions()); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 86754d494b..807c0b5ec8 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -153,11 +153,13 @@ private: }; using BlurParametersBuffer = gpu::StructBuffer; + using FrameParametersBuffer = gpu::StructBuffer< AmbientOcclusionFrameParams>; void updateGaussianDistribution(); void updateBlurParameters(); AOParametersBuffer _aoParametersBuffer; + FrameParametersBuffer _aoFrameParametersBuffer[SSAO_SPLIT_COUNT]; BlurParametersBuffer _vblurParametersBuffer; BlurParametersBuffer _hblurParametersBuffer; @@ -172,6 +174,8 @@ private: static gpu::PipelinePointer _mipCreationPipeline; AmbientOcclusionFramebufferPointer _framebuffer; + std::array _randomSamples; + int _frameId{ 0 }; gpu::RangeTimerPointer _gpuTimer; diff --git a/libraries/render-utils/src/render-utils/ShaderConstants.h b/libraries/render-utils/src/render-utils/ShaderConstants.h index c6bdfb759c..ce4e481ce3 100644 --- a/libraries/render-utils/src/render-utils/ShaderConstants.h +++ b/libraries/render-utils/src/render-utils/ShaderConstants.h @@ -87,6 +87,7 @@ #define RENDER_UTILS_BUFFER_SSAO_PARAMS 2 #define RENDER_UTILS_BUFFER_SSAO_DEBUG_PARAMS 3 #define RENDER_UTILS_BUFFER_SSAO_BLUR_PARAMS 4 +#define RENDER_UTILS_BUFFER_SSAO_FRAME_PARAMS 5 #define RENDER_UTILS_TEXTURE_SSAO_DEPTH 1 #define RENDER_UTILS_TEXTURE_SSAO_OCCLUSION 0 @@ -153,6 +154,7 @@ enum Buffer { LightClusterContent = RENDER_UTILS_BUFFER_LIGHT_CLUSTER_CONTENT, SsscParams = RENDER_UTILS_BUFFER_SSSC_PARAMS, SsaoParams = RENDER_UTILS_BUFFER_SSAO_PARAMS, + SsaoFrameParams = RENDER_UTILS_BUFFER_SSAO_FRAME_PARAMS, SsaoDebugParams = RENDER_UTILS_BUFFER_SSAO_DEBUG_PARAMS, SsaoBlurParams = RENDER_UTILS_BUFFER_SSAO_BLUR_PARAMS, LightIndex = RENDER_UTILS_BUFFER_LIGHT_INDEX, diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 38b7999924..fefa424bbd 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -40,9 +40,11 @@ layout(binding=RENDER_UTILS_BUFFER_SSAO_PARAMS) uniform ambientOcclusionParamsBu AmbientOcclusionParams params; }; +layout(binding=RENDER_UTILS_BUFFER_SSAO_FRAME_PARAMS) uniform ambientOcclusionFrameParamsBuffer { + AmbientOcclusionFrameParams frameParams; +}; float getPerspectiveScale() { - return (params._resolutionInfo.z); } int getResolutionLevel() { @@ -136,8 +138,16 @@ float getAngleDitheringWorldPos(in vec3 pixelWorldPos) { } float getAngleDithering(in ivec2 pixelPos) { +#if SSAO_USE_QUAD_SPLIT + return isDitheringEnabled() * frameParams._angleInfo.x; +#else // Hash function used in the AlchemyAO paper - return isDitheringEnabled() * float((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10); + return isDitheringEnabled() * float((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10); +#endif +} + +ivec2 getPixelOffset() { + return frameParams._pixelOffsets.xy; } float evalDiskRadius(float Zeye, vec2 sideImageSize) { diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 8c8832634c..e9e8c74f7b 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -25,10 +25,11 @@ layout(location=0) out vec4 outFragColor; void main(void) { vec2 sideImageSize = getSideImageSize(getResolutionLevel()); + ivec2 splitImageSize = ivec2(getWidthHeight(getResolutionLevel() + SSAO_USE_QUAD_SPLIT)); // Pixel being shaded vec2 fragCoord = gl_FragCoord.xy; - ivec2 fragPixelPos = ivec2(fragCoord.xy); + ivec2 fragPixelPos = ((ivec2(fragCoord.xy) - getPixelOffset()*splitImageSize) << SSAO_USE_QUAD_SPLIT) + getPixelOffset(); // Stereo side info ivec4 side = getStereoSideInfo(fragPixelPos.x, getResolutionLevel()); diff --git a/libraries/render-utils/src/ssao_shared.h b/libraries/render-utils/src/ssao_shared.h index 6b71c20c43..61bf14ccf8 100644 --- a/libraries/render-utils/src/ssao_shared.h +++ b/libraries/render-utils/src/ssao_shared.h @@ -15,13 +15,22 @@ #define RENDER_UTILS_SSAO_SHARED_H #define SSAO_USE_HORIZON_BASED 1 +#define SSAO_USE_QUAD_SPLIT 1 #define SSAO_BLUR_GAUSSIAN_COEFS_COUNT 16 -// glsl / C++ compatible source as interface for Shadows +#if SSAO_USE_QUAD_SPLIT +#define SSAO_SPLIT_COUNT 4 +#else +#define SSAO_SPLIT_COUNT 1 +#endif + +// glsl / C++ compatible source as interface for ambient occlusion #ifdef __cplusplus # define SSAO_VEC4 glm::vec4 +# define SSAO_IVEC4 glm::ivec4 #else # define SSAO_VEC4 vec4 +# define SSAO_IVEC4 ivec4 #endif struct AmbientOcclusionParams { @@ -33,6 +42,11 @@ struct AmbientOcclusionParams { float _gaussianCoefs[SSAO_BLUR_GAUSSIAN_COEFS_COUNT]; }; +struct AmbientOcclusionFrameParams { + SSAO_VEC4 _angleInfo; + SSAO_IVEC4 _pixelOffsets; +}; + #endif // RENDER_UTILS_SHADER_CONSTANTS_H // <@if 1@> From 3493d40fd74f566e69830c57aaae6cb1b76128cc Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 19 Sep 2018 10:37:27 +0200 Subject: [PATCH 29/81] Added gather to split AO --- .../src/AmbientOcclusionEffect.cpp | 34 ++++++++++++++++++- .../render-utils/src/AmbientOcclusionEffect.h | 6 ++-- .../src/render-utils/ssao_gather.slp | 1 + libraries/render-utils/src/ssao.slh | 8 +++++ libraries/render-utils/src/ssao_gather.slf | 34 +++++++++++++++++++ .../render-utils/src/ssao_makeOcclusion.slf | 21 ++++-------- 6 files changed, 86 insertions(+), 18 deletions(-) create mode 100644 libraries/render-utils/src/render-utils/ssao_gather.slp create mode 100644 libraries/render-utils/src/ssao_gather.slf diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index c1101ad395..9563192739 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -34,6 +34,7 @@ gpu::PipelinePointer AmbientOcclusionEffect::_occlusionPipeline; gpu::PipelinePointer AmbientOcclusionEffect::_hBlurPipeline; gpu::PipelinePointer AmbientOcclusionEffect::_vBlurPipeline; gpu::PipelinePointer AmbientOcclusionEffect::_mipCreationPipeline; +gpu::PipelinePointer AmbientOcclusionEffect::_gatherPipeline; AmbientOcclusionFramebuffer::AmbientOcclusionFramebuffer() { } @@ -395,6 +396,19 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getMipCreationPipeline() { return _mipCreationPipeline; } +const gpu::PipelinePointer& AmbientOcclusionEffect::getGatherPipeline() { + if (!_gatherPipeline) { + gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::ssao_gather); + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + state->setColorWriteMask(true, true, true, false); + + // Good to go add the brand new pipeline + _gatherPipeline = gpu::Pipeline::create(program, state); + } + return _gatherPipeline; +} + void AmbientOcclusionEffect::updateGaussianDistribution() { auto coefs = _aoParametersBuffer.edit()._gaussianCoefs; GaussianDistribution::evalSampling(coefs, SSAO_BLUR_GAUSSIAN_COEFS_COUNT, _aoParametersBuffer->getBlurRadius(), _aoParametersBuffer->getBlurDeviation()); @@ -448,7 +462,10 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #if SSAO_USE_HORIZON_BASED auto mipCreationPipeline = getMipCreationPipeline(); #endif - +#if SSAO_USE_QUAD_SPLIT + auto gatherPipeline = getGatherPipeline(); +#endif + // Update sample rotation const int SSAO_RANDOM_SAMPLE_COUNT = int(_randomSamples.size() / SSAO_SPLIT_COUNT); for (int splitId=0 ; splitId < SSAO_SPLIT_COUNT ; splitId++) { @@ -485,7 +502,11 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); +#if SSAO_USE_QUAD_SPLIT + batch.setFramebuffer(occlusionBlurredFBO); +#else batch.setFramebuffer(occlusionFBO); +#endif batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(1.0f)); batch.setPipeline(occlusionPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, occlusionDepthTexture); @@ -520,6 +541,17 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.popProfileRange(); +#if SSAO_USE_QUAD_SPLIT + // Gather back the four separate renders into one interleaved one + batch.pushProfileRange("Gather"); + batch.setViewportTransform(occlusionViewport); + batch.setFramebuffer(occlusionFBO); + batch.setPipeline(gatherPipeline); + batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionBlurredFBO->getRenderBuffer(0)); + batch.draw(gpu::TRIANGLE_STRIP, 4); + batch.popProfileRange(); +#endif + { PROFILE_RANGE_BATCH(batch, "Bilateral Blur"); // Blur 1st pass diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 807c0b5ec8..ee64dd3912 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -167,11 +167,13 @@ private: static const gpu::PipelinePointer& getHBlurPipeline(); // first static const gpu::PipelinePointer& getVBlurPipeline(); // second static const gpu::PipelinePointer& getMipCreationPipeline(); + static const gpu::PipelinePointer& getGatherPipeline(); - static gpu::PipelinePointer _occlusionPipeline; + static gpu::PipelinePointer _occlusionPipeline; static gpu::PipelinePointer _hBlurPipeline; static gpu::PipelinePointer _vBlurPipeline; - static gpu::PipelinePointer _mipCreationPipeline; + static gpu::PipelinePointer _mipCreationPipeline; + static gpu::PipelinePointer _gatherPipeline; AmbientOcclusionFramebufferPointer _framebuffer; std::array _randomSamples; diff --git a/libraries/render-utils/src/render-utils/ssao_gather.slp b/libraries/render-utils/src/render-utils/ssao_gather.slp new file mode 100644 index 0000000000..d4d8ec4b01 --- /dev/null +++ b/libraries/render-utils/src/render-utils/ssao_gather.slp @@ -0,0 +1 @@ +VERTEX gpu::vertex::DrawViewportQuadTransformTexcoord diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index fefa424bbd..b1103fbbac 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -364,6 +364,14 @@ float evalVisibilityHBAO(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, ve <@endfunc@> +<@func declareGatherPass()@> +<$declareAmbientOcclusion()$> + +// the source occlusion texture +layout(binding=RENDER_UTILS_TEXTURE_SSAO_OCCLUSION) uniform sampler2D occlusionMap; + +<@endfunc@> + <@func declareBlurPass(axis)@> <$declarePackOcclusionDepth()$> diff --git a/libraries/render-utils/src/ssao_gather.slf b/libraries/render-utils/src/ssao_gather.slf new file mode 100644 index 0000000000..32edec515b --- /dev/null +++ b/libraries/render-utils/src/ssao_gather.slf @@ -0,0 +1,34 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// ssao_gather.frag +// +// Created by Olivier Prat on 09/19/2018. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include ssao.slh@> + +// Hack comment + +<$declareGatherPass()$> + +layout(location=0) in vec4 varTexCoord0; + +layout(location=0) out vec4 outFragColor; + +void main(void) { + // Gather the four splits of the occlusion result back into an interleaved full size + // result (at the resolution level, of course) + ivec2 destPixelCoord = ivec2(gl_FragCoord.xy); + ivec2 sourcePixelCoord = destPixelCoord >> 1; + ivec2 splitImageSize = ivec2(getWidthHeight(getResolutionLevel() + 1)); + + sourcePixelCoord += (destPixelCoord & ivec2(1)) * splitImageSize; + + outFragColor = texelFetch(occlusionMap, sourcePixelCoord, 0); +} diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index e9e8c74f7b..bdaa87fff9 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -25,11 +25,14 @@ layout(location=0) out vec4 outFragColor; void main(void) { vec2 sideImageSize = getSideImageSize(getResolutionLevel()); - ivec2 splitImageSize = ivec2(getWidthHeight(getResolutionLevel() + SSAO_USE_QUAD_SPLIT)); // Pixel being shaded vec2 fragCoord = gl_FragCoord.xy; - ivec2 fragPixelPos = ((ivec2(fragCoord.xy) - getPixelOffset()*splitImageSize) << SSAO_USE_QUAD_SPLIT) + getPixelOffset(); + ivec2 fragPixelPos = ivec2(fragCoord.xy); +#if SSAO_USE_QUAD_SPLIT + ivec2 splitImageSize = ivec2(getWidthHeight(getResolutionLevel() + SSAO_USE_QUAD_SPLIT)); + fragPixelPos = ((fragPixelPos - getPixelOffset()*splitImageSize) << SSAO_USE_QUAD_SPLIT) + getPixelOffset(); +#endif // Stereo side info ivec4 side = getStereoSideInfo(fragPixelPos.x, getResolutionLevel()); @@ -41,7 +44,7 @@ void main(void) { // Fetch the z under the pixel (stereo or not) float Zeye = getZEyeAtUV(fragUVPos, 0); - // The position and normal of the pixel fragment in Eye space + // The position and normal of the pixel fragment in Eye space vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); vec3 fragNormalES = evalEyeNormal(fragPositionES); @@ -71,18 +74,6 @@ void main(void) { } float occlusion = clamp(1.0 - obscuranceSum * getObscuranceScaling() * getInvNumSamples(), 0.0, 1.0); - - // KEEP IT for Debugging - // Bilateral box-filter over a quad for free, respecting depth edges - // (the difference that this makes is subtle) -/* if (abs(dFdx(fragPositionES.z)) < 0.02) { - occlusion -= dFdx(occlusion) * ((fragPixelPos.x & 1) - 0.5); - } - if (abs(dFdy(fragPositionES.z)) < 0.02) { - occlusion -= dFdy(occlusion) * ((fragPixelPos.y & 1) - 0.5); - }*/ - //outFragColor = vec4(packOcclusionDepth(occlusion, CSZToDepthKey(fragPositionES.z)), 1.0); outFragColor = vec4(vec3(occlusion), 1.0); - } From 8a11d18f0d750451832fbd70718219a8217a63d2 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 19 Sep 2018 17:24:31 +0200 Subject: [PATCH 30/81] Quarter resolution with split rendering --- .../src/AmbientOcclusionEffect.cpp | 159 ++++++++++++------ .../render-utils/src/AmbientOcclusionEffect.h | 14 +- .../render-utils/src/SurfaceGeometryPass.cpp | 11 +- .../render-utils/src/SurfaceGeometryPass.h | 4 +- .../src/render-utils/ShaderConstants.h | 2 + .../src/render-utils/ssao_buildNormals.slp | 1 + libraries/render-utils/src/ssao.slh | 37 ++-- .../render-utils/src/ssao_buildNormals.slf | 45 +++++ .../render-utils/src/ssao_makeOcclusion.slf | 4 + libraries/render-utils/src/ssao_shared.h | 2 +- .../utilities/render/ambientOcclusionPass.qml | 6 +- 11 files changed, 194 insertions(+), 91 deletions(-) create mode 100644 libraries/render-utils/src/render-utils/ssao_buildNormals.slp create mode 100644 libraries/render-utils/src/ssao_buildNormals.slf diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 9563192739..667127983a 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -35,6 +35,7 @@ gpu::PipelinePointer AmbientOcclusionEffect::_hBlurPipeline; gpu::PipelinePointer AmbientOcclusionEffect::_vBlurPipeline; gpu::PipelinePointer AmbientOcclusionEffect::_mipCreationPipeline; gpu::PipelinePointer AmbientOcclusionEffect::_gatherPipeline; +gpu::PipelinePointer AmbientOcclusionEffect::_buildNormalsPipeline; AmbientOcclusionFramebuffer::AmbientOcclusionFramebuffer() { } @@ -66,6 +67,8 @@ void AmbientOcclusionFramebuffer::clear() { _occlusionTexture.reset(); _occlusionBlurredFramebuffer.reset(); _occlusionBlurredTexture.reset(); + _normalFramebuffer.reset(); + _normalTexture.reset(); } gpu::TexturePointer AmbientOcclusionFramebuffer::getLinearDepthTexture() { @@ -73,18 +76,21 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getLinearDepthTexture() { } void AmbientOcclusionFramebuffer::allocate() { - auto width = _frameSize.x; auto height = _frameSize.y; auto format = gpu::Element::COLOR_R_8; - _occlusionTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT, gpu::Sampler::WRAP_CLAMP)); + _occlusionTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); - _occlusionBlurredTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT, gpu::Sampler::WRAP_CLAMP)); + _occlusionBlurredTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusionBlurred")); _occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture); + + _normalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_R11G11B10, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT, gpu::Sampler::WRAP_CLAMP)); + _normalFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("ssaoNormals")); + _normalFramebuffer->setRenderBuffer(0, _normalTexture); } gpu::FramebufferPointer AmbientOcclusionFramebuffer::getOcclusionFramebuffer() { @@ -115,6 +121,19 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getOcclusionBlurredTexture() { return _occlusionBlurredTexture; } +gpu::FramebufferPointer AmbientOcclusionFramebuffer::getNormalFramebuffer() { + if (!_normalFramebuffer) { + allocate(); + } + return _normalFramebuffer; +} + +gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() { + if (!_normalTexture) { + allocate(); + } + return _normalTexture; +} class GaussianDistribution { public: @@ -189,11 +208,11 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : blurDeviation{ 2.5f }, numSpiralTurns{ 7.0f }, #if SSAO_USE_HORIZON_BASED - numSamples{ 1 }, + numSamples{ 2 }, #else numSamples{ 16 }, #endif - resolutionLevel{ 1 }, + resolutionLevel{ 2 }, blurRadius{ 4 }, ditheringEnabled{ true }, borderingEnabled{ true }, @@ -262,8 +281,8 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.x = config.numSamples; current.y = 1.0f / config.numSamples; - // Regenerate halton sequence - const int B = config.numSamples + 1; + // Regenerate offsets + const int B = 3; const float invB = 1.0f / (float)B; for (int i = 0; i < _randomSamples.size(); i++) { @@ -276,7 +295,7 @@ void AmbientOcclusionEffect::configure(const Config& config) { r = r + f * (float)(index % B); index = index / B; } - _randomSamples[i] = r; + _randomSamples[i] = r * M_PI / config.numSamples; } } @@ -296,7 +315,7 @@ void AmbientOcclusionEffect::configure(const Config& config) { if (config.resolutionLevel != _aoParametersBuffer->getResolutionLevel()) { auto& current = _aoParametersBuffer.edit()._resolutionInfo; - current.x = (float) config.resolutionLevel; + current.x = (float)config.resolutionLevel; shouldUpdateBlurs = true; _aoFrameParametersBuffer[0].edit()._pixelOffsets = { 0, 0, 0, 0 }; @@ -307,7 +326,7 @@ void AmbientOcclusionEffect::configure(const Config& config) { #endif } - if (config.blurRadius != _aoParametersBuffer->getBlurRadius()) { + if (config.blurRadius != _aoParametersBuffer.get().getBlurRadius()) { auto& current = _aoParametersBuffer.edit()._blurInfo; current.y = (float)config.blurRadius; shouldUpdateGaussian = true; @@ -361,7 +380,6 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { return _occlusionPipeline; } - const gpu::PipelinePointer& AmbientOcclusionEffect::getHBlurPipeline() { if (!_hBlurPipeline) { gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::ssao_makeHorizontalBlur); @@ -409,9 +427,24 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getGatherPipeline() { return _gatherPipeline; } +const gpu::PipelinePointer& AmbientOcclusionEffect::getBuildNormalsPipeline() { + if (!_buildNormalsPipeline) { + gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::ssao_buildNormals); + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + state->setColorWriteMask(true, true, true, false); + + // Good to go add the brand new pipeline + _buildNormalsPipeline = gpu::Pipeline::create(program, state); + } + return _buildNormalsPipeline; +} + void AmbientOcclusionEffect::updateGaussianDistribution() { - auto coefs = _aoParametersBuffer.edit()._gaussianCoefs; - GaussianDistribution::evalSampling(coefs, SSAO_BLUR_GAUSSIAN_COEFS_COUNT, _aoParametersBuffer->getBlurRadius(), _aoParametersBuffer->getBlurDeviation()); + auto filterTaps = _aoParametersBuffer.edit()._blurFilterTaps; + auto blurRadius = _aoParametersBuffer.get().getBlurRadius(); + + GaussianDistribution::evalSampling(filterTaps, SSAO_BLUR_GAUSSIAN_COEFS_COUNT, blurRadius, _aoParametersBuffer->getBlurDeviation() * 4.0f / blurRadius); } void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { @@ -436,7 +469,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte if (!_framebuffer) { _framebuffer = std::make_shared(); } - + const auto resolutionScale = powf(0.5f, _aoParametersBuffer->getResolutionLevel()); if (_aoParametersBuffer->getResolutionLevel() > 0) { occlusionViewport = occlusionViewport >> _aoParametersBuffer->getResolutionLevel(); @@ -464,15 +497,19 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #endif #if SSAO_USE_QUAD_SPLIT auto gatherPipeline = getGatherPipeline(); + auto buildNormalsPipeline = getBuildNormalsPipeline(); + auto occlusionNormalFramebuffer = _framebuffer->getNormalFramebuffer(); + auto occlusionNormalTexture = _framebuffer->getNormalTexture(); #endif + auto fullNormalTexture = linearDepthFramebuffer->getNormalTexture(); // Update sample rotation const int SSAO_RANDOM_SAMPLE_COUNT = int(_randomSamples.size() / SSAO_SPLIT_COUNT); for (int splitId=0 ; splitId < SSAO_SPLIT_COUNT ; splitId++) { auto& sample = _aoFrameParametersBuffer[splitId].edit(); - sample._angleInfo.x = _randomSamples[_frameId + SSAO_RANDOM_SAMPLE_COUNT * splitId] * M_PI; + sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId]; } - _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; + // TEMPO OP _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) { PROFILE_RANGE_BATCH(batch, "AmbientOcclusion"); @@ -480,7 +517,6 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte _gpuTimer->begin(batch); - batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); Transform model; @@ -490,53 +526,67 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte // We need this with the mips levels batch.pushProfileRange("Depth mip creation"); #if SSAO_USE_HORIZON_BASED - batch.setPipeline(mipCreationPipeline); - batch.generateTextureMipsWithPipeline(occlusionDepthTexture); + batch.setPipeline(mipCreationPipeline); + batch.generateTextureMipsWithPipeline(occlusionDepthTexture); #else - batch.generateTextureMips(occlusionDepthTexture); + batch.generateTextureMips(occlusionDepthTexture); #endif batch.popProfileRange(); +#if SSAO_USE_QUAD_SPLIT + // Build derivative normals pass + batch.pushProfileRange("Build Normals"); + batch.setViewportTransform(sourceViewport); + batch.setPipeline(buildNormalsPipeline); + batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); + batch.setFramebuffer(occlusionNormalFramebuffer); + batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); + batch.draw(gpu::TRIANGLE_STRIP, 4); + batch.popProfileRange(); +#endif + // Occlusion pass batch.pushProfileRange("Occlusion"); - batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); + batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); #if SSAO_USE_QUAD_SPLIT - batch.setFramebuffer(occlusionBlurredFBO); + batch.setFramebuffer(occlusionBlurredFBO); #else - batch.setFramebuffer(occlusionFBO); + batch.setFramebuffer(occlusionFBO); #endif - batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(1.0f)); - batch.setPipeline(occlusionPipeline); - batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, occlusionDepthTexture); + batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(1.0f)); + batch.setPipeline(occlusionPipeline); + batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, occlusionDepthTexture); #if SSAO_USE_QUAD_SPLIT - { - auto splitViewport = occlusionViewport >> SSAO_USE_QUAD_SPLIT; + batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture); + { + auto splitViewport = occlusionViewport >> SSAO_USE_QUAD_SPLIT; - batch.setViewportTransform(splitViewport); + batch.setViewportTransform(splitViewport); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + splitViewport.x += splitViewport.z; + batch.setViewportTransform(splitViewport); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[1]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + splitViewport.y += splitViewport.w; + batch.setViewportTransform(splitViewport); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[2]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + splitViewport.x = 0; + batch.setViewportTransform(splitViewport); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[3]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + } +#else batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); batch.draw(gpu::TRIANGLE_STRIP, 4); - - splitViewport.x += splitViewport.z; - batch.setViewportTransform(splitViewport); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[1]); - batch.draw(gpu::TRIANGLE_STRIP, 4); - - splitViewport.y += splitViewport.w; - batch.setViewportTransform(splitViewport); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[2]); - batch.draw(gpu::TRIANGLE_STRIP, 4); - - splitViewport.x = 0; - batch.setViewportTransform(splitViewport); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[3]); - batch.draw(gpu::TRIANGLE_STRIP, 4); - } -#else - batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); - batch.draw(gpu::TRIANGLE_STRIP, 4); #endif batch.popProfileRange(); @@ -544,11 +594,11 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #if SSAO_USE_QUAD_SPLIT // Gather back the four separate renders into one interleaved one batch.pushProfileRange("Gather"); - batch.setViewportTransform(occlusionViewport); - batch.setFramebuffer(occlusionFBO); - batch.setPipeline(gatherPipeline); - batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionBlurredFBO->getRenderBuffer(0)); - batch.draw(gpu::TRIANGLE_STRIP, 4); + batch.setViewportTransform(occlusionViewport); + batch.setFramebuffer(occlusionFBO); + batch.setPipeline(gatherPipeline); + batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionBlurredFBO->getRenderBuffer(0)); + batch.draw(gpu::TRIANGLE_STRIP, 4); batch.popProfileRange(); #endif @@ -561,6 +611,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setFramebuffer(occlusionBlurredFBO); // Use full resolution depth and normal for bilateral upscaling and blur batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); + batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, fullNormalTexture); batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _hblurParametersBuffer); batch.setPipeline(firstHBlurPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionFBO->getRenderBuffer(0)); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index ee64dd3912..e04e24b4f4 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -30,7 +30,10 @@ public: gpu::FramebufferPointer getOcclusionBlurredFramebuffer(); gpu::TexturePointer getOcclusionBlurredTexture(); - + + gpu::FramebufferPointer getNormalFramebuffer(); + gpu::TexturePointer getNormalTexture(); + // Update the source framebuffer size which will drive the allocation of all the other resources. bool updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer); gpu::TexturePointer getLinearDepthTexture(); @@ -44,10 +47,13 @@ protected: gpu::FramebufferPointer _occlusionFramebuffer; gpu::TexturePointer _occlusionTexture; - + gpu::FramebufferPointer _occlusionBlurredFramebuffer; gpu::TexturePointer _occlusionBlurredTexture; - + + gpu::FramebufferPointer _normalFramebuffer; + gpu::TexturePointer _normalTexture; + glm::ivec2 _frameSize; }; @@ -168,12 +174,14 @@ private: static const gpu::PipelinePointer& getVBlurPipeline(); // second static const gpu::PipelinePointer& getMipCreationPipeline(); static const gpu::PipelinePointer& getGatherPipeline(); + static const gpu::PipelinePointer& getBuildNormalsPipeline(); static gpu::PipelinePointer _occlusionPipeline; static gpu::PipelinePointer _hBlurPipeline; static gpu::PipelinePointer _vBlurPipeline; static gpu::PipelinePointer _mipCreationPipeline; static gpu::PipelinePointer _gatherPipeline; + static gpu::PipelinePointer _buildNormalsPipeline; AmbientOcclusionFramebufferPointer _framebuffer; std::array _randomSamples; diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index bf90aa3b22..374a509c5a 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -28,11 +28,12 @@ namespace ru { LinearDepthFramebuffer::LinearDepthFramebuffer() { } -void LinearDepthFramebuffer::update(const gpu::TexturePointer& depthBuffer) { +void LinearDepthFramebuffer::update(const gpu::TexturePointer& depthBuffer, const gpu::TexturePointer& normalTexture) { //If the depth buffer or size changed, we need to delete our FBOs bool reset = false; - if (_primaryDepthTexture != depthBuffer) { + if (_primaryDepthTexture != depthBuffer || _normalTexture != normalTexture) { _primaryDepthTexture = depthBuffer; + _normalTexture = normalTexture; reset = true; } if (_primaryDepthTexture) { @@ -100,6 +101,10 @@ gpu::TexturePointer LinearDepthFramebuffer::getLinearDepthTexture() { return _linearDepthTexture; } +gpu::TexturePointer LinearDepthFramebuffer::getNormalTexture() { + return _normalTexture; +} + gpu::FramebufferPointer LinearDepthFramebuffer::getDownsampleFramebuffer() { if (!_downsampleFramebuffer) { allocate(); @@ -148,7 +153,7 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con auto depthBuffer = deferredFramebuffer->getPrimaryDepthTexture(); auto normalTexture = deferredFramebuffer->getDeferredNormalTexture(); - _linearDepthFramebuffer->update(depthBuffer); + _linearDepthFramebuffer->update(depthBuffer, normalTexture); auto linearDepthFBO = _linearDepthFramebuffer->getLinearDepthFramebuffer(); auto linearDepthTexture = _linearDepthFramebuffer->getLinearDepthTexture(); diff --git a/libraries/render-utils/src/SurfaceGeometryPass.h b/libraries/render-utils/src/SurfaceGeometryPass.h index 1d8f77e67d..5ada56521a 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.h +++ b/libraries/render-utils/src/SurfaceGeometryPass.h @@ -28,13 +28,14 @@ public: gpu::FramebufferPointer getLinearDepthFramebuffer(); gpu::TexturePointer getLinearDepthTexture(); + gpu::TexturePointer getNormalTexture(); gpu::FramebufferPointer getDownsampleFramebuffer(); gpu::TexturePointer getHalfLinearDepthTexture(); gpu::TexturePointer getHalfNormalTexture(); // Update the depth buffer which will drive the allocation of all the other resources according to its size. - void update(const gpu::TexturePointer& depthBuffer); + void update(const gpu::TexturePointer& depthBuffer, const gpu::TexturePointer& normalTexture); const glm::ivec2& getDepthFrameSize() const { return _frameSize; } void setResolutionLevel(int level) { _resolutionLevel = std::max(0, level); } @@ -48,6 +49,7 @@ protected: gpu::FramebufferPointer _linearDepthFramebuffer; gpu::TexturePointer _linearDepthTexture; + gpu::TexturePointer _normalTexture; gpu::FramebufferPointer _downsampleFramebuffer; gpu::TexturePointer _halfLinearDepthTexture; diff --git a/libraries/render-utils/src/render-utils/ShaderConstants.h b/libraries/render-utils/src/render-utils/ShaderConstants.h index ce4e481ce3..e12cf150fd 100644 --- a/libraries/render-utils/src/render-utils/ShaderConstants.h +++ b/libraries/render-utils/src/render-utils/ShaderConstants.h @@ -89,6 +89,7 @@ #define RENDER_UTILS_BUFFER_SSAO_BLUR_PARAMS 4 #define RENDER_UTILS_BUFFER_SSAO_FRAME_PARAMS 5 #define RENDER_UTILS_TEXTURE_SSAO_DEPTH 1 +#define RENDER_UTILS_TEXTURE_SSAO_NORMAL 2 #define RENDER_UTILS_TEXTURE_SSAO_OCCLUSION 0 // Temporal anti-aliasing @@ -196,6 +197,7 @@ enum Texture { TaaNext = RENDER_UTILS_TEXTURE_TAA_NEXT, SsaoOcclusion = RENDER_UTILS_TEXTURE_SSAO_OCCLUSION, SsaoDepth = RENDER_UTILS_TEXTURE_SSAO_DEPTH, + SsaoNormal = RENDER_UTILS_TEXTURE_SSAO_NORMAL, HighlightSceneDepth = RENDER_UTILS_TEXTURE_HIGHLIGHT_SCENE_DEPTH, HighlightDepth = RENDER_UTILS_TEXTURE_HIGHLIGHT_DEPTH, SurfaceGeometryDepth = RENDER_UTILS_TEXTURE_SG_DEPTH, diff --git a/libraries/render-utils/src/render-utils/ssao_buildNormals.slp b/libraries/render-utils/src/render-utils/ssao_buildNormals.slp new file mode 100644 index 0000000000..d4d8ec4b01 --- /dev/null +++ b/libraries/render-utils/src/render-utils/ssao_buildNormals.slp @@ -0,0 +1 @@ +VERTEX gpu::vertex::DrawViewportQuadTransformTexcoord diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index b1103fbbac..bda163fb8c 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -98,32 +98,13 @@ float getBlurEdgeSharpness() { return params._blurInfo.x; } -#ifdef CONSTANT_GAUSSIAN -const int BLUR_RADIUS = 4; -const float gaussian[BLUR_RADIUS + 1] = -// KEEP this dead code for eventual performance improvment -// float[](0.356642, 0.239400, 0.072410, 0.009869); -// float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0 -float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0 -//float[](0.197413, 0.17467, 0.12098,0.065591,0.040059); -// float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0 - -int getBlurRadius() { - return BLUR_RADIUS; -} - -float getBlurCoef(int c) { - return gaussian[c]; -} -#else int getBlurRadius() { return int(params._blurInfo.y); } float getBlurCoef(int c) { - return params._gaussianCoefs[c]; + return params._blurFilterTaps[c]; } -#endif <@endfunc@> @@ -219,6 +200,7 @@ vec3 getTapLocationClampedSSAO(int sampleNumber, float spinAngle, float outerRad // the depth pyramid texture layout(binding=RENDER_UTILS_TEXTURE_SSAO_DEPTH) uniform sampler2D depthPyramidTex; +layout(binding=RENDER_UTILS_TEXTURE_SSAO_NORMAL) uniform sampler2D normalTex; float getZEyeAtPixel(ivec2 pixel, int level) { return -texelFetch(depthPyramidTex, pixel, level).x; @@ -228,8 +210,12 @@ float getZEyeAtUV(vec2 texCoord, int level) { return -texture(depthPyramidTex, texCoord, level).x; } +vec3 getNormalEyeAtUV(vec2 texCoord, int level) { + return normalize(texture(normalTex, texCoord, level).xyz*2.0 - vec3(1.0)); +} + int evalMipFromRadius(float radius) { - const int LOG_MAX_OFFSET = 1; + const int LOG_MAX_OFFSET = 2; const int MAX_MIP_LEVEL = 5; return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); } @@ -406,24 +392,22 @@ float fetchOcclusion(vec2 coords) { return raw.x; } -const float BLUR_WEIGHT_OFFSET = 0.01; const float BLUR_EDGE_DISTANCE_SCALE = 300.0; vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float fragDepth) { ivec2 tapOffset = <$axis$> * r; - ivec2 tapPixelCoord = destPixelCoord + tapOffset; + ivec2 tapPixelCoord = destPixelCoord + ivec2(tapOffset); if ((tapPixelCoord.x < side.y || tapPixelCoord.x >= side.z + side.y) || (tapPixelCoord.y < 0 || tapPixelCoord.y >= getBlurImageHeight())) { return vec2(0.0); } + vec2 tapTexCoord = scaledTexCoord + tapOffset * getOcclusionBlurScale(); float tapOcclusion = fetchOcclusion(tapTexCoord); tapTexCoord = fullTexCoord + tapOffset * getDepthBlurScale(); float tapDepth = getZEyeAtUV(tapTexCoord, 0); - - // spatial domain: offset gaussian tap - float weight = BLUR_WEIGHT_OFFSET + getBlurCoef(abs(r)); + float weight = getBlurCoef(abs(r)); // range domain (the "bilateral" weight). As depth difference increases, decrease weight. float zDistance = tapDepth - fragDepth; @@ -441,6 +425,7 @@ vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTex // Accumulate weighted contributions along the bluring axis in the [-radius, radius] range int blurRadius = getBlurRadius(); + // negative side first for (int r = -blurRadius; r <= -1; ++r) { weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth); diff --git a/libraries/render-utils/src/ssao_buildNormals.slf b/libraries/render-utils/src/ssao_buildNormals.slf new file mode 100644 index 0000000000..dbea5028c5 --- /dev/null +++ b/libraries/render-utils/src/ssao_buildNormals.slf @@ -0,0 +1,45 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// ssao_buildNormals.frag +// +// Created by Olivier Prat on 09/19/18. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include ssao.slh@> +<$declareAmbientOcclusion()$> +<$declareFetchDepthPyramidMap()$> + +layout(location=0) out vec4 outFragColor; + +void main(void) { + vec2 sideImageSize = getSideImageSize(0); + + // Pixel being shaded + vec2 fragCoord = gl_FragCoord.xy; + ivec2 fragPixelPos = ivec2(fragCoord.xy); + + // Stereo side info + ivec4 side = getStereoSideInfo(fragPixelPos.x, 0); + + // From now on, fragPixelPos is the pixel pos in the side + fragPixelPos.x -= side.y; + vec2 fragUVPos = (vec2(fragPixelPos) + vec2(0.5)) / sideImageSize; + + // Fetch the z under the pixel (stereo or not) + float Zeye = getZEyeAtUV(fragUVPos, 0); + + // The position and normal of the pixel fragment in Eye space + vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); + vec3 fragNormalES = evalEyeNormal(fragPositionES); + vec3 absFragNormalES = abs(fragNormalES); + + // Maximize encoding precision + fragNormalES /= max(max(absFragNormalES.x, absFragNormalES.y), absFragNormalES.z); + outFragColor = vec4(vec3(fragNormalES)*0.5 + vec3(0.5), 1.0); +} diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index bdaa87fff9..10310e8984 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -46,7 +46,11 @@ void main(void) { // The position and normal of the pixel fragment in Eye space vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); +#if SSAO_USE_QUAD_SPLIT + vec3 fragNormalES = getNormalEyeAtUV(fragUVPos, 0); +#else vec3 fragNormalES = evalEyeNormal(fragPositionES); +#endif // Choose the screen-space sample radius float diskPixelRadius = evalDiskRadius(fragPositionES.z, sideImageSize); diff --git a/libraries/render-utils/src/ssao_shared.h b/libraries/render-utils/src/ssao_shared.h index 61bf14ccf8..89738fcea0 100644 --- a/libraries/render-utils/src/ssao_shared.h +++ b/libraries/render-utils/src/ssao_shared.h @@ -39,7 +39,7 @@ struct AmbientOcclusionParams { SSAO_VEC4 _ditheringInfo; SSAO_VEC4 _sampleInfo; SSAO_VEC4 _blurInfo; - float _gaussianCoefs[SSAO_BLUR_GAUSSIAN_COEFS_COUNT]; + float _blurFilterTaps[SSAO_BLUR_GAUSSIAN_COEFS_COUNT]; }; struct AmbientOcclusionFrameParams { diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index f92b469626..141832e202 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -35,11 +35,12 @@ Rectangle { model: [ "Radius:radius:2.0:false", "Level:obscuranceLevel:1.0:false", - "Num Taps:numSamples:32:true", + "Num Taps:numSamples:16:true", "Taps Spiral:numSpiralTurns:10.0:false", "Falloff Angle:falloffAngle:0.5:false", "Blur Edge Sharpness:edgeSharpness:1.0:false", - "Blur Radius:blurRadius:15.0:false", + "Blur Radius:blurRadius:15.0:true", + "Resolution Downscale:resolutionLevel:2:true", ] ConfigSlider { label: qsTr(modelData.split(":")[0]) @@ -57,7 +58,6 @@ Rectangle { Column { Repeater { model: [ - "resolutionLevel:resolutionLevel", "ditheringEnabled:ditheringEnabled", "fetchMipsEnabled:fetchMipsEnabled", "borderingEnabled:borderingEnabled" From 6921e71a9aec8c2dc1a54dd0b5d5424e0826332f Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 19 Sep 2018 17:49:01 +0200 Subject: [PATCH 31/81] Added normal distance to bilateral filtering --- .../render-utils/src/AmbientOcclusionEffect.cpp | 2 +- libraries/render-utils/src/ssao.slh | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 667127983a..1e3f2d9db3 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -444,7 +444,7 @@ void AmbientOcclusionEffect::updateGaussianDistribution() { auto filterTaps = _aoParametersBuffer.edit()._blurFilterTaps; auto blurRadius = _aoParametersBuffer.get().getBlurRadius(); - GaussianDistribution::evalSampling(filterTaps, SSAO_BLUR_GAUSSIAN_COEFS_COUNT, blurRadius, _aoParametersBuffer->getBlurDeviation() * 4.0f / blurRadius); + GaussianDistribution::evalSampling(filterTaps, SSAO_BLUR_GAUSSIAN_COEFS_COUNT, blurRadius, _aoParametersBuffer->getBlurDeviation()); } void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index bda163fb8c..3d092d5e4a 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -393,8 +393,9 @@ float fetchOcclusion(vec2 coords) { } const float BLUR_EDGE_DISTANCE_SCALE = 300.0; +const float BLUR_EDGE_NORMAL_SCALE = 0.5; -vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float fragDepth) { +vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float fragDepth, vec3 fragNormal) { ivec2 tapOffset = <$axis$> * r; ivec2 tapPixelCoord = destPixelCoord + ivec2(tapOffset); @@ -407,11 +408,14 @@ vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTe tapTexCoord = fullTexCoord + tapOffset * getDepthBlurScale(); float tapDepth = getZEyeAtUV(tapTexCoord, 0); + vec3 tapNormal = getNormalEyeAtUV(tapTexCoord, 0); float weight = getBlurCoef(abs(r)); // range domain (the "bilateral" weight). As depth difference increases, decrease weight. float zDistance = tapDepth - fragDepth; - weight *= exp(-getBlurEdgeSharpness() * (zDistance * zDistance * BLUR_EDGE_DISTANCE_SCALE)); + tapNormal -= fragNormal; + float normalDistance = dot(tapNormal,tapNormal); + weight *= exp(-getBlurEdgeSharpness() * (zDistance * zDistance * BLUR_EDGE_DISTANCE_SCALE + normalDistance * BLUR_EDGE_NORMAL_SCALE)); return vec2(tapOcclusion * weight, weight); } @@ -421,6 +425,7 @@ vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTex ivec4 side = getStereoSideInfo(destPixelCoord.x, 0); float fragDepth = getZEyeAtUV(fullTexCoord, 0); + vec3 fragNormal = getNormalEyeAtUV(fullTexCoord, 0); vec2 weightedSums = vec2(0.0); // Accumulate weighted contributions along the bluring axis in the [-radius, radius] range @@ -428,7 +433,7 @@ vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTex // negative side first for (int r = -blurRadius; r <= -1; ++r) { - weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth); + weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth, fragNormal); } // Central pixel contribution @@ -438,7 +443,7 @@ vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTex // then positive side for (int r = 1; r <= blurRadius; ++r) { - weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth); + weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth, fragNormal); } // Final normalization From b1db7ab40356044d1a9035cc5f9c273fbe098870 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 20 Sep 2018 10:18:06 +0200 Subject: [PATCH 32/81] Fixed for stereo rendering with resolution level 0 --- .../src/AmbientOcclusionEffect.cpp | 46 ++++++++++--------- .../render-utils/src/DeferredTransform.slh | 12 ++++- libraries/render-utils/src/ssao.slh | 16 ++++--- .../render-utils/src/ssao_buildNormals.slf | 8 ++-- .../render-utils/src/ssao_debugOcclusion.slf | 2 +- libraries/render-utils/src/ssao_gather.slf | 4 +- .../render-utils/src/ssao_makeOcclusion.slf | 19 ++++---- libraries/render/src/render/BlurTask.slh | 2 +- .../src/render/blurGaussianDepthAwareH.slf | 2 +- .../src/render/blurGaussianDepthAwareV.slf | 2 +- libraries/render/src/render/blurGaussianH.slf | 2 +- libraries/render/src/render/blurGaussianV.slf | 2 +- 12 files changed, 67 insertions(+), 50 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 1e3f2d9db3..2314568720 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -212,7 +212,7 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : #else numSamples{ 16 }, #endif - resolutionLevel{ 2 }, + resolutionLevel{ 0 }, blurRadius{ 4 }, ditheringEnabled{ true }, borderingEnabled{ true }, @@ -509,7 +509,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto& sample = _aoFrameParametersBuffer[splitId].edit(); sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId]; } - // TEMPO OP _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; + // _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) { PROFILE_RANGE_BATCH(batch, "AmbientOcclusion"); @@ -605,27 +605,31 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte { PROFILE_RANGE_BATCH(batch, "Bilateral Blur"); // Blur 1st pass - model.setScale(resolutionScale); - batch.setModelTransform(model); - batch.setViewportTransform(firstBlurViewport); - batch.setFramebuffer(occlusionBlurredFBO); - // Use full resolution depth and normal for bilateral upscaling and blur - batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); - batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, fullNormalTexture); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _hblurParametersBuffer); - batch.setPipeline(firstHBlurPipeline); - batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionFBO->getRenderBuffer(0)); - batch.draw(gpu::TRIANGLE_STRIP, 4); + batch.pushProfileRange("Horizontal"); + model.setScale(resolutionScale); + batch.setModelTransform(model); + batch.setViewportTransform(firstBlurViewport); + batch.setFramebuffer(occlusionBlurredFBO); + // Use full resolution depth and normal for bilateral upscaling and blur + batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); + batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, fullNormalTexture); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _hblurParametersBuffer); + batch.setPipeline(firstHBlurPipeline); + batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionFBO->getRenderBuffer(0)); + batch.draw(gpu::TRIANGLE_STRIP, 4); + batch.popProfileRange(); // Blur 2nd pass - model.setScale(glm::vec3(1.0f, resolutionScale, 1.0f)); - batch.setModelTransform(model); - batch.setViewportTransform(sourceViewport); - batch.setFramebuffer(occlusionFBO); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _vblurParametersBuffer); - batch.setPipeline(lastVBlurPipeline); - batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionBlurredFBO->getRenderBuffer(0)); - batch.draw(gpu::TRIANGLE_STRIP, 4); + batch.pushProfileRange("Vertical"); + model.setScale(glm::vec3(1.0f, resolutionScale, 1.0f)); + batch.setModelTransform(model); + batch.setViewportTransform(sourceViewport); + batch.setFramebuffer(occlusionFBO); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _vblurParametersBuffer); + batch.setPipeline(lastVBlurPipeline); + batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionBlurredFBO->getRenderBuffer(0)); + batch.draw(gpu::TRIANGLE_STRIP, 4); + batch.popProfileRange(); } batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, nullptr); diff --git a/libraries/render-utils/src/DeferredTransform.slh b/libraries/render-utils/src/DeferredTransform.slh index 19986805f6..d9ced66edf 100644 --- a/libraries/render-utils/src/DeferredTransform.slh +++ b/libraries/render-utils/src/DeferredTransform.slh @@ -120,8 +120,8 @@ float getStereoSideHeight(int resolutionLevel) { return float(int(frameTransform._pixelInfo.w) >> resolutionLevel); } -vec2 getSideImageSize(int resolutionLevel) { - return vec2(float(int(frameTransform._stereoInfo.y) >> resolutionLevel), float(int(frameTransform._pixelInfo.w) >> resolutionLevel)); +vec2 getStereoSideSize(int resolutionLevel) { + return vec2(getStereoSideWidth(resolutionLevel), getStereoSideHeight(resolutionLevel)); } ivec4 getStereoSideInfo(int xPos, int resolutionLevel) { @@ -129,6 +129,14 @@ ivec4 getStereoSideInfo(int xPos, int resolutionLevel) { return ivec4(xPos < sideWidth ? ivec2(0, 0) : ivec2(1, sideWidth), sideWidth, isStereo()); } +int getStereoSide(ivec4 sideInfo) { + return sideInfo.x; +} + +bool isStereoFromInfo(ivec4 sideInfo) { + return sideInfo.w != 0; +} + float evalZeyeFromZdb(float depth) { return frameTransform._depthInfo.x / (depth * frameTransform._depthInfo.y + frameTransform._depthInfo.z); } diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 3d092d5e4a..c4efb3be89 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -214,19 +214,23 @@ vec3 getNormalEyeAtUV(vec2 texCoord, int level) { return normalize(texture(normalTex, texCoord, level).xyz*2.0 - vec3(1.0)); } +vec3 getNormalEyeAtPixel(ivec2 pixel, int level) { + return normalize(texelFetch(normalTex, pixel, level).xyz*2.0 - vec3(1.0)); +} + int evalMipFromRadius(float radius) { const int LOG_MAX_OFFSET = 2; const int MAX_MIP_LEVEL = 5; return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); } -vec4 fetchTap(ivec4 side, vec2 tapPixelPos, float tapRadius, vec2 sideImageSize) { +vec4 fetchTap(ivec4 side, vec2 tapSidePixelPos, float tapRadius, vec2 sideImageSize) { int mipLevel = evalMipFromRadius(tapRadius * float(doFetchMips())); // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. // Manually clamp to the texture size because texelFetch bypasses the texture unit - vec2 tapUV = (tapPixelPos + vec2(0.5)) / sideImageSize; - vec2 fetchUV = vec2(tapUV.x + side.w * 0.5 * (side.x - tapUV.x), tapUV.y); + vec2 tapUV = (tapSidePixelPos + vec2(0.5)) / sideImageSize; + vec2 fetchUV = mix(tapUV, vec2((tapUV.x + getStereoSide(side)) * 0.5, tapUV.y), isStereoFromInfo(side)); vec4 P; P.xy = tapUV; @@ -276,11 +280,11 @@ float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNo } <@func computeHorizon()@> - vec2 tapPixelPos = tapPixelOffset + shadedPixelPos; - if (tapPixelPos.x<0 && tapPixelPos.y<0 && tapPixelPos.x>=sideImageSize.x && tapPixelPos.y>=sideImageSize.y) { + vec2 tapSidePixelPos = tapPixelOffset + shadedPixelPos; + if (tapSidePixelPos.x<0 && tapSidePixelPos.y<0 && tapSidePixelPos.x>=sideImageSize.x && tapSidePixelPos.y>=sideImageSize.y) { break; } - vec4 tapUVZ_mip = fetchTap(side, tapPixelPos, radius, sideImageSize); + vec4 tapUVZ_mip = fetchTap(side, tapSidePixelPos, radius, sideImageSize); vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ_mip.z, tapUVZ_mip.xy); float tapCosHorizonAngle = computeHorizonFromTap(tapPositionES, fragPositionES, fragNormalES); diff --git a/libraries/render-utils/src/ssao_buildNormals.slf b/libraries/render-utils/src/ssao_buildNormals.slf index dbea5028c5..4d7d6e6530 100644 --- a/libraries/render-utils/src/ssao_buildNormals.slf +++ b/libraries/render-utils/src/ssao_buildNormals.slf @@ -18,12 +18,15 @@ layout(location=0) out vec4 outFragColor; void main(void) { - vec2 sideImageSize = getSideImageSize(0); + vec2 sideImageSize = getStereoSideSize(0); // Pixel being shaded vec2 fragCoord = gl_FragCoord.xy; ivec2 fragPixelPos = ivec2(fragCoord.xy); + // Fetch the z under the pixel (stereo or not) + float Zeye = getZEyeAtPixel(fragPixelPos, 0); + // Stereo side info ivec4 side = getStereoSideInfo(fragPixelPos.x, 0); @@ -31,9 +34,6 @@ void main(void) { fragPixelPos.x -= side.y; vec2 fragUVPos = (vec2(fragPixelPos) + vec2(0.5)) / sideImageSize; - // Fetch the z under the pixel (stereo or not) - float Zeye = getZEyeAtUV(fragUVPos, 0); - // The position and normal of the pixel fragment in Eye space vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); vec3 fragNormalES = evalEyeNormal(fragPositionES); diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf index 10069582aa..2c1824dce7 100644 --- a/libraries/render-utils/src/ssao_debugOcclusion.slf +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -37,7 +37,7 @@ vec2 getDebugCursorTexcoord(){ layout(location=0) out vec4 outFragColor; void main(void) { - vec2 imageSize = getSideImageSize(getResolutionLevel()); + vec2 imageSize = getStereoSideSize(getResolutionLevel()); // In debug adjust the correct frag pixel based on base resolution vec2 fragCoord = gl_FragCoord.xy; diff --git a/libraries/render-utils/src/ssao_gather.slf b/libraries/render-utils/src/ssao_gather.slf index 32edec515b..8f2282154a 100644 --- a/libraries/render-utils/src/ssao_gather.slf +++ b/libraries/render-utils/src/ssao_gather.slf @@ -25,8 +25,8 @@ void main(void) { // Gather the four splits of the occlusion result back into an interleaved full size // result (at the resolution level, of course) ivec2 destPixelCoord = ivec2(gl_FragCoord.xy); - ivec2 sourcePixelCoord = destPixelCoord >> 1; - ivec2 splitImageSize = ivec2(getWidthHeight(getResolutionLevel() + 1)); + ivec2 sourcePixelCoord = destPixelCoord / 2; + ivec2 splitImageSize = ivec2(getWidthHeight(getResolutionLevel()+1)); sourcePixelCoord += (destPixelCoord & ivec2(1)) * splitImageSize; diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 10310e8984..fee4d6f84f 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -24,14 +24,20 @@ layout(location=0) out vec4 outFragColor; void main(void) { - vec2 sideImageSize = getSideImageSize(getResolutionLevel()); + vec2 sideImageSize = getStereoSideSize(getResolutionLevel()); // Pixel being shaded vec2 fragCoord = gl_FragCoord.xy; ivec2 fragPixelPos = ivec2(fragCoord.xy); #if SSAO_USE_QUAD_SPLIT - ivec2 splitImageSize = ivec2(getWidthHeight(getResolutionLevel() + SSAO_USE_QUAD_SPLIT)); - fragPixelPos = ((fragPixelPos - getPixelOffset()*splitImageSize) << SSAO_USE_QUAD_SPLIT) + getPixelOffset(); + ivec2 splitImageSize = ivec2(getWidthHeight(getResolutionLevel()+1)); + fragPixelPos = ((fragPixelPos - getPixelOffset()*splitImageSize) * 2) + getPixelOffset(); +#endif + + // Fetch the z under the pixel (stereo or not) + float Zeye = getZEyeAtPixel(fragPixelPos, 0); +#if SSAO_USE_QUAD_SPLIT + vec3 fragNormalES = getNormalEyeAtPixel(fragPixelPos, 0); #endif // Stereo side info @@ -41,14 +47,9 @@ void main(void) { fragPixelPos.x -= side.y; vec2 fragUVPos = (vec2(fragPixelPos) + vec2(0.5)) / sideImageSize; - // Fetch the z under the pixel (stereo or not) - float Zeye = getZEyeAtUV(fragUVPos, 0); - // The position and normal of the pixel fragment in Eye space vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); -#if SSAO_USE_QUAD_SPLIT - vec3 fragNormalES = getNormalEyeAtUV(fragUVPos, 0); -#else +#if !SSAO_USE_QUAD_SPLIT vec3 fragNormalES = evalEyeNormal(fragPositionES); #endif diff --git a/libraries/render/src/render/BlurTask.slh b/libraries/render/src/render/BlurTask.slh index c07e71688a..a2862f123f 100644 --- a/libraries/render/src/render/BlurTask.slh +++ b/libraries/render/src/render/BlurTask.slh @@ -25,7 +25,7 @@ layout(binding=0) uniform blurParamsBuffer { BlurParameters parameters; }; -vec2 getViewportInvWidthHeight() { +vec2 getInvWidthHeight() { return parameters.resolutionInfo.zw; } diff --git a/libraries/render/src/render/blurGaussianDepthAwareH.slf b/libraries/render/src/render/blurGaussianDepthAwareH.slf index 09a92909ff..04894e3d51 100644 --- a/libraries/render/src/render/blurGaussianDepthAwareH.slf +++ b/libraries/render/src/render/blurGaussianDepthAwareH.slf @@ -19,6 +19,6 @@ layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; void main(void) { - outFragColor = pixelShaderGaussianDepthAware(varTexCoord0, vec2(1.0, 0.0), getViewportInvWidthHeight()); + outFragColor = pixelShaderGaussianDepthAware(varTexCoord0, vec2(1.0, 0.0), getInvWidthHeight()); } diff --git a/libraries/render/src/render/blurGaussianDepthAwareV.slf b/libraries/render/src/render/blurGaussianDepthAwareV.slf index 4f9bc86c01..129f9f7ce3 100644 --- a/libraries/render/src/render/blurGaussianDepthAwareV.slf +++ b/libraries/render/src/render/blurGaussianDepthAwareV.slf @@ -19,6 +19,6 @@ layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; void main(void) { - outFragColor = pixelShaderGaussianDepthAware(varTexCoord0, vec2(0.0, 1.0), getViewportInvWidthHeight()); + outFragColor = pixelShaderGaussianDepthAware(varTexCoord0, vec2(0.0, 1.0), getInvWidthHeight()); } diff --git a/libraries/render/src/render/blurGaussianH.slf b/libraries/render/src/render/blurGaussianH.slf index 1c13664907..251ef158f2 100644 --- a/libraries/render/src/render/blurGaussianH.slf +++ b/libraries/render/src/render/blurGaussianH.slf @@ -20,6 +20,6 @@ layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; void main(void) { - outFragColor = pixelShaderGaussian(varTexCoord0, vec2(1.0, 0.0), getViewportInvWidthHeight()); + outFragColor = pixelShaderGaussian(varTexCoord0, vec2(1.0, 0.0), getInvWidthHeight()); } diff --git a/libraries/render/src/render/blurGaussianV.slf b/libraries/render/src/render/blurGaussianV.slf index f8351f9670..c1215e8553 100644 --- a/libraries/render/src/render/blurGaussianV.slf +++ b/libraries/render/src/render/blurGaussianV.slf @@ -19,6 +19,6 @@ layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; void main(void) { - outFragColor = pixelShaderGaussian(varTexCoord0, vec2(0.0, 1.0), getViewportInvWidthHeight()); + outFragColor = pixelShaderGaussian(varTexCoord0, vec2(0.0, 1.0), getInvWidthHeight()); } From d5d0f056a9d89f676fd15c5372f0da3cb4320fdb Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 20 Sep 2018 11:15:25 +0200 Subject: [PATCH 33/81] Fixed for any resolution level in stereo --- .../src/AmbientOcclusionEffect.cpp | 48 +++++++++++-------- .../render-utils/src/AmbientOcclusionEffect.h | 7 ++- libraries/render-utils/src/ssao.slh | 4 ++ .../render-utils/src/ssao_buildNormals.slf | 10 ++-- .../render-utils/src/ssao_makeOcclusion.slf | 4 +- 5 files changed, 45 insertions(+), 28 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 2314568720..5cb95c01b2 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -87,10 +87,6 @@ void AmbientOcclusionFramebuffer::allocate() { _occlusionBlurredTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusionBlurred")); _occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture); - - _normalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_R11G11B10, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT, gpu::Sampler::WRAP_CLAMP)); - _normalFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("ssaoNormals")); - _normalFramebuffer->setRenderBuffer(0, _normalTexture); } gpu::FramebufferPointer AmbientOcclusionFramebuffer::getOcclusionFramebuffer() { @@ -121,16 +117,26 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getOcclusionBlurredTexture() { return _occlusionBlurredTexture; } -gpu::FramebufferPointer AmbientOcclusionFramebuffer::getNormalFramebuffer() { - if (!_normalFramebuffer) { - allocate(); +void AmbientOcclusionFramebuffer::allocate(int resolutionLevel) { + auto width = _frameSize.x >> resolutionLevel; + auto height = _frameSize.y >> resolutionLevel; + + _normalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_R11G11B10, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT, gpu::Sampler::WRAP_CLAMP)); + _normalFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("ssaoNormals")); + _normalFramebuffer->setRenderBuffer(0, _normalTexture); + _resolutionLevel = resolutionLevel; +} + +gpu::FramebufferPointer AmbientOcclusionFramebuffer::getNormalFramebuffer(int resolutionLevel) { + if (!_normalFramebuffer || resolutionLevel != _resolutionLevel) { + allocate(resolutionLevel); } return _normalFramebuffer; } -gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() { - if (!_normalTexture) { - allocate(); +gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture(int resolutionLevel) { + if (!_normalTexture || resolutionLevel != _resolutionLevel) { + allocate(resolutionLevel); } return _normalTexture; } @@ -208,11 +214,11 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : blurDeviation{ 2.5f }, numSpiralTurns{ 7.0f }, #if SSAO_USE_HORIZON_BASED - numSamples{ 2 }, + numSamples{ 3 }, #else numSamples{ 16 }, #endif - resolutionLevel{ 0 }, + resolutionLevel{ 2 }, blurRadius{ 4 }, ditheringEnabled{ true }, borderingEnabled{ true }, @@ -470,10 +476,11 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte _framebuffer = std::make_shared(); } - const auto resolutionScale = powf(0.5f, _aoParametersBuffer->getResolutionLevel()); - if (_aoParametersBuffer->getResolutionLevel() > 0) { - occlusionViewport = occlusionViewport >> _aoParametersBuffer->getResolutionLevel(); - firstBlurViewport.w = firstBlurViewport.w >> _aoParametersBuffer->getResolutionLevel(); + const int resolutionLevel = _aoParametersBuffer->getResolutionLevel(); + const auto resolutionScale = powf(0.5f, resolutionLevel); + if (resolutionLevel > 0) { + occlusionViewport = occlusionViewport >> resolutionLevel; + firstBlurViewport.w = firstBlurViewport.w >> resolutionLevel; occlusionDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); } @@ -498,8 +505,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #if SSAO_USE_QUAD_SPLIT auto gatherPipeline = getGatherPipeline(); auto buildNormalsPipeline = getBuildNormalsPipeline(); - auto occlusionNormalFramebuffer = _framebuffer->getNormalFramebuffer(); - auto occlusionNormalTexture = _framebuffer->getNormalTexture(); + auto occlusionNormalFramebuffer = _framebuffer->getNormalFramebuffer(resolutionLevel); + auto occlusionNormalTexture = _framebuffer->getNormalTexture(resolutionLevel); #endif auto fullNormalTexture = linearDepthFramebuffer->getNormalTexture(); @@ -536,12 +543,13 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #if SSAO_USE_QUAD_SPLIT // Build derivative normals pass batch.pushProfileRange("Build Normals"); - batch.setViewportTransform(sourceViewport); + batch.setViewportTransform(occlusionViewport); batch.setPipeline(buildNormalsPipeline); + batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); + batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, nullptr); batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); batch.setFramebuffer(occlusionNormalFramebuffer); - batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); batch.draw(gpu::TRIANGLE_STRIP, 4); batch.popProfileRange(); #endif diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index e04e24b4f4..1509cf6492 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -31,8 +31,8 @@ public: gpu::FramebufferPointer getOcclusionBlurredFramebuffer(); gpu::TexturePointer getOcclusionBlurredTexture(); - gpu::FramebufferPointer getNormalFramebuffer(); - gpu::TexturePointer getNormalTexture(); + gpu::FramebufferPointer getNormalFramebuffer(int resolutionLevel); + gpu::TexturePointer getNormalTexture(int resolutionLevel); // Update the source framebuffer size which will drive the allocation of all the other resources. bool updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer); @@ -40,8 +40,10 @@ public: const glm::ivec2& getSourceFrameSize() const { return _frameSize; } protected: + void clear(); void allocate(); + void allocate(int resolutionLevel); gpu::TexturePointer _linearDepthTexture; @@ -56,6 +58,7 @@ protected: glm::ivec2 _frameSize; + int _resolutionLevel{ 0 }; }; using AmbientOcclusionFramebufferPointer = std::shared_ptr; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index c4efb3be89..dec0109922 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -202,6 +202,10 @@ vec3 getTapLocationClampedSSAO(int sampleNumber, float spinAngle, float outerRad layout(binding=RENDER_UTILS_TEXTURE_SSAO_DEPTH) uniform sampler2D depthPyramidTex; layout(binding=RENDER_UTILS_TEXTURE_SSAO_NORMAL) uniform sampler2D normalTex; +ivec2 getDepthTextureSize(int level) { + return textureSize(depthPyramidTex, level); +} + float getZEyeAtPixel(ivec2 pixel, int level) { return -texelFetch(depthPyramidTex, pixel, level).x; } diff --git a/libraries/render-utils/src/ssao_buildNormals.slf b/libraries/render-utils/src/ssao_buildNormals.slf index 4d7d6e6530..8e06d4ffc9 100644 --- a/libraries/render-utils/src/ssao_buildNormals.slf +++ b/libraries/render-utils/src/ssao_buildNormals.slf @@ -18,17 +18,19 @@ layout(location=0) out vec4 outFragColor; void main(void) { - vec2 sideImageSize = getStereoSideSize(0); + vec2 sideImageSize = getStereoSideSize(getResolutionLevel()); + ivec2 renderSize = ivec2(sideImageSize) << ivec2(int(isStereo()) & 1, 0); // Pixel being shaded vec2 fragCoord = gl_FragCoord.xy; ivec2 fragPixelPos = ivec2(fragCoord.xy); // Fetch the z under the pixel (stereo or not) - float Zeye = getZEyeAtPixel(fragPixelPos, 0); + ivec2 depthTexFragPixelPos = fragPixelPos * getDepthTextureSize(0) / renderSize ; + float Zeye = getZEyeAtPixel(depthTexFragPixelPos, 0); // Stereo side info - ivec4 side = getStereoSideInfo(fragPixelPos.x, 0); + ivec4 side = getStereoSideInfo(fragPixelPos.x, getResolutionLevel()); // From now on, fragPixelPos is the pixel pos in the side fragPixelPos.x -= side.y; @@ -39,7 +41,5 @@ void main(void) { vec3 fragNormalES = evalEyeNormal(fragPositionES); vec3 absFragNormalES = abs(fragNormalES); - // Maximize encoding precision - fragNormalES /= max(max(absFragNormalES.x, absFragNormalES.y), absFragNormalES.z); outFragColor = vec4(vec3(fragNormalES)*0.5 + vec3(0.5), 1.0); } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index fee4d6f84f..3db497fdc7 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -25,6 +25,7 @@ layout(location=0) out vec4 outFragColor; void main(void) { vec2 sideImageSize = getStereoSideSize(getResolutionLevel()); + ivec2 renderSize = ivec2(sideImageSize) << ivec2(int(isStereo()) & 1, 0); // Pixel being shaded vec2 fragCoord = gl_FragCoord.xy; @@ -35,7 +36,8 @@ void main(void) { #endif // Fetch the z under the pixel (stereo or not) - float Zeye = getZEyeAtPixel(fragPixelPos, 0); + ivec2 depthTexFragPixelPos = fragPixelPos * getDepthTextureSize(0) / renderSize ; + float Zeye = getZEyeAtPixel(depthTexFragPixelPos, 0); #if SSAO_USE_QUAD_SPLIT vec3 fragNormalES = getNormalEyeAtPixel(fragPixelPos, 0); #endif From 64b72e353894ef407a79dd81903ad76302daee70 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 20 Sep 2018 11:27:00 +0200 Subject: [PATCH 34/81] Removed normal from bilateral blur... again --- .../render-utils/src/AmbientOcclusionEffect.cpp | 2 -- libraries/render-utils/src/ssao.slh | 13 ++++--------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 5cb95c01b2..2a3a3f9f4c 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -508,7 +508,6 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto occlusionNormalFramebuffer = _framebuffer->getNormalFramebuffer(resolutionLevel); auto occlusionNormalTexture = _framebuffer->getNormalTexture(resolutionLevel); #endif - auto fullNormalTexture = linearDepthFramebuffer->getNormalTexture(); // Update sample rotation const int SSAO_RANDOM_SAMPLE_COUNT = int(_randomSamples.size() / SSAO_SPLIT_COUNT); @@ -620,7 +619,6 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setFramebuffer(occlusionBlurredFBO); // Use full resolution depth and normal for bilateral upscaling and blur batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); - batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, fullNormalTexture); batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _hblurParametersBuffer); batch.setPipeline(firstHBlurPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionFBO->getRenderBuffer(0)); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index dec0109922..d34d92276b 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -401,9 +401,8 @@ float fetchOcclusion(vec2 coords) { } const float BLUR_EDGE_DISTANCE_SCALE = 300.0; -const float BLUR_EDGE_NORMAL_SCALE = 0.5; -vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float fragDepth, vec3 fragNormal) { +vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float fragDepth) { ivec2 tapOffset = <$axis$> * r; ivec2 tapPixelCoord = destPixelCoord + ivec2(tapOffset); @@ -416,14 +415,11 @@ vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTe tapTexCoord = fullTexCoord + tapOffset * getDepthBlurScale(); float tapDepth = getZEyeAtUV(tapTexCoord, 0); - vec3 tapNormal = getNormalEyeAtUV(tapTexCoord, 0); float weight = getBlurCoef(abs(r)); // range domain (the "bilateral" weight). As depth difference increases, decrease weight. float zDistance = tapDepth - fragDepth; - tapNormal -= fragNormal; - float normalDistance = dot(tapNormal,tapNormal); - weight *= exp(-getBlurEdgeSharpness() * (zDistance * zDistance * BLUR_EDGE_DISTANCE_SCALE + normalDistance * BLUR_EDGE_NORMAL_SCALE)); + weight *= exp(-getBlurEdgeSharpness() * (zDistance * zDistance * BLUR_EDGE_DISTANCE_SCALE)); return vec2(tapOcclusion * weight, weight); } @@ -433,7 +429,6 @@ vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTex ivec4 side = getStereoSideInfo(destPixelCoord.x, 0); float fragDepth = getZEyeAtUV(fullTexCoord, 0); - vec3 fragNormal = getNormalEyeAtUV(fullTexCoord, 0); vec2 weightedSums = vec2(0.0); // Accumulate weighted contributions along the bluring axis in the [-radius, radius] range @@ -441,7 +436,7 @@ vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTex // negative side first for (int r = -blurRadius; r <= -1; ++r) { - weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth, fragNormal); + weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth); } // Central pixel contribution @@ -451,7 +446,7 @@ vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTex // then positive side for (int r = 1; r <= blurRadius; ++r) { - weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth, fragNormal); + weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth); } // Final normalization From 1c2da13309b3a8859f44a50697cc64d6ef7ba4b8 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 20 Sep 2018 15:34:28 +0200 Subject: [PATCH 35/81] Much better face normal reconstruction --- libraries/render-utils/src/ssao.slh | 26 +++++++++++++++++++ .../render-utils/src/ssao_buildNormals.slf | 5 ++-- .../render-utils/src/ssao_makeOcclusion.slf | 5 ++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index d34d92276b..17ac229805 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -243,6 +243,32 @@ vec4 fetchTap(ivec4 side, vec2 tapSidePixelPos, float tapRadius, vec2 sideImageS return P; } +vec3 buildPosition(ivec4 side, vec2 fragUVPos, ivec2 depthTexFragPixelPos, ivec2 deltaDepthTexPixel, vec2 uvScale) { + depthTexFragPixelPos += deltaDepthTexPixel; + fragUVPos += deltaDepthTexPixel * uvScale; + float Zeye = getZEyeAtPixel(depthTexFragPixelPos, 0); + return evalEyePositionFromZeye(side.x, Zeye, fragUVPos); +} + +vec3 getMinDiff(vec3 centralPoint, vec3 offsetPoint0, vec3 offsetPoint1) { + vec3 delta0 = offsetPoint0 - centralPoint; + vec3 delta1 = centralPoint - offsetPoint1; + return dot(delta0, delta0) < dot(delta1, delta1) ? delta0 : delta1; +} + +vec3 buildNormal(ivec4 side, vec2 fragUVPos, ivec2 depthTexFragPixelPos, vec3 fragPositionES, ivec2 depthTextureScale, vec2 sideImageSize) { + vec2 uvScale = vec2(1.0) / (sideImageSize * depthTextureScale); + vec3 fragPositionDxPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(1,0), uvScale); + vec3 fragPositionDxNeg = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(-1,0), uvScale); + vec3 fragPositionDyPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(0,1), uvScale); + vec3 fragPositionDyNeg = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(0,-1), uvScale); + + vec3 fragPositionDx = getMinDiff(fragPositionES, fragPositionDxPos, fragPositionDxNeg); + vec3 fragPositionDy = getMinDiff(fragPositionES, fragPositionDyPos, fragPositionDyNeg); + + return normalize( cross(fragPositionDx, fragPositionDy) ); +} + <@endfunc@> diff --git a/libraries/render-utils/src/ssao_buildNormals.slf b/libraries/render-utils/src/ssao_buildNormals.slf index 8e06d4ffc9..f21a529807 100644 --- a/libraries/render-utils/src/ssao_buildNormals.slf +++ b/libraries/render-utils/src/ssao_buildNormals.slf @@ -26,7 +26,8 @@ void main(void) { ivec2 fragPixelPos = ivec2(fragCoord.xy); // Fetch the z under the pixel (stereo or not) - ivec2 depthTexFragPixelPos = fragPixelPos * getDepthTextureSize(0) / renderSize ; + ivec2 depthTextureScale = getDepthTextureSize(0) / renderSize; + ivec2 depthTexFragPixelPos = fragPixelPos * depthTextureScale; float Zeye = getZEyeAtPixel(depthTexFragPixelPos, 0); // Stereo side info @@ -38,7 +39,7 @@ void main(void) { // The position and normal of the pixel fragment in Eye space vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); - vec3 fragNormalES = evalEyeNormal(fragPositionES); + vec3 fragNormalES = buildNormal(side, fragUVPos, depthTexFragPixelPos, fragPositionES, depthTextureScale, sideImageSize); vec3 absFragNormalES = abs(fragNormalES); outFragColor = vec4(vec3(fragNormalES)*0.5 + vec3(0.5), 1.0); diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 3db497fdc7..cee5ef6fe3 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -36,7 +36,8 @@ void main(void) { #endif // Fetch the z under the pixel (stereo or not) - ivec2 depthTexFragPixelPos = fragPixelPos * getDepthTextureSize(0) / renderSize ; + ivec2 depthTextureScale = getDepthTextureSize(0) / renderSize; + ivec2 depthTexFragPixelPos = fragPixelPos * depthTextureScale; float Zeye = getZEyeAtPixel(depthTexFragPixelPos, 0); #if SSAO_USE_QUAD_SPLIT vec3 fragNormalES = getNormalEyeAtPixel(fragPixelPos, 0); @@ -52,7 +53,7 @@ void main(void) { // The position and normal of the pixel fragment in Eye space vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); #if !SSAO_USE_QUAD_SPLIT - vec3 fragNormalES = evalEyeNormal(fragPositionES); + vec3 fragNormalES = buildNormal(side, fragUVPos, depthTexFragPixelPos, fragPositionES, depthTextureScale, sideImageSize); #endif // Choose the screen-space sample radius From cf739db3a5df0461e8a59f9bd50d9e22f903b9a9 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 20 Sep 2018 18:01:02 +0200 Subject: [PATCH 36/81] Added AO normal to Luci --- .../src/AmbientOcclusionEffect.cpp | 6 ++- .../render-utils/src/AmbientOcclusionEffect.h | 1 + .../render-utils/src/DebugDeferredBuffer.cpp | 4 ++ .../render-utils/src/DebugDeferredBuffer.h | 1 + libraries/render-utils/src/ssao.slh | 39 +++++++++---------- .../render-utils/src/ssao_buildNormals.slf | 3 +- .../utilities/render/deferredLighting.qml | 1 + 7 files changed, 31 insertions(+), 24 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 2a3a3f9f4c..3fcf4ef656 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -141,6 +141,10 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture(int resolution return _normalTexture; } +gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() { + return _normalTexture; +} + class GaussianDistribution { public: @@ -540,7 +544,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.popProfileRange(); #if SSAO_USE_QUAD_SPLIT - // Build derivative normals pass + // Build face normals pass batch.pushProfileRange("Build Normals"); batch.setViewportTransform(occlusionViewport); batch.setPipeline(buildNormalsPipeline); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 1509cf6492..b0752277c2 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -33,6 +33,7 @@ public: gpu::FramebufferPointer getNormalFramebuffer(int resolutionLevel); gpu::TexturePointer getNormalTexture(int resolutionLevel); + gpu::TexturePointer getNormalTexture(); // Update the source framebuffer size which will drive the allocation of all the other resources. bool updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 4a8fad7c6d..3959105829 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -321,6 +321,8 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string cust return DEFAULT_AMBIENT_OCCLUSION_SHADER; case AmbientOcclusionBlurredMode: return DEFAULT_AMBIENT_OCCLUSION_BLURRED_SHADER; + case AmbientOcclusionNormalMode: + return DEFAULT_HALF_NORMAL_SHADER; case VelocityMode: return DEFAULT_VELOCITY_SHADER; case CustomMode: @@ -469,6 +471,8 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I batch.setResourceTexture(Textures::DebugTexture0, ambientOcclusionFramebuffer->getOcclusionTexture()); } else if (_mode == AmbientOcclusionBlurredMode) { batch.setResourceTexture(Textures::DebugTexture0, ambientOcclusionFramebuffer->getOcclusionBlurredTexture()); + } else if (_mode == AmbientOcclusionNormalMode) { + batch.setResourceTexture(Textures::DebugTexture0, ambientOcclusionFramebuffer->getNormalTexture()); } } const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index 0fc006b452..2b8b288a83 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -88,6 +88,7 @@ protected: ScatteringDebugMode, AmbientOcclusionMode, AmbientOcclusionBlurredMode, + AmbientOcclusionNormalMode, VelocityMode, CustomMode, // Needs to stay last diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 17ac229805..56566c9b6f 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -223,7 +223,7 @@ vec3 getNormalEyeAtPixel(ivec2 pixel, int level) { } int evalMipFromRadius(float radius) { - const int LOG_MAX_OFFSET = 2; + const int LOG_MAX_OFFSET = 1; const int MAX_MIP_LEVEL = 5; return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); } @@ -231,10 +231,8 @@ int evalMipFromRadius(float radius) { vec4 fetchTap(ivec4 side, vec2 tapSidePixelPos, float tapRadius, vec2 sideImageSize) { int mipLevel = evalMipFromRadius(tapRadius * float(doFetchMips())); - // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. - // Manually clamp to the texture size because texelFetch bypasses the texture unit vec2 tapUV = (tapSidePixelPos + vec2(0.5)) / sideImageSize; - vec2 fetchUV = mix(tapUV, vec2((tapUV.x + getStereoSide(side)) * 0.5, tapUV.y), isStereoFromInfo(side)); + vec2 fetchUV = mix(tapUV, vec2((tapUV.x + getStereoSide(side)) * 0.5, tapUV.y), isStereo()); vec4 P; P.xy = tapUV; @@ -250,21 +248,21 @@ vec3 buildPosition(ivec4 side, vec2 fragUVPos, ivec2 depthTexFragPixelPos, ivec2 return evalEyePositionFromZeye(side.x, Zeye, fragUVPos); } -vec3 getMinDiff(vec3 centralPoint, vec3 offsetPoint0, vec3 offsetPoint1) { - vec3 delta0 = offsetPoint0 - centralPoint; - vec3 delta1 = centralPoint - offsetPoint1; +vec3 getMinDelta(vec3 centralPoint, vec3 offsetPointPos, vec3 offsetPointNeg) { + vec3 delta0 = offsetPointPos - centralPoint; + vec3 delta1 = centralPoint - offsetPointNeg; return dot(delta0, delta0) < dot(delta1, delta1) ? delta0 : delta1; } -vec3 buildNormal(ivec4 side, vec2 fragUVPos, ivec2 depthTexFragPixelPos, vec3 fragPositionES, ivec2 depthTextureScale, vec2 sideImageSize) { +vec3 buildNormal(ivec4 side, vec2 fragUVPos, ivec2 depthTexFragPixelPos, vec3 fragPosition, ivec2 depthTextureScale, vec2 sideImageSize) { vec2 uvScale = vec2(1.0) / (sideImageSize * depthTextureScale); - vec3 fragPositionDxPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(1,0), uvScale); - vec3 fragPositionDxNeg = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(-1,0), uvScale); - vec3 fragPositionDyPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(0,1), uvScale); - vec3 fragPositionDyNeg = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(0,-1), uvScale); + vec3 fragPositionDxPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(1, 0), uvScale); + vec3 fragPositionDyPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(0, 1), uvScale); + vec3 fragPositionDxNeg = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(-1, 0), uvScale); + vec3 fragPositionDyNeg = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(0, -1), uvScale); - vec3 fragPositionDx = getMinDiff(fragPositionES, fragPositionDxPos, fragPositionDxNeg); - vec3 fragPositionDy = getMinDiff(fragPositionES, fragPositionDyPos, fragPositionDyNeg); + vec3 fragPositionDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg); + vec3 fragPositionDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg); return normalize( cross(fragPositionDx, fragPositionDy) ); } @@ -287,31 +285,30 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t float vv = dot(v, v); float vn = dot(v, centerNormal); - // Fall off function as recommended in SSAO paper + // Falloff function as recommended in SSAO paper const float epsilon = 0.01; float f = max(getRadius2() - vv, 0.0); return f * f * f * max((vn - getFalloffAngle()) / (epsilon + vv), 0.0); } float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES) { - const float epsilon = 0.01; + const float epsilon = 0.001; vec3 deltaVec = tapPositionES - fragPositionES; float distance = length(deltaVec); - float cosHorizonAngle = 0.0; + float cosHorizonAngle = dot(deltaVec, fragNormalES) / (distance + epsilon); float radiusFalloff = max(0.0, 1.0 - (distance*distance / getRadius2())); - cosHorizonAngle = dot(deltaVec, fragNormalES) / (distance + epsilon); cosHorizonAngle = max(0.0, (cosHorizonAngle - getFalloffAngle()) * getFalloffAngleScale()); cosHorizonAngle *= radiusFalloff; - return cosHorizonAngle; } <@func computeHorizon()@> vec2 tapSidePixelPos = tapPixelOffset + shadedPixelPos; - if (tapSidePixelPos.x<0 && tapSidePixelPos.y<0 && tapSidePixelPos.x>=sideImageSize.x && tapSidePixelPos.y>=sideImageSize.y) { + if (tapSidePixelPos.x<0 || tapSidePixelPos.y<0 || tapSidePixelPos.x>=sideImageSize.x || tapSidePixelPos.y>=sideImageSize.y) { + // Early exit because we've hit the borders of the frame break; } vec4 tapUVZ_mip = fetchTap(side, tapSidePixelPos, radius, sideImageSize); @@ -426,7 +423,7 @@ float fetchOcclusion(vec2 coords) { return raw.x; } -const float BLUR_EDGE_DISTANCE_SCALE = 300.0; +const float BLUR_EDGE_DISTANCE_SCALE = 1000.0; vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float fragDepth) { ivec2 tapOffset = <$axis$> * r; diff --git a/libraries/render-utils/src/ssao_buildNormals.slf b/libraries/render-utils/src/ssao_buildNormals.slf index f21a529807..f3af324455 100644 --- a/libraries/render-utils/src/ssao_buildNormals.slf +++ b/libraries/render-utils/src/ssao_buildNormals.slf @@ -40,7 +40,6 @@ void main(void) { // The position and normal of the pixel fragment in Eye space vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); vec3 fragNormalES = buildNormal(side, fragUVPos, depthTexFragPixelPos, fragPositionES, depthTextureScale, sideImageSize); - vec3 absFragNormalES = abs(fragNormalES); - + outFragColor = vec4(vec3(fragNormalES)*0.5 + vec3(0.5), 1.0); } diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 8a4a8f0622..1e1e6055f8 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -202,6 +202,7 @@ Rectangle { ListElement { text: "Debug Scattering"; color: "White" } ListElement { text: "Ambient Occlusion"; color: "White" } ListElement { text: "Ambient Occlusion Blurred"; color: "White" } + ListElement { text: "Ambient Occlusion Normal"; color: "White" } ListElement { text: "Velocity"; color: "White" } ListElement { text: "Custom"; color: "White" } } From 9f0201878db3ef9cce0661320be107e34b4f20b5 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 21 Sep 2018 17:14:39 +0200 Subject: [PATCH 37/81] Some work to try to find the odd resolution bug --- .../src/AmbientOcclusionEffect.cpp | 121 ++++++++++++------ .../render-utils/src/AmbientOcclusionEffect.h | 11 +- .../render-utils/src/DeferredTransform.slh | 13 +- .../render-utils/src/SurfaceGeometryPass.cpp | 26 ++-- .../render-utils/src/SurfaceGeometryPass.h | 3 +- libraries/render-utils/src/ssao.slh | 53 +++++++- .../render-utils/src/ssao_buildNormals.slf | 20 +-- libraries/render-utils/src/ssao_gather.slf | 2 +- .../render-utils/src/ssao_makeOcclusion.slf | 36 ++++-- libraries/render-utils/src/ssao_shared.h | 1 + libraries/shared/src/MathUtils.h | 21 +++ 11 files changed, 216 insertions(+), 91 deletions(-) create mode 100644 libraries/shared/src/MathUtils.h diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 3fcf4ef656..8e2a25b3e6 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "RenderUtilsLogging.h" @@ -40,13 +41,18 @@ gpu::PipelinePointer AmbientOcclusionEffect::_buildNormalsPipeline; AmbientOcclusionFramebuffer::AmbientOcclusionFramebuffer() { } -bool AmbientOcclusionFramebuffer::updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer) { +bool AmbientOcclusionFramebuffer::update(const gpu::TexturePointer& linearDepthBuffer, int resolutionLevel, bool isStereo) { // If the depth buffer or size changed, we need to delete our FBOs bool reset = false; - if ((_linearDepthTexture != linearDepthBuffer)) { + if (_linearDepthTexture != linearDepthBuffer) { _linearDepthTexture = linearDepthBuffer; reset = true; } + if (_resolutionLevel != resolutionLevel || isStereo != _isStereo) { + _resolutionLevel = resolutionLevel; + _isStereo = isStereo; + reset = true; + } if (_linearDepthTexture) { auto newFrameSize = glm::ivec2(_linearDepthTexture->getDimensions()); if (_frameSize != newFrameSize) { @@ -76,17 +82,38 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getLinearDepthTexture() { } void AmbientOcclusionFramebuffer::allocate() { - auto width = _frameSize.x; - auto height = _frameSize.y; - auto format = gpu::Element::COLOR_R_8; + // Full frame + { + auto width = _frameSize.x; + auto height = _frameSize.y; + auto format = gpu::Element::COLOR_R_8; - _occlusionTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); - _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); - _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); + _occlusionTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); + _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); + _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); - _occlusionBlurredTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); - _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusionBlurred")); - _occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture); + _occlusionBlurredTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); + _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusionBlurred")); + _occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture); + } + + // Lower res frame + { + auto sideSize = _frameSize; + if (_isStereo) { + sideSize.x >>= 1; + } + sideSize = divideRoundUp(sideSize, 1 << _resolutionLevel); + if (_isStereo) { + sideSize.x <<= 1; + } + auto width = sideSize.x; + auto height = sideSize.y; + + _normalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT, gpu::Sampler::WRAP_CLAMP)); + _normalFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("ssaoNormals")); + _normalFramebuffer->setRenderBuffer(0, _normalTexture); + } } gpu::FramebufferPointer AmbientOcclusionFramebuffer::getOcclusionFramebuffer() { @@ -117,31 +144,17 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getOcclusionBlurredTexture() { return _occlusionBlurredTexture; } -void AmbientOcclusionFramebuffer::allocate(int resolutionLevel) { - auto width = _frameSize.x >> resolutionLevel; - auto height = _frameSize.y >> resolutionLevel; - - _normalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_R11G11B10, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT, gpu::Sampler::WRAP_CLAMP)); - _normalFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("ssaoNormals")); - _normalFramebuffer->setRenderBuffer(0, _normalTexture); - _resolutionLevel = resolutionLevel; -} - -gpu::FramebufferPointer AmbientOcclusionFramebuffer::getNormalFramebuffer(int resolutionLevel) { - if (!_normalFramebuffer || resolutionLevel != _resolutionLevel) { - allocate(resolutionLevel); +gpu::FramebufferPointer AmbientOcclusionFramebuffer::getNormalFramebuffer() { + if (!_normalFramebuffer) { + allocate(); } return _normalFramebuffer; } -gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture(int resolutionLevel) { - if (!_normalTexture || resolutionLevel != _resolutionLevel) { - allocate(resolutionLevel); - } - return _normalTexture; -} - gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() { + if (!_normalTexture) { + allocate(); + } return _normalTexture; } @@ -377,6 +390,28 @@ void AmbientOcclusionEffect::updateBlurParameters() { vblur.scaleHeight.z = frameSize.y; } +void AmbientOcclusionEffect::updateFramebufferSizes() { + auto& params = _aoParametersBuffer.edit(); + const int widthScale = _framebuffer->isStereo() & 1; + auto sourceFrameSize = _framebuffer->getSourceFrameSize(); + const int resolutionLevel = _aoParametersBuffer.get().getResolutionLevel(); + // Depth is at maximum half depth + const int depthResolutionLevel = std::min(1, resolutionLevel); + + sourceFrameSize.x >>= widthScale; + + params._sideSizes[0].x = _framebuffer->getNormalTexture()->getWidth() >> widthScale; + params._sideSizes[0].y = _framebuffer->getNormalTexture()->getHeight(); + params._sideSizes[0].z = resolutionLevel; + params._sideSizes[0].w = depthResolutionLevel; + + params._sideSizes[1].x = params._sideSizes[0].x; + params._sideSizes[1].y = params._sideSizes[0].y; + auto occlusionSplitSize = divideRoundUp(sourceFrameSize, 1 << (resolutionLevel + SSAO_USE_QUAD_SPLIT)); + params._sideSizes[1].z = occlusionSplitSize.x; + params._sideSizes[1].w = occlusionSplitSize.y; +} + const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { if (!_occlusionPipeline) { gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::ssao_makeOcclusion); @@ -466,11 +501,20 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte const auto& frameTransform = inputs.get0(); const auto& linearDepthFramebuffer = inputs.get2(); + const int resolutionLevel = _aoParametersBuffer->getResolutionLevel(); + const auto resolutionScale = powf(0.5f, resolutionLevel); + auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); auto occlusionDepthTexture = linearDepthTexture; auto sourceViewport = args->_viewport; - auto occlusionViewport = sourceViewport; + // divideRoundUp is used two compute the quarter or half resolution render sizes. + // We need to take the rounded up resolution. + auto occlusionViewport = divideRoundUp(sourceViewport, 1 << resolutionLevel); auto firstBlurViewport = sourceViewport; +#if SSAO_USE_QUAD_SPLIT + auto splitViewport = divideRoundUp(sourceViewport, 1 << (resolutionLevel + SSAO_USE_QUAD_SPLIT)); +#endif + firstBlurViewport.w = divideRoundUp(firstBlurViewport.w, 1 << resolutionLevel); if (!_gpuTimer) { _gpuTimer = std::make_shared < gpu::RangeTimer>(__FUNCTION__); @@ -480,16 +524,13 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte _framebuffer = std::make_shared(); } - const int resolutionLevel = _aoParametersBuffer->getResolutionLevel(); - const auto resolutionScale = powf(0.5f, resolutionLevel); if (resolutionLevel > 0) { - occlusionViewport = occlusionViewport >> resolutionLevel; - firstBlurViewport.w = firstBlurViewport.w >> resolutionLevel; occlusionDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); } - if (_framebuffer->updateLinearDepth(linearDepthTexture)) { + if (_framebuffer->update(linearDepthTexture, resolutionLevel, args->isStereo())) { updateBlurParameters(); + updateFramebufferSizes(); } auto occlusionFBO = _framebuffer->getOcclusionFramebuffer(); @@ -499,7 +540,6 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte outputs.edit1() = _aoParametersBuffer; auto framebufferSize = _framebuffer->getSourceFrameSize(); - auto occlusionPipeline = getOcclusionPipeline(); auto firstHBlurPipeline = getHBlurPipeline(); auto lastVBlurPipeline = getVBlurPipeline(); @@ -509,8 +549,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #if SSAO_USE_QUAD_SPLIT auto gatherPipeline = getGatherPipeline(); auto buildNormalsPipeline = getBuildNormalsPipeline(); - auto occlusionNormalFramebuffer = _framebuffer->getNormalFramebuffer(resolutionLevel); - auto occlusionNormalTexture = _framebuffer->getNormalTexture(resolutionLevel); + auto occlusionNormalFramebuffer = _framebuffer->getNormalFramebuffer(); + auto occlusionNormalTexture = _framebuffer->getNormalTexture(); #endif // Update sample rotation @@ -567,7 +607,6 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #else batch.setFramebuffer(occlusionFBO); #endif - batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(1.0f)); batch.setPipeline(occlusionPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, occlusionDepthTexture); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index b0752277c2..c9f5d42b14 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -31,20 +31,19 @@ public: gpu::FramebufferPointer getOcclusionBlurredFramebuffer(); gpu::TexturePointer getOcclusionBlurredTexture(); - gpu::FramebufferPointer getNormalFramebuffer(int resolutionLevel); - gpu::TexturePointer getNormalTexture(int resolutionLevel); + gpu::FramebufferPointer getNormalFramebuffer(); gpu::TexturePointer getNormalTexture(); // Update the source framebuffer size which will drive the allocation of all the other resources. - bool updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer); + bool update(const gpu::TexturePointer& linearDepthBuffer, int resolutionLevel, bool isStereo); gpu::TexturePointer getLinearDepthTexture(); const glm::ivec2& getSourceFrameSize() const { return _frameSize; } - + bool isStereo() const { return _isStereo; } + protected: void clear(); void allocate(); - void allocate(int resolutionLevel); gpu::TexturePointer _linearDepthTexture; @@ -60,6 +59,7 @@ protected: glm::ivec2 _frameSize; int _resolutionLevel{ 0 }; + bool _isStereo{ false }; }; using AmbientOcclusionFramebufferPointer = std::shared_ptr; @@ -167,6 +167,7 @@ private: void updateGaussianDistribution(); void updateBlurParameters(); + void updateFramebufferSizes(); AOParametersBuffer _aoParametersBuffer; FrameParametersBuffer _aoFrameParametersBuffer[SSAO_SPLIT_COUNT]; diff --git a/libraries/render-utils/src/DeferredTransform.slh b/libraries/render-utils/src/DeferredTransform.slh index d9ced66edf..9b98029bd6 100644 --- a/libraries/render-utils/src/DeferredTransform.slh +++ b/libraries/render-utils/src/DeferredTransform.slh @@ -124,17 +124,18 @@ vec2 getStereoSideSize(int resolutionLevel) { return vec2(getStereoSideWidth(resolutionLevel), getStereoSideHeight(resolutionLevel)); } -ivec4 getStereoSideInfo(int xPos, int resolutionLevel) { - int sideWidth = int(getStereoSideWidth(resolutionLevel)); +ivec4 getStereoSideInfoFromWidth(int xPos, int sideWidth) { return ivec4(xPos < sideWidth ? ivec2(0, 0) : ivec2(1, sideWidth), sideWidth, isStereo()); } -int getStereoSide(ivec4 sideInfo) { - return sideInfo.x; +ivec4 getStereoSideInfo(int xPos, int resolutionLevel) { + int sideWidth = int(getStereoSideWidth(resolutionLevel)); + return getStereoSideInfoFromWidth(xPos, sideWidth); } -bool isStereoFromInfo(ivec4 sideInfo) { - return sideInfo.w != 0; + +int getStereoSide(ivec4 sideInfo) { + return sideInfo.x; } float evalZeyeFromZdb(float depth) { diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index 374a509c5a..8f337b66da 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -11,6 +11,7 @@ #include "SurfaceGeometryPass.h" #include +#include #include #include @@ -28,7 +29,7 @@ namespace ru { LinearDepthFramebuffer::LinearDepthFramebuffer() { } -void LinearDepthFramebuffer::update(const gpu::TexturePointer& depthBuffer, const gpu::TexturePointer& normalTexture) { +void LinearDepthFramebuffer::update(const gpu::TexturePointer& depthBuffer, const gpu::TexturePointer& normalTexture, bool isStereo) { //If the depth buffer or size changed, we need to delete our FBOs bool reset = false; if (_primaryDepthTexture != depthBuffer || _normalTexture != normalTexture) { @@ -38,10 +39,17 @@ void LinearDepthFramebuffer::update(const gpu::TexturePointer& depthBuffer, cons } if (_primaryDepthTexture) { auto newFrameSize = glm::ivec2(_primaryDepthTexture->getDimensions()); - if (_frameSize != newFrameSize) { + if (_frameSize != newFrameSize || _isStereo != isStereo) { _frameSize = newFrameSize; - _halfFrameSize = newFrameSize >> 1; - + _halfFrameSize = _frameSize; + if (isStereo) { + _halfFrameSize.x >>= 1; + } + _halfFrameSize = divideRoundUp(_halfFrameSize, 2); + if (isStereo) { + _halfFrameSize.x <<= 1; + } + _isStereo = isStereo; reset = true; } } @@ -66,7 +74,7 @@ void LinearDepthFramebuffer::allocate() { // For Linear Depth: const uint16_t LINEAR_DEPTH_MAX_MIP_LEVEL = 5; - // Point sampling of the depth is need for the AmbientOcclusionEffect in HBAO, as well as the clamp to edge + // Point sampling of the depth is needed for the AmbientOcclusionEffect in HBAO, as well as the clamp to edge const auto depthSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP); _linearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), width, height, LINEAR_DEPTH_MAX_MIP_LEVEL, depthSampler); @@ -153,7 +161,7 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con auto depthBuffer = deferredFramebuffer->getPrimaryDepthTexture(); auto normalTexture = deferredFramebuffer->getDeferredNormalTexture(); - _linearDepthFramebuffer->update(depthBuffer, normalTexture); + _linearDepthFramebuffer->update(depthBuffer, normalTexture, args->isStereo()); auto linearDepthFBO = _linearDepthFramebuffer->getLinearDepthFramebuffer(); auto linearDepthTexture = _linearDepthFramebuffer->getLinearDepthTexture(); @@ -172,7 +180,7 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con auto downsamplePipeline = getDownsamplePipeline(renderContext); auto depthViewport = args->_viewport; - auto halfViewport = depthViewport >> 1; + auto halfViewport = divideRoundUp(depthViewport, 2); float clearLinearDepth = args->getViewFrustum().getFarClip() * 2.0f; gpu::doInBatch("LinearDepthPass::run", args->_context, [=](gpu::Batch& batch) { @@ -195,7 +203,9 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con // Downsample batch.setViewportTransform(halfViewport); - + Transform model; + model.setScale( glm::vec3((depthViewport.z >> 1) / float(halfViewport.z), (depthViewport.w >> 1) / float(halfViewport.w), 1.0f) ); + batch.setModelTransform(model); batch.setFramebuffer(downsampleFBO); batch.setResourceTexture(ru::Texture::SurfaceGeometryDepth, linearDepthTexture); batch.setResourceTexture(ru::Texture::SurfaceGeometryNormal, normalTexture); diff --git a/libraries/render-utils/src/SurfaceGeometryPass.h b/libraries/render-utils/src/SurfaceGeometryPass.h index 5ada56521a..6ea03fbda5 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.h +++ b/libraries/render-utils/src/SurfaceGeometryPass.h @@ -35,7 +35,7 @@ public: gpu::TexturePointer getHalfNormalTexture(); // Update the depth buffer which will drive the allocation of all the other resources according to its size. - void update(const gpu::TexturePointer& depthBuffer, const gpu::TexturePointer& normalTexture); + void update(const gpu::TexturePointer& depthBuffer, const gpu::TexturePointer& normalTexture, bool isStereo); const glm::ivec2& getDepthFrameSize() const { return _frameSize; } void setResolutionLevel(int level) { _resolutionLevel = std::max(0, level); } @@ -59,6 +59,7 @@ protected: glm::ivec2 _frameSize; glm::ivec2 _halfFrameSize; int _resolutionLevel{ 0 }; + bool _isStereo{ false }; }; using LinearDepthFramebufferPointer = std::shared_ptr; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 56566c9b6f..3f4d361531 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -47,11 +47,32 @@ layout(binding=RENDER_UTILS_BUFFER_SSAO_FRAME_PARAMS) uniform ambientOcclusionFr float getPerspectiveScale() { return (params._resolutionInfo.z); } -int getResolutionLevel() { - +int getResolutionLevel() { return int(params._resolutionInfo.x); } +vec2 getNormalsSideSize() { + return params._sideSizes[0].xy; +} +int getNormalsResolutionLevel() { + return int(params._sideSizes[0].z); +} +int getDepthResolutionLevel() { + return int(params._sideSizes[0].w); +} +vec2 getOcclusionSideSize() { + return params._sideSizes[1].xy; +} +vec2 getOcclusionSplitSideSize() { + return params._sideSizes[1].zw; +} + +ivec2 getWidthHeightRoundUp(int resolutionLevel) { + ivec2 fullRes = ivec2(getWidthHeight(0)); + int resolutionDivisor = 1 << resolutionLevel; + return (fullRes + resolutionDivisor - 1) / resolutionDivisor; +} + float getRadius() { return params._radiusInfo.x; } @@ -205,6 +226,26 @@ layout(binding=RENDER_UTILS_TEXTURE_SSAO_NORMAL) uniform sampler2D normalTex; ivec2 getDepthTextureSize(int level) { return textureSize(depthPyramidTex, level); } +ivec2 getDepthTextureSideSize(int level) { + ivec2 size = getDepthTextureSize(level); + size.x >>= int(isStereo()) & 1; + return size; +} + +ivec2 getNormalTextureSize(int level) { + return textureSize(normalTex, level); +} +ivec2 getNormalTextureSideSize(int level) { + ivec2 size = getNormalTextureSize(level); + size.x >>= int(isStereo()) & 1; + return size; +} + +vec2 getStereoSideSizeRoundUp(int resolutionLevel) { + ivec2 fullRes = ivec2(getStereoSideSize(0)); + int resolutionDivisor = 1 << resolutionLevel; + return vec2((fullRes + resolutionDivisor - 1) / resolutionDivisor); +} float getZEyeAtPixel(ivec2 pixel, int level) { return -texelFetch(depthPyramidTex, pixel, level).x; @@ -254,8 +295,8 @@ vec3 getMinDelta(vec3 centralPoint, vec3 offsetPointPos, vec3 offsetPointNeg) { return dot(delta0, delta0) < dot(delta1, delta1) ? delta0 : delta1; } -vec3 buildNormal(ivec4 side, vec2 fragUVPos, ivec2 depthTexFragPixelPos, vec3 fragPosition, ivec2 depthTextureScale, vec2 sideImageSize) { - vec2 uvScale = vec2(1.0) / (sideImageSize * depthTextureScale); +vec3 buildNormal(ivec4 side, vec2 fragUVPos, ivec2 depthTexFragPixelPos, vec3 fragPosition, vec2 depthTextureSize) { + vec2 uvScale = vec2(1.0) / depthTextureSize; vec3 fragPositionDxPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(1, 0), uvScale); vec3 fragPositionDyPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(0, 1), uvScale); vec3 fragPositionDxNeg = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(-1, 0), uvScale); @@ -368,7 +409,7 @@ float computeHorizon(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, vec2 d float evalVisibilityHBAO(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, vec2 deltaTap, float diskPixelRadius, vec3 fragPositionES, vec3 fragNormalES) { vec2 searchVec = deltaTap * diskPixelRadius; - float obscurance; + float obscurance = 0.0; // Forward search for h1 obscurance = computeHorizon(side, shadedPixelPos, sideImageSize, deltaTap, fragPositionES, fragNormalES, searchVec, diskPixelRadius); @@ -376,7 +417,7 @@ float evalVisibilityHBAO(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, ve // Backward search for h2 obscurance += computeHorizon(side, shadedPixelPos, sideImageSize, deltaTap, fragPositionES, fragNormalES, -searchVec, diskPixelRadius); - return obscurance * 0.5 / PI; + return obscurance; } <@endfunc@> diff --git a/libraries/render-utils/src/ssao_buildNormals.slf b/libraries/render-utils/src/ssao_buildNormals.slf index f3af324455..36066b87df 100644 --- a/libraries/render-utils/src/ssao_buildNormals.slf +++ b/libraries/render-utils/src/ssao_buildNormals.slf @@ -18,28 +18,30 @@ layout(location=0) out vec4 outFragColor; void main(void) { - vec2 sideImageSize = getStereoSideSize(getResolutionLevel()); - ivec2 renderSize = ivec2(sideImageSize) << ivec2(int(isStereo()) & 1, 0); - // Pixel being shaded vec2 fragCoord = gl_FragCoord.xy; ivec2 fragPixelPos = ivec2(fragCoord.xy); - // Fetch the z under the pixel (stereo or not) - ivec2 depthTextureScale = getDepthTextureSize(0) / renderSize; - ivec2 depthTexFragPixelPos = fragPixelPos * depthTextureScale; + // Fetch the z under the pixel (stereo or not) from full res depth + int depthTextureRatio = 1 << getNormalsResolutionLevel(); + ivec2 depthTexFragPixelPos = fragPixelPos * depthTextureRatio; float Zeye = getZEyeAtPixel(depthTexFragPixelPos, 0); - // Stereo side info - ivec4 side = getStereoSideInfo(fragPixelPos.x, getResolutionLevel()); + // Stereo side info based on the real viewport size of this pass + ivec2 sideNormalsSize = ivec2( getNormalsSideSize() ); + ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideNormalsSize.x); // From now on, fragPixelPos is the pixel pos in the side + vec2 depthSideSize = getDepthTextureSideSize(0); + vec2 sideImageSize = depthSideSize / float(depthTextureRatio); fragPixelPos.x -= side.y; vec2 fragUVPos = (vec2(fragPixelPos) + vec2(0.5)) / sideImageSize; // The position and normal of the pixel fragment in Eye space vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); - vec3 fragNormalES = buildNormal(side, fragUVPos, depthTexFragPixelPos, fragPositionES, depthTextureScale, sideImageSize); + vec3 fragNormalES = buildNormal(side, fragUVPos, depthTexFragPixelPos, fragPositionES, depthSideSize); + vec3 absFragNormalES = abs(fragNormalES); + fragNormalES /= max(absFragNormalES.z, max(absFragNormalES.x, absFragNormalES.y)); outFragColor = vec4(vec3(fragNormalES)*0.5 + vec3(0.5), 1.0); } diff --git a/libraries/render-utils/src/ssao_gather.slf b/libraries/render-utils/src/ssao_gather.slf index 8f2282154a..6814498b38 100644 --- a/libraries/render-utils/src/ssao_gather.slf +++ b/libraries/render-utils/src/ssao_gather.slf @@ -26,7 +26,7 @@ void main(void) { // result (at the resolution level, of course) ivec2 destPixelCoord = ivec2(gl_FragCoord.xy); ivec2 sourcePixelCoord = destPixelCoord / 2; - ivec2 splitImageSize = ivec2(getWidthHeight(getResolutionLevel()+1)); + ivec2 splitImageSize = getWidthHeightRoundUp(getResolutionLevel()+1); sourcePixelCoord += (destPixelCoord & ivec2(1)) * splitImageSize; diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index cee5ef6fe3..f4962d8286 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -24,36 +24,36 @@ layout(location=0) out vec4 outFragColor; void main(void) { - vec2 sideImageSize = getStereoSideSize(getResolutionLevel()); - ivec2 renderSize = ivec2(sideImageSize) << ivec2(int(isStereo()) & 1, 0); - // Pixel being shaded vec2 fragCoord = gl_FragCoord.xy; ivec2 fragPixelPos = ivec2(fragCoord.xy); #if SSAO_USE_QUAD_SPLIT - ivec2 splitImageSize = ivec2(getWidthHeight(getResolutionLevel()+1)); + ivec2 splitImageSize = ivec2(getOcclusionSplitSideSize()); fragPixelPos = ((fragPixelPos - getPixelOffset()*splitImageSize) * 2) + getPixelOffset(); #endif // Fetch the z under the pixel (stereo or not) - ivec2 depthTextureScale = getDepthTextureSize(0) / renderSize; - ivec2 depthTexFragPixelPos = fragPixelPos * depthTextureScale; + int depthTextureRatio = 1 << (getResolutionLevel() - getDepthResolutionLevel()); + ivec2 depthTexFragPixelPos = fragPixelPos * depthTextureRatio; float Zeye = getZEyeAtPixel(depthTexFragPixelPos, 0); #if SSAO_USE_QUAD_SPLIT vec3 fragNormalES = getNormalEyeAtPixel(fragPixelPos, 0); #endif - // Stereo side info - ivec4 side = getStereoSideInfo(fragPixelPos.x, getResolutionLevel()); + // Stereo side info based on the real viewport size of this pass + ivec2 sideOcclusionSize = ivec2( getOcclusionSideSize() ); + ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideOcclusionSize.x); // From now on, fragPixelPos is the pixel pos in the side + vec2 depthSideSize = getDepthTextureSideSize(0); + vec2 sideImageSize = depthSideSize / float(depthTextureRatio); fragPixelPos.x -= side.y; vec2 fragUVPos = (vec2(fragPixelPos) + vec2(0.5)) / sideImageSize; // The position and normal of the pixel fragment in Eye space vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); #if !SSAO_USE_QUAD_SPLIT - vec3 fragNormalES = buildNormal(side, fragUVPos, depthTexFragPixelPos, fragPositionES, depthTextureScale, sideImageSize); + vec3 fragNormalES = buildNormal(side, fragUVPos, depthTexFragPixelPos, fragPositionES, depthSideSize); #endif // Choose the screen-space sample radius @@ -68,20 +68,28 @@ void main(void) { // Accumulate the obscurance for each samples float obscuranceSum = 0.0; int numSamples = int(getNumSamples()); + float invNumSamples = getInvNumSamples(); + + // Steps are in the depth texture resolution + depthTexFragPixelPos = fragPixelPos * depthTextureRatio; for (int i = 0; i < numSamples; ++i) { #if SSAO_USE_HORIZON_BASED vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); - obscuranceSum += evalVisibilityHBAO(side, vec2(fragPixelPos), sideImageSize, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); + obscuranceSum += evalVisibilityHBAO(side, vec2(depthTexFragPixelPos), depthSideSize, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); #else - vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, fragPixelPos, sideImageSize); - vec2 tapPixelPos = vec2(fragPixelPos) + tap.xy; - vec3 tapUVZ = fetchTap(side, tapPixelPos, tap.z, sideImageSize); + vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, depthTexFragPixelPos, depthSideSize); + vec2 tapPixelPos = vec2(depthTexFragPixelPos) + tap.xy; + vec3 tapUVZ = fetchTap(side, tapPixelPos, tap.z, depthSideSize); vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES); #endif } - float occlusion = clamp(1.0 - obscuranceSum * getObscuranceScaling() * getInvNumSamples(), 0.0, 1.0); +#if SSAO_USE_HORIZON_BASED + obscuranceSum *= 0.5 / PI; +#endif + + float occlusion = clamp(1.0 - obscuranceSum * getObscuranceScaling() * invNumSamples, 0.0, 1.0); outFragColor = vec4(vec3(occlusion), 1.0); } diff --git a/libraries/render-utils/src/ssao_shared.h b/libraries/render-utils/src/ssao_shared.h index 89738fcea0..109d471964 100644 --- a/libraries/render-utils/src/ssao_shared.h +++ b/libraries/render-utils/src/ssao_shared.h @@ -40,6 +40,7 @@ struct AmbientOcclusionParams { SSAO_VEC4 _sampleInfo; SSAO_VEC4 _blurInfo; float _blurFilterTaps[SSAO_BLUR_GAUSSIAN_COEFS_COUNT]; + SSAO_VEC4 _sideSizes[2]; }; struct AmbientOcclusionFrameParams { diff --git a/libraries/shared/src/MathUtils.h b/libraries/shared/src/MathUtils.h new file mode 100644 index 0000000000..799890915e --- /dev/null +++ b/libraries/shared/src/MathUtils.h @@ -0,0 +1,21 @@ +// +// MathUtils.h +// libraries/shared/src +// +// Created by Olivier Prat on 9/21/18. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_MathUtils_h +#define hifi_MathUtils_h + +template +T divideRoundUp(const T& numerator, int divisor) { + return (numerator + divisor - T(1)) / divisor; +} + +#endif // hifi_MathUtils_h + From 2e40a5f3ffb4ce8e29b5d0663610233b568e7fdf Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 24 Sep 2018 14:38:03 +0200 Subject: [PATCH 38/81] Using UVs for buildNormals --- .../src/AmbientOcclusionEffect.cpp | 66 +++++++++++++------ .../render-utils/src/SurfaceGeometryPass.cpp | 39 +++++++---- libraries/render-utils/src/ssao.slh | 23 +++---- .../render-utils/src/ssao_buildNormals.slf | 21 +++--- .../render-utils/src/ssao_makeOcclusion.slf | 5 +- 5 files changed, 97 insertions(+), 57 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 8e2a25b3e6..5e6bc39253 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -109,8 +109,8 @@ void AmbientOcclusionFramebuffer::allocate() { } auto width = sideSize.x; auto height = sideSize.y; - - _normalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT, gpu::Sampler::WRAP_CLAMP)); + auto format = gpu::Element::COLOR_RGBA_32; + _normalTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT, gpu::Sampler::WRAP_CLAMP)); _normalFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("ssaoNormals")); _normalFramebuffer->setRenderBuffer(0, _normalTexture); } @@ -561,8 +561,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte } // _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; - gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) { - PROFILE_RANGE_BATCH(batch, "AmbientOcclusion"); + gpu::doInBatch("AmbientOcclusionEffect::Depth mip creation", args->_context, [=](gpu::Batch& batch) { + PROFILE_RANGE_BATCH(batch, "AO::Depth mip creation"); batch.enableStereo(false); _gpuTimer->begin(batch); @@ -574,29 +574,57 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setModelTransform(model); // We need this with the mips levels - batch.pushProfileRange("Depth mip creation"); #if SSAO_USE_HORIZON_BASED - batch.setPipeline(mipCreationPipeline); - batch.generateTextureMipsWithPipeline(occlusionDepthTexture); + batch.setPipeline(mipCreationPipeline); + batch.generateTextureMipsWithPipeline(occlusionDepthTexture); #else - batch.generateTextureMips(occlusionDepthTexture); + batch.generateTextureMips(occlusionDepthTexture); #endif - batch.popProfileRange(); + + _gpuTimer->end(batch); + }); #if SSAO_USE_QUAD_SPLIT + gpu::doInBatch("AmbientOcclusionEffect::Build Normals", args->_context, [=](gpu::Batch& batch) { + PROFILE_RANGE_BATCH(batch, "AO::Build Normals"); + batch.enableStereo(false); + + _gpuTimer->begin(batch); + + batch.resetViewTransform(); + + batch.setProjectionTransform(glm::mat4()); + Transform model; + auto depthTextureSize = linearDepthTexture->getDimensions(); + model.setScale( glm::vec3(occlusionViewport.z / (depthTextureSize.x * resolutionScale), occlusionViewport.w / (depthTextureSize.y * resolutionScale), 1.0f) ); + batch.setModelTransform(model); + // Build face normals pass - batch.pushProfileRange("Build Normals"); - batch.setViewportTransform(occlusionViewport); - batch.setPipeline(buildNormalsPipeline); - batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); - batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, nullptr); - batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); - batch.setFramebuffer(occlusionNormalFramebuffer); - batch.draw(gpu::TRIANGLE_STRIP, 4); - batch.popProfileRange(); + batch.setViewportTransform(occlusionViewport); + batch.setPipeline(buildNormalsPipeline); + batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); + batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, nullptr); + batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); + batch.setFramebuffer(occlusionNormalFramebuffer); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + _gpuTimer->end(batch); + }); #endif + gpu::doInBatch("AmbientOcclusionEffect::Occlusion", args->_context, [=](gpu::Batch& batch) { + PROFILE_RANGE_BATCH(batch, "AO::Occlusion"); + batch.enableStereo(false); + + _gpuTimer->begin(batch); + + batch.resetViewTransform(); + + Transform model; + batch.setProjectionTransform(glm::mat4()); + batch.setModelTransform(model); + // Occlusion pass batch.pushProfileRange("Occlusion"); diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index 8f337b66da..66ac3669a4 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -73,19 +73,20 @@ void LinearDepthFramebuffer::allocate() { auto height = _frameSize.y; // For Linear Depth: - const uint16_t LINEAR_DEPTH_MAX_MIP_LEVEL = 5; - // Point sampling of the depth is needed for the AmbientOcclusionEffect in HBAO, as well as the clamp to edge - const auto depthSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP); + const uint16_t LINEAR_DEPTH_MAX_MIP_LEVEL = 1; + const auto depthSamplerFull = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT, gpu::Sampler::WRAP_CLAMP); _linearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), width, height, LINEAR_DEPTH_MAX_MIP_LEVEL, - depthSampler); + depthSamplerFull); _linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("linearDepth")); _linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture); _linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat()); // For Downsampling: - const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = LINEAR_DEPTH_MAX_MIP_LEVEL; + const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = 5; + // Point sampling of the depth, as well as the clamp to edge, are needed for the AmbientOcclusionEffect with HBAO + const auto depthSamplerHalf = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP); _halfLinearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), _halfFrameSize.x, _halfFrameSize.y, HALF_LINEAR_DEPTH_MAX_MIP_LEVEL, - depthSampler); + depthSamplerHalf); _halfNormalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _halfFrameSize.x, _halfFrameSize.y, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)); @@ -183,35 +184,47 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con auto halfViewport = divideRoundUp(depthViewport, 2); float clearLinearDepth = args->getViewFrustum().getFarClip() * 2.0f; - gpu::doInBatch("LinearDepthPass::run", args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch("LinearDepthPass::ZtoLinearDepth", args->_context, [=](gpu::Batch& batch) { + PROFILE_RANGE_BATCH(batch, "ZtoLinearDepth"); _gpuTimer->begin(batch); batch.enableStereo(false); - batch.setViewportTransform(depthViewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(_linearDepthFramebuffer->getDepthFrameSize(), depthViewport)); batch.setUniformBuffer(ru::Buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); // LinearDepth + batch.setViewportTransform(depthViewport); batch.setFramebuffer(linearDepthFBO); batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(clearLinearDepth, 0.0f, 0.0f, 0.0f)); batch.setPipeline(linearDepthPipeline); + batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(_linearDepthFramebuffer->getDepthFrameSize(), depthViewport)); batch.setResourceTexture(ru::Texture::SurfaceGeometryDepth, depthBuffer); batch.draw(gpu::TRIANGLE_STRIP, 4); + _gpuTimer->end(batch); + }); + + gpu::doInBatch("LinearDepthPass::halfDepth", args->_context, [=](gpu::Batch& batch) { + PROFILE_RANGE_BATCH(batch, "LinearDepthDownsample"); + _gpuTimer->begin(batch); + batch.enableStereo(false); + + batch.setProjectionTransform(glm::mat4()); + batch.resetViewTransform(); + + batch.setUniformBuffer(ru::Buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); + // Downsample batch.setViewportTransform(halfViewport); - Transform model; - model.setScale( glm::vec3((depthViewport.z >> 1) / float(halfViewport.z), (depthViewport.w >> 1) / float(halfViewport.w), 1.0f) ); - batch.setModelTransform(model); batch.setFramebuffer(downsampleFBO); batch.setResourceTexture(ru::Texture::SurfaceGeometryDepth, linearDepthTexture); batch.setResourceTexture(ru::Texture::SurfaceGeometryNormal, normalTexture); batch.setPipeline(downsamplePipeline); + batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(_linearDepthFramebuffer->getDepthFrameSize() >> 1, halfViewport)); batch.draw(gpu::TRIANGLE_STRIP, 4); - + _gpuTimer->end(batch); }); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 3f4d361531..f8bba54d6b 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -282,25 +282,26 @@ vec4 fetchTap(ivec4 side, vec2 tapSidePixelPos, float tapRadius, vec2 sideImageS return P; } -vec3 buildPosition(ivec4 side, vec2 fragUVPos, ivec2 depthTexFragPixelPos, ivec2 deltaDepthTexPixel, vec2 uvScale) { - depthTexFragPixelPos += deltaDepthTexPixel; - fragUVPos += deltaDepthTexPixel * uvScale; - float Zeye = getZEyeAtPixel(depthTexFragPixelPos, 0); +vec3 buildPosition(ivec4 side, vec2 fragUVPos) { + vec2 fetchUV = clamp(fragUVPos, vec2(0), vec2(1)); + fetchUV = mix(fetchUV, vec2((fetchUV.x + getStereoSide(side)) * 0.5, fetchUV.y), isStereo()); + float Zeye = getZEyeAtUV(fetchUV, 0); return evalEyePositionFromZeye(side.x, Zeye, fragUVPos); } vec3 getMinDelta(vec3 centralPoint, vec3 offsetPointPos, vec3 offsetPointNeg) { vec3 delta0 = offsetPointPos - centralPoint; vec3 delta1 = centralPoint - offsetPointNeg; - return dot(delta0, delta0) < dot(delta1, delta1) ? delta0 : delta1; + float sqrLength0 = dot(delta0, delta0); + float sqrLength1 = dot(delta1, delta1); + return sqrLength0 < sqrLength1 ? delta0 : delta1; } -vec3 buildNormal(ivec4 side, vec2 fragUVPos, ivec2 depthTexFragPixelPos, vec3 fragPosition, vec2 depthTextureSize) { - vec2 uvScale = vec2(1.0) / depthTextureSize; - vec3 fragPositionDxPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(1, 0), uvScale); - vec3 fragPositionDyPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(0, 1), uvScale); - vec3 fragPositionDxNeg = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(-1, 0), uvScale); - vec3 fragPositionDyNeg = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(0, -1), uvScale); +vec3 buildNormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec2 deltaDepthUV) { + vec3 fragPositionDxPos = buildPosition(side, fragUVPos + vec2(deltaDepthUV.x, 0)); + vec3 fragPositionDyPos = buildPosition(side, fragUVPos + vec2(0, deltaDepthUV.y)); + vec3 fragPositionDxNeg = buildPosition(side, fragUVPos - vec2(deltaDepthUV.x, 0)); + vec3 fragPositionDyNeg = buildPosition(side, fragUVPos - vec2(0, deltaDepthUV.y)); vec3 fragPositionDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg); vec3 fragPositionDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg); diff --git a/libraries/render-utils/src/ssao_buildNormals.slf b/libraries/render-utils/src/ssao_buildNormals.slf index 36066b87df..09502f2026 100644 --- a/libraries/render-utils/src/ssao_buildNormals.slf +++ b/libraries/render-utils/src/ssao_buildNormals.slf @@ -15,31 +15,28 @@ <$declareAmbientOcclusion()$> <$declareFetchDepthPyramidMap()$> +layout(location=0) in vec2 varTexCoord0; + layout(location=0) out vec4 outFragColor; void main(void) { // Pixel being shaded vec2 fragCoord = gl_FragCoord.xy; ivec2 fragPixelPos = ivec2(fragCoord.xy); - - // Fetch the z under the pixel (stereo or not) from full res depth - int depthTextureRatio = 1 << getNormalsResolutionLevel(); - ivec2 depthTexFragPixelPos = fragPixelPos * depthTextureRatio; - float Zeye = getZEyeAtPixel(depthTexFragPixelPos, 0); + vec2 fragUVPos = varTexCoord0; // Stereo side info based on the real viewport size of this pass ivec2 sideNormalsSize = ivec2( getNormalsSideSize() ); ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideNormalsSize.x); - // From now on, fragPixelPos is the pixel pos in the side - vec2 depthSideSize = getDepthTextureSideSize(0); - vec2 sideImageSize = depthSideSize / float(depthTextureRatio); - fragPixelPos.x -= side.y; - vec2 fragUVPos = (vec2(fragPixelPos) + vec2(0.5)) / sideImageSize; + // From now on, fragUVPos is the UV pos in the side + fragUVPos.x = mix(fragUVPos.x, fragUVPos.x - getStereoSide(side) * 0.5, isStereo()); + + vec2 deltaDepthUV = vec2(1.0) / vec2(getDepthTextureSideSize(0)); // The position and normal of the pixel fragment in Eye space - vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); - vec3 fragNormalES = buildNormal(side, fragUVPos, depthTexFragPixelPos, fragPositionES, depthSideSize); + vec3 fragPositionES = buildPosition(side, fragUVPos); + vec3 fragNormalES = buildNormal(side, fragUVPos, fragPositionES, deltaDepthUV); vec3 absFragNormalES = abs(fragNormalES); fragNormalES /= max(absFragNormalES.z, max(absFragNormalES.x, absFragNormalES.y)); diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index f4962d8286..510ca4ea7b 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -51,9 +51,10 @@ void main(void) { vec2 fragUVPos = (vec2(fragPixelPos) + vec2(0.5)) / sideImageSize; // The position and normal of the pixel fragment in Eye space - vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); + vec3 fragPositionES = buildPosition(side, fragUVPos); #if !SSAO_USE_QUAD_SPLIT - vec3 fragNormalES = buildNormal(side, fragUVPos, depthTexFragPixelPos, fragPositionES, depthSideSize); + vec2 deltaDepthUV = vec2(1.0) / depthSideSize; + vec3 fragNormalES = buildNormal(side, fragUVPos, fragPositionES, deltaDepthUV); #endif // Choose the screen-space sample radius From 6704a27b122c383218d459cfceadcff89a0d2120 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 24 Sep 2018 14:59:57 +0200 Subject: [PATCH 39/81] Back to one batch --- .../src/AmbientOcclusionEffect.cpp | 96 +++++++------------ .../render-utils/src/SurfaceGeometryPass.cpp | 18 +--- 2 files changed, 39 insertions(+), 75 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 5e6bc39253..c906809b38 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -561,8 +561,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte } // _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; - gpu::doInBatch("AmbientOcclusionEffect::Depth mip creation", args->_context, [=](gpu::Batch& batch) { - PROFILE_RANGE_BATCH(batch, "AO::Depth mip creation"); + gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) { + PROFILE_RANGE_BATCH(batch, "AmbientOcclusion"); batch.enableStereo(false); _gpuTimer->begin(batch); @@ -573,28 +573,18 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setProjectionTransform(glm::mat4()); batch.setModelTransform(model); - // We need this with the mips levels + batch.pushProfileRange("Depth Mip Generation"); + // We need this with the mips levels #if SSAO_USE_HORIZON_BASED batch.setPipeline(mipCreationPipeline); batch.generateTextureMipsWithPipeline(occlusionDepthTexture); #else batch.generateTextureMips(occlusionDepthTexture); #endif - - _gpuTimer->end(batch); - }); + batch.popProfileRange(); #if SSAO_USE_QUAD_SPLIT - gpu::doInBatch("AmbientOcclusionEffect::Build Normals", args->_context, [=](gpu::Batch& batch) { - PROFILE_RANGE_BATCH(batch, "AO::Build Normals"); - batch.enableStereo(false); - - _gpuTimer->begin(batch); - - batch.resetViewTransform(); - - batch.setProjectionTransform(glm::mat4()); - Transform model; + batch.pushProfileRange("Normal Generation"); auto depthTextureSize = linearDepthTexture->getDimensions(); model.setScale( glm::vec3(occlusionViewport.z / (depthTextureSize.x * resolutionScale), occlusionViewport.w / (depthTextureSize.y * resolutionScale), 1.0f) ); batch.setModelTransform(model); @@ -608,63 +598,49 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); batch.setFramebuffer(occlusionNormalFramebuffer); batch.draw(gpu::TRIANGLE_STRIP, 4); - - _gpuTimer->end(batch); - }); + batch.popProfileRange(); #endif - gpu::doInBatch("AmbientOcclusionEffect::Occlusion", args->_context, [=](gpu::Batch& batch) { - PROFILE_RANGE_BATCH(batch, "AO::Occlusion"); - batch.enableStereo(false); - - _gpuTimer->begin(batch); - - batch.resetViewTransform(); - - Transform model; - batch.setProjectionTransform(glm::mat4()); - batch.setModelTransform(model); - // Occlusion pass batch.pushProfileRange("Occlusion"); - batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); + batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); #if SSAO_USE_QUAD_SPLIT - batch.setFramebuffer(occlusionBlurredFBO); + batch.setFramebuffer(occlusionBlurredFBO); #else - batch.setFramebuffer(occlusionFBO); + batch.setFramebuffer(occlusionFBO); #endif - batch.setPipeline(occlusionPipeline); - batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, occlusionDepthTexture); + batch.setPipeline(occlusionPipeline); + batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, occlusionDepthTexture); #if SSAO_USE_QUAD_SPLIT - batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture); - { - auto splitViewport = occlusionViewport >> SSAO_USE_QUAD_SPLIT; + batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture); + { + auto splitViewport = occlusionViewport >> SSAO_USE_QUAD_SPLIT; - batch.setViewportTransform(splitViewport); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); - batch.draw(gpu::TRIANGLE_STRIP, 4); - - splitViewport.x += splitViewport.z; - batch.setViewportTransform(splitViewport); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[1]); - batch.draw(gpu::TRIANGLE_STRIP, 4); - - splitViewport.y += splitViewport.w; - batch.setViewportTransform(splitViewport); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[2]); - batch.draw(gpu::TRIANGLE_STRIP, 4); - - splitViewport.x = 0; - batch.setViewportTransform(splitViewport); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[3]); - batch.draw(gpu::TRIANGLE_STRIP, 4); - } -#else + batch.setViewportTransform(splitViewport); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); batch.draw(gpu::TRIANGLE_STRIP, 4); + + splitViewport.x += splitViewport.z; + batch.setViewportTransform(splitViewport); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[1]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + splitViewport.y += splitViewport.w; + batch.setViewportTransform(splitViewport); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[2]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + splitViewport.x = 0; + batch.setViewportTransform(splitViewport); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[3]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + } +#else + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); + batch.draw(gpu::TRIANGLE_STRIP, 4); #endif batch.popProfileRange(); diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index 66ac3669a4..d37c468cbb 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -184,9 +184,10 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con auto halfViewport = divideRoundUp(depthViewport, 2); float clearLinearDepth = args->getViewFrustum().getFarClip() * 2.0f; - gpu::doInBatch("LinearDepthPass::ZtoLinearDepth", args->_context, [=](gpu::Batch& batch) { - PROFILE_RANGE_BATCH(batch, "ZtoLinearDepth"); + gpu::doInBatch("LinearDepthPass::run", args->_context, [=](gpu::Batch& batch) { + PROFILE_RANGE_BATCH(batch, "LinearDepthPass"); _gpuTimer->begin(batch); + batch.enableStereo(false); batch.setProjectionTransform(glm::mat4()); @@ -203,19 +204,6 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con batch.setResourceTexture(ru::Texture::SurfaceGeometryDepth, depthBuffer); batch.draw(gpu::TRIANGLE_STRIP, 4); - _gpuTimer->end(batch); - }); - - gpu::doInBatch("LinearDepthPass::halfDepth", args->_context, [=](gpu::Batch& batch) { - PROFILE_RANGE_BATCH(batch, "LinearDepthDownsample"); - _gpuTimer->begin(batch); - batch.enableStereo(false); - - batch.setProjectionTransform(glm::mat4()); - batch.resetViewTransform(); - - batch.setUniformBuffer(ru::Buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); - // Downsample batch.setViewportTransform(halfViewport); batch.setFramebuffer(downsampleFBO); From 9cebdbd507eab997afd54a850988642dced1955a Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 24 Sep 2018 19:08:37 +0200 Subject: [PATCH 40/81] Separate frame buffers for each AO split --- .../src/AmbientOcclusionEffect.cpp | 118 ++++++++++++++---- .../render-utils/src/AmbientOcclusionEffect.h | 15 ++- libraries/render-utils/src/ssao.slh | 61 ++++----- libraries/render-utils/src/ssao_gather.slf | 11 +- .../render-utils/src/ssao_makeOcclusion.slf | 43 +++---- libraries/render-utils/src/ssao_shared.h | 1 - 6 files changed, 153 insertions(+), 96 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index c906809b38..bfa5ae79e5 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -103,7 +103,7 @@ void AmbientOcclusionFramebuffer::allocate() { if (_isStereo) { sideSize.x >>= 1; } - sideSize = divideRoundUp(sideSize, 1 << _resolutionLevel); + sideSize = divideRoundUp(sideSize, 1 << std::min(1, _resolutionLevel)); if (_isStereo) { sideSize.x <<= 1; } @@ -114,8 +114,48 @@ void AmbientOcclusionFramebuffer::allocate() { _normalFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("ssaoNormals")); _normalFramebuffer->setRenderBuffer(0, _normalTexture); } + +#if SSAO_USE_QUAD_SPLIT + { + auto splitSize = glm::ivec2(_normalFramebuffer->getSize()); + if (_isStereo) { + splitSize.x >>= 1; + } + splitSize = divideRoundUp(splitSize, 2); + if (_isStereo) { + splitSize.x <<= 1; + } + auto width = splitSize.x; + auto height = splitSize.y; + auto format = gpu::Element::COLOR_R_8; + + _occlusionSplitTexture = gpu::Texture::createRenderBufferArray(format, width, height, SSAO_SPLIT_COUNT, gpu::Texture::SINGLE_MIP, + gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); + for (int i = 0; i < SSAO_SPLIT_COUNT; i++) { + _occlusionSplitFramebuffers[i] = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); + _occlusionSplitFramebuffers[i]->setRenderBuffer(0, _occlusionSplitTexture, i); + } + } +#endif } +#if SSAO_USE_QUAD_SPLIT +gpu::FramebufferPointer AmbientOcclusionFramebuffer::getOcclusionSplitFramebuffer(int index) { + assert(index < SSAO_SPLIT_COUNT); + if (!_occlusionSplitFramebuffers[index]) { + allocate(); + } + return _occlusionSplitFramebuffers[index]; +} + +gpu::TexturePointer AmbientOcclusionFramebuffer::getOcclusionSplitTexture() { + if (!_occlusionSplitTexture) { + allocate(); + } + return _occlusionSplitTexture; +} +#endif + gpu::FramebufferPointer AmbientOcclusionFramebuffer::getOcclusionFramebuffer() { if (!_occlusionFramebuffer) { allocate(); @@ -340,13 +380,6 @@ void AmbientOcclusionEffect::configure(const Config& config) { auto& current = _aoParametersBuffer.edit()._resolutionInfo; current.x = (float)config.resolutionLevel; shouldUpdateBlurs = true; - - _aoFrameParametersBuffer[0].edit()._pixelOffsets = { 0, 0, 0, 0 }; -#if SSAO_USE_QUAD_SPLIT - _aoFrameParametersBuffer[1].edit()._pixelOffsets = { 1, 0, 0, 0 }; - _aoFrameParametersBuffer[2].edit()._pixelOffsets = { 1, 1, 0, 0 }; - _aoFrameParametersBuffer[3].edit()._pixelOffsets = { 0, 1, 0, 0 }; -#endif } if (config.blurRadius != _aoParametersBuffer.get().getBlurRadius()) { @@ -395,13 +428,19 @@ void AmbientOcclusionEffect::updateFramebufferSizes() { const int widthScale = _framebuffer->isStereo() & 1; auto sourceFrameSize = _framebuffer->getSourceFrameSize(); const int resolutionLevel = _aoParametersBuffer.get().getResolutionLevel(); + const float resolutionScale = powf(0.5f, resolutionLevel); // Depth is at maximum half depth const int depthResolutionLevel = std::min(1, resolutionLevel); + const float depthResolutionScale = powf(2.0f, depthResolutionLevel); + auto normalTextureSize = _framebuffer->getNormalTexture()->getDimensions(); + auto occlusionDepthFrameSize = divideRoundUp(sourceFrameSize, depthResolutionLevel); sourceFrameSize.x >>= widthScale; + normalTextureSize.x >>= widthScale; + occlusionDepthFrameSize.x >>= widthScale; - params._sideSizes[0].x = _framebuffer->getNormalTexture()->getWidth() >> widthScale; - params._sideSizes[0].y = _framebuffer->getNormalTexture()->getHeight(); + params._sideSizes[0].x = normalTextureSize.x; + params._sideSizes[0].y = normalTextureSize.y; params._sideSizes[0].z = resolutionLevel; params._sideSizes[0].w = depthResolutionLevel; @@ -512,7 +551,11 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto occlusionViewport = divideRoundUp(sourceViewport, 1 << resolutionLevel); auto firstBlurViewport = sourceViewport; #if SSAO_USE_QUAD_SPLIT - auto splitViewport = divideRoundUp(sourceViewport, 1 << (resolutionLevel + SSAO_USE_QUAD_SPLIT)); + auto splitViewport = glm::ivec4{ 0, 0, _framebuffer->getOcclusionSplitTexture()->getWidth(), _framebuffer->getOcclusionSplitTexture()->getHeight() }; + auto depthSideSize = glm::ivec2(linearDepthTexture->getDimensions()); + if (args->isStereo()) { + depthSideSize.x >>= 1; + } #endif firstBlurViewport.w = divideRoundUp(firstBlurViewport.w, 1 << resolutionLevel); @@ -551,7 +594,15 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto buildNormalsPipeline = getBuildNormalsPipeline(); auto occlusionNormalFramebuffer = _framebuffer->getNormalFramebuffer(); auto occlusionNormalTexture = _framebuffer->getNormalTexture(); + auto normalViewport = glm::ivec4{ 0, 0, occlusionNormalFramebuffer->getWidth(), occlusionNormalFramebuffer->getHeight() }; #endif + auto occlusionDepthSideSize = glm::ivec2(occlusionDepthTexture->getDimensions()); + if (args->isStereo()) { + occlusionDepthSideSize.x >>= 1; + } + + const auto depthResolutionLevel = std::min(1, resolutionLevel); + const auto depthResolutionScale = powf(2.0f, depthResolutionLevel); // Update sample rotation const int SSAO_RANDOM_SAMPLE_COUNT = int(_randomSamples.size() / SSAO_SPLIT_COUNT); @@ -585,12 +636,11 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #if SSAO_USE_QUAD_SPLIT batch.pushProfileRange("Normal Generation"); - auto depthTextureSize = linearDepthTexture->getDimensions(); - model.setScale( glm::vec3(occlusionViewport.z / (depthTextureSize.x * resolutionScale), occlusionViewport.w / (depthTextureSize.y * resolutionScale), 1.0f) ); + model.setScale( glm::vec3((normalViewport.z * depthResolutionScale) / depthSideSize.x, (normalViewport.w * depthResolutionScale) / depthSideSize.y, 1.0f) ); batch.setModelTransform(model); // Build face normals pass - batch.setViewportTransform(occlusionViewport); + batch.setViewportTransform(normalViewport); batch.setPipeline(buildNormalsPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, nullptr); @@ -617,28 +667,43 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #if SSAO_USE_QUAD_SPLIT batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture); { - auto splitViewport = occlusionViewport >> SSAO_USE_QUAD_SPLIT; + const auto scale = glm::vec3( + (splitViewport.z * 2.0f) / occlusionDepthSideSize.x, + (splitViewport.w * 2.0f) / occlusionDepthSideSize.y, + 1.0f); + const auto pixelUV = glm::vec2(1.0f) / (glm::vec2(occlusionDepthSideSize) * glm::vec2(scale.x, scale.y)); batch.setViewportTransform(splitViewport); + + model.setScale(scale); + model.setTranslation(glm::vec3(0.0f, 0.0f, 0.0f)); + batch.setModelTransform(model); + batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(0)); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); batch.draw(gpu::TRIANGLE_STRIP, 4); - splitViewport.x += splitViewport.z; - batch.setViewportTransform(splitViewport); + model.setTranslation(glm::vec3(pixelUV.x, 0.0f, 0.0f)); + batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(1)); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[1]); batch.draw(gpu::TRIANGLE_STRIP, 4); - splitViewport.y += splitViewport.w; - batch.setViewportTransform(splitViewport); + model.setTranslation(glm::vec3(pixelUV.x, pixelUV.y, 0.0f)); + batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(3)); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[2]); batch.draw(gpu::TRIANGLE_STRIP, 4); - splitViewport.x = 0; - batch.setViewportTransform(splitViewport); + model.setTranslation(glm::vec3(0.0f, pixelUV.y, 0.0f)); + batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(2)); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[3]); batch.draw(gpu::TRIANGLE_STRIP, 4); } #else + const auto scale = glm::vec3( + (occlusionViewport.z / (depthSideSize.x * resolutionScale)) * fullDepthToHalfDepthSizeRatio.x, + (occlusionViewport.w / (depthSideSize.y * resolutionScale)) * fullDepthToHalfDepthSizeRatio.y, + 1.0f); + model.setScale(scale); + batch.setViewportTransform(occlusionViewport); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); batch.draw(gpu::TRIANGLE_STRIP, 4); #endif @@ -648,11 +713,12 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #if SSAO_USE_QUAD_SPLIT // Gather back the four separate renders into one interleaved one batch.pushProfileRange("Gather"); - batch.setViewportTransform(occlusionViewport); - batch.setFramebuffer(occlusionFBO); - batch.setPipeline(gatherPipeline); - batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionBlurredFBO->getRenderBuffer(0)); - batch.draw(gpu::TRIANGLE_STRIP, 4); + batch.setViewportTransform(occlusionViewport); + batch.setModelTransform(Transform()); + batch.setFramebuffer(occlusionFBO); + batch.setPipeline(gatherPipeline); + batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, _framebuffer->getOcclusionSplitTexture()); + batch.draw(gpu::TRIANGLE_STRIP, 4); batch.popProfileRange(); #endif diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index c9f5d42b14..d4f16f0c10 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -21,6 +21,8 @@ #include "DeferredFramebuffer.h" #include "SurfaceGeometryPass.h" +#include "ssao_shared.h" + class AmbientOcclusionFramebuffer { public: AmbientOcclusionFramebuffer(); @@ -34,6 +36,11 @@ public: gpu::FramebufferPointer getNormalFramebuffer(); gpu::TexturePointer getNormalTexture(); +#if SSAO_USE_QUAD_SPLIT + gpu::FramebufferPointer getOcclusionSplitFramebuffer(int index); + gpu::TexturePointer getOcclusionSplitTexture(); +#endif + // Update the source framebuffer size which will drive the allocation of all the other resources. bool update(const gpu::TexturePointer& linearDepthBuffer, int resolutionLevel, bool isStereo); gpu::TexturePointer getLinearDepthTexture(); @@ -56,7 +63,11 @@ protected: gpu::FramebufferPointer _normalFramebuffer; gpu::TexturePointer _normalTexture; - +#if SSAO_USE_QUAD_SPLIT + gpu::FramebufferPointer _occlusionSplitFramebuffers[SSAO_SPLIT_COUNT]; + gpu::TexturePointer _occlusionSplitTexture; +#endif + glm::ivec2 _frameSize; int _resolutionLevel{ 0 }; bool _isStereo{ false }; @@ -126,8 +137,6 @@ public: void configure(const Config& config); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); -#include "ssao_shared.h" - // Class describing the uniform buffer with all the parameters common to the AO shaders class AOParameters : public AmbientOcclusionParams { public: diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index f8bba54d6b..5e250fe04b 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -148,10 +148,6 @@ float getAngleDithering(in ivec2 pixelPos) { #endif } -ivec2 getPixelOffset() { - return frameParams._pixelOffsets.xy; -} - float evalDiskRadius(float Zeye, vec2 sideImageSize) { // Choose the screen-space sample radius // proportional to the projected area of the sphere @@ -269,17 +265,16 @@ int evalMipFromRadius(float radius) { return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); } -vec4 fetchTap(ivec4 side, vec2 tapSidePixelPos, float tapRadius, vec2 sideImageSize) { +vec2 fetchTap(ivec4 side, vec2 tapUV, float tapRadius) { int mipLevel = evalMipFromRadius(tapRadius * float(doFetchMips())); - vec2 tapUV = (tapSidePixelPos + vec2(0.5)) / sideImageSize; - vec2 fetchUV = mix(tapUV, vec2((tapUV.x + getStereoSide(side)) * 0.5, tapUV.y), isStereo()); + vec2 fetchUV = clamp(tapUV, vec2(0), vec2(1)); + fetchUV = mix(fetchUV, vec2((fetchUV.x + getStereoSide(side)) * 0.5, fetchUV.y), isStereo()); - vec4 P; - P.xy = tapUV; - P.w = float(mipLevel); - P.z = -textureLod(depthPyramidTex, fetchUV, P.w).x; - return P; + vec2 P; + P.x = float(mipLevel); + P.y = -textureLod(depthPyramidTex, fetchUV, P.x).x; + return P; } vec3 buildPosition(ivec4 side, vec2 fragUVPos) { @@ -348,13 +343,13 @@ float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNo } <@func computeHorizon()@> - vec2 tapSidePixelPos = tapPixelOffset + shadedPixelPos; - if (tapSidePixelPos.x<0 || tapSidePixelPos.y<0 || tapSidePixelPos.x>=sideImageSize.x || tapSidePixelPos.y>=sideImageSize.y) { + vec2 tapSideUVPos = tapUVOffset + fragUVPos; + if (tapSideUVPos.x<0 || tapSideUVPos.y<0 || tapSideUVPos.x>=1.0 || tapSideUVPos.y>=1.0) { // Early exit because we've hit the borders of the frame break; } - vec4 tapUVZ_mip = fetchTap(side, tapSidePixelPos, radius, sideImageSize); - vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ_mip.z, tapUVZ_mip.xy); + vec2 tapMipZ = fetchTap(side, tapSideUVPos, radius); + vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, tapSideUVPos); float tapCosHorizonAngle = computeHorizonFromTap(tapPositionES, fragPositionES, fragNormalES); cosHorizonAngle = max(cosHorizonAngle, tapCosHorizonAngle); @@ -363,23 +358,22 @@ float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNo #define HBAO_HORIZON_SEARCH_CONSTANT_STEP 0 -float computeHorizon(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, vec2 deltaTap, - vec3 fragPositionES, vec3 fragNormalES, vec2 searchVec, float searchRadius) { +float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, vec3 fragNormalES, vec2 searchVec, float searchRadius) { vec2 absSearchVec = abs(searchVec); - int stepCount = int(ceil(max(absSearchVec.x, absSearchVec.y))); + int stepCount = int(ceil(searchRadius)); float cosHorizonAngle = 0.0; if (stepCount>0) { - vec2 deltaPixelTap = searchVec / float(stepCount); + vec2 deltaTapUV = searchVec / float(stepCount); float deltaRadius = searchRadius / float(stepCount); - vec2 tapPixelOffset = vec2(0); + vec2 tapUVOffset = vec2(0); #if HBAO_HORIZON_SEARCH_CONSTANT_STEP float radius = 0.0; int stepIndex; for (stepIndex=0 ; stepIndex @@ -390,14 +384,14 @@ float computeHorizon(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, vec2 d float mipLevel = evalMipFromRadius(radius * float(doFetchMips())); while (radius<=searchRadius) { - tapPixelOffset += deltaPixelTap; + tapUVOffset += deltaTapUV; <$computeHorizon()$> - if (tapUVZ_mip.w != mipLevel) { - mipLevel = tapUVZ_mip.w; + if (tapMipZ.x != mipLevel) { + mipLevel = tapMipZ.x; deltaRadius *= 2; - deltaPixelTap *= 2; + deltaTapUV *= 2; } radius += deltaRadius; } @@ -407,29 +401,22 @@ float computeHorizon(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, vec2 d return cosHorizonAngle; } -float evalVisibilityHBAO(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, vec2 deltaTap, float diskPixelRadius, +float evalVisibilityHBAO(ivec4 side, vec2 fragUVPos, vec2 invSideImageSize, vec2 deltaTap, float diskPixelRadius, vec3 fragPositionES, vec3 fragNormalES) { - vec2 searchVec = deltaTap * diskPixelRadius; + vec2 searchVec = (deltaTap * diskPixelRadius) * invSideImageSize; float obscurance = 0.0; // Forward search for h1 - obscurance = computeHorizon(side, shadedPixelPos, sideImageSize, deltaTap, fragPositionES, fragNormalES, searchVec, diskPixelRadius); + obscurance = computeHorizon(side, fragUVPos, fragPositionES, fragNormalES, searchVec, diskPixelRadius); // Backward search for h2 - obscurance += computeHorizon(side, shadedPixelPos, sideImageSize, deltaTap, fragPositionES, fragNormalES, -searchVec, diskPixelRadius); + obscurance += computeHorizon(side, fragUVPos, fragPositionES, fragNormalES, -searchVec, diskPixelRadius); return obscurance; } <@endfunc@> -<@func declareGatherPass()@> -<$declareAmbientOcclusion()$> - -// the source occlusion texture -layout(binding=RENDER_UTILS_TEXTURE_SSAO_OCCLUSION) uniform sampler2D occlusionMap; - -<@endfunc@> <@func declareBlurPass(axis)@> diff --git a/libraries/render-utils/src/ssao_gather.slf b/libraries/render-utils/src/ssao_gather.slf index 6814498b38..9a5eccb92b 100644 --- a/libraries/render-utils/src/ssao_gather.slf +++ b/libraries/render-utils/src/ssao_gather.slf @@ -15,7 +15,10 @@ // Hack comment -<$declareGatherPass()$> +<$declareAmbientOcclusion()$> + +// the source occlusion texture +layout(binding=RENDER_UTILS_TEXTURE_SSAO_OCCLUSION) uniform sampler2DArray occlusionMaps; layout(location=0) in vec4 varTexCoord0; @@ -27,8 +30,10 @@ void main(void) { ivec2 destPixelCoord = ivec2(gl_FragCoord.xy); ivec2 sourcePixelCoord = destPixelCoord / 2; ivec2 splitImageSize = getWidthHeightRoundUp(getResolutionLevel()+1); - + int occlusionMapIndex = (destPixelCoord.x & 1) + ((destPixelCoord.y) & 1)*2; + vec2 sourceUV = (sourcePixelCoord + vec2(0.5)) / splitImageSize; + sourcePixelCoord += (destPixelCoord & ivec2(1)) * splitImageSize; - outFragColor = texelFetch(occlusionMap, sourcePixelCoord, 0); + outFragColor = texture(occlusionMaps, vec3(sourceUV, occlusionMapIndex)); } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 510ca4ea7b..cc1f5d55ca 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -21,44 +21,35 @@ #define SSAO_HBAO_MAX_RADIUS 100.0 +layout(location=0) in vec2 varTexCoord0; + layout(location=0) out vec4 outFragColor; void main(void) { // Pixel being shaded vec2 fragCoord = gl_FragCoord.xy; ivec2 fragPixelPos = ivec2(fragCoord.xy); -#if SSAO_USE_QUAD_SPLIT - ivec2 splitImageSize = ivec2(getOcclusionSplitSideSize()); - fragPixelPos = ((fragPixelPos - getPixelOffset()*splitImageSize) * 2) + getPixelOffset(); -#endif - - // Fetch the z under the pixel (stereo or not) - int depthTextureRatio = 1 << (getResolutionLevel() - getDepthResolutionLevel()); - ivec2 depthTexFragPixelPos = fragPixelPos * depthTextureRatio; - float Zeye = getZEyeAtPixel(depthTexFragPixelPos, 0); -#if SSAO_USE_QUAD_SPLIT - vec3 fragNormalES = getNormalEyeAtPixel(fragPixelPos, 0); -#endif + vec2 fragUVPos = varTexCoord0; // Stereo side info based on the real viewport size of this pass + vec2 sideDepthSize = getDepthTextureSideSize(0); ivec2 sideOcclusionSize = ivec2( getOcclusionSideSize() ); ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideOcclusionSize.x); - // From now on, fragPixelPos is the pixel pos in the side - vec2 depthSideSize = getDepthTextureSideSize(0); - vec2 sideImageSize = depthSideSize / float(depthTextureRatio); - fragPixelPos.x -= side.y; - vec2 fragUVPos = (vec2(fragPixelPos) + vec2(0.5)) / sideImageSize; + // From now on, fragUVPos is the UV pos in the side + fragUVPos.x = mix(fragUVPos.x, fragUVPos.x - getStereoSide(side) * 0.5, isStereo()); // The position and normal of the pixel fragment in Eye space + vec2 deltaDepthUV = vec2(1.0) / sideDepthSize; vec3 fragPositionES = buildPosition(side, fragUVPos); -#if !SSAO_USE_QUAD_SPLIT - vec2 deltaDepthUV = vec2(1.0) / depthSideSize; +#if SSAO_USE_QUAD_SPLIT + vec3 fragNormalES = getNormalEyeAtUV(fragUVPos, 0); +#else vec3 fragNormalES = buildNormal(side, fragUVPos, fragPositionES, deltaDepthUV); #endif // Choose the screen-space sample radius - float diskPixelRadius = evalDiskRadius(fragPositionES.z, sideImageSize); + float diskPixelRadius = evalDiskRadius(fragPositionES.z, sideDepthSize); #if SSAO_USE_HORIZON_BASED diskPixelRadius = min(diskPixelRadius, SSAO_HBAO_MAX_RADIUS); #endif @@ -72,16 +63,16 @@ void main(void) { float invNumSamples = getInvNumSamples(); // Steps are in the depth texture resolution - depthTexFragPixelPos = fragPixelPos * depthTextureRatio; + vec2 depthTexFragPixelPos = fragUVPos * sideDepthSize; for (int i = 0; i < numSamples; ++i) { #if SSAO_USE_HORIZON_BASED vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); - obscuranceSum += evalVisibilityHBAO(side, vec2(depthTexFragPixelPos), depthSideSize, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); + obscuranceSum += evalVisibilityHBAO(side, fragUVPos, deltaDepthUV, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); #else - vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, depthTexFragPixelPos, depthSideSize); - vec2 tapPixelPos = vec2(depthTexFragPixelPos) + tap.xy; - vec3 tapUVZ = fetchTap(side, tapPixelPos, tap.z, depthSideSize); - vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); + vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, depthTexFragPixelPos, sideDepthSize); + vec2 tapUV = fragUVPos + tap.xy * deltaDepthUV; + vec2 tapMipZ = fetchTapWithUV(side, tapUV, tap.z); + vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, tapUV); obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES); #endif } diff --git a/libraries/render-utils/src/ssao_shared.h b/libraries/render-utils/src/ssao_shared.h index 109d471964..7410baf715 100644 --- a/libraries/render-utils/src/ssao_shared.h +++ b/libraries/render-utils/src/ssao_shared.h @@ -45,7 +45,6 @@ struct AmbientOcclusionParams { struct AmbientOcclusionFrameParams { SSAO_VEC4 _angleInfo; - SSAO_IVEC4 _pixelOffsets; }; #endif // RENDER_UTILS_SHADER_CONSTANTS_H From 190996e67033bea5f2fba193bb15329d43bb8b58 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 25 Sep 2018 10:01:30 +0200 Subject: [PATCH 41/81] Switched to full screen depth and normals --- .../src/AmbientOcclusionEffect.cpp | 60 +++++++++---------- .../render-utils/src/AmbientOcclusionEffect.h | 5 +- .../render-utils/src/SurfaceGeometryPass.cpp | 5 +- .../render-utils/src/ssao_buildNormals.slf | 6 +- .../render-utils/src/ssao_makeOcclusion.slf | 2 +- 5 files changed, 40 insertions(+), 38 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index bfa5ae79e5..26d63f913c 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -41,15 +41,16 @@ gpu::PipelinePointer AmbientOcclusionEffect::_buildNormalsPipeline; AmbientOcclusionFramebuffer::AmbientOcclusionFramebuffer() { } -bool AmbientOcclusionFramebuffer::update(const gpu::TexturePointer& linearDepthBuffer, int resolutionLevel, bool isStereo) { +bool AmbientOcclusionFramebuffer::update(const gpu::TexturePointer& linearDepthBuffer, int resolutionLevel, int depthResolutionLevel, bool isStereo) { // If the depth buffer or size changed, we need to delete our FBOs bool reset = false; if (_linearDepthTexture != linearDepthBuffer) { _linearDepthTexture = linearDepthBuffer; reset = true; } - if (_resolutionLevel != resolutionLevel || isStereo != _isStereo) { + if (_resolutionLevel != resolutionLevel || isStereo != _isStereo || _depthResolutionLevel != depthResolutionLevel) { _resolutionLevel = resolutionLevel; + _depthResolutionLevel = depthResolutionLevel; _isStereo = isStereo; reset = true; } @@ -103,7 +104,7 @@ void AmbientOcclusionFramebuffer::allocate() { if (_isStereo) { sideSize.x >>= 1; } - sideSize = divideRoundUp(sideSize, 1 << std::min(1, _resolutionLevel)); + sideSize = divideRoundUp(sideSize, 1 << _depthResolutionLevel); if (_isStereo) { sideSize.x <<= 1; } @@ -117,11 +118,11 @@ void AmbientOcclusionFramebuffer::allocate() { #if SSAO_USE_QUAD_SPLIT { - auto splitSize = glm::ivec2(_normalFramebuffer->getSize()); + auto splitSize = _frameSize; if (_isStereo) { splitSize.x >>= 1; } - splitSize = divideRoundUp(splitSize, 2); + splitSize = divideRoundUp(splitSize, 2 << _resolutionLevel); if (_isStereo) { splitSize.x <<= 1; } @@ -531,6 +532,11 @@ void AmbientOcclusionEffect::updateGaussianDistribution() { GaussianDistribution::evalSampling(filterTaps, SSAO_BLUR_GAUSSIAN_COEFS_COUNT, blurRadius, _aoParametersBuffer->getBlurDeviation()); } +int AmbientOcclusionEffect::getDepthResolutionLevel() const { + // Having some problems making a nice AO with Half resolution depth, so stick to full res. + return 0; +} + void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); @@ -543,6 +549,9 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte const int resolutionLevel = _aoParametersBuffer->getResolutionLevel(); const auto resolutionScale = powf(0.5f, resolutionLevel); + const auto depthResolutionLevel = getDepthResolutionLevel(); + const auto depthResolutionScale = powf(0.5f, depthResolutionLevel); + auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); auto occlusionDepthTexture = linearDepthTexture; auto sourceViewport = args->_viewport; @@ -550,13 +559,6 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte // We need to take the rounded up resolution. auto occlusionViewport = divideRoundUp(sourceViewport, 1 << resolutionLevel); auto firstBlurViewport = sourceViewport; -#if SSAO_USE_QUAD_SPLIT - auto splitViewport = glm::ivec4{ 0, 0, _framebuffer->getOcclusionSplitTexture()->getWidth(), _framebuffer->getOcclusionSplitTexture()->getHeight() }; - auto depthSideSize = glm::ivec2(linearDepthTexture->getDimensions()); - if (args->isStereo()) { - depthSideSize.x >>= 1; - } -#endif firstBlurViewport.w = divideRoundUp(firstBlurViewport.w, 1 << resolutionLevel); if (!_gpuTimer) { @@ -567,11 +569,11 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte _framebuffer = std::make_shared(); } - if (resolutionLevel > 0) { + if (depthResolutionLevel > 0) { occlusionDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); } - if (_framebuffer->update(linearDepthTexture, resolutionLevel, args->isStereo())) { + if (_framebuffer->update(linearDepthTexture, resolutionLevel, depthResolutionLevel, args->isStereo())) { updateBlurParameters(); updateFramebufferSizes(); } @@ -595,14 +597,10 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto occlusionNormalFramebuffer = _framebuffer->getNormalFramebuffer(); auto occlusionNormalTexture = _framebuffer->getNormalTexture(); auto normalViewport = glm::ivec4{ 0, 0, occlusionNormalFramebuffer->getWidth(), occlusionNormalFramebuffer->getHeight() }; + auto splitSize = glm::ivec2(_framebuffer->getOcclusionSplitTexture()->getDimensions()); + auto splitViewport = glm::ivec4{ 0, 0, splitSize.x, splitSize.y }; #endif - auto occlusionDepthSideSize = glm::ivec2(occlusionDepthTexture->getDimensions()); - if (args->isStereo()) { - occlusionDepthSideSize.x >>= 1; - } - - const auto depthResolutionLevel = std::min(1, resolutionLevel); - const auto depthResolutionScale = powf(2.0f, depthResolutionLevel); + auto occlusionDepthSize = glm::ivec2(occlusionDepthTexture->getDimensions()); // Update sample rotation const int SSAO_RANDOM_SAMPLE_COUNT = int(_randomSamples.size() / SSAO_SPLIT_COUNT); @@ -636,7 +634,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #if SSAO_USE_QUAD_SPLIT batch.pushProfileRange("Normal Generation"); - model.setScale( glm::vec3((normalViewport.z * depthResolutionScale) / depthSideSize.x, (normalViewport.w * depthResolutionScale) / depthSideSize.y, 1.0f) ); + model.setScale(glm::vec3(normalViewport.z / (sourceViewport.z * depthResolutionScale), normalViewport.w / (sourceViewport.w * depthResolutionScale), 1.0f)); batch.setModelTransform(model); // Build face normals pass @@ -668,39 +666,39 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture); { const auto scale = glm::vec3( - (splitViewport.z * 2.0f) / occlusionDepthSideSize.x, - (splitViewport.w * 2.0f) / occlusionDepthSideSize.y, + (splitSize.x * 2.0f * depthResolutionScale) / (occlusionDepthSize.x * resolutionScale), + (splitSize.y * 2.0f * depthResolutionScale) / (occlusionDepthSize.y * resolutionScale), 1.0f); - const auto pixelUV = glm::vec2(1.0f) / (glm::vec2(occlusionDepthSideSize) * glm::vec2(scale.x, scale.y)); + const auto pixelOffset = glm::vec2(0.5f) / glm::vec2(occlusionDepthSize); batch.setViewportTransform(splitViewport); model.setScale(scale); - model.setTranslation(glm::vec3(0.0f, 0.0f, 0.0f)); + model.setTranslation(glm::vec3(-pixelOffset.x, -pixelOffset.y, 0.0f)); batch.setModelTransform(model); batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(0)); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); batch.draw(gpu::TRIANGLE_STRIP, 4); - model.setTranslation(glm::vec3(pixelUV.x, 0.0f, 0.0f)); + model.setTranslation(glm::vec3(pixelOffset.x, -pixelOffset.y, 0.0f)); batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(1)); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[1]); batch.draw(gpu::TRIANGLE_STRIP, 4); - model.setTranslation(glm::vec3(pixelUV.x, pixelUV.y, 0.0f)); + model.setTranslation(glm::vec3(pixelOffset.x, pixelOffset.y, 0.0f)); batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(3)); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[2]); batch.draw(gpu::TRIANGLE_STRIP, 4); - model.setTranslation(glm::vec3(0.0f, pixelUV.y, 0.0f)); + model.setTranslation(glm::vec3(-pixelOffset.x, pixelOffset.y, 0.0f)); batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(2)); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[3]); batch.draw(gpu::TRIANGLE_STRIP, 4); } #else const auto scale = glm::vec3( - (occlusionViewport.z / (depthSideSize.x * resolutionScale)) * fullDepthToHalfDepthSizeRatio.x, - (occlusionViewport.w / (depthSideSize.y * resolutionScale)) * fullDepthToHalfDepthSizeRatio.y, + occlusionViewport.z / (framebufferSize.x * resolutionScale), + occlusionViewport.w / (framebufferSize.y * resolutionScale), 1.0f); model.setScale(scale); batch.setViewportTransform(occlusionViewport); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index d4f16f0c10..a86cce4d23 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -42,7 +42,7 @@ public: #endif // Update the source framebuffer size which will drive the allocation of all the other resources. - bool update(const gpu::TexturePointer& linearDepthBuffer, int resolutionLevel, bool isStereo); + bool update(const gpu::TexturePointer& linearDepthBuffer, int resolutionLevel, int depthResolutionLevel, bool isStereo); gpu::TexturePointer getLinearDepthTexture(); const glm::ivec2& getSourceFrameSize() const { return _frameSize; } bool isStereo() const { return _isStereo; } @@ -70,6 +70,7 @@ protected: glm::ivec2 _frameSize; int _resolutionLevel{ 0 }; + int _depthResolutionLevel{ 0 }; bool _isStereo{ false }; }; @@ -177,6 +178,8 @@ private: void updateGaussianDistribution(); void updateBlurParameters(); void updateFramebufferSizes(); + + int getDepthResolutionLevel() const; AOParametersBuffer _aoParametersBuffer; FrameParametersBuffer _aoFrameParametersBuffer[SSAO_SPLIT_COUNT]; diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index d37c468cbb..d5e0249a21 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -73,8 +73,9 @@ void LinearDepthFramebuffer::allocate() { auto height = _frameSize.y; // For Linear Depth: - const uint16_t LINEAR_DEPTH_MAX_MIP_LEVEL = 1; - const auto depthSamplerFull = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT, gpu::Sampler::WRAP_CLAMP); + const uint16_t LINEAR_DEPTH_MAX_MIP_LEVEL = 5; + // Point sampling of the depth, as well as the clamp to edge, are needed for the AmbientOcclusionEffect with HBAO + const auto depthSamplerFull = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP); _linearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), width, height, LINEAR_DEPTH_MAX_MIP_LEVEL, depthSamplerFull); _linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("linearDepth")); diff --git a/libraries/render-utils/src/ssao_buildNormals.slf b/libraries/render-utils/src/ssao_buildNormals.slf index 09502f2026..9c183f640c 100644 --- a/libraries/render-utils/src/ssao_buildNormals.slf +++ b/libraries/render-utils/src/ssao_buildNormals.slf @@ -29,11 +29,11 @@ void main(void) { ivec2 sideNormalsSize = ivec2( getNormalsSideSize() ); ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideNormalsSize.x); - // From now on, fragUVPos is the UV pos in the side - fragUVPos.x = mix(fragUVPos.x, fragUVPos.x - getStereoSide(side) * 0.5, isStereo()); - vec2 deltaDepthUV = vec2(1.0) / vec2(getDepthTextureSideSize(0)); + // From now on, fragUVPos is the UV pos in the side + fragUVPos.x = mix(fragUVPos.x, fragUVPos.x * 2.0 - getStereoSide(side), isStereo()); + // The position and normal of the pixel fragment in Eye space vec3 fragPositionES = buildPosition(side, fragUVPos); vec3 fragNormalES = buildNormal(side, fragUVPos, fragPositionES, deltaDepthUV); diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index cc1f5d55ca..f65a89ab09 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -37,7 +37,7 @@ void main(void) { ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideOcclusionSize.x); // From now on, fragUVPos is the UV pos in the side - fragUVPos.x = mix(fragUVPos.x, fragUVPos.x - getStereoSide(side) * 0.5, isStereo()); + fragUVPos.x = mix(fragUVPos.x, fragUVPos.x * 2.0 - getStereoSide(side), isStereo()); // The position and normal of the pixel fragment in Eye space vec2 deltaDepthUV = vec2(1.0) / sideDepthSize; From 0c586edeeb20a8eaeba870ed0824b7291ab98ce6 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 25 Sep 2018 10:31:24 +0200 Subject: [PATCH 42/81] Fixed for stereo --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 4 ++-- libraries/render-utils/src/ssao_makeOcclusion.slf | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 26d63f913c..776996536b 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -111,7 +111,7 @@ void AmbientOcclusionFramebuffer::allocate() { auto width = sideSize.x; auto height = sideSize.y; auto format = gpu::Element::COLOR_RGBA_32; - _normalTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT, gpu::Sampler::WRAP_CLAMP)); + _normalTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); _normalFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("ssaoNormals")); _normalFramebuffer->setRenderBuffer(0, _normalTexture); } @@ -131,7 +131,7 @@ void AmbientOcclusionFramebuffer::allocate() { auto format = gpu::Element::COLOR_R_8; _occlusionSplitTexture = gpu::Texture::createRenderBufferArray(format, width, height, SSAO_SPLIT_COUNT, gpu::Texture::SINGLE_MIP, - gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); + gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT, gpu::Sampler::WRAP_CLAMP)); for (int i = 0; i < SSAO_SPLIT_COUNT; i++) { _occlusionSplitFramebuffers[i] = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); _occlusionSplitFramebuffers[i]->setRenderBuffer(0, _occlusionSplitTexture, i); diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index f65a89ab09..044d11910a 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -31,20 +31,21 @@ void main(void) { ivec2 fragPixelPos = ivec2(fragCoord.xy); vec2 fragUVPos = varTexCoord0; +#if SSAO_USE_QUAD_SPLIT + vec3 fragNormalES = getNormalEyeAtUV(fragUVPos, 0); +#endif + // Stereo side info based on the real viewport size of this pass vec2 sideDepthSize = getDepthTextureSideSize(0); - ivec2 sideOcclusionSize = ivec2( getOcclusionSideSize() ); + ivec2 sideOcclusionSize = ivec2( getOcclusionSplitSideSize() ); ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideOcclusionSize.x); - // From now on, fragUVPos is the UV pos in the side fragUVPos.x = mix(fragUVPos.x, fragUVPos.x * 2.0 - getStereoSide(side), isStereo()); // The position and normal of the pixel fragment in Eye space vec2 deltaDepthUV = vec2(1.0) / sideDepthSize; vec3 fragPositionES = buildPosition(side, fragUVPos); -#if SSAO_USE_QUAD_SPLIT - vec3 fragNormalES = getNormalEyeAtUV(fragUVPos, 0); -#else +#if !SSAO_USE_QUAD_SPLIT vec3 fragNormalES = buildNormal(side, fragUVPos, fragPositionES, deltaDepthUV); #endif From 60f59130023e6ce10e6ea457ed5dfb7bbf14d892 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 25 Sep 2018 11:06:05 +0200 Subject: [PATCH 43/81] Bilateral blur taps are evaluated in shader --- .../src/AmbientOcclusionEffect.cpp | 69 ------------------- .../render-utils/src/AmbientOcclusionEffect.h | 1 - libraries/render-utils/src/ssao.slh | 23 ++++--- libraries/render-utils/src/ssao_shared.h | 2 - 4 files changed, 13 insertions(+), 82 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 776996536b..5a1a168894 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -199,61 +199,6 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() { return _normalTexture; } -class GaussianDistribution { -public: - - static double integral(float x, float deviation) { - return 0.5 * erf((double)x / ((double)deviation * sqrt(2.0))); - } - - static double rangeIntegral(float x0, float x1, float deviation) { - return integral(x1, deviation) - integral(x0, deviation); - } - - static std::vector evalSampling(int samplingRadius, float deviation) { - std::vector coefs(samplingRadius + 1, 0.0f); - - // corner case when radius is 0 or under - if (samplingRadius <= 0) { - coefs[0] = 1.0f; - return coefs; - } - - // Evaluate all the samples range integral of width 1 from center until the penultimate one - float halfWidth = 0.5f; - double sum = 0.0; - for (int i = 0; i < samplingRadius; i++) { - float x = (float) i; - double sample = rangeIntegral(x - halfWidth, x + halfWidth, deviation); - coefs[i] = sample; - sum += sample; - } - - // last sample goes to infinity - float lastSampleX0 = (float) samplingRadius - halfWidth; - float largeEnough = lastSampleX0 + 1000.0f * deviation; - double sample = rangeIntegral(lastSampleX0, largeEnough, deviation); - coefs[samplingRadius] = sample; - sum += sample; - - return coefs; - } - - static void evalSampling(float* coefs, unsigned int coefsLength, int samplingRadius, float deviation) { - auto coefsVector = evalSampling(samplingRadius, deviation); - if (coefsLength> coefsVector.size() + 1) { - unsigned int coefsNum = 0; - for (auto s : coefsVector) { - coefs[coefsNum] = s; - coefsNum++; - } - for (;coefsNum < coefsLength; coefsNum++) { - coefs[coefsNum] = 0.0f; - } - } - } -}; - AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false), #if SSAO_USE_HORIZON_BASED @@ -298,7 +243,6 @@ AmbientOcclusionEffect::AmbientOcclusionEffect() { void AmbientOcclusionEffect::configure(const Config& config) { DependencyManager::get()->setAmbientOcclusionEnabled(config.enabled); - bool shouldUpdateGaussian = false; bool shouldUpdateBlurs = false; const double RADIUS_POWER = 6.0; @@ -332,7 +276,6 @@ void AmbientOcclusionEffect::configure(const Config& config) { if (config.blurDeviation != _aoParametersBuffer->getBlurDeviation()) { auto& current = _aoParametersBuffer.edit()._blurInfo; current.z = config.blurDeviation; - shouldUpdateGaussian = true; } if (config.numSpiralTurns != _aoParametersBuffer->getNumSpiralTurns()) { @@ -386,7 +329,6 @@ void AmbientOcclusionEffect::configure(const Config& config) { if (config.blurRadius != _aoParametersBuffer.get().getBlurRadius()) { auto& current = _aoParametersBuffer.edit()._blurInfo; current.y = (float)config.blurRadius; - shouldUpdateGaussian = true; } if (config.ditheringEnabled != _aoParametersBuffer->isDitheringEnabled()) { @@ -399,10 +341,6 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.w = (float)config.borderingEnabled; } - if (shouldUpdateGaussian) { - updateGaussianDistribution(); - } - if (shouldUpdateBlurs) { updateBlurParameters(); } @@ -525,13 +463,6 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getBuildNormalsPipeline() { return _buildNormalsPipeline; } -void AmbientOcclusionEffect::updateGaussianDistribution() { - auto filterTaps = _aoParametersBuffer.edit()._blurFilterTaps; - auto blurRadius = _aoParametersBuffer.get().getBlurRadius(); - - GaussianDistribution::evalSampling(filterTaps, SSAO_BLUR_GAUSSIAN_COEFS_COUNT, blurRadius, _aoParametersBuffer->getBlurDeviation()); -} - int AmbientOcclusionEffect::getDepthResolutionLevel() const { // Having some problems making a nice AO with Half resolution depth, so stick to full res. return 0; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index a86cce4d23..3ad5ee2138 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -175,7 +175,6 @@ private: using FrameParametersBuffer = gpu::StructBuffer< AmbientOcclusionFrameParams>; - void updateGaussianDistribution(); void updateBlurParameters(); void updateFramebufferSizes(); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 5e250fe04b..468e3fc7d1 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -123,10 +123,6 @@ int getBlurRadius() { return int(params._blurInfo.y); } -float getBlurCoef(int c) { - return params._blurFilterTaps[c]; -} - <@endfunc@> <@func declareSamplingDisk()@> @@ -454,7 +450,12 @@ float fetchOcclusion(vec2 coords) { const float BLUR_EDGE_DISTANCE_SCALE = 1000.0; -vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float fragDepth) { +float evalBlurCoefficient(vec2 blurScales, float radialDistance, float zDistance) { + vec2 distances = vec2(radialDistance, zDistance); + return exp2(dot(blurScales, distances*distances)); +} + +vec2 evalTapWeightedValue(vec2 blurScales, ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float fragDepth) { ivec2 tapOffset = <$axis$> * r; ivec2 tapPixelCoord = destPixelCoord + ivec2(tapOffset); @@ -467,11 +468,10 @@ vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTe tapTexCoord = fullTexCoord + tapOffset * getDepthBlurScale(); float tapDepth = getZEyeAtUV(tapTexCoord, 0); - float weight = getBlurCoef(abs(r)); // range domain (the "bilateral" weight). As depth difference increases, decrease weight. float zDistance = tapDepth - fragDepth; - weight *= exp(-getBlurEdgeSharpness() * (zDistance * zDistance * BLUR_EDGE_DISTANCE_SCALE)); + float weight = evalBlurCoefficient(blurScales, abs(r), zDistance); return vec2(tapOcclusion * weight, weight); } @@ -485,20 +485,23 @@ vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTex // Accumulate weighted contributions along the bluring axis in the [-radius, radius] range int blurRadius = getBlurRadius(); + float blurRadialSigma = float(blurRadius) * 0.5; + float blurRadialScale = 1.0 / (2.0*blurRadialSigma*blurRadialSigma); + vec2 blurScales = -vec2(blurRadialScale, BLUR_EDGE_DISTANCE_SCALE) * getBlurEdgeSharpness(); // negative side first for (int r = -blurRadius; r <= -1; ++r) { - weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth); + weightedSums += evalTapWeightedValue(blurScales, side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth); } // Central pixel contribution - float mainWeight = getBlurCoef(0); + float mainWeight = 1.0; float pixelOcclusion = fetchOcclusion(scaledTexCoord); weightedSums += vec2(pixelOcclusion * mainWeight, mainWeight); // then positive side for (int r = 1; r <= blurRadius; ++r) { - weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth); + weightedSums += evalTapWeightedValue(blurScales, side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth); } // Final normalization diff --git a/libraries/render-utils/src/ssao_shared.h b/libraries/render-utils/src/ssao_shared.h index 7410baf715..11c7f894d5 100644 --- a/libraries/render-utils/src/ssao_shared.h +++ b/libraries/render-utils/src/ssao_shared.h @@ -16,7 +16,6 @@ #define SSAO_USE_HORIZON_BASED 1 #define SSAO_USE_QUAD_SPLIT 1 -#define SSAO_BLUR_GAUSSIAN_COEFS_COUNT 16 #if SSAO_USE_QUAD_SPLIT #define SSAO_SPLIT_COUNT 4 @@ -39,7 +38,6 @@ struct AmbientOcclusionParams { SSAO_VEC4 _ditheringInfo; SSAO_VEC4 _sampleInfo; SSAO_VEC4 _blurInfo; - float _blurFilterTaps[SSAO_BLUR_GAUSSIAN_COEFS_COUNT]; SSAO_VEC4 _sideSizes[2]; }; From 9899eb6d3ff5a066c1c55bc2c30ed7c27f8c2cb4 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 25 Sep 2018 15:46:07 +0200 Subject: [PATCH 44/81] Concentrating on resolution level 1 --- .../src/AmbientOcclusionEffect.cpp | 74 ++++++++++--------- libraries/render-utils/src/ssao.slh | 13 ++-- .../render-utils/src/ssao_makeOcclusion.slf | 2 +- 3 files changed, 48 insertions(+), 41 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 5a1a168894..1574a643db 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -89,6 +89,8 @@ void AmbientOcclusionFramebuffer::allocate() { auto height = _frameSize.y; auto format = gpu::Element::COLOR_R_8; + //TEMPO OP + format = gpu::Element::VEC4F_COLOR_RGBA; _occlusionTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); @@ -111,7 +113,8 @@ void AmbientOcclusionFramebuffer::allocate() { auto width = sideSize.x; auto height = sideSize.y; auto format = gpu::Element::COLOR_RGBA_32; - _normalTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); + _normalTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, + gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT, gpu::Sampler::WRAP_CLAMP)); _normalFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("ssaoNormals")); _normalFramebuffer->setRenderBuffer(0, _normalTexture); } @@ -221,7 +224,7 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : #else numSamples{ 16 }, #endif - resolutionLevel{ 2 }, + resolutionLevel{ 1 }, blurRadius{ 4 }, ditheringEnabled{ true }, borderingEnabled{ true }, @@ -395,7 +398,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::ssao_makeOcclusion); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setColorWriteMask(true, true, true, false); + state->setColorWriteMask(true, true, true, true); // Good to go add the brand new pipeline _occlusionPipeline = gpu::Pipeline::create(program, state); @@ -585,18 +588,13 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); -#if SSAO_USE_QUAD_SPLIT - batch.setFramebuffer(occlusionBlurredFBO); -#else - batch.setFramebuffer(occlusionFBO); -#endif batch.setPipeline(occlusionPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, occlusionDepthTexture); #if SSAO_USE_QUAD_SPLIT batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture); { - const auto scale = glm::vec3( + const auto uvScale = glm::vec3( (splitSize.x * 2.0f * depthResolutionScale) / (occlusionDepthSize.x * resolutionScale), (splitSize.y * 2.0f * depthResolutionScale) / (occlusionDepthSize.y * resolutionScale), 1.0f); @@ -604,7 +602,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setViewportTransform(splitViewport); - model.setScale(scale); + model.setScale(uvScale); model.setTranslation(glm::vec3(-pixelOffset.x, -pixelOffset.y, 0.0f)); batch.setModelTransform(model); batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(0)); @@ -612,27 +610,34 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.draw(gpu::TRIANGLE_STRIP, 4); model.setTranslation(glm::vec3(pixelOffset.x, -pixelOffset.y, 0.0f)); + batch.setModelTransform(model); batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(1)); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[1]); batch.draw(gpu::TRIANGLE_STRIP, 4); model.setTranslation(glm::vec3(pixelOffset.x, pixelOffset.y, 0.0f)); + batch.setModelTransform(model); batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(3)); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[2]); batch.draw(gpu::TRIANGLE_STRIP, 4); model.setTranslation(glm::vec3(-pixelOffset.x, pixelOffset.y, 0.0f)); + batch.setModelTransform(model); batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(2)); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[3]); batch.draw(gpu::TRIANGLE_STRIP, 4); } #else - const auto scale = glm::vec3( - occlusionViewport.z / (framebufferSize.x * resolutionScale), - occlusionViewport.w / (framebufferSize.y * resolutionScale), - 1.0f); - model.setScale(scale); batch.setViewportTransform(occlusionViewport); + { + const auto uvScale = glm::vec3( + (occlusionViewport.z * depthResolutionScale) / (occlusionDepthSize.x * resolutionScale), + (occlusionViewport.w * depthResolutionScale) / (occlusionDepthSize.y * resolutionScale), + 1.0f); + model.setScale(uvScale); + } + batch.setModelTransform(model); + batch.setFramebuffer(occlusionFBO); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); batch.draw(gpu::TRIANGLE_STRIP, 4); #endif @@ -655,34 +660,35 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte PROFILE_RANGE_BATCH(batch, "Bilateral Blur"); // Blur 1st pass batch.pushProfileRange("Horizontal"); - model.setScale(resolutionScale); - batch.setModelTransform(model); - batch.setViewportTransform(firstBlurViewport); - batch.setFramebuffer(occlusionBlurredFBO); - // Use full resolution depth and normal for bilateral upscaling and blur - batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _hblurParametersBuffer); - batch.setPipeline(firstHBlurPipeline); - batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionFBO->getRenderBuffer(0)); - batch.draw(gpu::TRIANGLE_STRIP, 4); + model.setScale(resolutionScale); + batch.setModelTransform(model); + batch.setViewportTransform(firstBlurViewport); + batch.setFramebuffer(occlusionBlurredFBO); + // Use full resolution depth and normal for bilateral upscaling and blur + batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _hblurParametersBuffer); + batch.setPipeline(firstHBlurPipeline); + batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionFBO->getRenderBuffer(0)); + batch.draw(gpu::TRIANGLE_STRIP, 4); batch.popProfileRange(); // Blur 2nd pass batch.pushProfileRange("Vertical"); - model.setScale(glm::vec3(1.0f, resolutionScale, 1.0f)); - batch.setModelTransform(model); - batch.setViewportTransform(sourceViewport); - batch.setFramebuffer(occlusionFBO); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _vblurParametersBuffer); - batch.setPipeline(lastVBlurPipeline); - batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionBlurredFBO->getRenderBuffer(0)); - batch.draw(gpu::TRIANGLE_STRIP, 4); + model.setScale(glm::vec3(1.0f, resolutionScale, 1.0f)); + batch.setModelTransform(model); + batch.setViewportTransform(sourceViewport); + batch.setFramebuffer(occlusionFBO); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _vblurParametersBuffer); + batch.setPipeline(lastVBlurPipeline); + batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionBlurredFBO->getRenderBuffer(0)); + batch.draw(gpu::TRIANGLE_STRIP, 4); batch.popProfileRange(); } batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, nullptr); + batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, nullptr); batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, nullptr); - + _gpuTimer->end(batch); }); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 468e3fc7d1..345eeebafb 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -275,7 +275,7 @@ vec2 fetchTap(ivec4 side, vec2 tapUV, float tapRadius) { vec3 buildPosition(ivec4 side, vec2 fragUVPos) { vec2 fetchUV = clamp(fragUVPos, vec2(0), vec2(1)); - fetchUV = mix(fetchUV, vec2((fetchUV.x + getStereoSide(side)) * 0.5, fetchUV.y), isStereo()); + fetchUV.x = mix(fetchUV.x, (fetchUV.x + getStereoSide(side)) * 0.5, isStereo()); float Zeye = getZEyeAtUV(fetchUV, 0); return evalEyePositionFromZeye(side.x, Zeye, fragUVPos); } @@ -354,9 +354,9 @@ float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNo #define HBAO_HORIZON_SEARCH_CONSTANT_STEP 0 -float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, vec3 fragNormalES, vec2 searchVec, float searchRadius) { +float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, vec3 fragNormalES, vec2 searchVec, vec2 pixelSearchVec, float searchRadius) { vec2 absSearchVec = abs(searchVec); - int stepCount = int(ceil(searchRadius)); + int stepCount = int(ceil(max(pixelSearchVec.x, pixelSearchVec.y))); float cosHorizonAngle = 0.0; if (stepCount>0) { @@ -399,14 +399,15 @@ float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, vec3 fragN float evalVisibilityHBAO(ivec4 side, vec2 fragUVPos, vec2 invSideImageSize, vec2 deltaTap, float diskPixelRadius, vec3 fragPositionES, vec3 fragNormalES) { - vec2 searchVec = (deltaTap * diskPixelRadius) * invSideImageSize; + vec2 pixelSearchVec = deltaTap * diskPixelRadius; + vec2 searchVec = pixelSearchVec * invSideImageSize; float obscurance = 0.0; // Forward search for h1 - obscurance = computeHorizon(side, fragUVPos, fragPositionES, fragNormalES, searchVec, diskPixelRadius); + obscurance = computeHorizon(side, fragUVPos, fragPositionES, fragNormalES, searchVec, pixelSearchVec, diskPixelRadius); // Backward search for h2 - obscurance += computeHorizon(side, fragUVPos, fragPositionES, fragNormalES, -searchVec, diskPixelRadius); + obscurance += computeHorizon(side, fragUVPos, fragPositionES, fragNormalES, -searchVec, pixelSearchVec, diskPixelRadius); return obscurance; } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 044d11910a..0a34b0df03 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -43,7 +43,7 @@ void main(void) { fragUVPos.x = mix(fragUVPos.x, fragUVPos.x * 2.0 - getStereoSide(side), isStereo()); // The position and normal of the pixel fragment in Eye space - vec2 deltaDepthUV = vec2(1.0) / sideDepthSize; + vec2 deltaDepthUV = vec2(2.0) / sideDepthSize; vec3 fragPositionES = buildPosition(side, fragUVPos); #if !SSAO_USE_QUAD_SPLIT vec3 fragNormalES = buildNormal(side, fragUVPos, fragPositionES, deltaDepthUV); From dee0a6afa238ccebff133d4f755e6a77ea430f8c Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 26 Sep 2018 16:59:01 +0200 Subject: [PATCH 45/81] Found bug with low res depth fetch in occlusion --- .../src/AmbientOcclusionEffect.cpp | 86 ++++++++++--------- .../render-utils/src/AmbientOcclusionEffect.h | 6 +- libraries/render-utils/src/ssao.slh | 14 +-- libraries/render-utils/src/ssao_gather.slf | 9 +- libraries/render-utils/src/ssao_shared.h | 5 +- 5 files changed, 64 insertions(+), 56 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 1574a643db..4c1ff6fe09 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -89,8 +89,6 @@ void AmbientOcclusionFramebuffer::allocate() { auto height = _frameSize.y; auto format = gpu::Element::COLOR_R_8; - //TEMPO OP - format = gpu::Element::VEC4F_COLOR_RGBA; _occlusionTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); @@ -125,7 +123,7 @@ void AmbientOcclusionFramebuffer::allocate() { if (_isStereo) { splitSize.x >>= 1; } - splitSize = divideRoundUp(splitSize, 2 << _resolutionLevel); + splitSize = divideRoundUp(splitSize, SSAO_SPLIT_COUNT << _resolutionLevel); if (_isStereo) { splitSize.x <<= 1; } @@ -133,9 +131,9 @@ void AmbientOcclusionFramebuffer::allocate() { auto height = splitSize.y; auto format = gpu::Element::COLOR_R_8; - _occlusionSplitTexture = gpu::Texture::createRenderBufferArray(format, width, height, SSAO_SPLIT_COUNT, gpu::Texture::SINGLE_MIP, - gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT, gpu::Sampler::WRAP_CLAMP)); - for (int i = 0; i < SSAO_SPLIT_COUNT; i++) { + _occlusionSplitTexture = gpu::Texture::createRenderBufferArray(format, width, height, SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT, gpu::Texture::SINGLE_MIP, + gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); + for (int i = 0; i < SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT; i++) { _occlusionSplitFramebuffers[i] = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); _occlusionSplitFramebuffers[i]->setRenderBuffer(0, _occlusionSplitTexture, i); } @@ -145,7 +143,7 @@ void AmbientOcclusionFramebuffer::allocate() { #if SSAO_USE_QUAD_SPLIT gpu::FramebufferPointer AmbientOcclusionFramebuffer::getOcclusionSplitFramebuffer(int index) { - assert(index < SSAO_SPLIT_COUNT); + assert(index < SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT); if (!_occlusionSplitFramebuffers[index]) { allocate(); } @@ -220,7 +218,7 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : blurDeviation{ 2.5f }, numSpiralTurns{ 7.0f }, #if SSAO_USE_HORIZON_BASED - numSamples{ 3 }, + numSamples{ 1 }, #else numSamples{ 16 }, #endif @@ -305,7 +303,7 @@ void AmbientOcclusionEffect::configure(const Config& config) { r = r + f * (float)(index % B); index = index / B; } - _randomSamples[i] = r * M_PI / config.numSamples; + _randomSamples[i] = r * 2.0f * M_PI / config.numSamples; } } @@ -445,7 +443,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getGatherPipeline() { gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::ssao_gather); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setColorWriteMask(true, true, true, false); + state->setColorWriteMask(true, true, true, true); // Good to go add the brand new pipeline _gatherPipeline = gpu::Pipeline::create(program, state); @@ -458,7 +456,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getBuildNormalsPipeline() { gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::ssao_buildNormals); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setColorWriteMask(true, true, true, false); + state->setColorWriteMask(true, true, true, true); // Good to go add the brand new pipeline _buildNormalsPipeline = gpu::Pipeline::create(program, state); @@ -537,8 +535,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto occlusionDepthSize = glm::ivec2(occlusionDepthTexture->getDimensions()); // Update sample rotation - const int SSAO_RANDOM_SAMPLE_COUNT = int(_randomSamples.size() / SSAO_SPLIT_COUNT); - for (int splitId=0 ; splitId < SSAO_SPLIT_COUNT ; splitId++) { + const int SSAO_RANDOM_SAMPLE_COUNT = int(_randomSamples.size() / (SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT)); + for (int splitId=0 ; splitId < SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT ; splitId++) { auto& sample = _aoFrameParametersBuffer[splitId].edit(); sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId]; } @@ -568,7 +566,22 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #if SSAO_USE_QUAD_SPLIT batch.pushProfileRange("Normal Generation"); - model.setScale(glm::vec3(normalViewport.z / (sourceViewport.z * depthResolutionScale), normalViewport.w / (sourceViewport.w * depthResolutionScale), 1.0f)); + { + const auto uvScale = glm::vec3( + normalViewport.z / (sourceViewport.z * depthResolutionScale), + normalViewport.w / (sourceViewport.w * depthResolutionScale), + 1.0f); + const auto postPixelOffset = glm::vec2(0.5f) / glm::vec2(occlusionDepthSize); + const auto prePixelOffset = glm::vec2(0.5f * uvScale.x, 0.5f * uvScale.y) / glm::vec2(normalViewport.z, normalViewport.w); + const auto uvTranslate = glm::vec3( + postPixelOffset.x - prePixelOffset.x, + postPixelOffset.y - prePixelOffset.y, + 0.0f + ); + + model.setScale(uvScale); + model.setTranslation(uvTranslate); + } batch.setModelTransform(model); // Build face normals pass @@ -595,37 +608,30 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture); { const auto uvScale = glm::vec3( - (splitSize.x * 2.0f * depthResolutionScale) / (occlusionDepthSize.x * resolutionScale), - (splitSize.y * 2.0f * depthResolutionScale) / (occlusionDepthSize.y * resolutionScale), + (splitSize.x * SSAO_SPLIT_COUNT * depthResolutionScale) / (occlusionDepthSize.x * resolutionScale), + (splitSize.y * SSAO_SPLIT_COUNT * depthResolutionScale) / (occlusionDepthSize.y * resolutionScale), 1.0f); - const auto pixelOffset = glm::vec2(0.5f) / glm::vec2(occlusionDepthSize); + const auto postPixelOffset = glm::vec2(0.5f) / glm::vec2(occlusionDepthSize); + const auto prePixelOffset = glm::vec2(0.5f * uvScale.x, 0.5f * uvScale.y) / glm::vec2(splitSize.x, splitSize.y); batch.setViewportTransform(splitViewport); model.setScale(uvScale); - model.setTranslation(glm::vec3(-pixelOffset.x, -pixelOffset.y, 0.0f)); - batch.setModelTransform(model); - batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(0)); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); - batch.draw(gpu::TRIANGLE_STRIP, 4); - - model.setTranslation(glm::vec3(pixelOffset.x, -pixelOffset.y, 0.0f)); - batch.setModelTransform(model); - batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(1)); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[1]); - batch.draw(gpu::TRIANGLE_STRIP, 4); - - model.setTranslation(glm::vec3(pixelOffset.x, pixelOffset.y, 0.0f)); - batch.setModelTransform(model); - batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(3)); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[2]); - batch.draw(gpu::TRIANGLE_STRIP, 4); - - model.setTranslation(glm::vec3(-pixelOffset.x, pixelOffset.y, 0.0f)); - batch.setModelTransform(model); - batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(2)); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[3]); - batch.draw(gpu::TRIANGLE_STRIP, 4); + for (int y = 0; y < SSAO_SPLIT_COUNT; y++) { + for (int x = 0; x < SSAO_SPLIT_COUNT; x++) { + const int splitIndex = x + y * SSAO_SPLIT_COUNT; + const auto uvTranslate = glm::vec3( + postPixelOffset.x * (2 * x + 1) - prePixelOffset.x, + postPixelOffset.y * (2 * y + 1) - prePixelOffset.y, + 0.0f + ); + model.setTranslation(uvTranslate); + batch.setModelTransform(model); + batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(splitIndex)); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[splitIndex]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + } + } } #else batch.setViewportTransform(occlusionViewport); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 3ad5ee2138..d84a8636ef 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -64,7 +64,7 @@ protected: gpu::TexturePointer _normalTexture; #if SSAO_USE_QUAD_SPLIT - gpu::FramebufferPointer _occlusionSplitFramebuffers[SSAO_SPLIT_COUNT]; + gpu::FramebufferPointer _occlusionSplitFramebuffers[SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT]; gpu::TexturePointer _occlusionSplitTexture; #endif @@ -181,7 +181,7 @@ private: int getDepthResolutionLevel() const; AOParametersBuffer _aoParametersBuffer; - FrameParametersBuffer _aoFrameParametersBuffer[SSAO_SPLIT_COUNT]; + FrameParametersBuffer _aoFrameParametersBuffer[SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT]; BlurParametersBuffer _vblurParametersBuffer; BlurParametersBuffer _hblurParametersBuffer; @@ -200,7 +200,7 @@ private: static gpu::PipelinePointer _buildNormalsPipeline; AmbientOcclusionFramebufferPointer _framebuffer; - std::array _randomSamples; + std::array _randomSamples; int _frameId{ 0 }; gpu::RangeTimerPointer _gpuTimer; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 345eeebafb..b3f66abb35 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -160,7 +160,7 @@ const float TWO_PI = 6.2831852; vec3 getUnitTapLocation(int sampleNumber, float spiralTurns, float spinAngle, float angleRange){ // Radius relative to ssR - float alpha = float(sampleNumber + 0.5) * getInvNumSamples(); + float alpha = float(sampleNumber) * getInvNumSamples(); float angle = alpha * (spiralTurns * angleRange) + spinAngle; return vec3(cos(angle), sin(angle), alpha); } @@ -244,11 +244,11 @@ float getZEyeAtPixel(ivec2 pixel, int level) { } float getZEyeAtUV(vec2 texCoord, int level) { - return -texture(depthPyramidTex, texCoord, level).x; + return -textureLod(depthPyramidTex, texCoord, level).x; } vec3 getNormalEyeAtUV(vec2 texCoord, int level) { - return normalize(texture(normalTex, texCoord, level).xyz*2.0 - vec3(1.0)); + return normalize(textureLod(normalTex, texCoord, level).xyz*2.0 - vec3(1.0)); } vec3 getNormalEyeAtPixel(ivec2 pixel, int level) { @@ -285,13 +285,14 @@ vec3 getMinDelta(vec3 centralPoint, vec3 offsetPointPos, vec3 offsetPointNeg) { vec3 delta1 = centralPoint - offsetPointNeg; float sqrLength0 = dot(delta0, delta0); float sqrLength1 = dot(delta1, delta1); - return sqrLength0 < sqrLength1 ? delta0 : delta1; + float epsilon = 1e-6; + return sqrLength0 < sqrLength1 && sqrLength0>epsilon ? delta0 : delta1; } vec3 buildNormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec2 deltaDepthUV) { vec3 fragPositionDxPos = buildPosition(side, fragUVPos + vec2(deltaDepthUV.x, 0)); - vec3 fragPositionDyPos = buildPosition(side, fragUVPos + vec2(0, deltaDepthUV.y)); vec3 fragPositionDxNeg = buildPosition(side, fragUVPos - vec2(deltaDepthUV.x, 0)); + vec3 fragPositionDyPos = buildPosition(side, fragUVPos + vec2(0, deltaDepthUV.y)); vec3 fragPositionDyNeg = buildPosition(side, fragUVPos - vec2(0, deltaDepthUV.y)); vec3 fragPositionDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg); @@ -356,6 +357,7 @@ float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNo float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, vec3 fragNormalES, vec2 searchVec, vec2 pixelSearchVec, float searchRadius) { vec2 absSearchVec = abs(searchVec); + pixelSearchVec = abs(pixelSearchVec); int stepCount = int(ceil(max(pixelSearchVec.x, pixelSearchVec.y))); float cosHorizonAngle = 0.0; @@ -488,7 +490,7 @@ vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTex int blurRadius = getBlurRadius(); float blurRadialSigma = float(blurRadius) * 0.5; float blurRadialScale = 1.0 / (2.0*blurRadialSigma*blurRadialSigma); - vec2 blurScales = -vec2(blurRadialScale, BLUR_EDGE_DISTANCE_SCALE) * getBlurEdgeSharpness(); + vec2 blurScales = -vec2(blurRadialScale, BLUR_EDGE_DISTANCE_SCALE * getBlurEdgeSharpness()); // negative side first for (int r = -blurRadius; r <= -1; ++r) { diff --git a/libraries/render-utils/src/ssao_gather.slf b/libraries/render-utils/src/ssao_gather.slf index 9a5eccb92b..64cbbdd0c7 100644 --- a/libraries/render-utils/src/ssao_gather.slf +++ b/libraries/render-utils/src/ssao_gather.slf @@ -28,12 +28,11 @@ void main(void) { // Gather the four splits of the occlusion result back into an interleaved full size // result (at the resolution level, of course) ivec2 destPixelCoord = ivec2(gl_FragCoord.xy); - ivec2 sourcePixelCoord = destPixelCoord / 2; - ivec2 splitImageSize = getWidthHeightRoundUp(getResolutionLevel()+1); - int occlusionMapIndex = (destPixelCoord.x & 1) + ((destPixelCoord.y) & 1)*2; + ivec2 sourcePixelCoord = destPixelCoord / SSAO_SPLIT_COUNT; + ivec2 splitImageSize = getWidthHeightRoundUp(getResolutionLevel()+SSAO_SPLIT_LOG2_COUNT); + ivec2 modPixelCoord = destPixelCoord % ivec2(SSAO_SPLIT_COUNT); + int occlusionMapIndex = modPixelCoord.x + modPixelCoord.y*SSAO_SPLIT_COUNT; vec2 sourceUV = (sourcePixelCoord + vec2(0.5)) / splitImageSize; - - sourcePixelCoord += (destPixelCoord & ivec2(1)) * splitImageSize; outFragColor = texture(occlusionMaps, vec3(sourceUV, occlusionMapIndex)); } diff --git a/libraries/render-utils/src/ssao_shared.h b/libraries/render-utils/src/ssao_shared.h index 11c7f894d5..7070d793ed 100644 --- a/libraries/render-utils/src/ssao_shared.h +++ b/libraries/render-utils/src/ssao_shared.h @@ -18,10 +18,11 @@ #define SSAO_USE_QUAD_SPLIT 1 #if SSAO_USE_QUAD_SPLIT -#define SSAO_SPLIT_COUNT 4 +#define SSAO_SPLIT_LOG2_COUNT 2 #else -#define SSAO_SPLIT_COUNT 1 +#define SSAO_SPLIT_LOG2_COUNT 0 #endif +#define SSAO_SPLIT_COUNT (1 << SSAO_SPLIT_LOG2_COUNT) // glsl / C++ compatible source as interface for ambient occlusion #ifdef __cplusplus From 94a162893aa154f82a29d0c808290314ae4c7aba Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 27 Sep 2018 10:44:06 +0200 Subject: [PATCH 46/81] Finally, a clean HBAO! --- .../src/AmbientOcclusionEffect.cpp | 124 +++++++++++------- .../render-utils/src/AmbientOcclusionEffect.h | 12 +- libraries/render-utils/src/ssao.slh | 74 ++++++----- libraries/render-utils/src/ssao_gather.slf | 10 +- .../src/ssao_makeHorizontalBlur.slf | 3 +- .../src/ssao_makeVerticalBlur.slf | 6 +- libraries/render-utils/src/ssao_shared.h | 10 +- 7 files changed, 134 insertions(+), 105 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 4c1ff6fe09..1dbabb7685 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -222,7 +222,7 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : #else numSamples{ 16 }, #endif - resolutionLevel{ 1 }, + resolutionLevel{ 2 }, blurRadius{ 4 }, ditheringEnabled{ true }, borderingEnabled{ true }, @@ -235,6 +235,9 @@ AmbientOcclusionEffect::AOParameters::AOParameters() { _radiusInfo = { 0.5f, 0.5f * 0.5f, 1.0f / (0.25f * 0.25f * 0.25f), 1.0f }; _ditheringInfo = { 0.0f, 0.0f, 0.01f, 1.0f }; _sampleInfo = { 11.0f, 1.0f / 11.0f, 7.0f, 1.0f }; +} + +AmbientOcclusionEffect::BlurParameters::BlurParameters() { _blurInfo = { 1.0f, 3.0f, 2.0f, 0.0f }; } @@ -269,14 +272,11 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.y = 1.0f / (1.0f - config.falloffAngle); } - if (config.edgeSharpness != _aoParametersBuffer->getEdgeSharpness()) { - auto& current = _aoParametersBuffer.edit()._blurInfo; - current.x = config.edgeSharpness; - } - - if (config.blurDeviation != _aoParametersBuffer->getBlurDeviation()) { - auto& current = _aoParametersBuffer.edit()._blurInfo; - current.z = config.blurDeviation; + if (config.edgeSharpness != _hblurParametersBuffer.get().getEdgeSharpness()) { + auto& hblur = _hblurParametersBuffer.edit()._blurInfo; + auto& vblur = _vblurParametersBuffer.edit()._blurInfo; + hblur.x = config.edgeSharpness; + vblur.x = config.edgeSharpness; } if (config.numSpiralTurns != _aoParametersBuffer->getNumSpiralTurns()) { @@ -327,9 +327,11 @@ void AmbientOcclusionEffect::configure(const Config& config) { shouldUpdateBlurs = true; } - if (config.blurRadius != _aoParametersBuffer.get().getBlurRadius()) { - auto& current = _aoParametersBuffer.edit()._blurInfo; - current.y = (float)config.blurRadius; + if (config.blurRadius != _hblurParametersBuffer.get().getBlurRadius()) { + auto& hblur = _hblurParametersBuffer.edit()._blurInfo; + auto& vblur = _vblurParametersBuffer.edit()._blurInfo; + hblur.y = (float)config.blurRadius; + vblur.y = (float)config.blurRadius; } if (config.ditheringEnabled != _aoParametersBuffer->isDitheringEnabled()) { @@ -353,31 +355,47 @@ void AmbientOcclusionEffect::updateBlurParameters() { auto& vblur = _vblurParametersBuffer.edit(); auto& hblur = _hblurParametersBuffer.edit(); auto frameSize = _framebuffer->getSourceFrameSize(); + if (_framebuffer->isStereo()) { + frameSize.x >>= 1; + } + const auto occlusionSize = divideRoundUp(frameSize, resolutionScale); - hblur.scaleHeight.x = 1.0f / frameSize.x; - hblur.scaleHeight.y = float(resolutionScale) / frameSize.x; - hblur.scaleHeight.z = frameSize.y / resolutionScale; + // Occlusion UV limit + hblur._blurInfo.z = occlusionSize.x / float(frameSize.x); + hblur._blurInfo.w = occlusionSize.y / float(frameSize.y); - vblur.scaleHeight.x = 1.0f / frameSize.y; - vblur.scaleHeight.y = float(resolutionScale) / frameSize.y; - vblur.scaleHeight.z = frameSize.y; + vblur._blurInfo.z = 1.0f; + vblur._blurInfo.w = occlusionSize.y / float(frameSize.y); + + // Depth axis + hblur._blurAxis.x = 1.0f / occlusionSize.x; + hblur._blurAxis.y = 0.0f; + + vblur._blurAxis.x = 0.0f; + vblur._blurAxis.y = 1.0f / occlusionSize.y; + + // Occlusion axis + hblur._blurAxis.z = hblur._blurAxis.x * hblur._blurInfo.z; + hblur._blurAxis.w = 0.0f; + + vblur._blurAxis.z = 0.0f; + vblur._blurAxis.w = vblur._blurAxis.y * vblur._blurInfo.w; } void AmbientOcclusionEffect::updateFramebufferSizes() { auto& params = _aoParametersBuffer.edit(); const int widthScale = _framebuffer->isStereo() & 1; - auto sourceFrameSize = _framebuffer->getSourceFrameSize(); - const int resolutionLevel = _aoParametersBuffer.get().getResolutionLevel(); - const float resolutionScale = powf(0.5f, resolutionLevel); - // Depth is at maximum half depth - const int depthResolutionLevel = std::min(1, resolutionLevel); - const float depthResolutionScale = powf(2.0f, depthResolutionLevel); - auto normalTextureSize = _framebuffer->getNormalTexture()->getDimensions(); - auto occlusionDepthFrameSize = divideRoundUp(sourceFrameSize, depthResolutionLevel); + auto sourceFrameSideSize = _framebuffer->getSourceFrameSize(); + sourceFrameSideSize.x >>= widthScale; + + const int resolutionLevel = _aoParametersBuffer.get().getResolutionLevel(); + // Depth is at maximum half depth + const int depthResolutionLevel = getDepthResolutionLevel(); + const auto occlusionDepthFrameSize = divideRoundUp(sourceFrameSideSize, 1 << depthResolutionLevel); + const auto occlusionFrameSize = divideRoundUp(sourceFrameSideSize, 1 << resolutionLevel); + auto normalTextureSize = _framebuffer->getNormalTexture()->getDimensions(); - sourceFrameSize.x >>= widthScale; normalTextureSize.x >>= widthScale; - occlusionDepthFrameSize.x >>= widthScale; params._sideSizes[0].x = normalTextureSize.x; params._sideSizes[0].y = normalTextureSize.y; @@ -386,7 +404,7 @@ void AmbientOcclusionEffect::updateFramebufferSizes() { params._sideSizes[1].x = params._sideSizes[0].x; params._sideSizes[1].y = params._sideSizes[0].y; - auto occlusionSplitSize = divideRoundUp(sourceFrameSize, 1 << (resolutionLevel + SSAO_USE_QUAD_SPLIT)); + auto occlusionSplitSize = divideRoundUp(occlusionFrameSize, SSAO_SPLIT_COUNT); params._sideSizes[1].z = occlusionSplitSize.x; params._sideSizes[1].w = occlusionSplitSize.y; } @@ -491,7 +509,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte // We need to take the rounded up resolution. auto occlusionViewport = divideRoundUp(sourceViewport, 1 << resolutionLevel); auto firstBlurViewport = sourceViewport; - firstBlurViewport.w = divideRoundUp(firstBlurViewport.w, 1 << resolutionLevel); + firstBlurViewport.w = occlusionViewport.w; if (!_gpuTimer) { _gpuTimer = std::make_shared < gpu::RangeTimer>(__FUNCTION__); @@ -550,9 +568,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.resetViewTransform(); - Transform model; batch.setProjectionTransform(glm::mat4()); - batch.setModelTransform(model); + batch.setModelTransform(Transform()); batch.pushProfileRange("Depth Mip Generation"); // We need this with the mips levels @@ -578,11 +595,12 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte postPixelOffset.y - prePixelOffset.y, 0.0f ); + Transform model; model.setScale(uvScale); model.setTranslation(uvTranslate); + batch.setModelTransform(model); } - batch.setModelTransform(model); // Build face normals pass batch.setViewportTransform(normalViewport); @@ -608,11 +626,12 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture); { const auto uvScale = glm::vec3( - (splitSize.x * SSAO_SPLIT_COUNT * depthResolutionScale) / (occlusionDepthSize.x * resolutionScale), - (splitSize.y * SSAO_SPLIT_COUNT * depthResolutionScale) / (occlusionDepthSize.y * resolutionScale), + (splitSize.x * SSAO_SPLIT_COUNT) / float(occlusionViewport.z), + (splitSize.y * SSAO_SPLIT_COUNT) / float(occlusionViewport.w), 1.0f); - const auto postPixelOffset = glm::vec2(0.5f) / glm::vec2(occlusionDepthSize); - const auto prePixelOffset = glm::vec2(0.5f * uvScale.x, 0.5f * uvScale.y) / glm::vec2(splitSize.x, splitSize.y); + const auto postPixelOffset = glm::vec2(0.5f) / glm::vec2(occlusionViewport.z, occlusionViewport.w); + const auto prePixelOffset = glm::vec2(0.5f * uvScale.x, 0.5f * uvScale.y) / glm::vec2(splitSize); + Transform model; batch.setViewportTransform(splitViewport); @@ -635,13 +654,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte } #else batch.setViewportTransform(occlusionViewport); - { - const auto uvScale = glm::vec3( - (occlusionViewport.z * depthResolutionScale) / (occlusionDepthSize.x * resolutionScale), - (occlusionViewport.w * depthResolutionScale) / (occlusionDepthSize.y * resolutionScale), - 1.0f); - model.setScale(uvScale); - } + model.setIdentity(); batch.setModelTransform(model); batch.setFramebuffer(occlusionFBO); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); @@ -666,8 +679,15 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte PROFILE_RANGE_BATCH(batch, "Bilateral Blur"); // Blur 1st pass batch.pushProfileRange("Horizontal"); - model.setScale(resolutionScale); - batch.setModelTransform(model); + { + const auto uvScale = glm::vec3( + occlusionViewport.z / float(sourceViewport.z), + occlusionViewport.w / float(sourceViewport.w), + 1.0f); + Transform model; + model.setScale(uvScale); + batch.setModelTransform(model); + } batch.setViewportTransform(firstBlurViewport); batch.setFramebuffer(occlusionBlurredFBO); // Use full resolution depth and normal for bilateral upscaling and blur @@ -680,8 +700,16 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte // Blur 2nd pass batch.pushProfileRange("Vertical"); - model.setScale(glm::vec3(1.0f, resolutionScale, 1.0f)); - batch.setModelTransform(model); + { + const auto uvScale = glm::vec3( + 1.0f, + occlusionViewport.w / float(sourceViewport.w), + 1.0f); + + Transform model; + model.setScale(uvScale); + batch.setModelTransform(model); + } batch.setViewportTransform(sourceViewport); batch.setFramebuffer(occlusionFBO); batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _vblurParametersBuffer); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index d84a8636ef..63ba82cf83 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -149,14 +149,11 @@ public: float getPerspectiveScale() const { return _resolutionInfo.z; } float getObscuranceLevel() const { return _radiusInfo.w; } float getFalloffAngle() const { return (float)_ditheringInfo.z; } - float getEdgeSharpness() const { return (float)_blurInfo.x; } - float getBlurDeviation() const { return _blurInfo.z; } float getNumSpiralTurns() const { return _sampleInfo.z; } int getNumSamples() const { return (int)_sampleInfo.x; } bool isFetchMipsEnabled() const { return _sampleInfo.w; } - int getBlurRadius() const { return (int)_blurInfo.y; } bool isDitheringEnabled() const { return _ditheringInfo.x; } bool isBorderingEnabled() const { return _ditheringInfo.w; } }; @@ -165,11 +162,14 @@ public: private: // Class describing the uniform buffer with all the parameters common to the bilateral blur shaders - class BlurParameters { + class BlurParameters : public AmbientOcclusionBlurParams { public: - glm::vec4 scaleHeight{ 0.0f }; - BlurParameters() {} + BlurParameters(); + + float getEdgeSharpness() const { return (float)_blurInfo.x; } + int getBlurRadius() const { return (int)_blurInfo.y; } + }; using BlurParametersBuffer = gpu::StructBuffer; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index b3f66abb35..ebe00ee740 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -115,14 +115,6 @@ int doFetchMips() { return int(params._sampleInfo.w); } -float getBlurEdgeSharpness() { - return params._blurInfo.x; -} - -int getBlurRadius() { - return int(params._blurInfo.y); -} - <@endfunc@> <@func declareSamplingDisk()@> @@ -247,6 +239,11 @@ float getZEyeAtUV(vec2 texCoord, int level) { return -textureLod(depthPyramidTex, texCoord, level).x; } +float getZEyeAtUV(ivec4 side, vec2 texCoord, int level) { + texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); + return getZEyeAtUV(texCoord, level); +} + vec3 getNormalEyeAtUV(vec2 texCoord, int level) { return normalize(textureLod(normalTex, texCoord, level).xyz*2.0 - vec3(1.0)); } @@ -417,37 +414,42 @@ float evalVisibilityHBAO(ivec4 side, vec2 fragUVPos, vec2 invSideImageSize, vec2 <@endfunc@> -<@func declareBlurPass(axis)@> +<@func declareBlurPass()@> -<$declarePackOcclusionDepth()$> <$declareAmbientOcclusion()$> <$declareFetchDepthPyramidMap()$> +<$declarePackOcclusionDepth()$> // the source occlusion texture layout(binding=RENDER_UTILS_TEXTURE_SSAO_OCCLUSION) uniform sampler2D occlusionMap; -struct BlurParams { - vec4 scaleHeight; -}; - layout(binding=RENDER_UTILS_BUFFER_SSAO_BLUR_PARAMS) uniform blurParamsBuffer { - BlurParams blurParams; + AmbientOcclusionBlurParams blurParams; }; -float getOcclusionBlurScale() { - return blurParams.scaleHeight.x; +vec2 getBlurOcclusionAxis() { + return blurParams._blurAxis.zw; } -float getDepthBlurScale() { - return blurParams.scaleHeight.y; +vec2 getBlurDepthAxis() { + return blurParams._blurAxis.xy; } -int getBlurImageHeight() { - return int(blurParams.scaleHeight.z); +vec2 getBlurOcclusionUVLimit() { + return blurParams._blurInfo.zw; } -float fetchOcclusion(vec2 coords) { - vec3 raw = texture(occlusionMap, coords, 0).xyz; +float getBlurEdgeSharpness() { + return blurParams._blurInfo.x; +} + +int getBlurRadius() { + return int(blurParams._blurInfo.y); +} + +float fetchOcclusion(ivec4 side, vec2 texCoord) { + texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); + vec3 raw = textureLod(occlusionMap, texCoord, 0).xyz; return raw.x; } @@ -458,19 +460,19 @@ float evalBlurCoefficient(vec2 blurScales, float radialDistance, float zDistance return exp2(dot(blurScales, distances*distances)); } -vec2 evalTapWeightedValue(vec2 blurScales, ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float fragDepth) { - ivec2 tapOffset = <$axis$> * r; - ivec2 tapPixelCoord = destPixelCoord + ivec2(tapOffset); +vec2 evalTapWeightedValue(vec2 blurScales, ivec4 side, int r, vec2 occlusionTexCoord, vec2 depthTexCoord, float fragDepth) { + vec2 tapOcclusionTexCoord = getBlurOcclusionAxis() * r + occlusionTexCoord; + vec2 occlusionTexCoordLimits = getBlurOcclusionUVLimit(); - if ((tapPixelCoord.x < side.y || tapPixelCoord.x >= side.z + side.y) || (tapPixelCoord.y < 0 || tapPixelCoord.y >= getBlurImageHeight())) { + if (tapOcclusionTexCoord.x < side.x || tapOcclusionTexCoord.x >= (side.x + occlusionTexCoordLimits.x) + || tapOcclusionTexCoord.y < 0 || tapOcclusionTexCoord.y >= occlusionTexCoordLimits.y) { return vec2(0.0); } - vec2 tapTexCoord = scaledTexCoord + tapOffset * getOcclusionBlurScale(); - float tapOcclusion = fetchOcclusion(tapTexCoord); + float tapOcclusion = fetchOcclusion(side, tapOcclusionTexCoord); - tapTexCoord = fullTexCoord + tapOffset * getDepthBlurScale(); - float tapDepth = getZEyeAtUV(tapTexCoord, 0); + vec2 tapDepthTexCoord = getBlurDepthAxis() * r + depthTexCoord; + float tapDepth = getZEyeAtUV(side, tapDepthTexCoord, 0); // range domain (the "bilateral" weight). As depth difference increases, decrease weight. float zDistance = tapDepth - fragDepth; @@ -479,11 +481,11 @@ vec2 evalTapWeightedValue(vec2 blurScales, ivec3 side, int r, ivec2 destPixelCoo return vec2(tapOcclusion * weight, weight); } -vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord) { +vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 depthTexCoord) { // Stereo side info ivec4 side = getStereoSideInfo(destPixelCoord.x, 0); - float fragDepth = getZEyeAtUV(fullTexCoord, 0); + float fragDepth = getZEyeAtUV(side, depthTexCoord, 0); vec2 weightedSums = vec2(0.0); // Accumulate weighted contributions along the bluring axis in the [-radius, radius] range @@ -494,17 +496,17 @@ vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTex // negative side first for (int r = -blurRadius; r <= -1; ++r) { - weightedSums += evalTapWeightedValue(blurScales, side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth); + weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, depthTexCoord, fragDepth); } // Central pixel contribution float mainWeight = 1.0; - float pixelOcclusion = fetchOcclusion(scaledTexCoord); + float pixelOcclusion = fetchOcclusion(side, occlusionTexCoord); weightedSums += vec2(pixelOcclusion * mainWeight, mainWeight); // then positive side for (int r = 1; r <= blurRadius; ++r) { - weightedSums += evalTapWeightedValue(blurScales, side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth); + weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, depthTexCoord, fragDepth); } // Final normalization diff --git a/libraries/render-utils/src/ssao_gather.slf b/libraries/render-utils/src/ssao_gather.slf index 64cbbdd0c7..aaad3a5798 100644 --- a/libraries/render-utils/src/ssao_gather.slf +++ b/libraries/render-utils/src/ssao_gather.slf @@ -28,11 +28,9 @@ void main(void) { // Gather the four splits of the occlusion result back into an interleaved full size // result (at the resolution level, of course) ivec2 destPixelCoord = ivec2(gl_FragCoord.xy); - ivec2 sourcePixelCoord = destPixelCoord / SSAO_SPLIT_COUNT; - ivec2 splitImageSize = getWidthHeightRoundUp(getResolutionLevel()+SSAO_SPLIT_LOG2_COUNT); - ivec2 modPixelCoord = destPixelCoord % ivec2(SSAO_SPLIT_COUNT); - int occlusionMapIndex = modPixelCoord.x + modPixelCoord.y*SSAO_SPLIT_COUNT; - vec2 sourceUV = (sourcePixelCoord + vec2(0.5)) / splitImageSize; + ivec2 sourcePixelCoord = destPixelCoord >> SSAO_SPLIT_LOG2_COUNT; + ivec2 modPixelCoord = destPixelCoord & (SSAO_SPLIT_COUNT-1); + int occlusionMapIndex = modPixelCoord.x + (modPixelCoord.y << SSAO_SPLIT_LOG2_COUNT); - outFragColor = texture(occlusionMaps, vec3(sourceUV, occlusionMapIndex)); + outFragColor = texelFetch(occlusionMaps, ivec3(sourcePixelCoord, occlusionMapIndex), 0); } diff --git a/libraries/render-utils/src/ssao_makeHorizontalBlur.slf b/libraries/render-utils/src/ssao_makeHorizontalBlur.slf index fc90052eed..e535398241 100644 --- a/libraries/render-utils/src/ssao_makeHorizontalBlur.slf +++ b/libraries/render-utils/src/ssao_makeHorizontalBlur.slf @@ -15,8 +15,7 @@ // Hack comment -const ivec2 horizontal = ivec2(1,0); -<$declareBlurPass(horizontal)$> +<$declareBlurPass()$> layout(location=0) in vec4 varTexCoord0; diff --git a/libraries/render-utils/src/ssao_makeVerticalBlur.slf b/libraries/render-utils/src/ssao_makeVerticalBlur.slf index 69b92000de..15550a73cd 100644 --- a/libraries/render-utils/src/ssao_makeVerticalBlur.slf +++ b/libraries/render-utils/src/ssao_makeVerticalBlur.slf @@ -14,14 +14,12 @@ // Hack comment -const ivec2 vertical = ivec2(0,1); -<$declareBlurPass(vertical)$> +<$declareBlurPass()$> layout(location=0) in vec4 varTexCoord0; layout(location=0) out vec4 outFragColor; void main(void) { - float occlusion = getBlurredOcclusion(ivec2(gl_FragCoord.xy), varTexCoord0.xy, varTexCoord0.zw).x; - outFragColor = vec4(occlusion, 0.0, 0.0, occlusion); + outFragColor = vec4(getBlurredOcclusion(ivec2(gl_FragCoord.xy), varTexCoord0.xy, varTexCoord0.zw), 1.0); } diff --git a/libraries/render-utils/src/ssao_shared.h b/libraries/render-utils/src/ssao_shared.h index 7070d793ed..c331dabd7a 100644 --- a/libraries/render-utils/src/ssao_shared.h +++ b/libraries/render-utils/src/ssao_shared.h @@ -27,10 +27,10 @@ // glsl / C++ compatible source as interface for ambient occlusion #ifdef __cplusplus # define SSAO_VEC4 glm::vec4 -# define SSAO_IVEC4 glm::ivec4 +# define SSAO_MAT4 glm::mat4 #else # define SSAO_VEC4 vec4 -# define SSAO_IVEC4 ivec4 +# define SSAO_MAT4 mat4 #endif struct AmbientOcclusionParams { @@ -38,7 +38,6 @@ struct AmbientOcclusionParams { SSAO_VEC4 _radiusInfo; SSAO_VEC4 _ditheringInfo; SSAO_VEC4 _sampleInfo; - SSAO_VEC4 _blurInfo; SSAO_VEC4 _sideSizes[2]; }; @@ -46,6 +45,11 @@ struct AmbientOcclusionFrameParams { SSAO_VEC4 _angleInfo; }; +struct AmbientOcclusionBlurParams { + SSAO_VEC4 _blurInfo; + SSAO_VEC4 _blurAxis; +}; + #endif // RENDER_UTILS_SHADER_CONSTANTS_H // <@if 1@> From 349a8b39adaa786c98f3a6a6a1e667a3620350a8 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 27 Sep 2018 16:39:42 +0200 Subject: [PATCH 47/81] Added config parameter to switch between HBAO / SSAO --- .../src/AmbientOcclusionEffect.cpp | 50 ++++++++----------- .../render-utils/src/AmbientOcclusionEffect.h | 8 ++- libraries/render-utils/src/ssao.slh | 4 ++ .../render-utils/src/ssao_makeOcclusion.slf | 40 +++++++-------- libraries/render-utils/src/ssao_shared.h | 1 - .../utilities/render/ambientOcclusionPass.qml | 1 + 6 files changed, 51 insertions(+), 53 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 1dbabb7685..b56da99ee6 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -202,36 +202,24 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() { AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false), -#if SSAO_USE_HORIZON_BASED radius{ 0.3f }, -#else - radius{ 0.5f }, -#endif perspectiveScale{ 1.0f }, obscuranceLevel{ 0.5f }, -#if SSAO_USE_HORIZON_BASED falloffAngle{ 0.3f }, -#else - falloffAngle{ 0.01f }, -#endif edgeSharpness{ 1.0f }, blurDeviation{ 2.5f }, numSpiralTurns{ 7.0f }, -#if SSAO_USE_HORIZON_BASED numSamples{ 1 }, -#else - numSamples{ 16 }, -#endif resolutionLevel{ 2 }, blurRadius{ 4 }, ditheringEnabled{ true }, borderingEnabled{ true }, - fetchMipsEnabled{ true } { - + fetchMipsEnabled{ true }, + horizonBased{ true } { } AmbientOcclusionEffect::AOParameters::AOParameters() { - _resolutionInfo = { -1.0f, 0.0f, 1.0f, 0.0f }; + _resolutionInfo = { -1.0f, 1.0f, 1.0f, 0.0f }; _radiusInfo = { 0.5f, 0.5f * 0.5f, 1.0f / (0.25f * 0.25f * 0.25f), 1.0f }; _ditheringInfo = { 0.0f, 0.0f, 0.01f, 1.0f }; _sampleInfo = { 11.0f, 1.0f / 11.0f, 7.0f, 1.0f }; @@ -251,14 +239,19 @@ void AmbientOcclusionEffect::configure(const Config& config) { const double RADIUS_POWER = 6.0; const auto& radius = config.radius; - if (radius != _aoParametersBuffer->getRadius()) { + if (radius != _aoParametersBuffer->getRadius() || config.horizonBased != _aoParametersBuffer->isHorizonBased()) { auto& current = _aoParametersBuffer.edit()._radiusInfo; current.x = radius; current.y = radius * radius; current.z = 10.0f; -#if !SSAO_USE_HORIZON_BASED - current.z *= (float)(1.0 / pow((double)radius, RADIUS_POWER)); -#endif + if (!config.horizonBased) { + current.z *= (float)(1.0 / pow((double)radius, RADIUS_POWER)); + } + } + + if (config.horizonBased != _aoParametersBuffer->isHorizonBased()) { + auto& current = _aoParametersBuffer.edit()._resolutionInfo; + current.y = config.horizonBased & 1; } if (config.obscuranceLevel != _aoParametersBuffer->getObscuranceLevel()) { @@ -501,6 +494,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte const auto depthResolutionLevel = getDepthResolutionLevel(); const auto depthResolutionScale = powf(0.5f, depthResolutionLevel); + const auto isHorizonBased = _aoParametersBuffer->isHorizonBased(); auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); auto occlusionDepthTexture = linearDepthTexture; @@ -538,9 +532,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto occlusionPipeline = getOcclusionPipeline(); auto firstHBlurPipeline = getHBlurPipeline(); auto lastVBlurPipeline = getVBlurPipeline(); -#if SSAO_USE_HORIZON_BASED auto mipCreationPipeline = getMipCreationPipeline(); -#endif #if SSAO_USE_QUAD_SPLIT auto gatherPipeline = getGatherPipeline(); auto buildNormalsPipeline = getBuildNormalsPipeline(); @@ -571,14 +563,14 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setProjectionTransform(glm::mat4()); batch.setModelTransform(Transform()); - batch.pushProfileRange("Depth Mip Generation"); // We need this with the mips levels -#if SSAO_USE_HORIZON_BASED - batch.setPipeline(mipCreationPipeline); - batch.generateTextureMipsWithPipeline(occlusionDepthTexture); -#else - batch.generateTextureMips(occlusionDepthTexture); -#endif + batch.pushProfileRange("Depth Mip Generation"); + if (isHorizonBased) { + batch.setPipeline(mipCreationPipeline); + batch.generateTextureMipsWithPipeline(occlusionDepthTexture); + } else { + batch.generateTextureMips(occlusionDepthTexture); + } batch.popProfileRange(); #if SSAO_USE_QUAD_SPLIT @@ -731,8 +723,6 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte config->setGPUBatchRunTime(_gpuTimer->getGPUAverage(), _gpuTimer->getBatchAverage()); } - - DebugAmbientOcclusion::DebugAmbientOcclusion() { } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 63ba82cf83..4ace549e9e 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -79,6 +79,7 @@ using AmbientOcclusionFramebufferPointer = std::shared_ptr; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index ebe00ee740..bc7473a3ba 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -51,6 +51,10 @@ int getResolutionLevel() { return int(params._resolutionInfo.x); } +bool isHorizonBased() { + return params._resolutionInfo.y!=0.0; +} + vec2 getNormalsSideSize() { return params._sideSizes[0].xy; } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 0a34b0df03..e2a94be134 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -51,9 +51,9 @@ void main(void) { // Choose the screen-space sample radius float diskPixelRadius = evalDiskRadius(fragPositionES.z, sideDepthSize); -#if SSAO_USE_HORIZON_BASED - diskPixelRadius = min(diskPixelRadius, SSAO_HBAO_MAX_RADIUS); -#endif + if (isHorizonBased()) { + diskPixelRadius = min(diskPixelRadius, SSAO_HBAO_MAX_RADIUS); + } // Let's make noise float randomPatternRotationAngle = getAngleDithering(fragPixelPos); @@ -63,24 +63,24 @@ void main(void) { int numSamples = int(getNumSamples()); float invNumSamples = getInvNumSamples(); - // Steps are in the depth texture resolution - vec2 depthTexFragPixelPos = fragUVPos * sideDepthSize; - for (int i = 0; i < numSamples; ++i) { -#if SSAO_USE_HORIZON_BASED - vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); - obscuranceSum += evalVisibilityHBAO(side, fragUVPos, deltaDepthUV, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); -#else - vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, depthTexFragPixelPos, sideDepthSize); - vec2 tapUV = fragUVPos + tap.xy * deltaDepthUV; - vec2 tapMipZ = fetchTapWithUV(side, tapUV, tap.z); - vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, tapUV); - obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES); -#endif - } + if (isHorizonBased()) { + for (int i = 0; i < numSamples; ++i) { + vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); + obscuranceSum += evalVisibilityHBAO(side, fragUVPos, deltaDepthUV, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); + } + obscuranceSum *= 0.5 / PI; + } else { + // Steps are in the depth texture resolution + vec2 depthTexFragPixelPos = fragUVPos * sideDepthSize; -#if SSAO_USE_HORIZON_BASED - obscuranceSum *= 0.5 / PI; -#endif + for (int i = 0; i < numSamples; ++i) { + vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, depthTexFragPixelPos, sideDepthSize); + vec2 tapUV = fragUVPos + tap.xy * deltaDepthUV; + vec2 tapMipZ = fetchTap(side, tapUV, tap.z); + vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, tapUV); + obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES); + } + } float occlusion = clamp(1.0 - obscuranceSum * getObscuranceScaling() * invNumSamples, 0.0, 1.0); diff --git a/libraries/render-utils/src/ssao_shared.h b/libraries/render-utils/src/ssao_shared.h index c331dabd7a..9c9e57337c 100644 --- a/libraries/render-utils/src/ssao_shared.h +++ b/libraries/render-utils/src/ssao_shared.h @@ -14,7 +14,6 @@ #ifndef RENDER_UTILS_SSAO_SHARED_H #define RENDER_UTILS_SSAO_SHARED_H -#define SSAO_USE_HORIZON_BASED 1 #define SSAO_USE_QUAD_SPLIT 1 #if SSAO_USE_QUAD_SPLIT diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index 141832e202..5197fc312d 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -58,6 +58,7 @@ Rectangle { Column { Repeater { model: [ + "horizonBased:horizonBased", "ditheringEnabled:ditheringEnabled", "fetchMipsEnabled:fetchMipsEnabled", "borderingEnabled:borderingEnabled" From 199809663050202472a26be68d46c1d9f7369609 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 27 Sep 2018 17:03:14 +0200 Subject: [PATCH 48/81] On single bilateral blur shader --- .../src/AmbientOcclusionEffect.cpp | 33 +++++-------------- .../render-utils/src/AmbientOcclusionEffect.h | 6 ++-- .../src/render-utils/ssao_bilateralBlur.slp | 1 + .../render-utils/ssao_makeHorizontalBlur.slp | 1 - .../render-utils/ssao_makeVerticalBlur.slp | 1 - ...erticalBlur.slf => ssao_bilateralBlur.slf} | 3 +- .../{ssao_blur.slv => ssao_bilateralBlur.slv} | 2 +- .../src/ssao_makeHorizontalBlur.slf | 26 --------------- 8 files changed, 14 insertions(+), 59 deletions(-) create mode 100644 libraries/render-utils/src/render-utils/ssao_bilateralBlur.slp delete mode 100644 libraries/render-utils/src/render-utils/ssao_makeHorizontalBlur.slp delete mode 100644 libraries/render-utils/src/render-utils/ssao_makeVerticalBlur.slp rename libraries/render-utils/src/{ssao_makeVerticalBlur.slf => ssao_bilateralBlur.slf} (94%) rename libraries/render-utils/src/{ssao_blur.slv => ssao_bilateralBlur.slv} (97%) delete mode 100644 libraries/render-utils/src/ssao_makeHorizontalBlur.slf diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index b56da99ee6..6084fc8f14 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -32,8 +32,7 @@ #include "ViewFrustum.h" gpu::PipelinePointer AmbientOcclusionEffect::_occlusionPipeline; -gpu::PipelinePointer AmbientOcclusionEffect::_hBlurPipeline; -gpu::PipelinePointer AmbientOcclusionEffect::_vBlurPipeline; +gpu::PipelinePointer AmbientOcclusionEffect::_bilateralBlurPipeline; gpu::PipelinePointer AmbientOcclusionEffect::_mipCreationPipeline; gpu::PipelinePointer AmbientOcclusionEffect::_gatherPipeline; gpu::PipelinePointer AmbientOcclusionEffect::_buildNormalsPipeline; @@ -415,31 +414,17 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { return _occlusionPipeline; } -const gpu::PipelinePointer& AmbientOcclusionEffect::getHBlurPipeline() { - if (!_hBlurPipeline) { - gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::ssao_makeHorizontalBlur); +const gpu::PipelinePointer& AmbientOcclusionEffect::getBilateralBlurPipeline() { + if (!_bilateralBlurPipeline) { + gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::ssao_bilateralBlur); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setColorWriteMask(true, true, true, false); // Good to go add the brand new pipeline - _hBlurPipeline = gpu::Pipeline::create(program, state); + _bilateralBlurPipeline = gpu::Pipeline::create(program, state); } - return _hBlurPipeline; -} - -const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { - if (!_vBlurPipeline) { - gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::ssao_makeVerticalBlur); - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - - // Vertical blur write just the final result Occlusion value in the alpha channel - state->setColorWriteMask(true, true, true, false); - - // Good to go add the brand new pipeline - _vBlurPipeline = gpu::Pipeline::create(program, state); - } - return _vBlurPipeline; + return _bilateralBlurPipeline; } const gpu::PipelinePointer& AmbientOcclusionEffect::getMipCreationPipeline() { @@ -530,8 +515,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto framebufferSize = _framebuffer->getSourceFrameSize(); auto occlusionPipeline = getOcclusionPipeline(); - auto firstHBlurPipeline = getHBlurPipeline(); - auto lastVBlurPipeline = getVBlurPipeline(); + auto bilateralBlurPipeline = getBilateralBlurPipeline(); auto mipCreationPipeline = getMipCreationPipeline(); #if SSAO_USE_QUAD_SPLIT auto gatherPipeline = getGatherPipeline(); @@ -680,12 +664,12 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte model.setScale(uvScale); batch.setModelTransform(model); } + batch.setPipeline(bilateralBlurPipeline); batch.setViewportTransform(firstBlurViewport); batch.setFramebuffer(occlusionBlurredFBO); // Use full resolution depth and normal for bilateral upscaling and blur batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _hblurParametersBuffer); - batch.setPipeline(firstHBlurPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionFBO->getRenderBuffer(0)); batch.draw(gpu::TRIANGLE_STRIP, 4); batch.popProfileRange(); @@ -705,7 +689,6 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setViewportTransform(sourceViewport); batch.setFramebuffer(occlusionFBO); batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _vblurParametersBuffer); - batch.setPipeline(lastVBlurPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionBlurredFBO->getRenderBuffer(0)); batch.draw(gpu::TRIANGLE_STRIP, 4); batch.popProfileRange(); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 4ace549e9e..dbbbee76d0 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -190,15 +190,13 @@ private: BlurParametersBuffer _hblurParametersBuffer; static const gpu::PipelinePointer& getOcclusionPipeline(); - static const gpu::PipelinePointer& getHBlurPipeline(); // first - static const gpu::PipelinePointer& getVBlurPipeline(); // second + static const gpu::PipelinePointer& getBilateralBlurPipeline(); static const gpu::PipelinePointer& getMipCreationPipeline(); static const gpu::PipelinePointer& getGatherPipeline(); static const gpu::PipelinePointer& getBuildNormalsPipeline(); static gpu::PipelinePointer _occlusionPipeline; - static gpu::PipelinePointer _hBlurPipeline; - static gpu::PipelinePointer _vBlurPipeline; + static gpu::PipelinePointer _bilateralBlurPipeline; static gpu::PipelinePointer _mipCreationPipeline; static gpu::PipelinePointer _gatherPipeline; static gpu::PipelinePointer _buildNormalsPipeline; diff --git a/libraries/render-utils/src/render-utils/ssao_bilateralBlur.slp b/libraries/render-utils/src/render-utils/ssao_bilateralBlur.slp new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/libraries/render-utils/src/render-utils/ssao_bilateralBlur.slp @@ -0,0 +1 @@ + diff --git a/libraries/render-utils/src/render-utils/ssao_makeHorizontalBlur.slp b/libraries/render-utils/src/render-utils/ssao_makeHorizontalBlur.slp deleted file mode 100644 index 49fd3dba93..0000000000 --- a/libraries/render-utils/src/render-utils/ssao_makeHorizontalBlur.slp +++ /dev/null @@ -1 +0,0 @@ -VERTEX ssao_blur diff --git a/libraries/render-utils/src/render-utils/ssao_makeVerticalBlur.slp b/libraries/render-utils/src/render-utils/ssao_makeVerticalBlur.slp deleted file mode 100644 index 49fd3dba93..0000000000 --- a/libraries/render-utils/src/render-utils/ssao_makeVerticalBlur.slp +++ /dev/null @@ -1 +0,0 @@ -VERTEX ssao_blur diff --git a/libraries/render-utils/src/ssao_makeVerticalBlur.slf b/libraries/render-utils/src/ssao_bilateralBlur.slf similarity index 94% rename from libraries/render-utils/src/ssao_makeVerticalBlur.slf rename to libraries/render-utils/src/ssao_bilateralBlur.slf index 15550a73cd..cadf00bf14 100644 --- a/libraries/render-utils/src/ssao_makeVerticalBlur.slf +++ b/libraries/render-utils/src/ssao_bilateralBlur.slf @@ -2,7 +2,7 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// ssao_makeVerticalBlur.frag +// ssao_bilateralBlur.frag // // Created by Sam Gateau on 1/1/16. // Copyright 2016 High Fidelity, Inc. @@ -10,6 +10,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + <@include ssao.slh@> // Hack comment diff --git a/libraries/render-utils/src/ssao_blur.slv b/libraries/render-utils/src/ssao_bilateralBlur.slv similarity index 97% rename from libraries/render-utils/src/ssao_blur.slv rename to libraries/render-utils/src/ssao_bilateralBlur.slv index aafd9adbf4..d45fdf8360 100644 --- a/libraries/render-utils/src/ssao_blur.slv +++ b/libraries/render-utils/src/ssao_bilateralBlur.slv @@ -2,7 +2,7 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// ssao_blur.vert +// ssao_bilateralBlur.vert // // Draw the unit quad [-1,-1 -> 1,1] filling in // Simply draw a Triangle_strip of 2 triangles, no input buffers or index buffer needed diff --git a/libraries/render-utils/src/ssao_makeHorizontalBlur.slf b/libraries/render-utils/src/ssao_makeHorizontalBlur.slf deleted file mode 100644 index e535398241..0000000000 --- a/libraries/render-utils/src/ssao_makeHorizontalBlur.slf +++ /dev/null @@ -1,26 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// ssao_makeHorizontalBlur.frag -// -// Created by Sam Gateau on 1/1/16. -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -<@include ssao.slh@> - -// Hack comment - -<$declareBlurPass()$> - -layout(location=0) in vec4 varTexCoord0; - -layout(location=0) out vec4 outFragColor; - -void main(void) { - outFragColor = vec4(getBlurredOcclusion(ivec2(gl_FragCoord.xy), varTexCoord0.xy, varTexCoord0.zw), 1.0); -} From 135e10eaa276b8472c361ff5b1ade79a0d3379a0 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 27 Sep 2018 19:51:01 +0200 Subject: [PATCH 49/81] Packed occlusion depth for faster bilateral filtering --- .../src/AmbientOcclusionEffect.cpp | 23 ++- libraries/render-utils/src/ssao.slh | 145 ++++-------------- .../render-utils/src/ssao_bilateralBlur.slf | 115 +++++++++++++- .../render-utils/src/ssao_debugOcclusion.slf | 2 +- .../render-utils/src/ssao_makeOcclusion.slf | 2 +- libraries/render-utils/src/ssao_shared.h | 1 + 6 files changed, 164 insertions(+), 124 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 6084fc8f14..6a702b1640 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -82,17 +82,22 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getLinearDepthTexture() { } void AmbientOcclusionFramebuffer::allocate() { +#if SSAO_BILATERAL_BLUR_USE_NORMAL + const auto occlusionformat = gpu::Element{ gpu::VEC4, gpu::HALF, gpu::RGBA }; +#else + const auto occlusionformat = gpu::Element{ gpu::VEC3, gpu::NUINT8, gpu::RGB }; +#endif + // Full frame { auto width = _frameSize.x; auto height = _frameSize.y; - auto format = gpu::Element::COLOR_R_8; - _occlusionTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); + _occlusionTexture = gpu::Texture::createRenderBuffer(occlusionformat, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); - _occlusionBlurredTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); + _occlusionBlurredTexture = gpu::Texture::createRenderBuffer(occlusionformat, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusionBlurred")); _occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture); } @@ -128,9 +133,8 @@ void AmbientOcclusionFramebuffer::allocate() { } auto width = splitSize.x; auto height = splitSize.y; - auto format = gpu::Element::COLOR_R_8; - _occlusionSplitTexture = gpu::Texture::createRenderBufferArray(format, width, height, SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT, gpu::Texture::SINGLE_MIP, + _occlusionSplitTexture = gpu::Texture::createRenderBufferArray(occlusionformat, width, height, SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); for (int i = 0; i < SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT; i++) { _occlusionSplitFramebuffers[i] = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); @@ -665,10 +669,15 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setModelTransform(model); } batch.setPipeline(bilateralBlurPipeline); - batch.setViewportTransform(firstBlurViewport); - batch.setFramebuffer(occlusionBlurredFBO); // Use full resolution depth and normal for bilateral upscaling and blur batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); +#if SSAO_USE_QUAD_SPLIT + batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture); +#else + batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, nullptr); +#endif + batch.setViewportTransform(firstBlurViewport); + batch.setFramebuffer(occlusionBlurredFBO); batch.setUniformBuffer(render_utils::slot::buffer::SsaoBlurParams, _hblurParametersBuffer); batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionFBO->getRenderBuffer(0)); batch.draw(gpu::TRIANGLE_STRIP, 4); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index bc7473a3ba..a02554a385 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -16,20 +16,39 @@ <@func declarePackOcclusionDepth()@> -const float FAR_PLANE_Z = -300.0; +#define SSAO_DEPTH_KEY_SCALE 300.0 float CSZToDepthKey(float z) { - return clamp(z * (1.0 / FAR_PLANE_Z), 0.0, 1.0); + return clamp(z * (-1.0 / SSAO_DEPTH_KEY_SCALE), 0.0, 1.0); } -vec3 packOcclusionDepth(float occlusion, float depth) { + +vec4 packOcclusionOutput(float occlusion, float depth, vec3 eyeNormal) { + depth = CSZToDepthKey(depth); +#if SSAO_BILATERAL_BLUR_USE_NORMAL + return vec4(occlusion, depth, eyeNormal.xy / eyeNormal.z); +#else // Round to the nearest 1/256.0 - float temp = floor(depth * 256.0); - return vec3(occlusion, temp * (1.0 / 256.0), depth * 256.0 - temp); + depth *= 256; + float temp = floor(depth); + return vec4(occlusion, temp * (1.0 / 256.0), depth - temp, 0.0); +#endif } -vec2 unpackOcclusionDepth(vec3 raw) { - float z = raw.y * (256.0 / 257.0) + raw.z * (1.0 / 257.0); - return vec2(raw.x, z); + +void unpackOcclusionOutput(vec4 raw, out float occlusion, out float depth, out vec3 eyeNormal) { + occlusion = raw.x; +#if SSAO_BILATERAL_BLUR_USE_NORMAL + depth = raw.y; + eyeNormal = normalize(vec3(raw.zw, 1.0)); +#else + depth = (raw.y + raw.z / 256.0); + eyeNormal = vec3(0,0,1); +#endif } + +float unpackOcclusion(vec4 raw) { + return raw.x; +} + <@endfunc@> <@func declareAmbientOcclusion()@> @@ -252,6 +271,11 @@ vec3 getNormalEyeAtUV(vec2 texCoord, int level) { return normalize(textureLod(normalTex, texCoord, level).xyz*2.0 - vec3(1.0)); } +vec3 getNormalEyeAtUV(ivec4 side, vec2 texCoord, int level) { + texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); + return getNormalEyeAtUV(texCoord, level); +} + vec3 getNormalEyeAtPixel(ivec2 pixel, int level) { return normalize(texelFetch(normalTex, pixel, level).xyz*2.0 - vec3(1.0)); } @@ -418,109 +442,4 @@ float evalVisibilityHBAO(ivec4 side, vec2 fragUVPos, vec2 invSideImageSize, vec2 <@endfunc@> -<@func declareBlurPass()@> - -<$declareAmbientOcclusion()$> -<$declareFetchDepthPyramidMap()$> -<$declarePackOcclusionDepth()$> - -// the source occlusion texture -layout(binding=RENDER_UTILS_TEXTURE_SSAO_OCCLUSION) uniform sampler2D occlusionMap; - -layout(binding=RENDER_UTILS_BUFFER_SSAO_BLUR_PARAMS) uniform blurParamsBuffer { - AmbientOcclusionBlurParams blurParams; -}; - -vec2 getBlurOcclusionAxis() { - return blurParams._blurAxis.zw; -} - -vec2 getBlurDepthAxis() { - return blurParams._blurAxis.xy; -} - -vec2 getBlurOcclusionUVLimit() { - return blurParams._blurInfo.zw; -} - -float getBlurEdgeSharpness() { - return blurParams._blurInfo.x; -} - -int getBlurRadius() { - return int(blurParams._blurInfo.y); -} - -float fetchOcclusion(ivec4 side, vec2 texCoord) { - texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); - vec3 raw = textureLod(occlusionMap, texCoord, 0).xyz; - return raw.x; -} - -const float BLUR_EDGE_DISTANCE_SCALE = 1000.0; - -float evalBlurCoefficient(vec2 blurScales, float radialDistance, float zDistance) { - vec2 distances = vec2(radialDistance, zDistance); - return exp2(dot(blurScales, distances*distances)); -} - -vec2 evalTapWeightedValue(vec2 blurScales, ivec4 side, int r, vec2 occlusionTexCoord, vec2 depthTexCoord, float fragDepth) { - vec2 tapOcclusionTexCoord = getBlurOcclusionAxis() * r + occlusionTexCoord; - vec2 occlusionTexCoordLimits = getBlurOcclusionUVLimit(); - - if (tapOcclusionTexCoord.x < side.x || tapOcclusionTexCoord.x >= (side.x + occlusionTexCoordLimits.x) - || tapOcclusionTexCoord.y < 0 || tapOcclusionTexCoord.y >= occlusionTexCoordLimits.y) { - return vec2(0.0); - } - - float tapOcclusion = fetchOcclusion(side, tapOcclusionTexCoord); - - vec2 tapDepthTexCoord = getBlurDepthAxis() * r + depthTexCoord; - float tapDepth = getZEyeAtUV(side, tapDepthTexCoord, 0); - - // range domain (the "bilateral" weight). As depth difference increases, decrease weight. - float zDistance = tapDepth - fragDepth; - float weight = evalBlurCoefficient(blurScales, abs(r), zDistance); - - return vec2(tapOcclusion * weight, weight); -} - -vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 depthTexCoord) { - // Stereo side info - ivec4 side = getStereoSideInfo(destPixelCoord.x, 0); - - float fragDepth = getZEyeAtUV(side, depthTexCoord, 0); - vec2 weightedSums = vec2(0.0); - - // Accumulate weighted contributions along the bluring axis in the [-radius, radius] range - int blurRadius = getBlurRadius(); - float blurRadialSigma = float(blurRadius) * 0.5; - float blurRadialScale = 1.0 / (2.0*blurRadialSigma*blurRadialSigma); - vec2 blurScales = -vec2(blurRadialScale, BLUR_EDGE_DISTANCE_SCALE * getBlurEdgeSharpness()); - - // negative side first - for (int r = -blurRadius; r <= -1; ++r) { - weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, depthTexCoord, fragDepth); - } - - // Central pixel contribution - float mainWeight = 1.0; - float pixelOcclusion = fetchOcclusion(side, occlusionTexCoord); - weightedSums += vec2(pixelOcclusion * mainWeight, mainWeight); - - // then positive side - for (int r = 1; r <= blurRadius; ++r) { - weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, depthTexCoord, fragDepth); - } - - // Final normalization - const float epsilon = 0.0001; - float result = weightedSums.x / (weightedSums.y + epsilon); - - return vec3(result); -} - -<@endfunc@> - - <@endif@> diff --git a/libraries/render-utils/src/ssao_bilateralBlur.slf b/libraries/render-utils/src/ssao_bilateralBlur.slf index cadf00bf14..e85fc42b9e 100644 --- a/libraries/render-utils/src/ssao_bilateralBlur.slf +++ b/libraries/render-utils/src/ssao_bilateralBlur.slf @@ -15,12 +15,123 @@ // Hack comment -<$declareBlurPass()$> +<$declareAmbientOcclusion()$> +<$declareFetchDepthPyramidMap()$> +<$declarePackOcclusionDepth()$> + +// the source occlusion texture +layout(binding=RENDER_UTILS_TEXTURE_SSAO_OCCLUSION) uniform sampler2D occlusionMap; + +layout(binding=RENDER_UTILS_BUFFER_SSAO_BLUR_PARAMS) uniform blurParamsBuffer { + AmbientOcclusionBlurParams blurParams; +}; + +vec2 getBlurOcclusionAxis() { + return blurParams._blurAxis.zw; +} + +vec2 getBlurDepthAxis() { + return blurParams._blurAxis.xy; +} + +vec2 getBlurOcclusionUVLimit() { + return blurParams._blurInfo.zw; +} + +float getBlurEdgeSharpness() { + return blurParams._blurInfo.x; +} + +int getBlurRadius() { + return int(blurParams._blurInfo.y); +} + +vec4 fetchOcclusionPacked(ivec4 side, vec2 texCoord) { + texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); + return textureLod(occlusionMap, texCoord, 0); +} + +float evalBlurCoefficient(vec3 blurScales, float radialDistance, float zDistance, float normalDistance) { + vec3 distances = vec3(radialDistance, zDistance, normalDistance); + return exp2(dot(blurScales, distances*distances)); +} + +const float BLUR_EDGE_DISTANCE_SCALE = 1000 * SSAO_DEPTH_KEY_SCALE; +const float BLUR_EDGE_NORMAL_SCALE = 2.0; +const float BLUR_EDGE_NORMAL_LIMIT = 0.25; + +vec2 evalTapWeightedValue(vec3 blurScales, ivec4 side, int r, vec2 occlusionTexCoord, vec2 depthTexCoord, float fragDepth, vec3 fragNormal) { + vec2 tapOcclusionTexCoord = getBlurOcclusionAxis() * r + occlusionTexCoord; + vec2 occlusionTexCoordLimits = getBlurOcclusionUVLimit(); + + if (tapOcclusionTexCoord.x < side.x || tapOcclusionTexCoord.x >= (side.x + occlusionTexCoordLimits.x) + || tapOcclusionTexCoord.y < 0 || tapOcclusionTexCoord.y >= occlusionTexCoordLimits.y) { + return vec2(0.0); + } + + vec4 tapOcclusionPacked = fetchOcclusionPacked(side, tapOcclusionTexCoord); + float tapOcclusion; + float tapDepth; + vec3 tapNormal; + unpackOcclusionOutput(tapOcclusionPacked, tapOcclusion, tapDepth, tapNormal); + + // range domain (the "bilateral" weight). As depth difference increases, decrease weight. + float zDistance = tapDepth - fragDepth; +#if SSAO_BILATERAL_BLUR_USE_NORMAL + float normalDistance = BLUR_EDGE_NORMAL_LIMIT - min(BLUR_EDGE_NORMAL_LIMIT, dot(tapNormal, fragNormal)); +#else + float normalDistance = 0.0; +#endif + float weight = evalBlurCoefficient(blurScales, abs(r), zDistance, normalDistance); + + return vec2(tapOcclusion * weight, weight); +} + +vec4 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 depthTexCoord) { + // Stereo side info + ivec4 side = getStereoSideInfo(destPixelCoord.x, 0); + + float fragDepth = getZEyeAtUV(side, depthTexCoord, 0); + float fragDepthKey = CSZToDepthKey(fragDepth); +#if SSAO_BILATERAL_BLUR_USE_NORMAL + vec3 fragNormal = getNormalEyeAtUV(side, depthTexCoord, 0); +#else + vec3 fragNormal = vec3(0, 0, 1); +#endif + vec2 weightedSums = vec2(0.0); + + // Accumulate weighted contributions along the bluring axis in the [-radius, radius] range + int blurRadius = getBlurRadius(); + float blurRadialSigma = float(blurRadius) * 0.5; + float blurRadialScale = 1.0 / (2.0*blurRadialSigma*blurRadialSigma); + vec3 blurScales = -vec3(blurRadialScale, vec2(BLUR_EDGE_DISTANCE_SCALE, BLUR_EDGE_NORMAL_SCALE) * getBlurEdgeSharpness()); + + // negative side first + for (int r = -blurRadius; r <= -1; ++r) { + weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, depthTexCoord, fragDepthKey, fragNormal); + } + + // Central pixel contribution + float mainWeight = 1.0; + float pixelOcclusion = unpackOcclusion(fetchOcclusionPacked(side, occlusionTexCoord)); + weightedSums += vec2(pixelOcclusion * mainWeight, mainWeight); + + // then positive side + for (int r = 1; r <= blurRadius; ++r) { + weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, depthTexCoord, fragDepthKey, fragNormal); + } + + // Final normalization + const float epsilon = 0.0001; + float result = weightedSums.x / (weightedSums.y + epsilon); + + return packOcclusionOutput(result, fragDepth, fragNormal); +} layout(location=0) in vec4 varTexCoord0; layout(location=0) out vec4 outFragColor; void main(void) { - outFragColor = vec4(getBlurredOcclusion(ivec2(gl_FragCoord.xy), varTexCoord0.xy, varTexCoord0.zw), 1.0); + outFragColor = getBlurredOcclusion(ivec2(gl_FragCoord.xy), varTexCoord0.xy, varTexCoord0.zw); } diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf index 2c1824dce7..efa6a02730 100644 --- a/libraries/render-utils/src/ssao_debugOcclusion.slf +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -116,7 +116,7 @@ void main(void) { } !> - outFragColor = vec4(packOcclusionDepth(A, CSZToDepthKey(Cp.z)), 1.0); + outFragColor = packOcclusionOutput(A, Cp.z, vec3(0,0,1)); if ((dot(fragToCursor,fragToCursor) < (100.0 * keepTapRadius * keepTapRadius) )) { // outFragColor = vec4(vec3(A), 1.0); diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index e2a94be134..74617cc4bb 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -84,5 +84,5 @@ void main(void) { float occlusion = clamp(1.0 - obscuranceSum * getObscuranceScaling() * invNumSamples, 0.0, 1.0); - outFragColor = vec4(vec3(occlusion), 1.0); + outFragColor = packOcclusionOutput(occlusion * occlusion, fragPositionES.z, fragNormalES); } diff --git a/libraries/render-utils/src/ssao_shared.h b/libraries/render-utils/src/ssao_shared.h index 9c9e57337c..667dd702ef 100644 --- a/libraries/render-utils/src/ssao_shared.h +++ b/libraries/render-utils/src/ssao_shared.h @@ -15,6 +15,7 @@ #define RENDER_UTILS_SSAO_SHARED_H #define SSAO_USE_QUAD_SPLIT 1 +#define SSAO_BILATERAL_BLUR_USE_NORMAL 0 #if SSAO_USE_QUAD_SPLIT #define SSAO_SPLIT_LOG2_COUNT 2 From 8e914fa565bea92330c68fc8514f42c1e5329fd7 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 28 Sep 2018 10:25:57 +0200 Subject: [PATCH 50/81] Bilateral blur shader cleanup and quad split normal at occlusion resolution --- .../src/AmbientOcclusionEffect.cpp | 32 ++++++++----------- .../render-utils/src/ssao_bilateralBlur.slf | 6 +--- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 6a702b1640..a89d17c5c4 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -108,7 +108,7 @@ void AmbientOcclusionFramebuffer::allocate() { if (_isStereo) { sideSize.x >>= 1; } - sideSize = divideRoundUp(sideSize, 1 << _depthResolutionLevel); + sideSize = divideRoundUp(sideSize, 1 << _resolutionLevel); if (_isStereo) { sideSize.x <<= 1; } @@ -208,7 +208,7 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : radius{ 0.3f }, perspectiveScale{ 1.0f }, obscuranceLevel{ 0.5f }, - falloffAngle{ 0.3f }, + falloffAngle{ 0.45f }, edgeSharpness{ 1.0f }, blurDeviation{ 2.5f }, numSpiralTurns{ 7.0f }, @@ -363,19 +363,12 @@ void AmbientOcclusionEffect::updateBlurParameters() { vblur._blurInfo.z = 1.0f; vblur._blurInfo.w = occlusionSize.y / float(frameSize.y); - // Depth axis - hblur._blurAxis.x = 1.0f / occlusionSize.x; + // Occlusion axis + hblur._blurAxis.x = hblur._blurInfo.z / occlusionSize.x; hblur._blurAxis.y = 0.0f; vblur._blurAxis.x = 0.0f; - vblur._blurAxis.y = 1.0f / occlusionSize.y; - - // Occlusion axis - hblur._blurAxis.z = hblur._blurAxis.x * hblur._blurInfo.z; - hblur._blurAxis.w = 0.0f; - - vblur._blurAxis.z = 0.0f; - vblur._blurAxis.w = vblur._blurAxis.y * vblur._blurInfo.w; + vblur._blurAxis.y = vblur._blurInfo.w / occlusionSize.y; } void AmbientOcclusionEffect::updateFramebufferSizes() { @@ -489,7 +482,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto occlusionDepthTexture = linearDepthTexture; auto sourceViewport = args->_viewport; // divideRoundUp is used two compute the quarter or half resolution render sizes. - // We need to take the rounded up resolution. + // We choose to take the rounded up resolution. auto occlusionViewport = divideRoundUp(sourceViewport, 1 << resolutionLevel); auto firstBlurViewport = sourceViewport; firstBlurViewport.w = occlusionViewport.w; @@ -541,7 +534,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte // _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) { - PROFILE_RANGE_BATCH(batch, "AmbientOcclusion"); + PROFILE_RANGE_BATCH(batch, "SSAO"); batch.enableStereo(false); _gpuTimer->begin(batch); @@ -552,7 +545,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setModelTransform(Transform()); // We need this with the mips levels - batch.pushProfileRange("Depth Mip Generation"); + batch.pushProfileRange("Depth Mips"); if (isHorizonBased) { batch.setPipeline(mipCreationPipeline); batch.generateTextureMipsWithPipeline(occlusionDepthTexture); @@ -562,7 +555,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.popProfileRange(); #if SSAO_USE_QUAD_SPLIT - batch.pushProfileRange("Normal Generation"); + batch.pushProfileRange("Normal Gen."); { const auto uvScale = glm::vec3( normalViewport.z / (sourceViewport.z * depthResolutionScale), @@ -579,7 +572,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte model.setScale(uvScale); model.setTranslation(uvTranslate); - batch.setModelTransform(model); + // TEMPO OP batch.setModelTransform(model); + batch.setModelTransform(Transform()); } // Build face normals pass @@ -658,7 +652,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte { PROFILE_RANGE_BATCH(batch, "Bilateral Blur"); // Blur 1st pass - batch.pushProfileRange("Horizontal"); + batch.pushProfileRange("Horiz."); { const auto uvScale = glm::vec3( occlusionViewport.z / float(sourceViewport.z), @@ -684,7 +678,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.popProfileRange(); // Blur 2nd pass - batch.pushProfileRange("Vertical"); + batch.pushProfileRange("Vert."); { const auto uvScale = glm::vec3( 1.0f, diff --git a/libraries/render-utils/src/ssao_bilateralBlur.slf b/libraries/render-utils/src/ssao_bilateralBlur.slf index e85fc42b9e..dc708b137b 100644 --- a/libraries/render-utils/src/ssao_bilateralBlur.slf +++ b/libraries/render-utils/src/ssao_bilateralBlur.slf @@ -27,10 +27,6 @@ layout(binding=RENDER_UTILS_BUFFER_SSAO_BLUR_PARAMS) uniform blurParamsBuffer { }; vec2 getBlurOcclusionAxis() { - return blurParams._blurAxis.zw; -} - -vec2 getBlurDepthAxis() { return blurParams._blurAxis.xy; } @@ -56,7 +52,7 @@ float evalBlurCoefficient(vec3 blurScales, float radialDistance, float zDistance return exp2(dot(blurScales, distances*distances)); } -const float BLUR_EDGE_DISTANCE_SCALE = 1000 * SSAO_DEPTH_KEY_SCALE; +const float BLUR_EDGE_DISTANCE_SCALE = 10000 * SSAO_DEPTH_KEY_SCALE; const float BLUR_EDGE_NORMAL_SCALE = 2.0; const float BLUR_EDGE_NORMAL_LIMIT = 0.25; From 6240454c551e2b6c3ac4558e92a371baacb4e2a6 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 28 Sep 2018 10:33:47 +0200 Subject: [PATCH 51/81] Switched back to half res depth when resolutionLevel>1 --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index a89d17c5c4..b0b371a715 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -458,8 +458,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getBuildNormalsPipeline() { } int AmbientOcclusionEffect::getDepthResolutionLevel() const { - // Having some problems making a nice AO with Half resolution depth, so stick to full res. - return 0; + return std::min(1, _aoParametersBuffer->getResolutionLevel()); } void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { From fbd158938ba578e7f5ae217476f62567ba24d8f4 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 28 Sep 2018 11:31:09 +0200 Subject: [PATCH 52/81] Put some bilateral blur computation on CPU --- .../src/AmbientOcclusionEffect.cpp | 42 +++++++++++-------- libraries/render-utils/src/ssao.slh | 2 - .../render-utils/src/ssao_bilateralBlur.slf | 14 +++---- libraries/render-utils/src/ssao_shared.h | 2 + 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index b0b371a715..1df3da2b70 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -229,7 +229,7 @@ AmbientOcclusionEffect::AOParameters::AOParameters() { } AmbientOcclusionEffect::BlurParameters::BlurParameters() { - _blurInfo = { 1.0f, 3.0f, 2.0f, 0.0f }; + _blurInfo = { 1.0f, 2.0f, 0.0f, 3.0f }; } AmbientOcclusionEffect::AmbientOcclusionEffect() { @@ -268,11 +268,26 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.y = 1.0f / (1.0f - config.falloffAngle); } - if (config.edgeSharpness != _hblurParametersBuffer.get().getEdgeSharpness()) { + // Update bilateral blur + { + const float BLUR_EDGE_DISTANCE_SCALE = float(10000 * SSAO_DEPTH_KEY_SCALE); + const float BLUR_EDGE_NORMAL_SCALE = 2.0f; + auto& hblur = _hblurParametersBuffer.edit()._blurInfo; auto& vblur = _vblurParametersBuffer.edit()._blurInfo; - hblur.x = config.edgeSharpness; - vblur.x = config.edgeSharpness; + float blurRadialSigma = float(config.blurRadius) * 0.5f; + float blurRadialScale = 1.0f / (2.0f*blurRadialSigma*blurRadialSigma); + glm::vec3 blurScales = -glm::vec3(blurRadialScale, glm::vec2(BLUR_EDGE_DISTANCE_SCALE, BLUR_EDGE_NORMAL_SCALE) * config.edgeSharpness); + + hblur.x = blurScales.x; + hblur.y = blurScales.y; + hblur.z = blurScales.z; + hblur.w = (float)config.blurRadius; + + vblur.x = blurScales.x; + vblur.y = blurScales.y; + vblur.z = blurScales.z; + vblur.w = (float)config.blurRadius; } if (config.numSpiralTurns != _aoParametersBuffer->getNumSpiralTurns()) { @@ -322,13 +337,6 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.x = (float)config.resolutionLevel; shouldUpdateBlurs = true; } - - if (config.blurRadius != _hblurParametersBuffer.get().getBlurRadius()) { - auto& hblur = _hblurParametersBuffer.edit()._blurInfo; - auto& vblur = _vblurParametersBuffer.edit()._blurInfo; - hblur.y = (float)config.blurRadius; - vblur.y = (float)config.blurRadius; - } if (config.ditheringEnabled != _aoParametersBuffer->isDitheringEnabled()) { auto& current = _aoParametersBuffer.edit()._ditheringInfo; @@ -357,18 +365,18 @@ void AmbientOcclusionEffect::updateBlurParameters() { const auto occlusionSize = divideRoundUp(frameSize, resolutionScale); // Occlusion UV limit - hblur._blurInfo.z = occlusionSize.x / float(frameSize.x); - hblur._blurInfo.w = occlusionSize.y / float(frameSize.y); + hblur._blurAxis.z = occlusionSize.x / float(frameSize.x); + hblur._blurAxis.w = occlusionSize.y / float(frameSize.y); - vblur._blurInfo.z = 1.0f; - vblur._blurInfo.w = occlusionSize.y / float(frameSize.y); + vblur._blurAxis.z = 1.0f; + vblur._blurAxis.w = occlusionSize.y / float(frameSize.y); // Occlusion axis - hblur._blurAxis.x = hblur._blurInfo.z / occlusionSize.x; + hblur._blurAxis.x = hblur._blurAxis.z / occlusionSize.x; hblur._blurAxis.y = 0.0f; vblur._blurAxis.x = 0.0f; - vblur._blurAxis.y = vblur._blurInfo.w / occlusionSize.y; + vblur._blurAxis.y = vblur._blurAxis.w / occlusionSize.y; } void AmbientOcclusionEffect::updateFramebufferSizes() { diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index a02554a385..c72d1f4c0d 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -16,8 +16,6 @@ <@func declarePackOcclusionDepth()@> -#define SSAO_DEPTH_KEY_SCALE 300.0 - float CSZToDepthKey(float z) { return clamp(z * (-1.0 / SSAO_DEPTH_KEY_SCALE), 0.0, 1.0); } diff --git a/libraries/render-utils/src/ssao_bilateralBlur.slf b/libraries/render-utils/src/ssao_bilateralBlur.slf index dc708b137b..e89d696cbb 100644 --- a/libraries/render-utils/src/ssao_bilateralBlur.slf +++ b/libraries/render-utils/src/ssao_bilateralBlur.slf @@ -31,15 +31,15 @@ vec2 getBlurOcclusionAxis() { } vec2 getBlurOcclusionUVLimit() { - return blurParams._blurInfo.zw; + return blurParams._blurAxis.zw; } -float getBlurEdgeSharpness() { - return blurParams._blurInfo.x; +vec3 getBlurScales() { + return blurParams._blurInfo.xyz; } int getBlurRadius() { - return int(blurParams._blurInfo.y); + return int(blurParams._blurInfo.w); } vec4 fetchOcclusionPacked(ivec4 side, vec2 texCoord) { @@ -52,8 +52,6 @@ float evalBlurCoefficient(vec3 blurScales, float radialDistance, float zDistance return exp2(dot(blurScales, distances*distances)); } -const float BLUR_EDGE_DISTANCE_SCALE = 10000 * SSAO_DEPTH_KEY_SCALE; -const float BLUR_EDGE_NORMAL_SCALE = 2.0; const float BLUR_EDGE_NORMAL_LIMIT = 0.25; vec2 evalTapWeightedValue(vec3 blurScales, ivec4 side, int r, vec2 occlusionTexCoord, vec2 depthTexCoord, float fragDepth, vec3 fragNormal) { @@ -98,9 +96,7 @@ vec4 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 dept // Accumulate weighted contributions along the bluring axis in the [-radius, radius] range int blurRadius = getBlurRadius(); - float blurRadialSigma = float(blurRadius) * 0.5; - float blurRadialScale = 1.0 / (2.0*blurRadialSigma*blurRadialSigma); - vec3 blurScales = -vec3(blurRadialScale, vec2(BLUR_EDGE_DISTANCE_SCALE, BLUR_EDGE_NORMAL_SCALE) * getBlurEdgeSharpness()); + vec3 blurScales = getBlurScales(); // negative side first for (int r = -blurRadius; r <= -1; ++r) { diff --git a/libraries/render-utils/src/ssao_shared.h b/libraries/render-utils/src/ssao_shared.h index 667dd702ef..1552a38947 100644 --- a/libraries/render-utils/src/ssao_shared.h +++ b/libraries/render-utils/src/ssao_shared.h @@ -17,6 +17,8 @@ #define SSAO_USE_QUAD_SPLIT 1 #define SSAO_BILATERAL_BLUR_USE_NORMAL 0 +#define SSAO_DEPTH_KEY_SCALE 300.0 + #if SSAO_USE_QUAD_SPLIT #define SSAO_SPLIT_LOG2_COUNT 2 #else From 086ba998c89088dd62aff692798aa6702817734a Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 28 Sep 2018 16:41:18 +0200 Subject: [PATCH 53/81] Some small cleanups --- .../src/AmbientOcclusionEffect.cpp | 25 ++------------ libraries/render-utils/src/ssao.slh | 34 +++++++++++-------- .../render-utils/src/ssao_makeOcclusion.slf | 7 ++-- 3 files changed, 27 insertions(+), 39 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 1df3da2b70..5b27cfa41d 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -83,9 +83,9 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getLinearDepthTexture() { void AmbientOcclusionFramebuffer::allocate() { #if SSAO_BILATERAL_BLUR_USE_NORMAL - const auto occlusionformat = gpu::Element{ gpu::VEC4, gpu::HALF, gpu::RGBA }; + auto occlusionformat = gpu::Element{ gpu::VEC4, gpu::HALF, gpu::RGBA }; #else - const auto occlusionformat = gpu::Element{ gpu::VEC3, gpu::NUINT8, gpu::RGB }; + auto occlusionformat = gpu::Element{ gpu::VEC3, gpu::NUINT8, gpu::RGB }; #endif // Full frame @@ -563,27 +563,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #if SSAO_USE_QUAD_SPLIT batch.pushProfileRange("Normal Gen."); - { - const auto uvScale = glm::vec3( - normalViewport.z / (sourceViewport.z * depthResolutionScale), - normalViewport.w / (sourceViewport.w * depthResolutionScale), - 1.0f); - const auto postPixelOffset = glm::vec2(0.5f) / glm::vec2(occlusionDepthSize); - const auto prePixelOffset = glm::vec2(0.5f * uvScale.x, 0.5f * uvScale.y) / glm::vec2(normalViewport.z, normalViewport.w); - const auto uvTranslate = glm::vec3( - postPixelOffset.x - prePixelOffset.x, - postPixelOffset.y - prePixelOffset.y, - 0.0f - ); - Transform model; - - model.setScale(uvScale); - model.setTranslation(uvTranslate); - // TEMPO OP batch.setModelTransform(model); - batch.setModelTransform(Transform()); - } - // Build face normals pass + batch.setModelTransform(Transform()); batch.setViewportTransform(normalViewport); batch.setPipeline(buildNormalsPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index c72d1f4c0d..9590dd9277 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -297,9 +297,7 @@ vec2 fetchTap(ivec4 side, vec2 tapUV, float tapRadius) { } vec3 buildPosition(ivec4 side, vec2 fragUVPos) { - vec2 fetchUV = clamp(fragUVPos, vec2(0), vec2(1)); - fetchUV.x = mix(fetchUV.x, (fetchUV.x + getStereoSide(side)) * 0.5, isStereo()); - float Zeye = getZEyeAtUV(fetchUV, 0); + float Zeye = getZEyeAtUV(side, fragUVPos, 0); return evalEyePositionFromZeye(side.x, Zeye, fragUVPos); } @@ -348,12 +346,20 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t return f * f * f * max((vn - getFalloffAngle()) / (epsilon + vv), 0.0); } -float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES) { +vec2 computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES) { const float epsilon = 0.001; vec3 deltaVec = tapPositionES - fragPositionES; float distance = length(deltaVec); float cosHorizonAngle = dot(deltaVec, fragNormalES) / (distance + epsilon); + + return vec2(cosHorizonAngle, distance); +} + +float computeWeightedHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES) { + vec2 rawHorizon = computeHorizonFromTap(tapPositionES, fragPositionES, fragNormalES); + float distance = rawHorizon.y; + float cosHorizonAngle = rawHorizon.x; float radiusFalloff = max(0.0, 1.0 - (distance*distance / getRadius2())); cosHorizonAngle = max(0.0, (cosHorizonAngle - getFalloffAngle()) * getFalloffAngleScale()); @@ -363,14 +369,13 @@ float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNo } <@func computeHorizon()@> - vec2 tapSideUVPos = tapUVOffset + fragUVPos; - if (tapSideUVPos.x<0 || tapSideUVPos.y<0 || tapSideUVPos.x>=1.0 || tapSideUVPos.y>=1.0) { + if (fragUVPos.x<0 || fragUVPos.y<0 || fragUVPos.x>=1.0 || fragUVPos.y>=1.0) { // Early exit because we've hit the borders of the frame break; } - vec2 tapMipZ = fetchTap(side, tapSideUVPos, radius); - vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, tapSideUVPos); - float tapCosHorizonAngle = computeHorizonFromTap(tapPositionES, fragPositionES, fragNormalES); + vec2 tapMipZ = fetchTap(side, fragUVPos, radius); + vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, fragUVPos); + float tapCosHorizonAngle = computeWeightedHorizonFromTap(tapPositionES, fragPositionES, fragNormalES); cosHorizonAngle = max(cosHorizonAngle, tapCosHorizonAngle); @@ -378,7 +383,8 @@ float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNo #define HBAO_HORIZON_SEARCH_CONSTANT_STEP 0 -float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, vec3 fragNormalES, vec2 searchVec, vec2 pixelSearchVec, float searchRadius) { +float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, vec3 fragNormalES, vec2 searchVec, vec2 pixelSearchVec, + float searchRadius) { vec2 absSearchVec = abs(searchVec); pixelSearchVec = abs(pixelSearchVec); int stepCount = int(ceil(max(pixelSearchVec.x, pixelSearchVec.y))); @@ -386,26 +392,26 @@ float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, vec3 fragN if (stepCount>0) { vec2 deltaTapUV = searchVec / float(stepCount); + float deltaRadius = searchRadius / float(stepCount); - vec2 tapUVOffset = vec2(0); #if HBAO_HORIZON_SEARCH_CONSTANT_STEP float radius = 0.0; int stepIndex; for (stepIndex=0 ; stepIndex } -// Step is adapted to Mip level #else + // Step is adapted to Mip level float radius = deltaRadius; float mipLevel = evalMipFromRadius(radius * float(doFetchMips())); while (radius<=searchRadius) { - tapUVOffset += deltaTapUV; + fragUVPos += deltaTapUV; <$computeHorizon()$> diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 74617cc4bb..cfccf32938 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -19,7 +19,7 @@ <$declarePackOcclusionDepth()$> -#define SSAO_HBAO_MAX_RADIUS 100.0 +#define SSAO_HBAO_MAX_RADIUS 300.0 layout(location=0) in vec2 varTexCoord0; @@ -82,7 +82,8 @@ void main(void) { } } - float occlusion = clamp(1.0 - obscuranceSum * getObscuranceScaling() * invNumSamples, 0.0, 1.0); + obscuranceSum *= getObscuranceScaling() * invNumSamples; + float occlusion = clamp(1.0 - obscuranceSum * obscuranceSum, 0.0, 1.0); - outFragColor = packOcclusionOutput(occlusion * occlusion, fragPositionES.z, fragNormalES); + outFragColor = packOcclusionOutput(occlusion, fragPositionES.z, fragNormalES); } From 9f9fe909b0fc242b8cd960d9c19b1781fc21673a Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 28 Sep 2018 19:22:20 +0200 Subject: [PATCH 54/81] Fixed bugs in stereo --- .../src/AmbientOcclusionEffect.cpp | 49 +++++++++---------- .../render-utils/src/SurfaceGeometryPass.cpp | 4 +- libraries/render-utils/src/ssao.slh | 26 +++++++--- .../render-utils/src/ssao_bilateralBlur.slf | 19 ++++--- 4 files changed, 56 insertions(+), 42 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 5b27cfa41d..86de3cec04 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -92,12 +92,13 @@ void AmbientOcclusionFramebuffer::allocate() { { auto width = _frameSize.x; auto height = _frameSize.y; + auto sampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP); - _occlusionTexture = gpu::Texture::createRenderBuffer(occlusionformat, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); + _occlusionTexture = gpu::Texture::createRenderBuffer(occlusionformat, width, height, gpu::Texture::SINGLE_MIP, sampler); _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); - _occlusionBlurredTexture = gpu::Texture::createRenderBuffer(occlusionformat, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); + _occlusionBlurredTexture = gpu::Texture::createRenderBuffer(occlusionformat, width, height, gpu::Texture::SINGLE_MIP, sampler); _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusionBlurred")); _occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture); } @@ -108,7 +109,7 @@ void AmbientOcclusionFramebuffer::allocate() { if (_isStereo) { sideSize.x >>= 1; } - sideSize = divideRoundUp(sideSize, 1 << _resolutionLevel); + sideSize >>= _resolutionLevel; if (_isStereo) { sideSize.x <<= 1; } @@ -127,7 +128,7 @@ void AmbientOcclusionFramebuffer::allocate() { if (_isStereo) { splitSize.x >>= 1; } - splitSize = divideRoundUp(splitSize, SSAO_SPLIT_COUNT << _resolutionLevel); + splitSize = divideRoundUp(_frameSize >> _resolutionLevel, SSAO_SPLIT_COUNT); if (_isStereo) { splitSize.x <<= 1; } @@ -355,14 +356,13 @@ void AmbientOcclusionEffect::configure(const Config& config) { void AmbientOcclusionEffect::updateBlurParameters() { const auto resolutionLevel = _aoParametersBuffer->getResolutionLevel(); - const auto resolutionScale = 1 << resolutionLevel; auto& vblur = _vblurParametersBuffer.edit(); auto& hblur = _hblurParametersBuffer.edit(); auto frameSize = _framebuffer->getSourceFrameSize(); if (_framebuffer->isStereo()) { frameSize.x >>= 1; } - const auto occlusionSize = divideRoundUp(frameSize, resolutionScale); + const auto occlusionSize = frameSize >> resolutionLevel; // Occlusion UV limit hblur._blurAxis.z = occlusionSize.x / float(frameSize.x); @@ -381,18 +381,17 @@ void AmbientOcclusionEffect::updateBlurParameters() { void AmbientOcclusionEffect::updateFramebufferSizes() { auto& params = _aoParametersBuffer.edit(); - const int widthScale = _framebuffer->isStereo() & 1; + const int stereoDivide = _framebuffer->isStereo() & 1; auto sourceFrameSideSize = _framebuffer->getSourceFrameSize(); - sourceFrameSideSize.x >>= widthScale; + sourceFrameSideSize.x >>= stereoDivide; const int resolutionLevel = _aoParametersBuffer.get().getResolutionLevel(); - // Depth is at maximum half depth const int depthResolutionLevel = getDepthResolutionLevel(); - const auto occlusionDepthFrameSize = divideRoundUp(sourceFrameSideSize, 1 << depthResolutionLevel); - const auto occlusionFrameSize = divideRoundUp(sourceFrameSideSize, 1 << resolutionLevel); + const auto occlusionDepthFrameSize = sourceFrameSideSize >> depthResolutionLevel; + const auto occlusionFrameSize = sourceFrameSideSize >> resolutionLevel; auto normalTextureSize = _framebuffer->getNormalTexture()->getDimensions(); - normalTextureSize.x >>= widthScale; + normalTextureSize.x >>= stereoDivide; params._sideSizes[0].x = normalTextureSize.x; params._sideSizes[0].y = normalTextureSize.y; @@ -485,12 +484,10 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte const auto depthResolutionScale = powf(0.5f, depthResolutionLevel); const auto isHorizonBased = _aoParametersBuffer->isHorizonBased(); - auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); - auto occlusionDepthTexture = linearDepthTexture; + auto fullResDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); + auto occlusionDepthTexture = fullResDepthTexture; auto sourceViewport = args->_viewport; - // divideRoundUp is used two compute the quarter or half resolution render sizes. - // We choose to take the rounded up resolution. - auto occlusionViewport = divideRoundUp(sourceViewport, 1 << resolutionLevel); + auto occlusionViewport = sourceViewport >> resolutionLevel; auto firstBlurViewport = sourceViewport; firstBlurViewport.w = occlusionViewport.w; @@ -506,7 +503,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte occlusionDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); } - if (_framebuffer->update(linearDepthTexture, resolutionLevel, depthResolutionLevel, args->isStereo())) { + if (_framebuffer->update(fullResDepthTexture, resolutionLevel, depthResolutionLevel, args->isStereo())) { updateBlurParameters(); updateFramebufferSizes(); } @@ -538,7 +535,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto& sample = _aoFrameParametersBuffer[splitId].edit(); sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId]; } - // _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; + _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) { PROFILE_RANGE_BATCH(batch, "SSAO"); @@ -567,7 +564,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setModelTransform(Transform()); batch.setViewportTransform(normalViewport); batch.setPipeline(buildNormalsPipeline); - batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); + batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, fullResDepthTexture); batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, nullptr); batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); @@ -651,8 +648,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setModelTransform(model); } batch.setPipeline(bilateralBlurPipeline); - // Use full resolution depth and normal for bilateral upscaling and blur - batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); + // Use full resolution depth for bilateral upscaling and blur + batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, fullResDepthTexture); #if SSAO_USE_QUAD_SPLIT batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture); #else @@ -742,18 +739,18 @@ void DebugAmbientOcclusion::run(const render::RenderContextPointer& renderContex return; } - auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); + auto fullResDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); auto sourceViewport = args->_viewport; auto occlusionViewport = sourceViewport; auto resolutionLevel = ambientOcclusionUniforms->getResolutionLevel(); if (resolutionLevel > 0) { - linearDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); + fullResDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); occlusionViewport = occlusionViewport >> ambientOcclusionUniforms->getResolutionLevel(); } - auto framebufferSize = glm::ivec2(linearDepthTexture->getDimensions()); + auto framebufferSize = glm::ivec2(fullResDepthTexture->getDimensions()); float sMin = occlusionViewport.x / (float)framebufferSize.x; float sWidth = occlusionViewport.z / (float)framebufferSize.x; @@ -779,7 +776,7 @@ void DebugAmbientOcclusion::run(const render::RenderContextPointer& renderContex batch.setUniformBuffer(render_utils::slot::buffer::SsaoDebugParams, _parametersBuffer); batch.setPipeline(debugPipeline); - batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); + batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, fullResDepthTexture); batch.draw(gpu::TRIANGLE_STRIP, 4); diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index d5e0249a21..59d2198daa 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -45,7 +45,7 @@ void LinearDepthFramebuffer::update(const gpu::TexturePointer& depthBuffer, cons if (isStereo) { _halfFrameSize.x >>= 1; } - _halfFrameSize = divideRoundUp(_halfFrameSize, 2); + _halfFrameSize >>= 1; if (isStereo) { _halfFrameSize.x <<= 1; } @@ -182,7 +182,7 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con auto downsamplePipeline = getDownsamplePipeline(renderContext); auto depthViewport = args->_viewport; - auto halfViewport = divideRoundUp(depthViewport, 2); + auto halfViewport = depthViewport >> 1; float clearLinearDepth = args->getViewFrustum().getFarClip() * 2.0f; gpu::doInBatch("LinearDepthPass::run", args->_context, [=](gpu::Batch& batch) { diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 9590dd9277..a5bb689d06 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -260,11 +260,20 @@ float getZEyeAtUV(vec2 texCoord, int level) { return -textureLod(depthPyramidTex, texCoord, level).x; } +float getZEyeAtUV(vec2 texCoord, int level, ivec2 texelOffset) { + return -textureLodOffset(depthPyramidTex, texCoord, level, texelOffset).x; +} + float getZEyeAtUV(ivec4 side, vec2 texCoord, int level) { texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); return getZEyeAtUV(texCoord, level); } +float getZEyeAtUV(ivec4 side, vec2 texCoord, int level, ivec2 texelOffset) { + texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); + return getZEyeAtUV(texCoord, level, texelOffset); +} + vec3 getNormalEyeAtUV(vec2 texCoord, int level) { return normalize(textureLod(normalTex, texCoord, level).xyz*2.0 - vec3(1.0)); } @@ -301,20 +310,25 @@ vec3 buildPosition(ivec4 side, vec2 fragUVPos) { return evalEyePositionFromZeye(side.x, Zeye, fragUVPos); } +vec3 buildPosition(ivec4 side, vec2 fragUVPos, ivec2 texelOffset, vec2 deltaUV) { + float Zeye = getZEyeAtUV(side, fragUVPos, 0, texelOffset); + return evalEyePositionFromZeye(side.x, Zeye, fragUVPos + texelOffset*deltaUV); +} + vec3 getMinDelta(vec3 centralPoint, vec3 offsetPointPos, vec3 offsetPointNeg) { vec3 delta0 = offsetPointPos - centralPoint; vec3 delta1 = centralPoint - offsetPointNeg; float sqrLength0 = dot(delta0, delta0); float sqrLength1 = dot(delta1, delta1); - float epsilon = 1e-6; - return sqrLength0 < sqrLength1 && sqrLength0>epsilon ? delta0 : delta1; + + return sqrLength0 < sqrLength1 ? delta0 : delta1; } vec3 buildNormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec2 deltaDepthUV) { - vec3 fragPositionDxPos = buildPosition(side, fragUVPos + vec2(deltaDepthUV.x, 0)); - vec3 fragPositionDxNeg = buildPosition(side, fragUVPos - vec2(deltaDepthUV.x, 0)); - vec3 fragPositionDyPos = buildPosition(side, fragUVPos + vec2(0, deltaDepthUV.y)); - vec3 fragPositionDyNeg = buildPosition(side, fragUVPos - vec2(0, deltaDepthUV.y)); + vec3 fragPositionDxPos = buildPosition(side, fragUVPos, ivec2(1,0), deltaDepthUV); + vec3 fragPositionDxNeg = buildPosition(side, fragUVPos, ivec2(-1,0), deltaDepthUV); + vec3 fragPositionDyPos = buildPosition(side, fragUVPos, ivec2(0,1), deltaDepthUV); + vec3 fragPositionDyNeg = buildPosition(side, fragUVPos, ivec2(0,-1), deltaDepthUV); vec3 fragPositionDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg); vec3 fragPositionDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg); diff --git a/libraries/render-utils/src/ssao_bilateralBlur.slf b/libraries/render-utils/src/ssao_bilateralBlur.slf index e89d696cbb..bec6793307 100644 --- a/libraries/render-utils/src/ssao_bilateralBlur.slf +++ b/libraries/render-utils/src/ssao_bilateralBlur.slf @@ -43,7 +43,7 @@ int getBlurRadius() { } vec4 fetchOcclusionPacked(ivec4 side, vec2 texCoord) { - texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); + texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side) * getBlurOcclusionUVLimit().x) * 0.5, isStereo()); return textureLod(occlusionMap, texCoord, 0); } @@ -54,12 +54,11 @@ float evalBlurCoefficient(vec3 blurScales, float radialDistance, float zDistance const float BLUR_EDGE_NORMAL_LIMIT = 0.25; -vec2 evalTapWeightedValue(vec3 blurScales, ivec4 side, int r, vec2 occlusionTexCoord, vec2 depthTexCoord, float fragDepth, vec3 fragNormal) { +vec2 evalTapWeightedValue(vec3 blurScales, ivec4 side, int r, vec2 occlusionTexCoord, float fragDepth, vec3 fragNormal) { vec2 tapOcclusionTexCoord = getBlurOcclusionAxis() * r + occlusionTexCoord; vec2 occlusionTexCoordLimits = getBlurOcclusionUVLimit(); - if (tapOcclusionTexCoord.x < side.x || tapOcclusionTexCoord.x >= (side.x + occlusionTexCoordLimits.x) - || tapOcclusionTexCoord.y < 0 || tapOcclusionTexCoord.y >= occlusionTexCoordLimits.y) { + if (any(lessThan(tapOcclusionTexCoord, vec2(0.0))) || any(greaterThanEqual(tapOcclusionTexCoord, occlusionTexCoordLimits)) ) { return vec2(0.0); } @@ -85,10 +84,10 @@ vec4 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 dept // Stereo side info ivec4 side = getStereoSideInfo(destPixelCoord.x, 0); - float fragDepth = getZEyeAtUV(side, depthTexCoord, 0); + float fragDepth = getZEyeAtUV(depthTexCoord, 0); float fragDepthKey = CSZToDepthKey(fragDepth); #if SSAO_BILATERAL_BLUR_USE_NORMAL - vec3 fragNormal = getNormalEyeAtUV(side, depthTexCoord, 0); + vec3 fragNormal = getNormalEyeAtUV(depthTexCoord, 0); #else vec3 fragNormal = vec3(0, 0, 1); #endif @@ -98,9 +97,13 @@ vec4 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 dept int blurRadius = getBlurRadius(); vec3 blurScales = getBlurScales(); + // From now on, occlusionTexCoord is the UV pos in the side + float sideTexCoord = occlusionTexCoord.x * 2.0 - getStereoSide(side) * getBlurOcclusionUVLimit().x; + occlusionTexCoord.x = mix(occlusionTexCoord.x, sideTexCoord, isStereo()); + // negative side first for (int r = -blurRadius; r <= -1; ++r) { - weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, depthTexCoord, fragDepthKey, fragNormal); + weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, fragDepthKey, fragNormal); } // Central pixel contribution @@ -110,7 +113,7 @@ vec4 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 dept // then positive side for (int r = 1; r <= blurRadius; ++r) { - weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, depthTexCoord, fragDepthKey, fragNormal); + weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, fragDepthKey, fragNormal); } // Final normalization From abc415c5ad265f1ed7ea03247d8c27ffd9a3c9c5 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 28 Sep 2018 19:33:34 +0200 Subject: [PATCH 55/81] Put back temporal jitter of SSAO (but without filtering) --- libraries/render-utils/src/AmbientOcclusionEffect.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index dbbbee76d0..50b35f7941 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -202,7 +202,7 @@ private: static gpu::PipelinePointer _buildNormalsPipeline; AmbientOcclusionFramebufferPointer _framebuffer; - std::array _randomSamples; + std::array _randomSamples; int _frameId{ 0 }; gpu::RangeTimerPointer _gpuTimer; From 7f6c9a6cc1fb1677a3e7be8d61ea492545e9467d Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 1 Oct 2018 19:22:54 +0200 Subject: [PATCH 56/81] Switched to sin based HBAO --- .../src/AmbientOcclusionEffect.cpp | 20 ++- .../render-utils/src/AmbientOcclusionEffect.h | 2 +- libraries/render-utils/src/ssao.slh | 137 +++++++++++++----- .../render-utils/src/ssao_makeOcclusion.slf | 25 +++- libraries/render-utils/src/ssao_shared.h | 1 + .../utilities/render/ambientOcclusionPass.qml | 2 +- 6 files changed, 135 insertions(+), 52 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 86de3cec04..54edfad3ec 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -206,10 +206,10 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() { AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false), - radius{ 0.3f }, + radius{ 0.5f }, perspectiveScale{ 1.0f }, - obscuranceLevel{ 0.5f }, - falloffAngle{ 0.45f }, + obscuranceLevel{ 0.25f }, + falloffAngle{ 0.7f }, edgeSharpness{ 1.0f }, blurDeviation{ 2.5f }, numSpiralTurns{ 7.0f }, @@ -227,6 +227,7 @@ AmbientOcclusionEffect::AOParameters::AOParameters() { _radiusInfo = { 0.5f, 0.5f * 0.5f, 1.0f / (0.25f * 0.25f * 0.25f), 1.0f }; _ditheringInfo = { 0.0f, 0.0f, 0.01f, 1.0f }; _sampleInfo = { 11.0f, 1.0f / 11.0f, 7.0f, 1.0f }; + _falloffInfo = { 0.5f, 2.0f, 0.866f, 1.1547f }; } AmbientOcclusionEffect::BlurParameters::BlurParameters() { @@ -263,10 +264,13 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.w = config.obscuranceLevel; } - if (config.falloffAngle != _aoParametersBuffer->getFalloffAngle()) { - auto& current = _aoParametersBuffer.edit()._ditheringInfo; - current.z = config.falloffAngle; - current.y = 1.0f / (1.0f - config.falloffAngle); + if (config.falloffAngle != _aoParametersBuffer->getFalloffCosAngle()) { + auto& current = _aoParametersBuffer.edit()._falloffInfo; + current.x = config.falloffAngle; + current.y = 1.0f / (1.0f - current.x); + // Compute sin from cos + current.z = sqrtf(1.0f - config.falloffAngle * config.falloffAngle); + current.w = 1.0f / current.z; } // Update bilateral blur @@ -535,7 +539,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto& sample = _aoFrameParametersBuffer[splitId].edit(); sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId]; } - _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; + //_frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) { PROFILE_RANGE_BATCH(batch, "SSAO"); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 50b35f7941..8d5eef42a5 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -150,7 +150,7 @@ public: float getRadius() const { return _radiusInfo.x; } float getPerspectiveScale() const { return _resolutionInfo.z; } float getObscuranceLevel() const { return _radiusInfo.w; } - float getFalloffAngle() const { return (float)_ditheringInfo.z; } + float getFalloffCosAngle() const { return (float)_falloffInfo.x; } float getNumSpiralTurns() const { return _sampleInfo.z; } int getNumSamples() const { return (int)_sampleInfo.x; } diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index a5bb689d06..a289654486 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -115,11 +115,18 @@ float isBorderingEnabled() { return params._ditheringInfo.w; } -float getFalloffAngle() { - return params._ditheringInfo.z; +float getFalloffCosAngle() { + return params._falloffInfo.x; } -float getFalloffAngleScale() { - return params._ditheringInfo.y; +float getFalloffCosAngleScale() { + return params._falloffInfo.y; +} + +float getFalloffSinAngle() { + return params._falloffInfo.z; +} +float getFalloffSinAngleScale() { + return params._falloffInfo.w; } float getNumSamples() { @@ -330,10 +337,27 @@ vec3 buildNormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec2 deltaDepthU vec3 fragPositionDyPos = buildPosition(side, fragUVPos, ivec2(0,1), deltaDepthUV); vec3 fragPositionDyNeg = buildPosition(side, fragUVPos, ivec2(0,-1), deltaDepthUV); - vec3 fragPositionDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg); - vec3 fragPositionDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg); + vec3 fragDeltaDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg); + vec3 fragDeltaDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg); - return normalize( cross(fragPositionDx, fragPositionDy) ); + return normalize( cross(fragDeltaDx, fragDeltaDy) ); +} + +void buildTangentBinormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec3 fragNormal, vec2 deltaDepthUV, + out vec3 fragTangent, out vec3 fragBinormal) { + vec3 fragPositionDxPos = buildPosition(side, fragUVPos, ivec2(1,0), deltaDepthUV); + vec3 fragPositionDxNeg = buildPosition(side, fragUVPos, ivec2(-1,0), deltaDepthUV); + vec3 fragPositionDyPos = buildPosition(side, fragUVPos, ivec2(0,1), deltaDepthUV); + vec3 fragPositionDyNeg = buildPosition(side, fragUVPos, ivec2(0,-1), deltaDepthUV); + + vec3 fragDeltaDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg); + vec3 fragDeltaDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg); + + //fragTangent = normalize( cross(fragDeltaDy, fragNormal) ); + //fragBinormal = normalize( cross(fragNormal, fragDeltaDx) ); + + fragTangent = fragDeltaDx; + fragBinormal = fragDeltaDy; } <@endfunc@> @@ -341,6 +365,12 @@ vec3 buildNormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec2 deltaDepthU <@func declareEvalObscurance()@> +struct TBNFrame { + vec3 tangent; + vec3 binormal; + vec3 normal; +}; + vec3 fastAcos(vec3 x) { // [Eberly2014] GPGPU Programming for Games and Science vec3 absX = abs(x); @@ -357,29 +387,25 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t // Falloff function as recommended in SSAO paper const float epsilon = 0.01; float f = max(getRadius2() - vv, 0.0); - return f * f * f * max((vn - getFalloffAngle()) / (epsilon + vv), 0.0); + return f * f * f * max((vn - getFalloffCosAngle()) / (epsilon + vv), 0.0); } -vec2 computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES) { - const float epsilon = 0.001; +#define HBAO_USE_COS_ANGLE 0 - vec3 deltaVec = tapPositionES - fragPositionES; - float distance = length(deltaVec); - float cosHorizonAngle = dot(deltaVec, fragNormalES) / (distance + epsilon); +float computeWeightedHorizon(float horizonLimit, float distanceSquared) { + float radiusFalloff = distanceSquared / getRadius2(); - return vec2(cosHorizonAngle, distance); -} + radiusFalloff = max(0.0, 1.0 - radiusFalloff); -float computeWeightedHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES) { - vec2 rawHorizon = computeHorizonFromTap(tapPositionES, fragPositionES, fragNormalES); - float distance = rawHorizon.y; - float cosHorizonAngle = rawHorizon.x; - float radiusFalloff = max(0.0, 1.0 - (distance*distance / getRadius2())); +#if !HBAO_USE_COS_ANGLE + horizonLimit = getFalloffSinAngle() - horizonLimit; +#endif + horizonLimit *= radiusFalloff; +#if !HBAO_USE_COS_ANGLE + horizonLimit = getFalloffSinAngle() - horizonLimit; +#endif - cosHorizonAngle = max(0.0, (cosHorizonAngle - getFalloffAngle()) * getFalloffAngleScale()); - cosHorizonAngle *= radiusFalloff; - - return cosHorizonAngle; + return horizonLimit; } <@func computeHorizon()@> @@ -389,24 +415,46 @@ float computeWeightedHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec } vec2 tapMipZ = fetchTap(side, fragUVPos, radius); vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, fragUVPos); - float tapCosHorizonAngle = computeWeightedHorizonFromTap(tapPositionES, fragPositionES, fragNormalES); + vec3 deltaVec = tapPositionES - fragPositionES; + float distanceSquared = dot(deltaVec, deltaVec); + float distance = sqrt(distanceSquared); + float deltaDotNormal = dot(deltaVec, fragFrameES.normal); +#if HBAO_USE_COS_ANGLE + float tapHorizonLimit = deltaDotNormal; +#else + float tapHorizonLimit = dot(deltaVec, fragFrameES.tangent); +#endif + float epsilon = 0.0001; + tapHorizonLimit /= (distance + epsilon); - cosHorizonAngle = max(cosHorizonAngle, tapCosHorizonAngle); - + if (distanceSquared < getRadius2() && deltaDotNormal>0.0 && +#if HBAO_USE_COS_ANGLE + tapHorizonLimit > horizonLimit +#else + tapHorizonLimit < horizonLimit +#endif + ) { + tapHorizonLimit = computeWeightedHorizon(tapHorizonLimit, distanceSquared); +#if HBAO_USE_COS_ANGLE + horizonLimit = max(horizonLimit, tapHorizonLimit); +#else + horizonLimit = min(horizonLimit, tapHorizonLimit); +#endif + } <@endfunc@> #define HBAO_HORIZON_SEARCH_CONSTANT_STEP 0 -float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, vec3 fragNormalES, vec2 searchVec, vec2 pixelSearchVec, - float searchRadius) { +float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, TBNFrame fragFrameES, vec2 searchVec, float searchRadius, int stepCount) { vec2 absSearchVec = abs(searchVec); - pixelSearchVec = abs(pixelSearchVec); - int stepCount = int(ceil(max(pixelSearchVec.x, pixelSearchVec.y))); - float cosHorizonAngle = 0.0; +#if HBAO_USE_COS_ANGLE + float horizonLimit = getFalloffCosAngle(); +#else + float horizonLimit = getFalloffSinAngle(); +#endif if (stepCount>0) { vec2 deltaTapUV = searchVec / float(stepCount); - float deltaRadius = searchRadius / float(stepCount); #if HBAO_HORIZON_SEARCH_CONSTANT_STEP @@ -439,22 +487,33 @@ float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, vec3 fragN #endif } - return cosHorizonAngle; + return horizonLimit; } float evalVisibilityHBAO(ivec4 side, vec2 fragUVPos, vec2 invSideImageSize, vec2 deltaTap, float diskPixelRadius, - vec3 fragPositionES, vec3 fragNormalES) { + vec3 fragPositionES, TBNFrame fragFrameES) { vec2 pixelSearchVec = deltaTap * diskPixelRadius; vec2 searchVec = pixelSearchVec * invSideImageSize; - float obscurance = 0.0; + float obscuranceH1 = 0.0; + float obscuranceH2 = 0.0; + +#if !HBAO_USE_COS_ANGLE + fragFrameES.tangent = normalize(fragFrameES.tangent * deltaTap.x + fragFrameES.binormal * deltaTap.y); +#endif + + pixelSearchVec = abs(pixelSearchVec); + int stepCount = int(ceil(max(pixelSearchVec.x, pixelSearchVec.y))); // Forward search for h1 - obscurance = computeHorizon(side, fragUVPos, fragPositionES, fragNormalES, searchVec, pixelSearchVec, diskPixelRadius); + obscuranceH1 = computeHorizon(side, fragUVPos, fragPositionES, fragFrameES, searchVec, diskPixelRadius, stepCount); // Backward search for h2 - obscurance += computeHorizon(side, fragUVPos, fragPositionES, fragNormalES, -searchVec, pixelSearchVec, diskPixelRadius); +#if !HBAO_USE_COS_ANGLE + fragFrameES.tangent = -fragFrameES.tangent; +#endif + obscuranceH2 = computeHorizon(side, fragUVPos, fragPositionES, fragFrameES, -searchVec, diskPixelRadius, stepCount); - return obscurance; + return obscuranceH1 + obscuranceH2; } <@endfunc@> diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index cfccf32938..76357ffbb9 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -55,6 +55,15 @@ void main(void) { diskPixelRadius = min(diskPixelRadius, SSAO_HBAO_MAX_RADIUS); } + TBNFrame fragFrameES; + + fragFrameES.tangent = vec3(0.0); + fragFrameES.binormal = vec3(0.0); + fragFrameES.normal = fragNormalES; +#if !HBAO_USE_COS_ANGLE + buildTangentBinormal(side, fragUVPos, fragPositionES, fragNormalES, deltaDepthUV, fragFrameES.tangent, fragFrameES.binormal); +#endif + // Let's make noise float randomPatternRotationAngle = getAngleDithering(fragPixelPos); @@ -66,9 +75,18 @@ void main(void) { if (isHorizonBased()) { for (int i = 0; i < numSamples; ++i) { vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); - obscuranceSum += evalVisibilityHBAO(side, fragUVPos, deltaDepthUV, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); + obscuranceSum += evalVisibilityHBAO(side, fragUVPos, deltaDepthUV, deltaTap.xy, diskPixelRadius, fragPositionES, fragFrameES); } + obscuranceSum *= invNumSamples; +#if HBAO_USE_COS_ANGLE obscuranceSum *= 0.5 / PI; + obscuranceSum = 1.0 - obscuranceSum * obscuranceSum * getObscuranceScaling(); +#else + obscuranceSum *= 0.5; + obscuranceSum += 1.0 - getFalloffSinAngle(); + + obscuranceSum = mix(1.0, obscuranceSum, getObscuranceScaling()); +#endif } else { // Steps are in the depth texture resolution vec2 depthTexFragPixelPos = fragUVPos * sideDepthSize; @@ -80,10 +98,11 @@ void main(void) { vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, tapUV); obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES); } + obscuranceSum *= invNumSamples; + obscuranceSum = 1.0 - obscuranceSum * obscuranceSum * getObscuranceScaling(); } - obscuranceSum *= getObscuranceScaling() * invNumSamples; - float occlusion = clamp(1.0 - obscuranceSum * obscuranceSum, 0.0, 1.0); + float occlusion = clamp(obscuranceSum, 0.0, 1.0); outFragColor = packOcclusionOutput(occlusion, fragPositionES.z, fragNormalES); } diff --git a/libraries/render-utils/src/ssao_shared.h b/libraries/render-utils/src/ssao_shared.h index 1552a38947..46e373c073 100644 --- a/libraries/render-utils/src/ssao_shared.h +++ b/libraries/render-utils/src/ssao_shared.h @@ -40,6 +40,7 @@ struct AmbientOcclusionParams { SSAO_VEC4 _radiusInfo; SSAO_VEC4 _ditheringInfo; SSAO_VEC4 _sampleInfo; + SSAO_VEC4 _falloffInfo; SSAO_VEC4 _sideSizes[2]; }; diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index 5197fc312d..2ea3a6c416 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -37,7 +37,7 @@ Rectangle { "Level:obscuranceLevel:1.0:false", "Num Taps:numSamples:16:true", "Taps Spiral:numSpiralTurns:10.0:false", - "Falloff Angle:falloffAngle:0.5:false", + "Falloff Angle:falloffAngle:1.0:false", "Blur Edge Sharpness:edgeSharpness:1.0:false", "Blur Radius:blurRadius:15.0:true", "Resolution Downscale:resolutionLevel:2:true", From 454531e3c32832ca417980fc834f5951f878effe Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 2 Oct 2018 10:26:55 +0200 Subject: [PATCH 57/81] Switched back to cos HBAO --- .../src/AmbientOcclusionEffect.cpp | 35 ++++++---- .../render-utils/src/AmbientOcclusionEffect.h | 4 ++ libraries/render-utils/src/ssao.slh | 67 ++++++++++--------- .../render-utils/src/ssao_makeOcclusion.slf | 8 +-- .../utilities/render/ambientOcclusionPass.qml | 1 + 5 files changed, 66 insertions(+), 49 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 54edfad3ec..8e82cf9a9c 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -209,7 +209,7 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : radius{ 0.5f }, perspectiveScale{ 1.0f }, obscuranceLevel{ 0.25f }, - falloffAngle{ 0.7f }, + falloffAngle{ 0.4f }, edgeSharpness{ 1.0f }, blurDeviation{ 2.5f }, numSpiralTurns{ 7.0f }, @@ -219,15 +219,16 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : ditheringEnabled{ true }, borderingEnabled{ true }, fetchMipsEnabled{ true }, - horizonBased{ true } { + horizonBased{ true }, + jitterEnabled{ true }{ } AmbientOcclusionEffect::AOParameters::AOParameters() { - _resolutionInfo = { -1.0f, 1.0f, 1.0f, 0.0f }; - _radiusInfo = { 0.5f, 0.5f * 0.5f, 1.0f / (0.25f * 0.25f * 0.25f), 1.0f }; - _ditheringInfo = { 0.0f, 0.0f, 0.01f, 1.0f }; - _sampleInfo = { 11.0f, 1.0f / 11.0f, 7.0f, 1.0f }; - _falloffInfo = { 0.5f, 2.0f, 0.866f, 1.1547f }; + _resolutionInfo = glm::vec4{ 0.0f }; + _radiusInfo = glm::vec4{ 0.0f }; + _ditheringInfo = glm::vec4{ 0.0f }; + _sampleInfo = glm::vec4{ 0.0f }; + _falloffInfo = glm::vec4{ 0.0f }; } AmbientOcclusionEffect::BlurParameters::BlurParameters() { @@ -242,6 +243,8 @@ void AmbientOcclusionEffect::configure(const Config& config) { bool shouldUpdateBlurs = false; + _isJitterEnabled = config.jitterEnabled; + const double RADIUS_POWER = 6.0; const auto& radius = config.radius; if (radius != _aoParametersBuffer->getRadius() || config.horizonBased != _aoParametersBuffer->isHorizonBased()) { @@ -321,6 +324,7 @@ void AmbientOcclusionEffect::configure(const Config& config) { } _randomSamples[i] = r * 2.0f * M_PI / config.numSamples; } + updateJitterSamples(); } if (config.fetchMipsEnabled != _aoParametersBuffer->isFetchMipsEnabled()) { @@ -472,6 +476,14 @@ int AmbientOcclusionEffect::getDepthResolutionLevel() const { return std::min(1, _aoParametersBuffer->getResolutionLevel()); } +void AmbientOcclusionEffect::updateJitterSamples() { + const int SSAO_RANDOM_SAMPLE_COUNT = int(_randomSamples.size() / (SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT)); + for (int splitId = 0; splitId < SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT; splitId++) { + auto& sample = _aoFrameParametersBuffer[splitId].edit(); + sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId]; + } +} + void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); @@ -534,12 +546,11 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto occlusionDepthSize = glm::ivec2(occlusionDepthTexture->getDimensions()); // Update sample rotation - const int SSAO_RANDOM_SAMPLE_COUNT = int(_randomSamples.size() / (SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT)); - for (int splitId=0 ; splitId < SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT ; splitId++) { - auto& sample = _aoFrameParametersBuffer[splitId].edit(); - sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId]; + if (_isJitterEnabled) { + const int SSAO_RANDOM_SAMPLE_COUNT = int(_randomSamples.size() / (SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT)); + updateJitterSamples(); + _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; } - //_frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) { PROFILE_RANGE_BATCH(batch, "SSAO"); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 8d5eef42a5..3fb58e3437 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -83,6 +83,7 @@ class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent { Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled NOTIFY dirty) Q_PROPERTY(bool borderingEnabled MEMBER borderingEnabled NOTIFY dirty) Q_PROPERTY(bool fetchMipsEnabled MEMBER fetchMipsEnabled NOTIFY dirty) + Q_PROPERTY(bool jitterEnabled MEMBER jitterEnabled NOTIFY dirty) Q_PROPERTY(float radius MEMBER radius WRITE setRadius) Q_PROPERTY(float obscuranceLevel MEMBER obscuranceLevel WRITE setObscuranceLevel) Q_PROPERTY(float falloffAngle MEMBER falloffAngle WRITE setFalloffAngle) @@ -123,6 +124,7 @@ public: bool ditheringEnabled; // randomize the distribution of taps per pixel, should always be true bool borderingEnabled; // avoid evaluating information from non existing pixels out of the frame, should always be true bool fetchMipsEnabled; // fetch taps in sub mips to otpimize cache, should always be true + bool jitterEnabled; // Add small jittering to AO samples at each frame signals: void dirty(); @@ -181,6 +183,7 @@ private: void updateBlurParameters(); void updateFramebufferSizes(); + void updateJitterSamples(); int getDepthResolutionLevel() const; @@ -204,6 +207,7 @@ private: AmbientOcclusionFramebufferPointer _framebuffer; std::array _randomSamples; int _frameId{ 0 }; + bool _isJitterEnabled{ true }; gpu::RangeTimerPointer _gpuTimer; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index a289654486..93d0fb95e7 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -390,12 +390,14 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t return f * f * f * max((vn - getFalloffCosAngle()) / (epsilon + vv), 0.0); } -#define HBAO_USE_COS_ANGLE 0 +#define HBAO_USE_COS_ANGLE 1 + +float computeWeightForHorizon(float horizonLimit, float distanceSquared) { + return max(0.0, 1.0 - distanceSquared / getRadius2()); +} float computeWeightedHorizon(float horizonLimit, float distanceSquared) { - float radiusFalloff = distanceSquared / getRadius2(); - - radiusFalloff = max(0.0, 1.0 - radiusFalloff); + float radiusFalloff = computeWeightForHorizon(horizonLimit, distanceSquared); #if !HBAO_USE_COS_ANGLE horizonLimit = getFalloffSinAngle() - horizonLimit; @@ -417,44 +419,46 @@ float computeWeightedHorizon(float horizonLimit, float distanceSquared) { vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, fragUVPos); vec3 deltaVec = tapPositionES - fragPositionES; float distanceSquared = dot(deltaVec, deltaVec); - float distance = sqrt(distanceSquared); float deltaDotNormal = dot(deltaVec, fragFrameES.normal); #if HBAO_USE_COS_ANGLE float tapHorizonLimit = deltaDotNormal; #else float tapHorizonLimit = dot(deltaVec, fragFrameES.tangent); #endif - float epsilon = 0.0001; - tapHorizonLimit /= (distance + epsilon); + tapHorizonLimit *= inversesqrt(distanceSquared); - if (distanceSquared < getRadius2() && deltaDotNormal>0.0 && + if (distanceSquared < getRadius2() && deltaDotNormal>0.0) { #if HBAO_USE_COS_ANGLE - tapHorizonLimit > horizonLimit -#else - tapHorizonLimit < horizonLimit -#endif - ) { - tapHorizonLimit = computeWeightedHorizon(tapHorizonLimit, distanceSquared); -#if HBAO_USE_COS_ANGLE - horizonLimit = max(horizonLimit, tapHorizonLimit); + float weight = computeWeightForHorizon(tapHorizonLimit, distanceSquared); + if (tapHorizonLimit > horizonLimit) { + occlusion += weight * (tapHorizonLimit - horizonLimit); + horizonLimit = tapHorizonLimit; + } else if (dot(deltaVec, fragFrameES.tangent) < 0.0) { + // This is a hack to try to handle the case where the occlusion angle is + // greater than 90° + occlusion = mix(occlusion, (occlusion+1.0) * 0.5, weight); + } #else - horizonLimit = min(horizonLimit, tapHorizonLimit); + if (tapHorizonLimit < horizonLimit) { + tapHorizonLimit = computeWeightedHorizon(tapHorizonLimit, distanceSquared); + horizonLimit = min(horizonLimit, tapHorizonLimit); + } #endif } <@endfunc@> #define HBAO_HORIZON_SEARCH_CONSTANT_STEP 0 -float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, TBNFrame fragFrameES, vec2 searchVec, float searchRadius, int stepCount) { - vec2 absSearchVec = abs(searchVec); +float computeOcclusion(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, TBNFrame fragFrameES, vec2 searchDir, float searchRadius, int stepCount) { #if HBAO_USE_COS_ANGLE float horizonLimit = getFalloffCosAngle(); + float occlusion = 0.0; #else float horizonLimit = getFalloffSinAngle(); #endif if (stepCount>0) { - vec2 deltaTapUV = searchVec / float(stepCount); + vec2 deltaTapUV = searchDir / float(stepCount); float deltaRadius = searchRadius / float(stepCount); #if HBAO_HORIZON_SEARCH_CONSTANT_STEP @@ -487,31 +491,32 @@ float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, TBNFrame f #endif } - return horizonLimit; +#if HBAO_USE_COS_ANGLE + occlusion = min(occlusion * getFalloffCosAngleScale(), 1.0); +#else + occlusion = horizonLimit > 0.0 ? horizonLimit * getFalloffSinAngleScale() : horizonLimit; +#endif + + return occlusion; } float evalVisibilityHBAO(ivec4 side, vec2 fragUVPos, vec2 invSideImageSize, vec2 deltaTap, float diskPixelRadius, vec3 fragPositionES, TBNFrame fragFrameES) { vec2 pixelSearchVec = deltaTap * diskPixelRadius; - vec2 searchVec = pixelSearchVec * invSideImageSize; + vec2 searchDir = pixelSearchVec * invSideImageSize; float obscuranceH1 = 0.0; float obscuranceH2 = 0.0; - -#if !HBAO_USE_COS_ANGLE - fragFrameES.tangent = normalize(fragFrameES.tangent * deltaTap.x + fragFrameES.binormal * deltaTap.y); -#endif - pixelSearchVec = abs(pixelSearchVec); int stepCount = int(ceil(max(pixelSearchVec.x, pixelSearchVec.y))); + fragFrameES.tangent = normalize(fragFrameES.tangent * deltaTap.x + fragFrameES.binormal * deltaTap.y); + // Forward search for h1 - obscuranceH1 = computeHorizon(side, fragUVPos, fragPositionES, fragFrameES, searchVec, diskPixelRadius, stepCount); + obscuranceH1 = computeOcclusion(side, fragUVPos, fragPositionES, fragFrameES, searchDir, diskPixelRadius, stepCount); // Backward search for h2 -#if !HBAO_USE_COS_ANGLE fragFrameES.tangent = -fragFrameES.tangent; -#endif - obscuranceH2 = computeHorizon(side, fragUVPos, fragPositionES, fragFrameES, -searchVec, diskPixelRadius, stepCount); + obscuranceH2 = computeOcclusion(side, fragUVPos, fragPositionES, fragFrameES, -searchDir, diskPixelRadius, stepCount); return obscuranceH1 + obscuranceH2; } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 76357ffbb9..f0c406f446 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -60,9 +60,7 @@ void main(void) { fragFrameES.tangent = vec3(0.0); fragFrameES.binormal = vec3(0.0); fragFrameES.normal = fragNormalES; -#if !HBAO_USE_COS_ANGLE buildTangentBinormal(side, fragUVPos, fragPositionES, fragNormalES, deltaDepthUV, fragFrameES.tangent, fragFrameES.binormal); -#endif // Let's make noise float randomPatternRotationAngle = getAngleDithering(fragPixelPos); @@ -79,12 +77,10 @@ void main(void) { } obscuranceSum *= invNumSamples; #if HBAO_USE_COS_ANGLE - obscuranceSum *= 0.5 / PI; - obscuranceSum = 1.0 - obscuranceSum * obscuranceSum * getObscuranceScaling(); + obscuranceSum *= 0.5; + obscuranceSum = 1.0 - obscuranceSum * getObscuranceScaling(); #else obscuranceSum *= 0.5; - obscuranceSum += 1.0 - getFalloffSinAngle(); - obscuranceSum = mix(1.0, obscuranceSum, getObscuranceScaling()); #endif } else { diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index 2ea3a6c416..91e385edb8 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -59,6 +59,7 @@ Rectangle { Repeater { model: [ "horizonBased:horizonBased", + "jitterEnabled:jitterEnabled", "ditheringEnabled:ditheringEnabled", "fetchMipsEnabled:fetchMipsEnabled", "borderingEnabled:borderingEnabled" From 6420d961498bc6700c61eee0cb3f3c719044e9a4 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 2 Oct 2018 11:16:23 +0200 Subject: [PATCH 58/81] Tried to limit banding effect --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 4 +--- libraries/render-utils/src/AmbientOcclusionEffect.h | 4 +++- libraries/render-utils/src/ssao.slh | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 8e82cf9a9c..eec8cc18a4 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -477,7 +477,6 @@ int AmbientOcclusionEffect::getDepthResolutionLevel() const { } void AmbientOcclusionEffect::updateJitterSamples() { - const int SSAO_RANDOM_SAMPLE_COUNT = int(_randomSamples.size() / (SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT)); for (int splitId = 0; splitId < SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT; splitId++) { auto& sample = _aoFrameParametersBuffer[splitId].edit(); sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId]; @@ -547,9 +546,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte // Update sample rotation if (_isJitterEnabled) { - const int SSAO_RANDOM_SAMPLE_COUNT = int(_randomSamples.size() / (SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT)); updateJitterSamples(); - _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; + _frameId = (_frameId + 1) % (SSAO_RANDOM_SAMPLE_COUNT); } gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) { diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 3fb58e3437..29dc665961 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -130,6 +130,8 @@ signals: void dirty(); }; +#define SSAO_RANDOM_SAMPLE_COUNT 16 + class AmbientOcclusionEffect { public: using Inputs = render::VaryingSet3; @@ -205,7 +207,7 @@ private: static gpu::PipelinePointer _buildNormalsPipeline; AmbientOcclusionFramebufferPointer _framebuffer; - std::array _randomSamples; + std::array _randomSamples; int _frameId{ 0 }; bool _isJitterEnabled{ true }; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 93d0fb95e7..72da94a4dd 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -295,7 +295,7 @@ vec3 getNormalEyeAtPixel(ivec2 pixel, int level) { } int evalMipFromRadius(float radius) { - const int LOG_MAX_OFFSET = 1; + const int LOG_MAX_OFFSET = 2; const int MAX_MIP_LEVEL = 5; return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); } @@ -433,11 +433,11 @@ float computeWeightedHorizon(float horizonLimit, float distanceSquared) { if (tapHorizonLimit > horizonLimit) { occlusion += weight * (tapHorizonLimit - horizonLimit); horizonLimit = tapHorizonLimit; - } else if (dot(deltaVec, fragFrameES.tangent) < 0.0) { + } /*else if (dot(deltaVec, fragFrameES.tangent) < 0.0) { // This is a hack to try to handle the case where the occlusion angle is // greater than 90° occlusion = mix(occlusion, (occlusion+1.0) * 0.5, weight); - } + }*/ #else if (tapHorizonLimit < horizonLimit) { tapHorizonLimit = computeWeightedHorizon(tapHorizonLimit, distanceSquared); From 1ed0bd68b9f46b2315cbe3e7399341752e51614b Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 2 Oct 2018 12:25:00 +0200 Subject: [PATCH 59/81] Small bilateral blur optim --- .../src/AmbientOcclusionEffect.cpp | 2 +- libraries/render-utils/src/ssao.slh | 31 +++++++++++++------ .../render-utils/src/ssao_bilateralBlur.slf | 27 +++++++++------- .../render-utils/src/ssao_makeOcclusion.slf | 3 +- 4 files changed, 40 insertions(+), 23 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index eec8cc18a4..8c56d17b71 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -220,7 +220,7 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : borderingEnabled{ true }, fetchMipsEnabled{ true }, horizonBased{ true }, - jitterEnabled{ true }{ + jitterEnabled{ false }{ } AmbientOcclusionEffect::AOParameters::AOParameters() { diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 72da94a4dd..9ae32695c5 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -32,14 +32,20 @@ vec4 packOcclusionOutput(float occlusion, float depth, vec3 eyeNormal) { #endif } -void unpackOcclusionOutput(vec4 raw, out float occlusion, out float depth, out vec3 eyeNormal) { - occlusion = raw.x; +struct UnpackedOcclusion { + vec3 normal; + float depth; + float occlusion; +}; + +void unpackOcclusionOutput(vec4 raw, out UnpackedOcclusion result) { + result.occlusion = raw.x; #if SSAO_BILATERAL_BLUR_USE_NORMAL - depth = raw.y; - eyeNormal = normalize(vec3(raw.zw, 1.0)); + result.depth = raw.y; + result.normal = normalize(vec3(raw.zw, 1.0)); #else - depth = (raw.y + raw.z / 256.0); - eyeNormal = vec3(0,0,1); + result.depth = (raw.y + raw.z / 256.0); + result.normal = vec3(0,0,1); #endif } @@ -391,6 +397,7 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t } #define HBAO_USE_COS_ANGLE 1 +#define HBAO_USE_OVERHANG_HACK 0 float computeWeightForHorizon(float horizonLimit, float distanceSquared) { return max(0.0, 1.0 - distanceSquared / getRadius2()); @@ -433,11 +440,14 @@ float computeWeightedHorizon(float horizonLimit, float distanceSquared) { if (tapHorizonLimit > horizonLimit) { occlusion += weight * (tapHorizonLimit - horizonLimit); horizonLimit = tapHorizonLimit; - } /*else if (dot(deltaVec, fragFrameES.tangent) < 0.0) { + } +#if HBAO_USE_OVERHANG_HACK + else if (dot(deltaVec, fragFrameES.tangent) < 0.0) { // This is a hack to try to handle the case where the occlusion angle is // greater than 90° occlusion = mix(occlusion, (occlusion+1.0) * 0.5, weight); - }*/ + } +#endif #else if (tapHorizonLimit < horizonLimit) { tapHorizonLimit = computeWeightedHorizon(tapHorizonLimit, distanceSquared); @@ -509,13 +519,16 @@ float evalVisibilityHBAO(ivec4 side, vec2 fragUVPos, vec2 invSideImageSize, vec2 pixelSearchVec = abs(pixelSearchVec); int stepCount = int(ceil(max(pixelSearchVec.x, pixelSearchVec.y))); +#if HBAO_USE_OVERHANG_HACK || !HBAO_USE_COS_ANGLE fragFrameES.tangent = normalize(fragFrameES.tangent * deltaTap.x + fragFrameES.binormal * deltaTap.y); - +#endif // Forward search for h1 obscuranceH1 = computeOcclusion(side, fragUVPos, fragPositionES, fragFrameES, searchDir, diskPixelRadius, stepCount); // Backward search for h2 +#if HBAO_USE_OVERHANG_HACK || !HBAO_USE_COS_ANGLE fragFrameES.tangent = -fragFrameES.tangent; +#endif obscuranceH2 = computeOcclusion(side, fragUVPos, fragPositionES, fragFrameES, -searchDir, diskPixelRadius, stepCount); return obscuranceH1 + obscuranceH2; diff --git a/libraries/render-utils/src/ssao_bilateralBlur.slf b/libraries/render-utils/src/ssao_bilateralBlur.slf index bec6793307..73d1e794ed 100644 --- a/libraries/render-utils/src/ssao_bilateralBlur.slf +++ b/libraries/render-utils/src/ssao_bilateralBlur.slf @@ -55,29 +55,26 @@ float evalBlurCoefficient(vec3 blurScales, float radialDistance, float zDistance const float BLUR_EDGE_NORMAL_LIMIT = 0.25; vec2 evalTapWeightedValue(vec3 blurScales, ivec4 side, int r, vec2 occlusionTexCoord, float fragDepth, vec3 fragNormal) { - vec2 tapOcclusionTexCoord = getBlurOcclusionAxis() * r + occlusionTexCoord; vec2 occlusionTexCoordLimits = getBlurOcclusionUVLimit(); - if (any(lessThan(tapOcclusionTexCoord, vec2(0.0))) || any(greaterThanEqual(tapOcclusionTexCoord, occlusionTexCoordLimits)) ) { + if (any(lessThan(occlusionTexCoord, vec2(0.0))) || any(greaterThanEqual(occlusionTexCoord, occlusionTexCoordLimits)) ) { return vec2(0.0); } - vec4 tapOcclusionPacked = fetchOcclusionPacked(side, tapOcclusionTexCoord); - float tapOcclusion; - float tapDepth; - vec3 tapNormal; - unpackOcclusionOutput(tapOcclusionPacked, tapOcclusion, tapDepth, tapNormal); + vec4 tapOcclusionPacked = fetchOcclusionPacked(side, occlusionTexCoord); + UnpackedOcclusion tap; + unpackOcclusionOutput(tapOcclusionPacked, tap); // range domain (the "bilateral" weight). As depth difference increases, decrease weight. - float zDistance = tapDepth - fragDepth; + float zDistance = tap.depth - fragDepth; #if SSAO_BILATERAL_BLUR_USE_NORMAL - float normalDistance = BLUR_EDGE_NORMAL_LIMIT - min(BLUR_EDGE_NORMAL_LIMIT, dot(tapNormal, fragNormal)); + float normalDistance = BLUR_EDGE_NORMAL_LIMIT - min(BLUR_EDGE_NORMAL_LIMIT, dot(tap.normal, fragNormal)); #else float normalDistance = 0.0; #endif float weight = evalBlurCoefficient(blurScales, abs(r), zDistance, normalDistance); - return vec2(tapOcclusion * weight, weight); + return vec2(tap.occlusion * weight, weight); } vec4 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 depthTexCoord) { @@ -96,24 +93,30 @@ vec4 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 dept // Accumulate weighted contributions along the bluring axis in the [-radius, radius] range int blurRadius = getBlurRadius(); vec3 blurScales = getBlurScales(); + int r; // From now on, occlusionTexCoord is the UV pos in the side float sideTexCoord = occlusionTexCoord.x * 2.0 - getStereoSide(side) * getBlurOcclusionUVLimit().x; occlusionTexCoord.x = mix(occlusionTexCoord.x, sideTexCoord, isStereo()); + occlusionTexCoord -= getBlurOcclusionAxis() * blurRadius; + // negative side first - for (int r = -blurRadius; r <= -1; ++r) { + for (r = -blurRadius; r <= -1; r++) { weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, fragDepthKey, fragNormal); + occlusionTexCoord += getBlurOcclusionAxis(); } // Central pixel contribution float mainWeight = 1.0; float pixelOcclusion = unpackOcclusion(fetchOcclusionPacked(side, occlusionTexCoord)); weightedSums += vec2(pixelOcclusion * mainWeight, mainWeight); + occlusionTexCoord += getBlurOcclusionAxis(); // then positive side - for (int r = 1; r <= blurRadius; ++r) { + for (r = 1; r <= blurRadius; ++r) { weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, fragDepthKey, fragNormal); + occlusionTexCoord += getBlurOcclusionAxis(); } // Final normalization diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index f0c406f446..d456b7bb9a 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -60,8 +60,9 @@ void main(void) { fragFrameES.tangent = vec3(0.0); fragFrameES.binormal = vec3(0.0); fragFrameES.normal = fragNormalES; +#if HBAO_USE_OVERHANG_HACK || !HBAO_USE_COS_ANGLE buildTangentBinormal(side, fragUVPos, fragPositionES, fragNormalES, deltaDepthUV, fragFrameES.tangent, fragFrameES.binormal); - +#endif // Let's make noise float randomPatternRotationAngle = getAngleDithering(fragPixelPos); From 6fcd63ed64dffa6169be2db56fafbefe8b426993 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 2 Oct 2018 15:08:39 +0200 Subject: [PATCH 60/81] Improved acnee issues --- .../src/gpu/gl/GLTexelFormat.cpp | 9 +++- .../src/AmbientOcclusionEffect.cpp | 8 ++-- libraries/render-utils/src/ssao.slh | 45 +++++++++++++++---- .../render-utils/src/ssao_buildNormals.slf | 4 +- .../render-utils/src/ssao_makeOcclusion.slf | 12 ++--- 5 files changed, 52 insertions(+), 26 deletions(-) diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLTexelFormat.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLTexelFormat.cpp index 4d94f8d8e7..fef823718f 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLTexelFormat.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLTexelFormat.cpp @@ -329,6 +329,8 @@ GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) { result = GL_RGBA8_SNORM; break; case gpu::NINT2_10_10_10: + result = GL_RGB10_A2; + break; case gpu::NUINT32: case gpu::NINT32: case gpu::COMPRESSED: @@ -729,9 +731,9 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E texel.internalFormat = GL_DEPTH_COMPONENT24; break; } + case gpu::NINT2_10_10_10: case gpu::COMPRESSED: case gpu::NUINT2: - case gpu::NINT2_10_10_10: case gpu::NUM_TYPES: { // quiet compiler Q_UNREACHABLE(); } @@ -893,9 +895,12 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E texel.format = GL_RGBA; texel.internalFormat = GL_RGBA2; break; + case gpu::NINT2_10_10_10: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGB10_A2; + break; case gpu::NUINT32: case gpu::NINT32: - case gpu::NINT2_10_10_10: case gpu::COMPRESSED: case gpu::NUM_TYPES: // quiet compiler Q_UNREACHABLE(); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 8c56d17b71..9110285fc9 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -115,7 +115,7 @@ void AmbientOcclusionFramebuffer::allocate() { } auto width = sideSize.x; auto height = sideSize.y; - auto format = gpu::Element::COLOR_RGBA_32; + auto format = gpu::Element{ gpu::VEC4, gpu::NINT2_10_10_10, gpu::RGBA }; _normalTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT, gpu::Sampler::WRAP_CLAMP)); _normalFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("ssaoNormals")); @@ -206,10 +206,10 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() { AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false), - radius{ 0.5f }, + radius{ 0.7f }, perspectiveScale{ 1.0f }, - obscuranceLevel{ 0.25f }, - falloffAngle{ 0.4f }, + obscuranceLevel{ 0.15f }, + falloffAngle{ 0.1f }, edgeSharpness{ 1.0f }, blurDeviation{ 2.5f }, numSpiralTurns{ 7.0f }, diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 9ae32695c5..09c3cd3a66 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -287,8 +287,17 @@ float getZEyeAtUV(ivec4 side, vec2 texCoord, int level, ivec2 texelOffset) { return getZEyeAtUV(texCoord, level, texelOffset); } +vec3 packNormal(vec3 normal) { + vec3 absNormal = abs(normal); + return 0.5 + normal * 0.5 / max(absNormal.x, max(absNormal.y, absNormal.z)); +} + +vec3 unpackNormal(vec3 packedNormal) { + return normalize(packedNormal*2.0 - 1.0); +} + vec3 getNormalEyeAtUV(vec2 texCoord, int level) { - return normalize(textureLod(normalTex, texCoord, level).xyz*2.0 - vec3(1.0)); + return unpackNormal(textureLod(normalTex, texCoord, level).xyz); } vec3 getNormalEyeAtUV(ivec4 side, vec2 texCoord, int level) { @@ -297,7 +306,11 @@ vec3 getNormalEyeAtUV(ivec4 side, vec2 texCoord, int level) { } vec3 getNormalEyeAtPixel(ivec2 pixel, int level) { - return normalize(texelFetch(normalTex, pixel, level).xyz*2.0 - vec3(1.0)); + return unpackNormal(texelFetch(normalTex, pixel, level).xyz); +} + +vec2 snapToTexel(vec2 uv, vec2 pixelSize) { + return (floor(uv * pixelSize - 0.5) + 0.5) / pixelSize; } int evalMipFromRadius(float radius) { @@ -418,12 +431,12 @@ float computeWeightedHorizon(float horizonLimit, float distanceSquared) { } <@func computeHorizon()@> - if (fragUVPos.x<0 || fragUVPos.y<0 || fragUVPos.x>=1.0 || fragUVPos.y>=1.0) { + if (tapUVPos.x<0 || tapUVPos.y<0 || tapUVPos.x>=1.0 || tapUVPos.y>=1.0) { // Early exit because we've hit the borders of the frame break; } - vec2 tapMipZ = fetchTap(side, fragUVPos, radius); - vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, fragUVPos); + vec2 tapMipZ = fetchTap(side, tapUVPos, radius); + vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, tapUVPos); vec3 deltaVec = tapPositionES - fragPositionES; float distanceSquared = dot(deltaVec, deltaVec); float deltaDotNormal = dot(deltaVec, fragFrameES.normal); @@ -460,16 +473,18 @@ float computeWeightedHorizon(float horizonLimit, float distanceSquared) { #define HBAO_HORIZON_SEARCH_CONSTANT_STEP 0 float computeOcclusion(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, TBNFrame fragFrameES, vec2 searchDir, float searchRadius, int stepCount) { + float occlusion = 0.0; #if HBAO_USE_COS_ANGLE float horizonLimit = getFalloffCosAngle(); - float occlusion = 0.0; #else float horizonLimit = getFalloffSinAngle(); #endif if (stepCount>0) { vec2 deltaTapUV = searchDir / float(stepCount); + vec2 tapUVPos; float deltaRadius = searchRadius / float(stepCount); + vec2 sideDepthSize = getDepthTextureSideSize(0); #if HBAO_HORIZON_SEARCH_CONSTANT_STEP float radius = 0.0; @@ -478,6 +493,7 @@ float computeOcclusion(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, TBNFrame for (stepIndex=0 ; stepIndex } @@ -488,6 +504,7 @@ float computeOcclusion(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, TBNFrame while (radius<=searchRadius) { fragUVPos += deltaTapUV; + tapUVPos = snapToTexel(fragUVPos, sideDepthSize); <$computeHorizon()$> @@ -495,6 +512,7 @@ float computeOcclusion(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, TBNFrame mipLevel = tapMipZ.x; deltaRadius *= 2; deltaTapUV *= 2; + sideDepthSize = getDepthTextureSideSize(int(mipLevel)); } radius += deltaRadius; } @@ -511,16 +529,27 @@ float computeOcclusion(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, TBNFrame } float evalVisibilityHBAO(ivec4 side, vec2 fragUVPos, vec2 invSideImageSize, vec2 deltaTap, float diskPixelRadius, - vec3 fragPositionES, TBNFrame fragFrameES) { + vec3 fragPositionES, vec3 fragNormalES) { vec2 pixelSearchVec = deltaTap * diskPixelRadius; vec2 searchDir = pixelSearchVec * invSideImageSize; + vec2 deltaTapUV = deltaTap * invSideImageSize; float obscuranceH1 = 0.0; float obscuranceH2 = 0.0; pixelSearchVec = abs(pixelSearchVec); int stepCount = int(ceil(max(pixelSearchVec.x, pixelSearchVec.y))); + TBNFrame fragFrameES; + + fragFrameES.tangent = vec3(0.0); + fragFrameES.binormal = vec3(0.0); + fragFrameES.normal = fragNormalES; #if HBAO_USE_OVERHANG_HACK || !HBAO_USE_COS_ANGLE - fragFrameES.tangent = normalize(fragFrameES.tangent * deltaTap.x + fragFrameES.binormal * deltaTap.y); + vec3 positionPos = buildPosition(side, fragUVPos + deltaTapUV); + vec3 positionNeg = buildPosition(side, fragUVPos - deltaTapUV); + + fragFrameES.tangent = getMinDelta(fragPositionES, positionPos, positionNeg); + fragFrameES.tangent -= dot(fragNormalES, fragFrameES.tangent) * fragNormalES; + fragFrameES.tangent = normalize(fragFrameES.tangent); #endif // Forward search for h1 obscuranceH1 = computeOcclusion(side, fragUVPos, fragPositionES, fragFrameES, searchDir, diskPixelRadius, stepCount); diff --git a/libraries/render-utils/src/ssao_buildNormals.slf b/libraries/render-utils/src/ssao_buildNormals.slf index 9c183f640c..0dea63ae14 100644 --- a/libraries/render-utils/src/ssao_buildNormals.slf +++ b/libraries/render-utils/src/ssao_buildNormals.slf @@ -37,8 +37,6 @@ void main(void) { // The position and normal of the pixel fragment in Eye space vec3 fragPositionES = buildPosition(side, fragUVPos); vec3 fragNormalES = buildNormal(side, fragUVPos, fragPositionES, deltaDepthUV); - vec3 absFragNormalES = abs(fragNormalES); - fragNormalES /= max(absFragNormalES.z, max(absFragNormalES.x, absFragNormalES.y)); - outFragColor = vec4(vec3(fragNormalES)*0.5 + vec3(0.5), 1.0); + outFragColor = vec4(packNormal(fragNormalES), 1.0); } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index d456b7bb9a..aabc28a326 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -42,6 +42,8 @@ void main(void) { // From now on, fragUVPos is the UV pos in the side fragUVPos.x = mix(fragUVPos.x, fragUVPos.x * 2.0 - getStereoSide(side), isStereo()); + fragUVPos = snapToTexel(fragUVPos, sideDepthSize); + // The position and normal of the pixel fragment in Eye space vec2 deltaDepthUV = vec2(2.0) / sideDepthSize; vec3 fragPositionES = buildPosition(side, fragUVPos); @@ -55,14 +57,6 @@ void main(void) { diskPixelRadius = min(diskPixelRadius, SSAO_HBAO_MAX_RADIUS); } - TBNFrame fragFrameES; - - fragFrameES.tangent = vec3(0.0); - fragFrameES.binormal = vec3(0.0); - fragFrameES.normal = fragNormalES; -#if HBAO_USE_OVERHANG_HACK || !HBAO_USE_COS_ANGLE - buildTangentBinormal(side, fragUVPos, fragPositionES, fragNormalES, deltaDepthUV, fragFrameES.tangent, fragFrameES.binormal); -#endif // Let's make noise float randomPatternRotationAngle = getAngleDithering(fragPixelPos); @@ -74,7 +68,7 @@ void main(void) { if (isHorizonBased()) { for (int i = 0; i < numSamples; ++i) { vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); - obscuranceSum += evalVisibilityHBAO(side, fragUVPos, deltaDepthUV, deltaTap.xy, diskPixelRadius, fragPositionES, fragFrameES); + obscuranceSum += evalVisibilityHBAO(side, fragUVPos, deltaDepthUV, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); } obscuranceSum *= invNumSamples; #if HBAO_USE_COS_ANGLE From dfe9deb1544a5908bd4133148d34bcabd7b669af Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 2 Oct 2018 17:47:33 +0200 Subject: [PATCH 61/81] Two group of config settings for SSAO and HBAO --- .../src/AmbientOcclusionEffect.cpp | 343 ++++++++++++------ .../render-utils/src/AmbientOcclusionEffect.h | 71 ++-- .../render-utils/src/SurfaceGeometryPass.cpp | 2 +- libraries/render-utils/src/ssao.slh | 20 +- .../render-utils/src/ssao_makeOcclusion.slf | 19 +- .../utilities/render/ambientOcclusionPass.qml | 81 ++++- 6 files changed, 384 insertions(+), 152 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 9110285fc9..9df3c86d41 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -206,23 +206,87 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() { AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false), - radius{ 0.7f }, perspectiveScale{ 1.0f }, - obscuranceLevel{ 0.15f }, - falloffAngle{ 0.1f }, edgeSharpness{ 1.0f }, - blurDeviation{ 2.5f }, - numSpiralTurns{ 7.0f }, - numSamples{ 1 }, resolutionLevel{ 2 }, blurRadius{ 4 }, + + ssaoRadius{ 1.0f }, + ssaoObscuranceLevel{ 0.4f }, + ssaoFalloffAngle{ 0.1f }, + ssaoNumSamples{ 32 }, + ssaoNumSpiralTurns{ 7.0f }, + + hbaoRadius{ 0.7f }, + hbaoObscuranceLevel{ 0.75f }, + hbaoFalloffAngle{ 0.3f }, + hbaoNumSamples{ 1 }, + ditheringEnabled{ true }, borderingEnabled{ true }, fetchMipsEnabled{ true }, - horizonBased{ true }, + horizonBased{ false }, jitterEnabled{ false }{ } +void AmbientOcclusionEffectConfig::setSSAORadius(float newRadius) { + ssaoRadius = std::max(0.01f, newRadius); emit dirty(); +} + +void AmbientOcclusionEffectConfig::setSSAOObscuranceLevel(float level) { + ssaoObscuranceLevel = std::max(0.01f, level); + emit dirty(); +} + +void AmbientOcclusionEffectConfig::setSSAOFalloffAngle(float bias) { + ssaoFalloffAngle = std::max(0.0f, std::min(bias, 1.0f)); + emit dirty(); +} + +void AmbientOcclusionEffectConfig::setSSAONumSpiralTurns(float turns) { + ssaoNumSpiralTurns = std::max(0.0f, (float)turns); + emit dirty(); +} + +void AmbientOcclusionEffectConfig::setSSAONumSamples(int samples) { + ssaoNumSamples = std::max(1.0f, (float)samples); + emit dirty(); +} + +void AmbientOcclusionEffectConfig::setHBAORadius(float newRadius) { + hbaoRadius = std::max(0.01f, newRadius); emit dirty(); +} + +void AmbientOcclusionEffectConfig::setHBAOObscuranceLevel(float level) { + hbaoObscuranceLevel = std::max(0.01f, level); + emit dirty(); +} + +void AmbientOcclusionEffectConfig::setHBAOFalloffAngle(float bias) { + hbaoFalloffAngle = std::max(0.0f, std::min(bias, 1.0f)); + emit dirty(); +} + +void AmbientOcclusionEffectConfig::setHBAONumSamples(int samples) { + hbaoNumSamples = std::max(1.0f, (float)samples); + emit dirty(); +} + +void AmbientOcclusionEffectConfig::setEdgeSharpness(float sharpness) { + edgeSharpness = std::max(0.0f, (float)sharpness); + emit dirty(); +} + +void AmbientOcclusionEffectConfig::setResolutionLevel(int level) { + resolutionLevel = std::max(0, std::min(level, MAX_RESOLUTION_LEVEL)); + emit dirty(); +} + +void AmbientOcclusionEffectConfig::setBlurRadius(int radius) { + blurRadius = std::max(0, std::min(MAX_BLUR_RADIUS, radius)); + emit dirty(); +} + AmbientOcclusionEffect::AOParameters::AOParameters() { _resolutionInfo = glm::vec4{ 0.0f }; _radiusInfo = glm::vec4{ 0.0f }; @@ -242,42 +306,17 @@ void AmbientOcclusionEffect::configure(const Config& config) { DependencyManager::get()->setAmbientOcclusionEnabled(config.enabled); bool shouldUpdateBlurs = false; + bool shouldUpdateTechnique = false; _isJitterEnabled = config.jitterEnabled; - const double RADIUS_POWER = 6.0; - const auto& radius = config.radius; - if (radius != _aoParametersBuffer->getRadius() || config.horizonBased != _aoParametersBuffer->isHorizonBased()) { - auto& current = _aoParametersBuffer.edit()._radiusInfo; - current.x = radius; - current.y = radius * radius; - current.z = 10.0f; - if (!config.horizonBased) { - current.z *= (float)(1.0 / pow((double)radius, RADIUS_POWER)); - } - } - - if (config.horizonBased != _aoParametersBuffer->isHorizonBased()) { - auto& current = _aoParametersBuffer.edit()._resolutionInfo; - current.y = config.horizonBased & 1; - } - - if (config.obscuranceLevel != _aoParametersBuffer->getObscuranceLevel()) { - auto& current = _aoParametersBuffer.edit()._radiusInfo; - current.w = config.obscuranceLevel; - } - - if (config.falloffAngle != _aoParametersBuffer->getFalloffCosAngle()) { - auto& current = _aoParametersBuffer.edit()._falloffInfo; - current.x = config.falloffAngle; - current.y = 1.0f / (1.0f - current.x); - // Compute sin from cos - current.z = sqrtf(1.0f - config.falloffAngle * config.falloffAngle); - current.w = 1.0f / current.z; + if (!_framebuffer) { + _framebuffer = std::make_shared(); + shouldUpdateBlurs = true; } // Update bilateral blur - { + if (config.blurRadius != _hblurParametersBuffer->getBlurRadius() || _blurEdgeSharpness != config.edgeSharpness) { const float BLUR_EDGE_DISTANCE_SCALE = float(10000 * SSAO_DEPTH_KEY_SCALE); const float BLUR_EDGE_NORMAL_SCALE = 2.0f; @@ -287,6 +326,8 @@ void AmbientOcclusionEffect::configure(const Config& config) { float blurRadialScale = 1.0f / (2.0f*blurRadialSigma*blurRadialSigma); glm::vec3 blurScales = -glm::vec3(blurRadialScale, glm::vec2(BLUR_EDGE_DISTANCE_SCALE, BLUR_EDGE_NORMAL_SCALE) * config.edgeSharpness); + _blurEdgeSharpness = config.edgeSharpness; + hblur.x = blurScales.x; hblur.y = blurScales.y; hblur.z = blurScales.z; @@ -298,33 +339,10 @@ void AmbientOcclusionEffect::configure(const Config& config) { vblur.w = (float)config.blurRadius; } - if (config.numSpiralTurns != _aoParametersBuffer->getNumSpiralTurns()) { - auto& current = _aoParametersBuffer.edit()._sampleInfo; - current.z = config.numSpiralTurns; - } - - if (config.numSamples != _aoParametersBuffer->getNumSamples()) { - auto& current = _aoParametersBuffer.edit()._sampleInfo; - current.x = config.numSamples; - current.y = 1.0f / config.numSamples; - - // Regenerate offsets - const int B = 3; - const float invB = 1.0f / (float)B; - - for (int i = 0; i < _randomSamples.size(); i++) { - int index = i+1; // Indices start at 1, not 0 - float f = 1.0f; - float r = 0.0f; - - while (index > 0) { - f = f * invB; - r = r + f * (float)(index % B); - index = index / B; - } - _randomSamples[i] = r * 2.0f * M_PI / config.numSamples; - } - updateJitterSamples(); + if (_aoParametersBuffer->isHorizonBased() != config.horizonBased) { + auto& current = _aoParametersBuffer.edit()._resolutionInfo; + current.y = config.horizonBased & 1; + shouldUpdateTechnique = true; } if (config.fetchMipsEnabled != _aoParametersBuffer->isFetchMipsEnabled()) { @@ -332,11 +350,6 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.w = (float)config.fetchMipsEnabled; } - if (!_framebuffer) { - _framebuffer = std::make_shared(); - shouldUpdateBlurs = true; - } - if (config.perspectiveScale != _aoParametersBuffer->getPerspectiveScale()) { _aoParametersBuffer.edit()._resolutionInfo.z = config.perspectiveScale; } @@ -357,11 +370,102 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.w = (float)config.borderingEnabled; } + if (config.horizonBased) { + // Configure for HBAO + const auto& radius = config.hbaoRadius; + if (shouldUpdateTechnique || radius != _aoParametersBuffer->getRadius()) { + auto& current = _aoParametersBuffer.edit()._radiusInfo; + current.x = radius; + current.y = radius * radius; + current.z = 1.0f / current.y; + } + + if (shouldUpdateTechnique || config.hbaoObscuranceLevel != _aoParametersBuffer->getObscuranceLevel()) { + auto& current = _aoParametersBuffer.edit()._radiusInfo; + current.w = config.hbaoObscuranceLevel; + } + + if (shouldUpdateTechnique || config.hbaoFalloffAngle != _aoParametersBuffer->getFalloffAngle()) { + auto& current = _aoParametersBuffer.edit()._falloffInfo; + current.x = config.hbaoFalloffAngle; + current.y = 1.0f / (1.0f - current.x); + // Compute sin from cos + current.z = sqrtf(1.0f - config.hbaoFalloffAngle * config.hbaoFalloffAngle); + current.w = 1.0f / current.z; + } + + if (shouldUpdateTechnique || config.hbaoNumSamples != _aoParametersBuffer->getNumSamples()) { + auto& current = _aoParametersBuffer.edit()._sampleInfo; + current.x = config.hbaoNumSamples; + current.y = 1.0f / config.hbaoNumSamples; + updateRandomSamples(); + updateJitterSamples(); + } + } else { + // Configure for SSAO + const double RADIUS_POWER = 6.0; + const auto& radius = config.ssaoRadius; + if (shouldUpdateTechnique || radius != _aoParametersBuffer->getRadius()) { + auto& current = _aoParametersBuffer.edit()._radiusInfo; + current.x = radius; + current.y = radius * radius; + current.z = (float)(10.0 / pow((double)radius, RADIUS_POWER)); + } + + if (shouldUpdateTechnique || config.ssaoObscuranceLevel != _aoParametersBuffer->getObscuranceLevel()) { + auto& current = _aoParametersBuffer.edit()._radiusInfo; + current.w = config.ssaoObscuranceLevel; + } + + if (shouldUpdateTechnique || config.ssaoFalloffAngle != _aoParametersBuffer->getFalloffAngle()) { + auto& current = _aoParametersBuffer.edit()._falloffInfo; + current.x = config.ssaoFalloffAngle; + } + + if (shouldUpdateTechnique || config.ssaoNumSpiralTurns != _aoParametersBuffer->getNumSpiralTurns()) { + auto& current = _aoParametersBuffer.edit()._sampleInfo; + current.z = config.ssaoNumSpiralTurns; + } + + if (shouldUpdateTechnique || config.ssaoNumSamples != _aoParametersBuffer->getNumSamples()) { + auto& current = _aoParametersBuffer.edit()._sampleInfo; + current.x = config.ssaoNumSamples; + current.y = 1.0f / config.ssaoNumSamples; + updateRandomSamples(); + updateJitterSamples(); + } + } + if (shouldUpdateBlurs) { updateBlurParameters(); } } +void AmbientOcclusionEffect::updateRandomSamples() { + // Regenerate offsets + if (_aoParametersBuffer->isHorizonBased()) { + const int B = 3; + const float invB = 1.0f / (float)B; + float sampleScale = 2.0f * M_PI / _aoParametersBuffer->getNumSamples(); + + for (int i = 0; i < _randomSamples.size(); i++) { + int index = i + 1; // Indices start at 1, not 0 + float f = 1.0f; + float r = 0.0f; + + while (index > 0) { + f = f * invB; + r = r + f * (float)(index % B); + index = index / B; + } + _randomSamples[i] = r * sampleScale; + } + } else { + for (int i = 0; i < _randomSamples.size(); i++) { + _randomSamples[i] = randFloat() * 2.0f * M_PI; + } + } +} void AmbientOcclusionEffect::updateBlurParameters() { const auto resolutionLevel = _aoParametersBuffer->getResolutionLevel(); auto& vblur = _vblurParametersBuffer.edit(); @@ -477,9 +581,14 @@ int AmbientOcclusionEffect::getDepthResolutionLevel() const { } void AmbientOcclusionEffect::updateJitterSamples() { - for (int splitId = 0; splitId < SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT; splitId++) { - auto& sample = _aoFrameParametersBuffer[splitId].edit(); - sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId]; + if (_aoParametersBuffer->isHorizonBased()) { + for (int splitId = 0; splitId < SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT; splitId++) { + auto& sample = _aoFrameParametersBuffer[splitId].edit(); + sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId]; + } + } else { + auto& sample = _aoFrameParametersBuffer[0].edit(); + sample._angleInfo.x = _randomSamples[_frameId]; } } @@ -594,57 +703,69 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte batch.setPipeline(occlusionPipeline); batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, occlusionDepthTexture); + if (_aoParametersBuffer->isHorizonBased()) { #if SSAO_USE_QUAD_SPLIT - batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture); - { - const auto uvScale = glm::vec3( - (splitSize.x * SSAO_SPLIT_COUNT) / float(occlusionViewport.z), - (splitSize.y * SSAO_SPLIT_COUNT) / float(occlusionViewport.w), - 1.0f); - const auto postPixelOffset = glm::vec2(0.5f) / glm::vec2(occlusionViewport.z, occlusionViewport.w); - const auto prePixelOffset = glm::vec2(0.5f * uvScale.x, 0.5f * uvScale.y) / glm::vec2(splitSize); - Transform model; + batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture); + { + const auto uvScale = glm::vec3( + (splitSize.x * SSAO_SPLIT_COUNT) / float(occlusionViewport.z), + (splitSize.y * SSAO_SPLIT_COUNT) / float(occlusionViewport.w), + 1.0f); + const auto postPixelOffset = glm::vec2(0.5f) / glm::vec2(occlusionViewport.z, occlusionViewport.w); + const auto prePixelOffset = glm::vec2(0.5f * uvScale.x, 0.5f * uvScale.y) / glm::vec2(splitSize); + Transform model; - batch.setViewportTransform(splitViewport); + batch.setViewportTransform(splitViewport); - model.setScale(uvScale); - for (int y = 0; y < SSAO_SPLIT_COUNT; y++) { - for (int x = 0; x < SSAO_SPLIT_COUNT; x++) { - const int splitIndex = x + y * SSAO_SPLIT_COUNT; - const auto uvTranslate = glm::vec3( - postPixelOffset.x * (2 * x + 1) - prePixelOffset.x, - postPixelOffset.y * (2 * y + 1) - prePixelOffset.y, - 0.0f + model.setScale(uvScale); + for (int y = 0; y < SSAO_SPLIT_COUNT; y++) { + for (int x = 0; x < SSAO_SPLIT_COUNT; x++) { + const int splitIndex = x + y * SSAO_SPLIT_COUNT; + const auto uvTranslate = glm::vec3( + postPixelOffset.x * (2 * x + 1) - prePixelOffset.x, + postPixelOffset.y * (2 * y + 1) - prePixelOffset.y, + 0.0f ); - model.setTranslation(uvTranslate); - batch.setModelTransform(model); - batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(splitIndex)); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[splitIndex]); - batch.draw(gpu::TRIANGLE_STRIP, 4); + model.setTranslation(uvTranslate); + batch.setModelTransform(model); + batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(splitIndex)); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[splitIndex]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + } } } - } #else - batch.setViewportTransform(occlusionViewport); - model.setIdentity(); - batch.setModelTransform(model); - batch.setFramebuffer(occlusionFBO); - batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); - batch.draw(gpu::TRIANGLE_STRIP, 4); + batch.setViewportTransform(occlusionViewport); + batch.setModelTransform(Transform()); + batch.setFramebuffer(occlusionFBO); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); + batch.draw(gpu::TRIANGLE_STRIP, 4); #endif + } else { +#if SSAO_USE_QUAD_SPLIT + batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture); +#endif + batch.setViewportTransform(occlusionViewport); + batch.setModelTransform(Transform()); + batch.setFramebuffer(occlusionFBO); + batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + } batch.popProfileRange(); #if SSAO_USE_QUAD_SPLIT - // Gather back the four separate renders into one interleaved one - batch.pushProfileRange("Gather"); - batch.setViewportTransform(occlusionViewport); - batch.setModelTransform(Transform()); - batch.setFramebuffer(occlusionFBO); - batch.setPipeline(gatherPipeline); - batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, _framebuffer->getOcclusionSplitTexture()); - batch.draw(gpu::TRIANGLE_STRIP, 4); - batch.popProfileRange(); + if (_aoParametersBuffer->isHorizonBased()) { + // Gather back the four separate renders into one interleaved one + batch.pushProfileRange("Gather"); + batch.setViewportTransform(occlusionViewport); + batch.setModelTransform(Transform()); + batch.setFramebuffer(occlusionFBO); + batch.setPipeline(gatherPipeline); + batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, _framebuffer->getOcclusionSplitTexture()); + batch.draw(gpu::TRIANGLE_STRIP, 4); + batch.popProfileRange(); + } #endif { diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 29dc665961..a5b3ec1fdb 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -84,42 +84,61 @@ class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent { Q_PROPERTY(bool borderingEnabled MEMBER borderingEnabled NOTIFY dirty) Q_PROPERTY(bool fetchMipsEnabled MEMBER fetchMipsEnabled NOTIFY dirty) Q_PROPERTY(bool jitterEnabled MEMBER jitterEnabled NOTIFY dirty) - Q_PROPERTY(float radius MEMBER radius WRITE setRadius) - Q_PROPERTY(float obscuranceLevel MEMBER obscuranceLevel WRITE setObscuranceLevel) - Q_PROPERTY(float falloffAngle MEMBER falloffAngle WRITE setFalloffAngle) - Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness WRITE setEdgeSharpness) - Q_PROPERTY(float blurDeviation MEMBER blurDeviation WRITE setBlurDeviation) - Q_PROPERTY(float numSpiralTurns MEMBER numSpiralTurns WRITE setNumSpiralTurns) - Q_PROPERTY(int numSamples MEMBER numSamples WRITE setNumSamples) + Q_PROPERTY(int resolutionLevel MEMBER resolutionLevel WRITE setResolutionLevel) + Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness WRITE setEdgeSharpness) Q_PROPERTY(int blurRadius MEMBER blurRadius WRITE setBlurRadius) + // SSAO + Q_PROPERTY(float ssaoRadius MEMBER ssaoRadius WRITE setSSAORadius) + Q_PROPERTY(float ssaoObscuranceLevel MEMBER ssaoObscuranceLevel WRITE setSSAOObscuranceLevel) + Q_PROPERTY(float ssaoFalloffAngle MEMBER ssaoFalloffAngle WRITE setSSAOFalloffAngle) + Q_PROPERTY(float ssaoNumSpiralTurns MEMBER ssaoNumSpiralTurns WRITE setSSAONumSpiralTurns) + Q_PROPERTY(int ssaoNumSamples MEMBER ssaoNumSamples WRITE setSSAONumSamples) + + // HBAO + Q_PROPERTY(float hbaoRadius MEMBER hbaoRadius WRITE setHBAORadius) + Q_PROPERTY(float hbaoObscuranceLevel MEMBER hbaoObscuranceLevel WRITE setHBAOObscuranceLevel) + Q_PROPERTY(float hbaoFalloffAngle MEMBER hbaoFalloffAngle WRITE setHBAOFalloffAngle) + Q_PROPERTY(int hbaoNumSamples MEMBER hbaoNumSamples WRITE setHBAONumSamples) + public: AmbientOcclusionEffectConfig(); const int MAX_RESOLUTION_LEVEL = 4; const int MAX_BLUR_RADIUS = 15; - void setRadius(float newRadius) { radius = std::max(0.01f, newRadius); emit dirty(); } - void setObscuranceLevel(float level) { obscuranceLevel = std::max(0.01f, level); emit dirty(); } - void setFalloffAngle(float bias) { falloffAngle = std::max(0.0f, std::min(bias, 1.0f)); emit dirty(); } - void setEdgeSharpness(float sharpness) { edgeSharpness = std::max(0.0f, (float)sharpness); emit dirty(); } - void setBlurDeviation(float deviation) { blurDeviation = std::max(0.0f, deviation); emit dirty(); } - void setNumSpiralTurns(float turns) { numSpiralTurns = std::max(0.0f, (float)turns); emit dirty(); } - void setNumSamples(int samples) { numSamples = std::max(1.0f, (float)samples); emit dirty(); } - void setResolutionLevel(int level) { resolutionLevel = std::max(0, std::min(level, MAX_RESOLUTION_LEVEL)); emit dirty(); } - void setBlurRadius(int radius) { blurRadius = std::max(0, std::min(MAX_BLUR_RADIUS, radius)); emit dirty(); } + void setEdgeSharpness(float sharpness); + void setResolutionLevel(int level); + void setBlurRadius(int radius); + + void setSSAORadius(float newRadius); + void setSSAOObscuranceLevel(float level); + void setSSAOFalloffAngle(float bias); + void setSSAONumSpiralTurns(float turns); + void setSSAONumSamples(int samples); + + void setHBAORadius(float newRadius); + void setHBAOObscuranceLevel(float level); + void setHBAOFalloffAngle(float bias); + void setHBAONumSamples(int samples); - float radius; float perspectiveScale; - float obscuranceLevel; // intensify or dim down the obscurance effect - float falloffAngle; float edgeSharpness; - float blurDeviation; - float numSpiralTurns; // defining an angle span to distribute the samples ray directions - int numSamples; - int resolutionLevel; int blurRadius; // 0 means no blurring + int resolutionLevel; + + float ssaoRadius; + float ssaoObscuranceLevel; // intensify or dim down the obscurance effect + float ssaoFalloffAngle; + float ssaoNumSpiralTurns; // defining an angle span to distribute the samples ray directions + int ssaoNumSamples; + + float hbaoRadius; + float hbaoObscuranceLevel; // intensify or dim down the obscurance effect + float hbaoFalloffAngle; + int hbaoNumSamples; + bool horizonBased; // Use horizon based AO bool ditheringEnabled; // randomize the distribution of taps per pixel, should always be true bool borderingEnabled; // avoid evaluating information from non existing pixels out of the frame, should always be true @@ -154,7 +173,7 @@ public: float getRadius() const { return _radiusInfo.x; } float getPerspectiveScale() const { return _resolutionInfo.z; } float getObscuranceLevel() const { return _radiusInfo.w; } - float getFalloffCosAngle() const { return (float)_falloffInfo.x; } + float getFalloffAngle() const { return (float)_falloffInfo.x; } float getNumSpiralTurns() const { return _sampleInfo.z; } int getNumSamples() const { return (int)_sampleInfo.x; } @@ -176,7 +195,7 @@ private: BlurParameters(); float getEdgeSharpness() const { return (float)_blurInfo.x; } - int getBlurRadius() const { return (int)_blurInfo.y; } + int getBlurRadius() const { return (int)_blurInfo.w; } }; using BlurParametersBuffer = gpu::StructBuffer; @@ -185,6 +204,7 @@ private: void updateBlurParameters(); void updateFramebufferSizes(); + void updateRandomSamples(); void updateJitterSamples(); int getDepthResolutionLevel() const; @@ -193,6 +213,7 @@ private: FrameParametersBuffer _aoFrameParametersBuffer[SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT]; BlurParametersBuffer _vblurParametersBuffer; BlurParametersBuffer _hblurParametersBuffer; + float _blurEdgeSharpness{ 0.0f }; static const gpu::PipelinePointer& getOcclusionPipeline(); static const gpu::PipelinePointer& getBilateralBlurPipeline(); diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index 59d2198daa..4917cd31e1 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -86,7 +86,7 @@ void LinearDepthFramebuffer::allocate() { const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = 5; // Point sampling of the depth, as well as the clamp to edge, are needed for the AmbientOcclusionEffect with HBAO const auto depthSamplerHalf = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP); - _halfLinearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), _halfFrameSize.x, _halfFrameSize.y, HALF_LINEAR_DEPTH_MAX_MIP_LEVEL, + _halfLinearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::HALF, gpu::RED), _halfFrameSize.x, _halfFrameSize.y, HALF_LINEAR_DEPTH_MAX_MIP_LEVEL, depthSamplerHalf); _halfNormalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _halfFrameSize.x, _halfFrameSize.y, gpu::Texture::SINGLE_MIP, diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 09c3cd3a66..2a80850eca 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -107,11 +107,14 @@ float getRadius2() { return params._radiusInfo.y; } float getInvRadius6() { + return mix(params._radiusInfo.z, 1.0, isHorizonBased()); +} +float getInvRadius2() { return params._radiusInfo.z; } float getObscuranceScaling() { - return params._radiusInfo.z * params._radiusInfo.w; + return getInvRadius6() * params._radiusInfo.w; } float isDitheringEnabled() { @@ -161,15 +164,24 @@ float getAngleDitheringWorldPos(in vec3 pixelWorldPos) { return isDitheringEnabled() * float(((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) + (3 * pixelPos.y ^ pixelPos.z + pixelPos.x * pixelPos.z)) * 10); } +float getAngleDitheringSplit() { + return isDitheringEnabled() * frameParams._angleInfo.x; +} + float getAngleDithering(in ivec2 pixelPos) { #if SSAO_USE_QUAD_SPLIT - return isDitheringEnabled() * frameParams._angleInfo.x; + return getAngleDitheringSplit(); #else // Hash function used in the AlchemyAO paper - return isDitheringEnabled() * float((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10); + return getAngleDitheringPixelPos(pixelPos); #endif } +float getAngleDitheringPixelPos(in ivec2 pixelPos) { + // Hash function used in the AlchemyAO paper + return isDitheringEnabled() * float((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10); +} + float evalDiskRadius(float Zeye, vec2 sideImageSize) { // Choose the screen-space sample radius // proportional to the projected area of the sphere @@ -413,7 +425,7 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t #define HBAO_USE_OVERHANG_HACK 0 float computeWeightForHorizon(float horizonLimit, float distanceSquared) { - return max(0.0, 1.0 - distanceSquared / getRadius2()); + return max(0.0, 1.0 - distanceSquared * getInvRadius2()); } float computeWeightedHorizon(float horizonLimit, float distanceSquared) { diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index aabc28a326..ec747062e8 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -37,13 +37,18 @@ void main(void) { // Stereo side info based on the real viewport size of this pass vec2 sideDepthSize = getDepthTextureSideSize(0); - ivec2 sideOcclusionSize = ivec2( getOcclusionSplitSideSize() ); + ivec2 sideOcclusionSize; + if (isHorizonBased()) { + sideOcclusionSize = ivec2( getOcclusionSplitSideSize() ); + } else { + sideOcclusionSize = ivec2( getOcclusionSideSize() ); + } ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideOcclusionSize.x); // From now on, fragUVPos is the UV pos in the side fragUVPos.x = mix(fragUVPos.x, fragUVPos.x * 2.0 - getStereoSide(side), isStereo()); fragUVPos = snapToTexel(fragUVPos, sideDepthSize); - + // The position and normal of the pixel fragment in Eye space vec2 deltaDepthUV = vec2(2.0) / sideDepthSize; vec3 fragPositionES = buildPosition(side, fragUVPos); @@ -58,7 +63,7 @@ void main(void) { } // Let's make noise - float randomPatternRotationAngle = getAngleDithering(fragPixelPos); + float randomPatternRotationAngle = 0.0; // Accumulate the obscurance for each samples float obscuranceSum = 0.0; @@ -66,22 +71,24 @@ void main(void) { float invNumSamples = getInvNumSamples(); if (isHorizonBased()) { + randomPatternRotationAngle = getAngleDithering(fragPixelPos); + for (int i = 0; i < numSamples; ++i) { vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); obscuranceSum += evalVisibilityHBAO(side, fragUVPos, deltaDepthUV, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); } obscuranceSum *= invNumSamples; #if HBAO_USE_COS_ANGLE - obscuranceSum *= 0.5; obscuranceSum = 1.0 - obscuranceSum * getObscuranceScaling(); #else - obscuranceSum *= 0.5; obscuranceSum = mix(1.0, obscuranceSum, getObscuranceScaling()); #endif } else { // Steps are in the depth texture resolution vec2 depthTexFragPixelPos = fragUVPos * sideDepthSize; + randomPatternRotationAngle = getAngleDitheringPixelPos(fragPixelPos) + getAngleDitheringSplit(); + for (int i = 0; i < numSamples; ++i) { vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, depthTexFragPixelPos, sideDepthSize); vec2 tapUV = fragUVPos + tap.xy * deltaDepthUV; @@ -90,7 +97,7 @@ void main(void) { obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES); } obscuranceSum *= invNumSamples; - obscuranceSum = 1.0 - obscuranceSum * obscuranceSum * getObscuranceScaling(); + obscuranceSum = 1.0 - obscuranceSum * getObscuranceScaling(); } float occlusion = clamp(obscuranceSum, 0.0, 1.0); diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index 91e385edb8..d6323c351a 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -33,11 +33,6 @@ Rectangle { Repeater { model: [ - "Radius:radius:2.0:false", - "Level:obscuranceLevel:1.0:false", - "Num Taps:numSamples:16:true", - "Taps Spiral:numSpiralTurns:10.0:false", - "Falloff Angle:falloffAngle:1.0:false", "Blur Edge Sharpness:edgeSharpness:1.0:false", "Blur Radius:blurRadius:15.0:true", "Resolution Downscale:resolutionLevel:2:true", @@ -102,5 +97,81 @@ Rectangle { } ] } + + + + TabView { + anchors.left: parent.left + anchors.right: parent.right + height: 400 + + Tab { + title: "SSAO" + + Rectangle { + color: hifi.colors.baseGray; + + Column { + spacing: 8 + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: hifi.dimensions.contentMargin.x + + Repeater { + model: [ + "Radius:ssaoRadius:2.0:false", + "Level:ssaoObscuranceLevel:1.0:false", + "Num Taps:ssaoNumSamples:64:true", + "Taps Spiral:ssaoNumSpiralTurns:10.0:false", + "Falloff Angle:ssaoFalloffAngle:1.0:false", + ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: (modelData.split(":")[3] == 'true') + config: Render.getConfig("RenderMainView.AmbientOcclusion") + property: modelData.split(":")[1] + max: modelData.split(":")[2] + min: 0.0 + height:38 + } + } + } + } + } + + Tab { + title: "HBAO" + + Rectangle { + color: hifi.colors.baseGray; + + Column { + spacing: 8 + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: hifi.dimensions.contentMargin.x + + Repeater { + model: [ + "Radius:hbaoRadius:2.0:false", + "Level:hbaoObscuranceLevel:1.0:false", + "Num Taps:hbaoNumSamples:6:true", + "Falloff Angle:hbaoFalloffAngle:1.0:false", + ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: (modelData.split(":")[3] == 'true') + config: Render.getConfig("RenderMainView.AmbientOcclusion") + property: modelData.split(":")[1] + max: modelData.split(":")[2] + min: 0.0 + height:38 + } + } + } + } + } + } + } } From 72d069325293549277197ae02e1303f8a557ca3e Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 2 Oct 2018 18:46:01 +0200 Subject: [PATCH 62/81] Clean up for stereo --- .../render-utils/src/ssao_makeOcclusion.slf | 77 ++++++++++--------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index ec747062e8..8b44fd8301 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -56,51 +56,54 @@ void main(void) { vec3 fragNormalES = buildNormal(side, fragUVPos, fragPositionES, deltaDepthUV); #endif - // Choose the screen-space sample radius - float diskPixelRadius = evalDiskRadius(fragPositionES.z, sideDepthSize); - if (isHorizonBased()) { - diskPixelRadius = min(diskPixelRadius, SSAO_HBAO_MAX_RADIUS); - } + float occlusion = 1.0; - // Let's make noise - float randomPatternRotationAngle = 0.0; - - // Accumulate the obscurance for each samples - float obscuranceSum = 0.0; - int numSamples = int(getNumSamples()); - float invNumSamples = getInvNumSamples(); - - if (isHorizonBased()) { - randomPatternRotationAngle = getAngleDithering(fragPixelPos); - - for (int i = 0; i < numSamples; ++i) { - vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); - obscuranceSum += evalVisibilityHBAO(side, fragUVPos, deltaDepthUV, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); + if (fragPositionES.z > (1.0-getPosLinearDepthFar())) { + // Choose the screen-space sample radius + float diskPixelRadius = evalDiskRadius(fragPositionES.z, sideDepthSize); + if (isHorizonBased()) { + diskPixelRadius = min(diskPixelRadius, SSAO_HBAO_MAX_RADIUS); } - obscuranceSum *= invNumSamples; + + // Let's make noise + float randomPatternRotationAngle = 0.0; + + // Accumulate the obscurance for each samples + float obscuranceSum = 0.0; + int numSamples = int(getNumSamples()); + float invNumSamples = getInvNumSamples(); + + if (isHorizonBased()) { + randomPatternRotationAngle = getAngleDithering(fragPixelPos); + + for (int i = 0; i < numSamples; ++i) { + vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); + obscuranceSum += evalVisibilityHBAO(side, fragUVPos, deltaDepthUV, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); + } + obscuranceSum *= invNumSamples; #if HBAO_USE_COS_ANGLE - obscuranceSum = 1.0 - obscuranceSum * getObscuranceScaling(); + obscuranceSum = 1.0 - obscuranceSum * getObscuranceScaling(); #else - obscuranceSum = mix(1.0, obscuranceSum, getObscuranceScaling()); + obscuranceSum = mix(1.0, obscuranceSum, getObscuranceScaling()); #endif - } else { - // Steps are in the depth texture resolution - vec2 depthTexFragPixelPos = fragUVPos * sideDepthSize; + } else { + // Steps are in the depth texture resolution + vec2 depthTexFragPixelPos = fragUVPos * sideDepthSize; - randomPatternRotationAngle = getAngleDitheringPixelPos(fragPixelPos) + getAngleDitheringSplit(); + randomPatternRotationAngle = getAngleDitheringPixelPos(fragPixelPos) + getAngleDitheringSplit(); - for (int i = 0; i < numSamples; ++i) { - vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, depthTexFragPixelPos, sideDepthSize); - vec2 tapUV = fragUVPos + tap.xy * deltaDepthUV; - vec2 tapMipZ = fetchTap(side, tapUV, tap.z); - vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, tapUV); - obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES); + for (int i = 0; i < numSamples; ++i) { + vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, depthTexFragPixelPos, sideDepthSize); + vec2 tapUV = fragUVPos + tap.xy * deltaDepthUV; + vec2 tapMipZ = fetchTap(side, tapUV, tap.z); + vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, tapUV); + obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES); + } + obscuranceSum *= invNumSamples; + obscuranceSum = 1.0 - obscuranceSum * getObscuranceScaling(); } - obscuranceSum *= invNumSamples; - obscuranceSum = 1.0 - obscuranceSum * getObscuranceScaling(); - } - float occlusion = clamp(obscuranceSum, 0.0, 1.0); - + occlusion = clamp(obscuranceSum, 0.0, 1.0); + } outFragColor = packOcclusionOutput(occlusion, fragPositionES.z, fragNormalES); } From 8ad58754dac8a79b9fb1cd6e12795174265db03d Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 3 Oct 2018 08:41:03 +0200 Subject: [PATCH 63/81] Fixed compilation on Mac, Ubuntu and Android --- .../gpu-gles/src/gpu/gles/GLESBackend.cpp | 23 +++++++++++++++++++ libraries/gpu-gles/src/gpu/gles/GLESBackend.h | 3 +++ .../src/AmbientOcclusionEffect.cpp | 18 +++++---------- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackend.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackend.cpp index b277889771..cb40b4fc9b 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackend.cpp +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackend.cpp @@ -20,6 +20,29 @@ using namespace gpu::gles; const std::string GLESBackend::GLES_VERSION { "GLES" }; +void GLESBackend::draw(GLenum mode, uint32 numVertices, uint32 startVertex) { + if (isStereo()) { +#ifdef GPU_STEREO_DRAWCALL_INSTANCED + glDrawArraysInstanced(mode, startVertex, numVertices, 2); +#else + setupStereoSide(0); + glDrawArrays(mode, startVertex, numVertices); + setupStereoSide(1); + glDrawArrays(mode, startVertex, numVertices); +#endif + _stats._DSNumTriangles += 2 * numVertices / 3; + _stats._DSNumDrawcalls += 2; + + } else { + glDrawArrays(mode, startVertex, numVertices); + _stats._DSNumTriangles += numVertices / 3; + _stats._DSNumDrawcalls++; + } + _stats._DSNumAPIDrawcalls++; + + (void)CHECK_GL_ERROR(); +} + void GLESBackend::do_draw(const Batch& batch, size_t paramOffset) { Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackend.h b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h index 56ae41da31..7f6765c129 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackend.h +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h @@ -126,6 +126,9 @@ public: }; protected: + + void draw(GLenum mode, uint32 numVertices, uint32 startVertex) override; + GLuint getFramebufferID(const FramebufferPointer& framebuffer) override; GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 9df3c86d41..92654a66e6 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -208,24 +208,24 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false), perspectiveScale{ 1.0f }, edgeSharpness{ 1.0f }, - resolutionLevel{ 2 }, blurRadius{ 4 }, + resolutionLevel{ 2 }, ssaoRadius{ 1.0f }, ssaoObscuranceLevel{ 0.4f }, ssaoFalloffAngle{ 0.1f }, - ssaoNumSamples{ 32 }, ssaoNumSpiralTurns{ 7.0f }, + ssaoNumSamples{ 32 }, hbaoRadius{ 0.7f }, hbaoObscuranceLevel{ 0.75f }, hbaoFalloffAngle{ 0.3f }, hbaoNumSamples{ 1 }, + horizonBased{ false }, ditheringEnabled{ true }, borderingEnabled{ true }, fetchMipsEnabled{ true }, - horizonBased{ false }, jitterEnabled{ false }{ } @@ -446,9 +446,9 @@ void AmbientOcclusionEffect::updateRandomSamples() { if (_aoParametersBuffer->isHorizonBased()) { const int B = 3; const float invB = 1.0f / (float)B; - float sampleScale = 2.0f * M_PI / _aoParametersBuffer->getNumSamples(); + float sampleScale = float(2.0f * M_PI / _aoParametersBuffer->getNumSamples()); - for (int i = 0; i < _randomSamples.size(); i++) { + for (auto i = 0; i < _randomSamples.size(); i++) { int index = i + 1; // Indices start at 1, not 0 float f = 1.0f; float r = 0.0f; @@ -461,7 +461,7 @@ void AmbientOcclusionEffect::updateRandomSamples() { _randomSamples[i] = r * sampleScale; } } else { - for (int i = 0; i < _randomSamples.size(); i++) { + for (auto i = 0; i < _randomSamples.size(); i++) { _randomSamples[i] = randFloat() * 2.0f * M_PI; } } @@ -499,7 +499,6 @@ void AmbientOcclusionEffect::updateFramebufferSizes() { const int resolutionLevel = _aoParametersBuffer.get().getResolutionLevel(); const int depthResolutionLevel = getDepthResolutionLevel(); - const auto occlusionDepthFrameSize = sourceFrameSideSize >> depthResolutionLevel; const auto occlusionFrameSize = sourceFrameSideSize >> resolutionLevel; auto normalTextureSize = _framebuffer->getNormalTexture()->getDimensions(); @@ -602,10 +601,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte const auto& linearDepthFramebuffer = inputs.get2(); const int resolutionLevel = _aoParametersBuffer->getResolutionLevel(); - const auto resolutionScale = powf(0.5f, resolutionLevel); - const auto depthResolutionLevel = getDepthResolutionLevel(); - const auto depthResolutionScale = powf(0.5f, depthResolutionLevel); const auto isHorizonBased = _aoParametersBuffer->isHorizonBased(); auto fullResDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); @@ -638,7 +634,6 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte outputs.edit0() = _framebuffer; outputs.edit1() = _aoParametersBuffer; - auto framebufferSize = _framebuffer->getSourceFrameSize(); auto occlusionPipeline = getOcclusionPipeline(); auto bilateralBlurPipeline = getBilateralBlurPipeline(); auto mipCreationPipeline = getMipCreationPipeline(); @@ -651,7 +646,6 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte auto splitSize = glm::ivec2(_framebuffer->getOcclusionSplitTexture()->getDimensions()); auto splitViewport = glm::ivec4{ 0, 0, splitSize.x, splitSize.y }; #endif - auto occlusionDepthSize = glm::ivec2(occlusionDepthTexture->getDimensions()); // Update sample rotation if (_isJitterEnabled) { From b131de9e5104445be43e594b057c4f5f4fa35a1b Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 3 Oct 2018 08:43:51 +0200 Subject: [PATCH 64/81] Added some comments --- libraries/render-utils/src/SurfaceGeometryPass.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index 4917cd31e1..83595b5a64 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -86,6 +86,7 @@ void LinearDepthFramebuffer::allocate() { const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = 5; // Point sampling of the depth, as well as the clamp to edge, are needed for the AmbientOcclusionEffect with HBAO const auto depthSamplerHalf = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP); + // The depth format here is half float as it increases performance in the AmbientOcclusion. But it might be needed elsewhere... _halfLinearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::HALF, gpu::RED), _halfFrameSize.x, _halfFrameSize.y, HALF_LINEAR_DEPTH_MAX_MIP_LEVEL, depthSamplerHalf); From 7124474b0e931d38f341c9d79b0a74c8d2815bc1 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 3 Oct 2018 09:33:40 +0200 Subject: [PATCH 65/81] Fix ubuntu compilation --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 92654a66e6..42f9673294 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -446,9 +446,9 @@ void AmbientOcclusionEffect::updateRandomSamples() { if (_aoParametersBuffer->isHorizonBased()) { const int B = 3; const float invB = 1.0f / (float)B; - float sampleScale = float(2.0f * M_PI / _aoParametersBuffer->getNumSamples()); + float sampleScale = float(2.0 * M_PI / double(_aoParametersBuffer->getNumSamples())); - for (auto i = 0; i < _randomSamples.size(); i++) { + for (size_t i = 0; i < _randomSamples.size(); i++) { int index = i + 1; // Indices start at 1, not 0 float f = 1.0f; float r = 0.0f; @@ -461,8 +461,8 @@ void AmbientOcclusionEffect::updateRandomSamples() { _randomSamples[i] = r * sampleScale; } } else { - for (auto i = 0; i < _randomSamples.size(); i++) { - _randomSamples[i] = randFloat() * 2.0f * M_PI; + for (size_t i = 0; i < _randomSamples.size(); i++) { + _randomSamples[i] = randFloat() * float(2.0 * M_PI); } } } From fe15063459f08706435797c0ae1c644023102568 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 3 Oct 2018 09:34:31 +0200 Subject: [PATCH 66/81] Another compilation fix --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 42f9673294..d5c38ca47b 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -449,7 +449,7 @@ void AmbientOcclusionEffect::updateRandomSamples() { float sampleScale = float(2.0 * M_PI / double(_aoParametersBuffer->getNumSamples())); for (size_t i = 0; i < _randomSamples.size(); i++) { - int index = i + 1; // Indices start at 1, not 0 + auto index = i + 1; // Indices start at 1, not 0 float f = 1.0f; float r = 0.0f; From 1322302b6b995275f7bd4ffa36d1e0c29639cb8d Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 3 Oct 2018 14:17:24 +0200 Subject: [PATCH 67/81] Default parameter tweaking --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index d5c38ca47b..0e380b6c02 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -213,7 +213,7 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : ssaoRadius{ 1.0f }, ssaoObscuranceLevel{ 0.4f }, - ssaoFalloffAngle{ 0.1f }, + ssaoFalloffAngle{ 0.15f }, ssaoNumSpiralTurns{ 7.0f }, ssaoNumSamples{ 32 }, From aa64e51281ed5bc1c52195b03b9f35ac96b0c2d7 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 24 Oct 2018 11:04:32 +0200 Subject: [PATCH 68/81] Fixed shaders for GLSL 4.1 --- libraries/render-utils/src/ssao.slh | 60 ++++++++---- .../render-utils/src/ssao_debugOcclusion.slf | 93 ++----------------- libraries/render-utils/src/ssao_mip_depth.slf | 5 +- 3 files changed, 49 insertions(+), 109 deletions(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 7af0d0a7d6..4fd5e1fd5f 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -285,20 +285,15 @@ float getZEyeAtUV(vec2 texCoord, int level) { return -textureLod(depthPyramidTex, texCoord, level).x; } -float getZEyeAtUV(vec2 texCoord, int level, ivec2 texelOffset) { - return -textureLodOffset(depthPyramidTex, texCoord, level, texelOffset).x; -} +<@func getZEyeAtUVOffset(texCoord, level, texelOffset)@> +-textureLodOffset(depthPyramidTex, <$texCoord$>, <$level$>, <$texelOffset$>).x; +<@endfunc@> float getZEyeAtUV(ivec4 side, vec2 texCoord, int level) { texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); return getZEyeAtUV(texCoord, level); } -float getZEyeAtUV(ivec4 side, vec2 texCoord, int level, ivec2 texelOffset) { - texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); - return getZEyeAtUV(texCoord, level, texelOffset); -} - vec3 packNormal(vec3 normal) { vec3 absNormal = abs(normal); return 0.5 + normal * 0.5 / max(absNormal.x, max(absNormal.y, absNormal.z)); @@ -335,7 +330,7 @@ vec2 fetchTap(ivec4 side, vec2 tapUV, float tapRadius) { int mipLevel = evalMipFromRadius(tapRadius * float(doFetchMips())); vec2 fetchUV = clamp(tapUV, vec2(0), vec2(1)); - fetchUV = mix(fetchUV, vec2((fetchUV.x + getStereoSide(side)) * 0.5, fetchUV.y), isStereo()); + fetchUV = isStereo() ? vec2((fetchUV.x + getStereoSide(side)) * 0.5, fetchUV.y) : fetchUV; vec2 P; P.x = float(mipLevel); @@ -348,10 +343,12 @@ vec3 buildPosition(ivec4 side, vec2 fragUVPos) { return evalEyePositionFromZeye(side.x, Zeye, fragUVPos); } -vec3 buildPosition(ivec4 side, vec2 fragUVPos, ivec2 texelOffset, vec2 deltaUV) { - float Zeye = getZEyeAtUV(side, fragUVPos, 0, texelOffset); - return evalEyePositionFromZeye(side.x, Zeye, fragUVPos + texelOffset*deltaUV); +<@func buildPositionOffset(side, fragUVPos, sideFragUVPos, texelOffset, deltaUV, position)@> +{ + float Zeye = <$getZEyeAtUVOffset($sideFragUVPos$, 0, $texelOffset$)$> + <$position$> = evalEyePositionFromZeye(<$side$>.x, Zeye, <$fragUVPos$> + <$texelOffset$>*<$deltaUV$>); } +<@endfunc@> vec3 getMinDelta(vec3 centralPoint, vec3 offsetPointPos, vec3 offsetPointNeg) { vec3 delta0 = offsetPointPos - centralPoint; @@ -362,11 +359,25 @@ vec3 getMinDelta(vec3 centralPoint, vec3 offsetPointPos, vec3 offsetPointNeg) { return sqrLength0 < sqrLength1 ? delta0 : delta1; } +const ivec2 UV_RIGHT = ivec2(1,0); +const ivec2 UV_LEFT = ivec2(-1,0); +const ivec2 UV_TOP = ivec2(0,1); +const ivec2 UV_BOTTOM = ivec2(0,-1); + vec3 buildNormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec2 deltaDepthUV) { - vec3 fragPositionDxPos = buildPosition(side, fragUVPos, ivec2(1,0), deltaDepthUV); - vec3 fragPositionDxNeg = buildPosition(side, fragUVPos, ivec2(-1,0), deltaDepthUV); - vec3 fragPositionDyPos = buildPosition(side, fragUVPos, ivec2(0,1), deltaDepthUV); - vec3 fragPositionDyNeg = buildPosition(side, fragUVPos, ivec2(0,-1), deltaDepthUV); + vec2 sideUVPos = fragUVPos; + + sideUVPos.x = mix(sideUVPos.x, (sideUVPos.x + getStereoSide(side)) * 0.5, isStereo()); + + vec3 fragPositionDxPos; + vec3 fragPositionDxNeg; + vec3 fragPositionDyPos; + vec3 fragPositionDyNeg; + + <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_RIGHT, deltaDepthUV, fragPositionDxPos)$> + <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_LEFT, deltaDepthUV, fragPositionDxNeg)$> + <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_TOP, deltaDepthUV, fragPositionDyPos)$> + <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_BOTTOM, deltaDepthUV, fragPositionDyNeg)$> vec3 fragDeltaDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg); vec3 fragDeltaDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg); @@ -376,10 +387,19 @@ vec3 buildNormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec2 deltaDepthU void buildTangentBinormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec3 fragNormal, vec2 deltaDepthUV, out vec3 fragTangent, out vec3 fragBinormal) { - vec3 fragPositionDxPos = buildPosition(side, fragUVPos, ivec2(1,0), deltaDepthUV); - vec3 fragPositionDxNeg = buildPosition(side, fragUVPos, ivec2(-1,0), deltaDepthUV); - vec3 fragPositionDyPos = buildPosition(side, fragUVPos, ivec2(0,1), deltaDepthUV); - vec3 fragPositionDyNeg = buildPosition(side, fragUVPos, ivec2(0,-1), deltaDepthUV); + vec2 sideUVPos = fragUVPos; + + sideUVPos.x = mix(sideUVPos.x, (sideUVPos.x + getStereoSide(side)) * 0.5, isStereo()); + + vec3 fragPositionDxPos; + vec3 fragPositionDxNeg; + vec3 fragPositionDyPos; + vec3 fragPositionDyNeg; + + <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_RIGHT, deltaDepthUV, fragPositionDxPos)$> + <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_LEFT, deltaDepthUV, fragPositionDxNeg)$> + <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_TOP, deltaDepthUV, fragPositionDyPos)$> + <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_BOTTOM, deltaDepthUV, fragPositionDyNeg)$> vec3 fragDeltaDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg); vec3 fragDeltaDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg); diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf index 52929d65cd..75e3ed5194 100644 --- a/libraries/render-utils/src/ssao_debugOcclusion.slf +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -37,96 +37,15 @@ vec2 getDebugCursorTexcoord(){ layout(location=0) out vec4 outFragColor; void main(void) { - vec2 imageSize = getStereoSideSize(getResolutionLevel()); - - // In debug adjust the correct frag pixel based on base resolution - vec2 fragCoord = gl_FragCoord.xy; - if (getResolutionLevel() > 0) { - fragCoord /= float (1 << getResolutionLevel()); - } - + // Stereo side info based on the real viewport size of this pass + vec2 sideDepthSize = getDepthTextureSideSize(0); // Pixel Debugged vec2 cursorUV = getDebugCursorTexcoord(); - vec2 cursorPixelPos = cursorUV * imageSize; + vec2 cursorPixelPos = cursorUV * sideDepthSize; - ivec2 ssC = ivec2(cursorPixelPos); - - // Fetch the z under the pixel (stereo or not) - float Zeye = getZEyeAtPixel(ssC, 0); + ivec2 fragUVPos = ivec2(cursorPixelPos); - // Stereo side info - ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel()); + // TODO - // From now on, ssC is the pixel pos in the side - ssC.x -= side.y; - vec2 fragPos = (vec2(ssC) + vec2(0.5)) / imageSize; - - // The position and normal of the pixel fragment in Eye space - vec3 Cp = evalEyePositionFromZeye(side.x, Zeye, fragPos); - vec3 Cn = evalEyeNormal(Cp); - - // Choose the screen-space sample radius - float ssDiskRadius = evalDiskRadius(Cp.z, imageSize); - - vec2 fragToCursor = cursorPixelPos - fragCoord.xy; - if (dot(fragToCursor,fragToCursor) > ssDiskRadius * ssDiskRadius) { - discard; - } - - // Let's make noise - //float randomPatternRotationAngle = getAngleDithering(ssC); - vec3 wCp = (getViewInverse() * vec4(Cp, 1.0)).xyz; - float randomPatternRotationAngle = getAngleDitheringWorldPos(wCp); - - - // Accumulate the Obscurance for each samples - float sum = 0.0; - float keepTapRadius = 1.0; - int keptMip = -1; - bool keep = false; - int sampleCount = int(getNumSamples()); - for (int i = 0; i < sampleCount; ++i) { - vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, ssDiskRadius, cursorPixelPos, imageSize); - - // The occluding point in camera space - vec2 fragToTap = vec2(ssC) + tap.xy - fragCoord.xy; - if (dot(fragToTap,fragToTap) < keepTapRadius) { - keep = true; - keptMip = evalMipFromRadius(tap.z * float(doFetchMips())); - } - - vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize); - - vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); - - sum += float(tap.z > 0.0) * evalVisibilitySSAO(Cp, Cn, Q); - } - - - float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples()); - - - - outFragColor = packOcclusionOutput(A, Cp.z, vec3(0,0,1)); - - if ((dot(fragToCursor,fragToCursor) < (100.0 * keepTapRadius * keepTapRadius) )) { - // outFragColor = vec4(vec3(A), 1.0); - outFragColor = vec4(vec3(A), 1.0); - return; - } - - if (!keep) { - outFragColor = vec4(0.1); - } else { - outFragColor.rgb = colorWheel(float(keptMip)/float(MAX_MIP_LEVEL)); - } + outFragColor = packOcclusionOutput(0.0, 0.0, vec3(0.0, 0.0, 1.0)); } diff --git a/libraries/render-utils/src/ssao_mip_depth.slf b/libraries/render-utils/src/ssao_mip_depth.slf index e83e017065..92b9012556 100644 --- a/libraries/render-utils/src/ssao_mip_depth.slf +++ b/libraries/render-utils/src/ssao_mip_depth.slf @@ -15,8 +15,9 @@ LAYOUT(binding=GPU_TEXTURE_MIP_CREATION_INPUT) uniform sampler2D depthTexture; -in vec2 varTexCoord0; -out vec4 outFragColor; +layout(location=0) in vec2 varTexCoord0; + +layout(location=0) out vec4 outFragColor; void main(void) { vec4 depths = textureGather(depthTexture, varTexCoord0); From 7e93d91bfa841cb4b35cba92eb58aef8f9bc7fb6 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Nov 2018 09:29:02 +0100 Subject: [PATCH 69/81] Fixed android shader compilation --- libraries/render-utils/src/ssao.slh | 18 +++++------------- .../render-utils/src/ssao_bilateralBlur.slf | 6 +++--- .../render-utils/src/ssao_makeOcclusion.slf | 2 +- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 4fd5e1fd5f..bd2e29d04d 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -277,11 +277,7 @@ vec2 getStereoSideSizeRoundUp(int resolutionLevel) { return vec2((fullRes + resolutionDivisor - 1) / resolutionDivisor); } -float getZEyeAtPixel(ivec2 pixel, int level) { - return -texelFetch(depthPyramidTex, pixel, level).x; -} - -float getZEyeAtUV(vec2 texCoord, int level) { +float getZEyeAtUV(vec2 texCoord, float level) { return -textureLod(depthPyramidTex, texCoord, level).x; } @@ -289,7 +285,7 @@ float getZEyeAtUV(vec2 texCoord, int level) { -textureLodOffset(depthPyramidTex, <$texCoord$>, <$level$>, <$texelOffset$>).x; <@endfunc@> -float getZEyeAtUV(ivec4 side, vec2 texCoord, int level) { +float getZEyeAtUV(ivec4 side, vec2 texCoord, float level) { texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); return getZEyeAtUV(texCoord, level); } @@ -303,19 +299,15 @@ vec3 unpackNormal(vec3 packedNormal) { return normalize(packedNormal*2.0 - 1.0); } -vec3 getNormalEyeAtUV(vec2 texCoord, int level) { +vec3 getNormalEyeAtUV(vec2 texCoord, float level) { return unpackNormal(textureLod(normalTex, texCoord, level).xyz); } -vec3 getNormalEyeAtUV(ivec4 side, vec2 texCoord, int level) { +vec3 getNormalEyeAtUV(ivec4 side, vec2 texCoord, float level) { texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); return getNormalEyeAtUV(texCoord, level); } -vec3 getNormalEyeAtPixel(ivec2 pixel, int level) { - return unpackNormal(texelFetch(normalTex, pixel, level).xyz); -} - vec2 snapToTexel(vec2 uv, vec2 pixelSize) { return (floor(uv * pixelSize - 0.5) + 0.5) / pixelSize; } @@ -339,7 +331,7 @@ vec2 fetchTap(ivec4 side, vec2 tapUV, float tapRadius) { } vec3 buildPosition(ivec4 side, vec2 fragUVPos) { - float Zeye = getZEyeAtUV(side, fragUVPos, 0); + float Zeye = getZEyeAtUV(side, fragUVPos, 0.0); return evalEyePositionFromZeye(side.x, Zeye, fragUVPos); } diff --git a/libraries/render-utils/src/ssao_bilateralBlur.slf b/libraries/render-utils/src/ssao_bilateralBlur.slf index a68c22b5ef..cf13065555 100644 --- a/libraries/render-utils/src/ssao_bilateralBlur.slf +++ b/libraries/render-utils/src/ssao_bilateralBlur.slf @@ -44,7 +44,7 @@ int getBlurRadius() { vec4 fetchOcclusionPacked(ivec4 side, vec2 texCoord) { texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side) * getBlurOcclusionUVLimit().x) * 0.5, isStereo()); - return textureLod(occlusionMap, texCoord, 0); + return textureLod(occlusionMap, texCoord, 0.0); } float evalBlurCoefficient(vec3 blurScales, float radialDistance, float zDistance, float normalDistance) { @@ -81,10 +81,10 @@ vec4 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 dept // Stereo side info ivec4 side = getStereoSideInfo(destPixelCoord.x, 0); - float fragDepth = getZEyeAtUV(depthTexCoord, 0); + float fragDepth = getZEyeAtUV(depthTexCoord, 0.0); float fragDepthKey = CSZToDepthKey(fragDepth); #if SSAO_BILATERAL_BLUR_USE_NORMAL - vec3 fragNormal = getNormalEyeAtUV(depthTexCoord, 0); + vec3 fragNormal = getNormalEyeAtUV(depthTexCoord, 0.0); #else vec3 fragNormal = vec3(0, 0, 1); #endif diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 8b44fd8301..cc161d7323 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -32,7 +32,7 @@ void main(void) { vec2 fragUVPos = varTexCoord0; #if SSAO_USE_QUAD_SPLIT - vec3 fragNormalES = getNormalEyeAtUV(fragUVPos, 0); + vec3 fragNormalES = getNormalEyeAtUV(fragUVPos, 0.0); #endif // Stereo side info based on the real viewport size of this pass From c79c403a52ac6e86b19b0210042d1edf715717bd Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Nov 2018 10:47:24 +0100 Subject: [PATCH 70/81] More android shader compilation fixes --- libraries/render-utils/src/ssao.slh | 38 ++++++++++--------- .../render-utils/src/ssao_bilateralBlur.slf | 4 +- .../render-utils/src/ssao_buildNormals.slf | 2 +- .../render-utils/src/ssao_makeOcclusion.slf | 3 +- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index bd2e29d04d..248a9f930e 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -253,6 +253,14 @@ vec3 getTapLocationClampedSSAO(int sampleNumber, float spinAngle, float outerRad LAYOUT(binding=RENDER_UTILS_TEXTURE_SSAO_DEPTH) uniform sampler2D depthPyramidTex; LAYOUT(binding=RENDER_UTILS_TEXTURE_SSAO_NORMAL) uniform sampler2D normalTex; +vec2 getFramebufferUVFromSideUV(ivec4 side, vec2 uv) { + return isStereo() ? vec2((uv.x + float(getStereoSide(side))) * 0.5, uv.y) : uv; +} + +vec2 getSideUVFromFramebufferUV(ivec4 side, vec2 uv) { + return isStereo() ? vec2(uv.x * 2.0 - float(getStereoSide(side)), uv.y) : uv; +} + ivec2 getDepthTextureSize(int level) { return textureSize(depthPyramidTex, level); } @@ -286,7 +294,7 @@ float getZEyeAtUV(vec2 texCoord, float level) { <@endfunc@> float getZEyeAtUV(ivec4 side, vec2 texCoord, float level) { - texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); + texCoord = getFramebufferUVFromSideUV(side, texCoord); return getZEyeAtUV(texCoord, level); } @@ -304,7 +312,7 @@ vec3 getNormalEyeAtUV(vec2 texCoord, float level) { } vec3 getNormalEyeAtUV(ivec4 side, vec2 texCoord, float level) { - texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); + texCoord = getFramebufferUVFromSideUV(side, texCoord); return getNormalEyeAtUV(texCoord, level); } @@ -322,7 +330,7 @@ vec2 fetchTap(ivec4 side, vec2 tapUV, float tapRadius) { int mipLevel = evalMipFromRadius(tapRadius * float(doFetchMips())); vec2 fetchUV = clamp(tapUV, vec2(0), vec2(1)); - fetchUV = isStereo() ? vec2((fetchUV.x + getStereoSide(side)) * 0.5, fetchUV.y) : fetchUV; + fetchUV = getFramebufferUVFromSideUV(side, fetchUV); vec2 P; P.x = float(mipLevel); @@ -357,19 +365,17 @@ const ivec2 UV_TOP = ivec2(0,1); const ivec2 UV_BOTTOM = ivec2(0,-1); vec3 buildNormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec2 deltaDepthUV) { - vec2 sideUVPos = fragUVPos; - - sideUVPos.x = mix(sideUVPos.x, (sideUVPos.x + getStereoSide(side)) * 0.5, isStereo()); + vec2 fullUVPos = getFramebufferUVFromSideUV(side, fragUVPos); vec3 fragPositionDxPos; vec3 fragPositionDxNeg; vec3 fragPositionDyPos; vec3 fragPositionDyNeg; - <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_RIGHT, deltaDepthUV, fragPositionDxPos)$> - <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_LEFT, deltaDepthUV, fragPositionDxNeg)$> - <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_TOP, deltaDepthUV, fragPositionDyPos)$> - <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_BOTTOM, deltaDepthUV, fragPositionDyNeg)$> + <$buildPositionOffset(side, fragUVPos, fullUVPos, UV_RIGHT, deltaDepthUV, fragPositionDxPos)$> + <$buildPositionOffset(side, fragUVPos, fullUVPos, UV_LEFT, deltaDepthUV, fragPositionDxNeg)$> + <$buildPositionOffset(side, fragUVPos, fullUVPos, UV_TOP, deltaDepthUV, fragPositionDyPos)$> + <$buildPositionOffset(side, fragUVPos, fullUVPos, UV_BOTTOM, deltaDepthUV, fragPositionDyNeg)$> vec3 fragDeltaDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg); vec3 fragDeltaDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg); @@ -379,19 +385,17 @@ vec3 buildNormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec2 deltaDepthU void buildTangentBinormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec3 fragNormal, vec2 deltaDepthUV, out vec3 fragTangent, out vec3 fragBinormal) { - vec2 sideUVPos = fragUVPos; - - sideUVPos.x = mix(sideUVPos.x, (sideUVPos.x + getStereoSide(side)) * 0.5, isStereo()); + vec2 fullUVPos = getFramebufferUVFromSideUV(side, fragUVPos); vec3 fragPositionDxPos; vec3 fragPositionDxNeg; vec3 fragPositionDyPos; vec3 fragPositionDyNeg; - <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_RIGHT, deltaDepthUV, fragPositionDxPos)$> - <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_LEFT, deltaDepthUV, fragPositionDxNeg)$> - <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_TOP, deltaDepthUV, fragPositionDyPos)$> - <$buildPositionOffset(side, fragUVPos, sideUVPos, UV_BOTTOM, deltaDepthUV, fragPositionDyNeg)$> + <$buildPositionOffset(side, fragUVPos, fullUVPos, UV_RIGHT, deltaDepthUV, fragPositionDxPos)$> + <$buildPositionOffset(side, fragUVPos, fullUVPos, UV_LEFT, deltaDepthUV, fragPositionDxNeg)$> + <$buildPositionOffset(side, fragUVPos, fullUVPos, UV_TOP, deltaDepthUV, fragPositionDyPos)$> + <$buildPositionOffset(side, fragUVPos, fullUVPos, UV_BOTTOM, deltaDepthUV, fragPositionDyNeg)$> vec3 fragDeltaDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg); vec3 fragDeltaDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg); diff --git a/libraries/render-utils/src/ssao_bilateralBlur.slf b/libraries/render-utils/src/ssao_bilateralBlur.slf index cf13065555..c392f79322 100644 --- a/libraries/render-utils/src/ssao_bilateralBlur.slf +++ b/libraries/render-utils/src/ssao_bilateralBlur.slf @@ -43,7 +43,7 @@ int getBlurRadius() { } vec4 fetchOcclusionPacked(ivec4 side, vec2 texCoord) { - texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side) * getBlurOcclusionUVLimit().x) * 0.5, isStereo()); + texCoord.x = isStereo() ? (texCoord.x + float(getStereoSide(side)) * getBlurOcclusionUVLimit().x) * 0.5 : texCoord.x; return textureLod(occlusionMap, texCoord, 0.0); } @@ -96,7 +96,7 @@ vec4 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 dept int r; // From now on, occlusionTexCoord is the UV pos in the side - float sideTexCoord = occlusionTexCoord.x * 2.0 - getStereoSide(side) * getBlurOcclusionUVLimit().x; + float sideTexCoord = occlusionTexCoord.x * 2.0 - float(getStereoSide(side)) * getBlurOcclusionUVLimit().x; occlusionTexCoord.x = mix(occlusionTexCoord.x, sideTexCoord, isStereo()); occlusionTexCoord -= getBlurOcclusionAxis() * blurRadius; diff --git a/libraries/render-utils/src/ssao_buildNormals.slf b/libraries/render-utils/src/ssao_buildNormals.slf index 0dea63ae14..2f205119d9 100644 --- a/libraries/render-utils/src/ssao_buildNormals.slf +++ b/libraries/render-utils/src/ssao_buildNormals.slf @@ -32,7 +32,7 @@ void main(void) { vec2 deltaDepthUV = vec2(1.0) / vec2(getDepthTextureSideSize(0)); // From now on, fragUVPos is the UV pos in the side - fragUVPos.x = mix(fragUVPos.x, fragUVPos.x * 2.0 - getStereoSide(side), isStereo()); + fragUVPos = getSideUVFromFramebufferUV(side, fragUVPos); // The position and normal of the pixel fragment in Eye space vec3 fragPositionES = buildPosition(side, fragUVPos); diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index cc161d7323..5dfa879c69 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -45,8 +45,7 @@ void main(void) { } ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideOcclusionSize.x); // From now on, fragUVPos is the UV pos in the side - fragUVPos.x = mix(fragUVPos.x, fragUVPos.x * 2.0 - getStereoSide(side), isStereo()); - + fragUVPos = getSideUVFromFramebufferUV(side, fragUVPos); fragUVPos = snapToTexel(fragUVPos, sideDepthSize); // The position and normal of the pixel fragment in Eye space From 851cfff96006174b2efb49191eefb82eb0d57cf6 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Nov 2018 11:06:28 +0100 Subject: [PATCH 71/81] Again, android shader compilatio fix --- libraries/render-utils/src/ssao.slh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 248a9f930e..e942c15002 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -345,7 +345,7 @@ vec3 buildPosition(ivec4 side, vec2 fragUVPos) { <@func buildPositionOffset(side, fragUVPos, sideFragUVPos, texelOffset, deltaUV, position)@> { - float Zeye = <$getZEyeAtUVOffset($sideFragUVPos$, 0, $texelOffset$)$> + float Zeye = <$getZEyeAtUVOffset($sideFragUVPos$, 0.0, $texelOffset$)$> <$position$> = evalEyePositionFromZeye(<$side$>.x, Zeye, <$fragUVPos$> + <$texelOffset$>*<$deltaUV$>); } <@endfunc@> From 05ac2fccb6714557a869cab9d697b4ce5dca3d24 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Nov 2018 11:24:46 +0100 Subject: [PATCH 72/81] Still android fixes --- libraries/render-utils/src/ssao.slh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index e942c15002..1b73c71ed5 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -346,7 +346,7 @@ vec3 buildPosition(ivec4 side, vec2 fragUVPos) { <@func buildPositionOffset(side, fragUVPos, sideFragUVPos, texelOffset, deltaUV, position)@> { float Zeye = <$getZEyeAtUVOffset($sideFragUVPos$, 0.0, $texelOffset$)$> - <$position$> = evalEyePositionFromZeye(<$side$>.x, Zeye, <$fragUVPos$> + <$texelOffset$>*<$deltaUV$>); + <$position$> = evalEyePositionFromZeye(<$side$>.x, Zeye, <$fragUVPos$> + vec2(<$texelOffset$>)*<$deltaUV$>); } <@endfunc@> From de2f1c52ccb2f2f145085e38e3d5ff04eb6bad8e Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Nov 2018 11:44:47 +0100 Subject: [PATCH 73/81] Another android shader compilation fix --- libraries/render-utils/src/ssao.slh | 4 ++-- libraries/render-utils/src/ssao_bilateralBlur.slf | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 1b73c71ed5..64a279c578 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -26,7 +26,7 @@ vec4 packOcclusionOutput(float occlusion, float depth, vec3 eyeNormal) { return vec4(occlusion, depth, eyeNormal.xy / eyeNormal.z); #else // Round to the nearest 1/256.0 - depth *= 256; + depth *= 256.0; float temp = floor(depth); return vec4(occlusion, temp * (1.0 / 256.0), depth - temp, 0.0); #endif @@ -45,7 +45,7 @@ void unpackOcclusionOutput(vec4 raw, out UnpackedOcclusion result) { result.normal = normalize(vec3(raw.zw, 1.0)); #else result.depth = (raw.y + raw.z / 256.0); - result.normal = vec3(0,0,1); + result.normal = vec3(0.0, 0.0, 1.0); #endif } diff --git a/libraries/render-utils/src/ssao_bilateralBlur.slf b/libraries/render-utils/src/ssao_bilateralBlur.slf index c392f79322..3d8fe531bf 100644 --- a/libraries/render-utils/src/ssao_bilateralBlur.slf +++ b/libraries/render-utils/src/ssao_bilateralBlur.slf @@ -86,7 +86,7 @@ vec4 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 dept #if SSAO_BILATERAL_BLUR_USE_NORMAL vec3 fragNormal = getNormalEyeAtUV(depthTexCoord, 0.0); #else - vec3 fragNormal = vec3(0, 0, 1); + vec3 fragNormal = vec3(0.0, 0.0, 1.0); #endif vec2 weightedSums = vec2(0.0); From cd89ce538833ef167d5d735539112d1695951023 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Nov 2018 12:07:17 +0100 Subject: [PATCH 74/81] Another stupid android shader compilation error fix --- libraries/render-utils/src/ssao_bilateralBlur.slf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/ssao_bilateralBlur.slf b/libraries/render-utils/src/ssao_bilateralBlur.slf index 3d8fe531bf..f9fb7288a5 100644 --- a/libraries/render-utils/src/ssao_bilateralBlur.slf +++ b/libraries/render-utils/src/ssao_bilateralBlur.slf @@ -72,7 +72,7 @@ vec2 evalTapWeightedValue(vec3 blurScales, ivec4 side, int r, vec2 occlusionTexC #else float normalDistance = 0.0; #endif - float weight = evalBlurCoefficient(blurScales, abs(r), zDistance, normalDistance); + float weight = evalBlurCoefficient(blurScales, float(abs(r)), zDistance, normalDistance); return vec2(tap.occlusion * weight, weight); } From 40b7b42f5bc4657c33e6d9854a06c350ff150b36 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Nov 2018 12:29:01 +0100 Subject: [PATCH 75/81] Bis --- libraries/render-utils/src/ssao_bilateralBlur.slf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/ssao_bilateralBlur.slf b/libraries/render-utils/src/ssao_bilateralBlur.slf index f9fb7288a5..52e7356e85 100644 --- a/libraries/render-utils/src/ssao_bilateralBlur.slf +++ b/libraries/render-utils/src/ssao_bilateralBlur.slf @@ -99,7 +99,7 @@ vec4 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 dept float sideTexCoord = occlusionTexCoord.x * 2.0 - float(getStereoSide(side)) * getBlurOcclusionUVLimit().x; occlusionTexCoord.x = mix(occlusionTexCoord.x, sideTexCoord, isStereo()); - occlusionTexCoord -= getBlurOcclusionAxis() * blurRadius; + occlusionTexCoord -= getBlurOcclusionAxis() * float(blurRadius); // negative side first for (r = -blurRadius; r <= -1; r++) { From 09b26db6507dbbb6a5862f4a901db03b7e68fb97 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Nov 2018 13:19:42 +0100 Subject: [PATCH 76/81] Shader fix for android... --- libraries/render-utils/src/ssao.slh | 18 +++++------------- .../render-utils/src/ssao_buildNormals.slf | 2 +- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 64a279c578..af7f8029b8 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -261,22 +261,14 @@ vec2 getSideUVFromFramebufferUV(ivec4 side, vec2 uv) { return isStereo() ? vec2(uv.x * 2.0 - float(getStereoSide(side)), uv.y) : uv; } -ivec2 getDepthTextureSize(int level) { - return textureSize(depthPyramidTex, level); -} -ivec2 getDepthTextureSideSize(int level) { - ivec2 size = getDepthTextureSize(level); - size.x >>= int(isStereo()) & 1; - return size; +vec2 getDepthTextureSize(int level) { + return vec2(textureSize(depthPyramidTex, level)); } -ivec2 getNormalTextureSize(int level) { - return textureSize(normalTex, level); -} -ivec2 getNormalTextureSideSize(int level) { - ivec2 size = getNormalTextureSize(level); +vec2 getDepthTextureSideSize(int level) { + ivec2 size = textureSize(depthPyramidTex, level); size.x >>= int(isStereo()) & 1; - return size; + return vec2(size); } vec2 getStereoSideSizeRoundUp(int resolutionLevel) { diff --git a/libraries/render-utils/src/ssao_buildNormals.slf b/libraries/render-utils/src/ssao_buildNormals.slf index 2f205119d9..0a733ff451 100644 --- a/libraries/render-utils/src/ssao_buildNormals.slf +++ b/libraries/render-utils/src/ssao_buildNormals.slf @@ -29,7 +29,7 @@ void main(void) { ivec2 sideNormalsSize = ivec2( getNormalsSideSize() ); ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideNormalsSize.x); - vec2 deltaDepthUV = vec2(1.0) / vec2(getDepthTextureSideSize(0)); + vec2 deltaDepthUV = vec2(1.0) / getDepthTextureSideSize(0); // From now on, fragUVPos is the UV pos in the side fragUVPos = getSideUVFromFramebufferUV(side, fragUVPos); From 829e5ff44f4ccffeb8458b5ec20753e8d6e09f4c Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Nov 2018 13:37:22 +0100 Subject: [PATCH 77/81] Same android problem fix, but elsewhere --- libraries/render-utils/src/ssao.slh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index af7f8029b8..942578fc44 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -520,7 +520,7 @@ float computeOcclusion(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, TBNFrame #else // Step is adapted to Mip level float radius = deltaRadius; - float mipLevel = evalMipFromRadius(radius * float(doFetchMips())); + float mipLevel = float(evalMipFromRadius(radius * float(doFetchMips()))); while (radius<=searchRadius) { fragUVPos += deltaTapUV; @@ -530,8 +530,8 @@ float computeOcclusion(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, TBNFrame if (tapMipZ.x != mipLevel) { mipLevel = tapMipZ.x; - deltaRadius *= 2; - deltaTapUV *= 2; + deltaRadius *= 2.0; + deltaTapUV *= 2.0; sideDepthSize = getDepthTextureSideSize(int(mipLevel)); } radius += deltaRadius; From d64127aa9c9defb13e5e10aba50c12b1e947af51 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Nov 2018 13:48:19 +0100 Subject: [PATCH 78/81] Android shader compilation fix --- libraries/render-utils/src/ssao.slh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 942578fc44..ee31f2b701 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -451,7 +451,7 @@ float computeWeightedHorizon(float horizonLimit, float distanceSquared) { } <@func computeHorizon()@> - if (tapUVPos.x<0 || tapUVPos.y<0 || tapUVPos.x>=1.0 || tapUVPos.y>=1.0) { + if (tapUVPos.x<0.0 || tapUVPos.y<0.0 || tapUVPos.x>=1.0 || tapUVPos.y>=1.0) { // Early exit because we've hit the borders of the frame break; } From 87e6bffc461c0577c58cd3c97d9e3cc5fcb244b9 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Nov 2018 14:28:00 +0100 Subject: [PATCH 79/81] Added sampler2Darray precision for GLES --- libraries/shaders/headers/310es/header.glsl | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shaders/headers/310es/header.glsl b/libraries/shaders/headers/310es/header.glsl index ac48d5c94c..9a0af85281 100644 --- a/libraries/shaders/headers/310es/header.glsl +++ b/libraries/shaders/headers/310es/header.glsl @@ -13,3 +13,4 @@ precision highp float; precision highp samplerBuffer; precision highp sampler2DShadow; precision highp sampler2DArrayShadow; +precision lowp sampler2DArray; From be7806644a4deae2899b1b65b32ee7f3415d3788 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Nov 2018 17:29:00 +0100 Subject: [PATCH 80/81] Removed ternary operators with mix (try to limit branching) --- libraries/render-utils/src/ssao.slh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index ee31f2b701..b683dc38f1 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -254,11 +254,11 @@ LAYOUT(binding=RENDER_UTILS_TEXTURE_SSAO_DEPTH) uniform sampler2D depthPyramidTe LAYOUT(binding=RENDER_UTILS_TEXTURE_SSAO_NORMAL) uniform sampler2D normalTex; vec2 getFramebufferUVFromSideUV(ivec4 side, vec2 uv) { - return isStereo() ? vec2((uv.x + float(getStereoSide(side))) * 0.5, uv.y) : uv; + return mix(uv, vec2((uv.x + float(getStereoSide(side))) * 0.5, uv.y), float(isStereo())); } vec2 getSideUVFromFramebufferUV(ivec4 side, vec2 uv) { - return isStereo() ? vec2(uv.x * 2.0 - float(getStereoSide(side)), uv.y) : uv; + return mix(uv, vec2(uv.x * 2.0 - float(getStereoSide(side)), uv.y), float(isStereo())); } vec2 getDepthTextureSize(int level) { @@ -348,7 +348,7 @@ vec3 getMinDelta(vec3 centralPoint, vec3 offsetPointPos, vec3 offsetPointNeg) { float sqrLength0 = dot(delta0, delta0); float sqrLength1 = dot(delta1, delta1); - return sqrLength0 < sqrLength1 ? delta0 : delta1; + return mix(delta1, delta0, float(sqrLength0 < sqrLength1)); } const ivec2 UV_RIGHT = ivec2(1,0); @@ -542,7 +542,7 @@ float computeOcclusion(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, TBNFrame #if HBAO_USE_COS_ANGLE occlusion = min(occlusion * getFalloffCosAngleScale(), 1.0); #else - occlusion = horizonLimit > 0.0 ? horizonLimit * getFalloffSinAngleScale() : horizonLimit; + occlusion = horizonLimit * mix(1.0, getFalloffSinAngleScale(), horizonLimit > 0.0); #endif return occlusion; From 4e89e9ed2a3a91d84c7327bfdc2d67d48ff6e3c3 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 9 Nov 2018 09:58:17 +0100 Subject: [PATCH 81/81] Fixed draw / do_draw in GLBackends --- .../src/gpu/gl/GLBackendTexture.cpp | 12 ++++---- libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp | 28 ------------------ libraries/gpu-gl/src/gpu/gl41/GL41Backend.h | 1 - libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp | 29 ------------------- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 1 - 5 files changed, 6 insertions(+), 65 deletions(-) diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp index d4009302e2..b74ff079d7 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp @@ -71,13 +71,13 @@ void GLBackend::do_generateTextureMips(const Batch& batch, size_t paramOffset) { return; } - // DO not transfer the texture, this call is expected for rendering texture - GLTexture* object = syncGPUObject(resourceTexture); - if (!object) { - return; - } + // DO not transfer the texture, this call is expected for rendering texture + GLTexture* object = syncGPUObject(resourceTexture); + if (!object) { + return; + } - object->generateMips(); + object->generateMips(); } void GLBackend::do_generateTextureMipsWithPipeline(const Batch& batch, size_t paramOffset) { diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp index 43ae4691b9..ea884fe125 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp @@ -43,34 +43,6 @@ void GL41Backend::draw(GLenum mode, uint32 numVertices, uint32 startVertex) { (void)CHECK_GL_ERROR(); } -void GL41Backend::do_draw(const Batch& batch, size_t paramOffset) { - Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; - GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; - uint32 numVertices = batch._params[paramOffset + 1]._uint; - uint32 startVertex = batch._params[paramOffset + 0]._uint; - - if (isStereo()) { -#ifdef GPU_STEREO_DRAWCALL_INSTANCED - glDrawArraysInstanced(mode, startVertex, numVertices, 2); -#else - setupStereoSide(0); - glDrawArrays(mode, startVertex, numVertices); - setupStereoSide(1); - glDrawArrays(mode, startVertex, numVertices); -#endif - _stats._DSNumTriangles += 2 * numVertices / 3; - _stats._DSNumDrawcalls += 2; - - } else { - glDrawArrays(mode, startVertex, numVertices); - _stats._DSNumTriangles += numVertices / 3; - _stats._DSNumDrawcalls++; - } - _stats._DSNumAPIDrawcalls++; - - (void) CHECK_GL_ERROR(); -} - void GL41Backend::do_drawIndexed(const Batch& batch, size_t paramOffset) { Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index 881487c9db..23e49773ae 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -147,7 +147,6 @@ protected: GLQuery* syncGPUObject(const Query& query) override; // Draw Stage - void do_draw(const Batch& batch, size_t paramOffset) override; void do_drawIndexed(const Batch& batch, size_t paramOffset) override; void do_drawInstanced(const Batch& batch, size_t paramOffset) override; void do_drawIndexedInstanced(const Batch& batch, size_t paramOffset) override; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp index c4de7359d2..29c2a230a0 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp @@ -66,35 +66,6 @@ void GL45Backend::draw(GLenum mode, uint32 numVertices, uint32 startVertex) { (void)CHECK_GL_ERROR(); } -void GL45Backend::do_draw(const Batch& batch, size_t paramOffset) { - Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; - GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; - uint32 numVertices = batch._params[paramOffset + 1]._uint; - uint32 startVertex = batch._params[paramOffset + 0]._uint; - - if (isStereo()) { -#ifdef GPU_STEREO_DRAWCALL_INSTANCED - glDrawArraysInstanced(mode, startVertex, numVertices, 2); -#else - setupStereoSide(0); - glDrawArrays(mode, startVertex, numVertices); - setupStereoSide(1); - glDrawArrays(mode, startVertex, numVertices); -#endif - - _stats._DSNumTriangles += 2 * numVertices / 3; - _stats._DSNumDrawcalls += 2; - - } else { - glDrawArrays(mode, startVertex, numVertices); - _stats._DSNumTriangles += numVertices / 3; - _stats._DSNumDrawcalls++; - } - _stats._DSNumAPIDrawcalls++; - - (void)CHECK_GL_ERROR(); -} - void GL45Backend::do_drawIndexed(const Batch& batch, size_t paramOffset) { Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index c1ce074188..391fec45ce 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -248,7 +248,6 @@ protected: GLQuery* syncGPUObject(const Query& query) override; // Draw Stage - void do_draw(const Batch& batch, size_t paramOffset) override; void do_drawIndexed(const Batch& batch, size_t paramOffset) override; void do_drawInstanced(const Batch& batch, size_t paramOffset) override; void do_drawIndexedInstanced(const Batch& batch, size_t paramOffset) override;