From 59781583584fcaa931dbc6a1491cba0e0797a6d6 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 11 Apr 2018 17:21:44 +0200 Subject: [PATCH 001/182] 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 002/182] 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 003/182] 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 004/182] 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 005/182] 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 006/182] 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 007/182] 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 008/182] 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 009/182] 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 010/182] 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 011/182] 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 012/182] 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 013/182] 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 014/182] 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 015/182] 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 016/182] 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 017/182] 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 018/182] 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 019/182] 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 020/182] 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 021/182] 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 022/182] 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 023/182] 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 024/182] 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 025/182] 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 026/182] 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 027/182] 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 028/182] 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 029/182] 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 030/182] 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 031/182] 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 032/182] 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 033/182] 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 034/182] 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 035/182] 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 036/182] 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 037/182] 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 038/182] 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 039/182] 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 040/182] 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 041/182] 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 042/182] 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 043/182] 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 044/182] 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 045/182] 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 046/182] 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 047/182] 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 048/182] 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 049/182] 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 050/182] 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 051/182] 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 052/182] 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 053/182] 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 054/182] 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 055/182] 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 056/182] 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 057/182] 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 058/182] 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 059/182] 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 060/182] 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 061/182] 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 062/182] 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 9cf94c968aa7a5e02a0d44b50dbb8b068439a9c4 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Wed, 3 Oct 2018 02:55:33 +0300 Subject: [PATCH 063/182] FB18573 - Other avatars' avatar entities may appear to be successfully deleted until edited note: partially revert commit 888f2f64a5971b18c0dbcdac2b15d83c14deac45 / "Merge pull request #10981 from druiz17/bug/delete-avatar-entity --- libraries/entities/src/EntityScriptingInterface.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 22eb57e051..7b9b6a8cba 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -712,11 +712,6 @@ void EntityScriptingInterface::deleteEntity(QUuid id) { const QUuid myNodeID = nodeList->getSessionUUID(); if (entity->getClientOnly() && entity->getOwningAvatarID() != myNodeID) { // don't delete other avatar's avatarEntities - // If you actually own the entity but the onwership property is not set because of a domain switch - // The lines below makes sure the entity is deleted once its properties are set. - auto avatarHashMap = DependencyManager::get(); - AvatarSharedPointer myAvatar = avatarHashMap->getAvatarBySessionID(myNodeID); - myAvatar->insertDetachedEntityID(id); shouldSendDeleteToServer = false; return; } From 8ad58754dac8a79b9fb1cd6e12795174265db03d Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 3 Oct 2018 08:41:03 +0200 Subject: [PATCH 064/182] 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 065/182] 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 066/182] 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 067/182] 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 068/182] 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 f7cfc61494a8ff4cdfccd2abcbd096556a28b040 Mon Sep 17 00:00:00 2001 From: humbletim Date: Mon, 22 Oct 2018 15:02:33 -0400 Subject: [PATCH 069/182] Package Model... -> Package Avatar... --- interface/src/Menu.cpp | 2 +- interface/src/Menu.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index eef14c873e..110ae3d892 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -141,7 +141,7 @@ Menu::Menu() { assetServerAction->setEnabled(nodeList->getThisNodeCanWriteAssets()); } - // Edit > Package Model as .fst... + // Edit > Package Avatar as .fst... addActionToQMenuAndActionHash(editMenu, MenuOption::PackageModel, 0, qApp, SLOT(packageModel())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 031ee2561c..8d8c59d654 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -139,7 +139,7 @@ namespace MenuOption { const QString OpenVrThreadedSubmit = "OpenVR Threaded Submit"; const QString OutputMenu = "Display"; const QString Overlays = "Show Overlays"; - const QString PackageModel = "Package Model as .fst..."; + const QString PackageModel = "Package Avatar as .fst..."; const QString Pair = "Pair"; const QString PhysicsShowOwned = "Highlight Simulation Ownership"; const QString VerboseLogging = "Verbose Logging"; From b1d8a9a96bee5d172505f40c387150508475e845 Mon Sep 17 00:00:00 2001 From: humbletim Date: Mon, 22 Oct 2018 15:04:21 -0400 Subject: [PATCH 070/182] remove Qt "whatsthis" dialog icon --- interface/src/ModelSelector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ModelSelector.cpp b/interface/src/ModelSelector.cpp index 7d91359a11..d813e13f91 100644 --- a/interface/src/ModelSelector.cpp +++ b/interface/src/ModelSelector.cpp @@ -27,7 +27,7 @@ ModelSelector::ModelSelector() { setWindowTitle("Select Model"); setLayout(form); - + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); _browseButton = new QPushButton("Browse", this); connect(_browseButton, &QPushButton::clicked, this, &ModelSelector::browse); form->addRow("Model File:", _browseButton); From 2cf633ca026e0d51e068384d3039229aedf03c7a Mon Sep 17 00:00:00 2001 From: humbletim Date: Mon, 22 Oct 2018 15:05:49 -0400 Subject: [PATCH 071/182] remove Model Type dropdown and related code paths --- interface/src/ModelPackager.cpp | 67 +++++------- interface/src/ModelPackager.h | 1 - interface/src/ModelPropertiesDialog.cpp | 140 ++++++++---------------- interface/src/ModelPropertiesDialog.h | 6 +- interface/src/ModelSelector.cpp | 20 ---- interface/src/ModelSelector.h | 2 - 6 files changed, 74 insertions(+), 162 deletions(-) diff --git a/interface/src/ModelPackager.cpp b/interface/src/ModelPackager.cpp index 3a5d92eb8c..9bc10c072c 100644 --- a/interface/src/ModelPackager.cpp +++ b/interface/src/ModelPackager.cpp @@ -68,7 +68,6 @@ bool ModelPackager::selectModel() { ModelSelector selector; if(selector.exec() == QDialog::Accepted) { _modelFile = selector.getFileInfo(); - _modelType = selector.getModelType(); return true; } return false; @@ -122,28 +121,26 @@ bool ModelPackager::loadModel() { bool ModelPackager::editProperties() { // open the dialog to configure the rest - ModelPropertiesDialog properties(_modelType, _mapping, _modelFile.path(), *_geometry); + ModelPropertiesDialog properties(_mapping, _modelFile.path(), *_geometry); if (properties.exec() == QDialog::Rejected) { return false; } _mapping = properties.getMapping(); - if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) { - // Make sure that a mapping for the root joint has been specified - QVariantHash joints = _mapping.value(JOINT_FIELD).toHash(); - if (!joints.contains("jointRoot")) { - qWarning() << QString("%1 root joint not configured for skeleton.").arg(_modelFile.fileName()); + // Make sure that a mapping for the root joint has been specified + QVariantHash joints = _mapping.value(JOINT_FIELD).toHash(); + if (!joints.contains("jointRoot")) { + qWarning() << QString("%1 root joint not configured for skeleton.").arg(_modelFile.fileName()); - QString message = "Your did not configure a root joint for your skeleton model.\n\nPackaging will be canceled."; - QMessageBox msgBox; - msgBox.setWindowTitle("Model Packager"); - msgBox.setText(message); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); + QString message = "Your did not configure a root joint for your skeleton model.\n\nPackaging will be canceled."; + QMessageBox msgBox; + msgBox.setWindowTitle("Model Packager"); + msgBox.setText(message); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setIcon(QMessageBox::Warning); + msgBox.exec(); - return false; - } + return false; } return true; @@ -237,8 +234,6 @@ bool ModelPackager::zipModel() { void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename, const FBXGeometry& geometry) { - bool isBodyType = _modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL; - // mixamo files - in the event that a mixamo file was edited by some other tool, it's likely the applicationName will // be rewritten, so we detect the existence of several different blendshapes which indicate we're likely a mixamo file bool likelyMixamoFile = geometry.applicationName == "mixamo.com" || @@ -279,19 +274,17 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename joints.insert("jointNeck", geometry.jointIndices.contains("jointNeck") ? "jointNeck" : "Neck"); } - if (isBodyType) { - if (!joints.contains("jointRoot")) { - joints.insert("jointRoot", "Hips"); - } - if (!joints.contains("jointLean")) { - joints.insert("jointLean", "Spine"); - } - if (!joints.contains("jointLeftHand")) { - joints.insert("jointLeftHand", "LeftHand"); - } - if (!joints.contains("jointRightHand")) { - joints.insert("jointRightHand", "RightHand"); - } + if (!joints.contains("jointRoot")) { + joints.insert("jointRoot", "Hips"); + } + if (!joints.contains("jointLean")) { + joints.insert("jointLean", "Spine"); + } + if (!joints.contains("jointLeftHand")) { + joints.insert("jointLeftHand", "LeftHand"); + } + if (!joints.contains("jointRightHand")) { + joints.insert("jointRightHand", "RightHand"); } if (!joints.contains("jointHead")) { @@ -301,13 +294,11 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename mapping.insert(JOINT_FIELD, joints); - if (isBodyType) { - if (!mapping.contains(FREE_JOINT_FIELD)) { - mapping.insertMulti(FREE_JOINT_FIELD, "LeftArm"); - mapping.insertMulti(FREE_JOINT_FIELD, "LeftForeArm"); - mapping.insertMulti(FREE_JOINT_FIELD, "RightArm"); - mapping.insertMulti(FREE_JOINT_FIELD, "RightForeArm"); - } + if (!mapping.contains(FREE_JOINT_FIELD)) { + mapping.insertMulti(FREE_JOINT_FIELD, "LeftArm"); + mapping.insertMulti(FREE_JOINT_FIELD, "LeftForeArm"); + mapping.insertMulti(FREE_JOINT_FIELD, "RightArm"); + mapping.insertMulti(FREE_JOINT_FIELD, "RightForeArm"); } // If there are no blendshape mappings, and we detect that this is likely a mixamo file, diff --git a/interface/src/ModelPackager.h b/interface/src/ModelPackager.h index 76295e5a85..8f9e437939 100644 --- a/interface/src/ModelPackager.h +++ b/interface/src/ModelPackager.h @@ -39,7 +39,6 @@ private: QFileInfo _modelFile; QFileInfo _fbxInfo; - FSTReader::ModelType _modelType; QString _texDir; QString _scriptDir; diff --git a/interface/src/ModelPropertiesDialog.cpp b/interface/src/ModelPropertiesDialog.cpp index 8984f89d07..066218205d 100644 --- a/interface/src/ModelPropertiesDialog.cpp +++ b/interface/src/ModelPropertiesDialog.cpp @@ -26,9 +26,8 @@ #include -ModelPropertiesDialog::ModelPropertiesDialog(FSTReader::ModelType modelType, const QVariantHash& originalMapping, +ModelPropertiesDialog::ModelPropertiesDialog(const QVariantHash& originalMapping, const QString& basePath, const FBXGeometry& geometry) : -_modelType(modelType), _originalMapping(originalMapping), _basePath(basePath), _geometry(geometry) @@ -50,36 +49,19 @@ _geometry(geometry) _scale->setMaximum(FLT_MAX); _scale->setSingleStep(0.01); - if (_modelType != FSTReader::ENTITY_MODEL) { - if (_modelType == FSTReader::ATTACHMENT_MODEL) { - QHBoxLayout* translation = new QHBoxLayout(); - form->addRow("Translation:", translation); - translation->addWidget(_translationX = createTranslationBox()); - translation->addWidget(_translationY = createTranslationBox()); - translation->addWidget(_translationZ = createTranslationBox()); - form->addRow("Pivot About Center:", _pivotAboutCenter = new QCheckBox()); - form->addRow("Pivot Joint:", _pivotJoint = createJointBox()); - connect(_pivotAboutCenter, SIGNAL(toggled(bool)), SLOT(updatePivotJoint())); - _pivotAboutCenter->setChecked(true); + form->addRow("Left Eye Joint:", _leftEyeJoint = createJointBox()); + form->addRow("Right Eye Joint:", _rightEyeJoint = createJointBox()); + form->addRow("Neck Joint:", _neckJoint = createJointBox()); + form->addRow("Root Joint:", _rootJoint = createJointBox()); + form->addRow("Lean Joint:", _leanJoint = createJointBox()); + form->addRow("Head Joint:", _headJoint = createJointBox()); + form->addRow("Left Hand Joint:", _leftHandJoint = createJointBox()); + form->addRow("Right Hand Joint:", _rightHandJoint = createJointBox()); - } else { - form->addRow("Left Eye Joint:", _leftEyeJoint = createJointBox()); - form->addRow("Right Eye Joint:", _rightEyeJoint = createJointBox()); - form->addRow("Neck Joint:", _neckJoint = createJointBox()); - } - if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) { - form->addRow("Root Joint:", _rootJoint = createJointBox()); - form->addRow("Lean Joint:", _leanJoint = createJointBox()); - form->addRow("Head Joint:", _headJoint = createJointBox()); - form->addRow("Left Hand Joint:", _leftHandJoint = createJointBox()); - form->addRow("Right Hand Joint:", _rightHandJoint = createJointBox()); - - form->addRow("Free Joints:", _freeJoints = new QVBoxLayout()); - QPushButton* newFreeJoint = new QPushButton("New Free Joint"); - _freeJoints->addWidget(newFreeJoint); - connect(newFreeJoint, SIGNAL(clicked(bool)), SLOT(createNewFreeJoint())); - } - } + form->addRow("Free Joints:", _freeJoints = new QVBoxLayout()); + QPushButton* newFreeJoint = new QPushButton("New Free Joint"); + _freeJoints->addWidget(newFreeJoint); + connect(newFreeJoint, SIGNAL(clicked(bool)), SLOT(createNewFreeJoint())); QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Reset); @@ -93,14 +75,9 @@ _geometry(geometry) reset(); } - -QString ModelPropertiesDialog::getType() const { - return FSTReader::getNameFromType(_modelType); -} - QVariantHash ModelPropertiesDialog::getMapping() const { QVariantHash mapping = _originalMapping; - mapping.insert(TYPE_FIELD, getType()); + mapping.insert(TYPE_FIELD, FSTReader::getNameFromType(FSTReader::HEAD_AND_BODY_MODEL)); mapping.insert(NAME_FIELD, _name->text()); mapping.insert(TEXDIR_FIELD, _textureDirectory->text()); mapping.insert(SCRIPT_FIELD, _scriptDirectory->text()); @@ -113,42 +90,24 @@ QVariantHash ModelPropertiesDialog::getMapping() const { } mapping.insert(JOINT_INDEX_FIELD, jointIndices); - if (_modelType != FSTReader::ENTITY_MODEL) { - QVariantHash joints = mapping.value(JOINT_FIELD).toHash(); - if (_modelType == FSTReader::ATTACHMENT_MODEL) { - glm::vec3 pivot; - if (_pivotAboutCenter->isChecked()) { - pivot = (_geometry.meshExtents.minimum + _geometry.meshExtents.maximum) * 0.5f; - - } else if (_pivotJoint->currentIndex() != 0) { - pivot = extractTranslation(_geometry.joints.at(_pivotJoint->currentIndex() - 1).transform); - } - mapping.insert(TRANSLATION_X_FIELD, -pivot.x * (float)_scale->value() + (float)_translationX->value()); - mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * (float)_scale->value() + (float)_translationY->value()); - mapping.insert(TRANSLATION_Z_FIELD, -pivot.z * (float)_scale->value() + (float)_translationZ->value()); - - } else { - insertJointMapping(joints, "jointEyeLeft", _leftEyeJoint->currentText()); - insertJointMapping(joints, "jointEyeRight", _rightEyeJoint->currentText()); - insertJointMapping(joints, "jointNeck", _neckJoint->currentText()); - } + QVariantHash joints = mapping.value(JOINT_FIELD).toHash(); + insertJointMapping(joints, "jointEyeLeft", _leftEyeJoint->currentText()); + insertJointMapping(joints, "jointEyeRight", _rightEyeJoint->currentText()); + insertJointMapping(joints, "jointNeck", _neckJoint->currentText()); - if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) { - insertJointMapping(joints, "jointRoot", _rootJoint->currentText()); - insertJointMapping(joints, "jointLean", _leanJoint->currentText()); - insertJointMapping(joints, "jointHead", _headJoint->currentText()); - insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText()); - insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText()); + insertJointMapping(joints, "jointRoot", _rootJoint->currentText()); + insertJointMapping(joints, "jointLean", _leanJoint->currentText()); + insertJointMapping(joints, "jointHead", _headJoint->currentText()); + insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText()); + insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText()); - mapping.remove(FREE_JOINT_FIELD); - for (int i = 0; i < _freeJoints->count() - 1; i++) { - QComboBox* box = static_cast(_freeJoints->itemAt(i)->widget()->layout()->itemAt(0)->widget()); - mapping.insertMulti(FREE_JOINT_FIELD, box->currentText()); - } - } - mapping.insert(JOINT_FIELD, joints); + mapping.remove(FREE_JOINT_FIELD); + for (int i = 0; i < _freeJoints->count() - 1; i++) { + QComboBox* box = static_cast(_freeJoints->itemAt(i)->widget()->layout()->itemAt(0)->widget()); + mapping.insertMulti(FREE_JOINT_FIELD, box->currentText()); } + mapping.insert(JOINT_FIELD, joints); return mapping; } @@ -165,36 +124,23 @@ void ModelPropertiesDialog::reset() { QVariantHash jointHash = _originalMapping.value(JOINT_FIELD).toHash(); - if (_modelType != FSTReader::ENTITY_MODEL) { - if (_modelType == FSTReader::ATTACHMENT_MODEL) { - _translationX->setValue(_originalMapping.value(TRANSLATION_X_FIELD).toDouble()); - _translationY->setValue(_originalMapping.value(TRANSLATION_Y_FIELD).toDouble()); - _translationZ->setValue(_originalMapping.value(TRANSLATION_Z_FIELD).toDouble()); - _pivotAboutCenter->setChecked(true); - _pivotJoint->setCurrentIndex(0); + setJointText(_leftEyeJoint, jointHash.value("jointEyeLeft").toString()); + setJointText(_rightEyeJoint, jointHash.value("jointEyeRight").toString()); + setJointText(_neckJoint, jointHash.value("jointNeck").toString()); - } else { - setJointText(_leftEyeJoint, jointHash.value("jointEyeLeft").toString()); - setJointText(_rightEyeJoint, jointHash.value("jointEyeRight").toString()); - setJointText(_neckJoint, jointHash.value("jointNeck").toString()); - } + setJointText(_rootJoint, jointHash.value("jointRoot").toString()); + setJointText(_leanJoint, jointHash.value("jointLean").toString()); + setJointText(_headJoint, jointHash.value("jointHead").toString()); + setJointText(_leftHandJoint, jointHash.value("jointLeftHand").toString()); + setJointText(_rightHandJoint, jointHash.value("jointRightHand").toString()); - if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) { - setJointText(_rootJoint, jointHash.value("jointRoot").toString()); - setJointText(_leanJoint, jointHash.value("jointLean").toString()); - setJointText(_headJoint, jointHash.value("jointHead").toString()); - setJointText(_leftHandJoint, jointHash.value("jointLeftHand").toString()); - setJointText(_rightHandJoint, jointHash.value("jointRightHand").toString()); - - while (_freeJoints->count() > 1) { - delete _freeJoints->itemAt(0)->widget(); - } - foreach (const QVariant& joint, _originalMapping.values(FREE_JOINT_FIELD)) { - QString jointName = joint.toString(); - if (_geometry.jointIndices.contains(jointName)) { - createNewFreeJoint(jointName); - } - } + while (_freeJoints->count() > 1) { + delete _freeJoints->itemAt(0)->widget(); + } + foreach (const QVariant& joint, _originalMapping.values(FREE_JOINT_FIELD)) { + QString jointName = joint.toString(); + if (_geometry.jointIndices.contains(jointName)) { + createNewFreeJoint(jointName); } } } diff --git a/interface/src/ModelPropertiesDialog.h b/interface/src/ModelPropertiesDialog.h index e3c2d8ed6a..6e0f1b1a2e 100644 --- a/interface/src/ModelPropertiesDialog.h +++ b/interface/src/ModelPropertiesDialog.h @@ -29,7 +29,7 @@ class ModelPropertiesDialog : public QDialog { Q_OBJECT public: - ModelPropertiesDialog(FSTReader::ModelType modelType, const QVariantHash& originalMapping, + ModelPropertiesDialog(const QVariantHash& originalMapping, const QString& basePath, const FBXGeometry& geometry); QVariantHash getMapping() const; @@ -45,9 +45,7 @@ private: QComboBox* createJointBox(bool withNone = true) const; QDoubleSpinBox* createTranslationBox() const; void insertJointMapping(QVariantHash& joints, const QString& joint, const QString& name) const; - QString getType() const; - FSTReader::ModelType _modelType; QVariantHash _originalMapping; QString _basePath; FBXGeometry _geometry; @@ -71,4 +69,4 @@ private: QVBoxLayout* _freeJoints = nullptr; }; -#endif // hifi_ModelPropertiesDialog_h \ No newline at end of file +#endif // hifi_ModelPropertiesDialog_h diff --git a/interface/src/ModelSelector.cpp b/interface/src/ModelSelector.cpp index d813e13f91..7e428a294d 100644 --- a/interface/src/ModelSelector.cpp +++ b/interface/src/ModelSelector.cpp @@ -32,13 +32,6 @@ ModelSelector::ModelSelector() { connect(_browseButton, &QPushButton::clicked, this, &ModelSelector::browse); form->addRow("Model File:", _browseButton); - _modelType = new QComboBox(this); - - _modelType->addItem(AVATAR_HEAD_AND_BODY_STRING); - _modelType->addItem(AVATAR_ATTACHEMENT_STRING); - _modelType->addItem(ENTITY_MODEL_STRING); - form->addRow("Model Type:", _modelType); - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect(buttons, &QDialogButtonBox::accepted, this, &ModelSelector::accept); connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); @@ -49,19 +42,6 @@ QFileInfo ModelSelector::getFileInfo() const { return _modelFile; } -FSTReader::ModelType ModelSelector::getModelType() const { - QString text = _modelType->currentText(); - -if (text == AVATAR_HEAD_AND_BODY_STRING) { - return FSTReader::HEAD_AND_BODY_MODEL; - } else if (text == AVATAR_ATTACHEMENT_STRING) { - return FSTReader::ATTACHMENT_MODEL; - } else if (text == ENTITY_MODEL_STRING) { - return FSTReader::ENTITY_MODEL; - } - Q_UNREACHABLE(); -} - void ModelSelector::accept() { if (!_modelFile.isFile()) { return; diff --git a/interface/src/ModelSelector.h b/interface/src/ModelSelector.h index ee9e75c17a..5bbeb4665e 100644 --- a/interface/src/ModelSelector.h +++ b/interface/src/ModelSelector.h @@ -29,7 +29,6 @@ public: ModelSelector(); QFileInfo getFileInfo() const; - FSTReader::ModelType getModelType() const; public slots: virtual void accept() override; @@ -40,7 +39,6 @@ public: private: QFileInfo _modelFile; QPushButton* _browseButton; - QComboBox* _modelType; }; #endif // hifi_ModelSelector_h From aa64e51281ed5bc1c52195b03b9f35ac96b0c2d7 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 24 Oct 2018 11:04:32 +0200 Subject: [PATCH 072/182] 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 936c3beea0d8816c6cc7ae41df8935e55cc61fc6 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 24 Oct 2018 15:56:29 -0700 Subject: [PATCH 073/182] Exit if Python executable not found --- tools/auto-tester/src/PythonInterface.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/auto-tester/src/PythonInterface.cpp b/tools/auto-tester/src/PythonInterface.cpp index 4922b8a8df..c5878939cc 100644 --- a/tools/auto-tester/src/PythonInterface.cpp +++ b/tools/auto-tester/src/PythonInterface.cpp @@ -18,7 +18,9 @@ PythonInterface::PythonInterface() { QString _pythonPath = QProcessEnvironment::systemEnvironment().value("PYTHON_PATH"); if (!QFile::exists(_pythonPath + "/" + _pythonExe)) { QMessageBox::critical(0, _pythonExe, QString("Python executable not found in ") + _pythonPath); + exit(-1); } + _pythonCommand = _pythonPath + "/" + _pythonExe; } else { QMessageBox::critical(0, "PYTHON_PATH not defined", From 34a03bfc99ee02ec3652a3f913d99a3561af4da5 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 24 Oct 2018 15:57:06 -0700 Subject: [PATCH 074/182] Python executable for MAC is `python` --- tools/auto-tester/src/PythonInterface.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/auto-tester/src/PythonInterface.h b/tools/auto-tester/src/PythonInterface.h index f32a39a644..a218b68039 100644 --- a/tools/auto-tester/src/PythonInterface.h +++ b/tools/auto-tester/src/PythonInterface.h @@ -19,7 +19,13 @@ public: QString getPythonCommand(); private: +#ifdef Q_OS_WIN const QString _pythonExe{ "python.exe" }; +#endif +#ifdef Q_OS_MACOS + const QString _pythonExe{ "python" }; +#endif + QString _pythonCommand; }; From 14216bdeca89856d4d8e7588744e8d4a115b267f Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 24 Oct 2018 16:22:12 -0700 Subject: [PATCH 075/182] Starting v7.0 Increased a button size for Mac. --- tools/auto-tester/src/ui/AutoTester.cpp | 2 +- tools/auto-tester/src/ui/AutoTester.ui | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 32457c2224..d49f3aaa1c 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -36,7 +36,7 @@ AutoTester::AutoTester(QWidget* parent) : QMainWindow(parent) { _ui.statusLabel->setText(""); _ui.plainTextEdit->setReadOnly(true); - setWindowTitle("Auto Tester - v6.7"); + setWindowTitle("Auto Tester - v7.0"); // Coming soon to an auto-tester near you... //// _helpWindow.textBrowser->setText() diff --git a/tools/auto-tester/src/ui/AutoTester.ui b/tools/auto-tester/src/ui/AutoTester.ui index b277fbdb2a..cf2ffd35cd 100644 --- a/tools/auto-tester/src/ui/AutoTester.ui +++ b/tools/auto-tester/src/ui/AutoTester.ui @@ -43,7 +43,7 @@ - 0 + 3 @@ -572,7 +572,7 @@ 330 170 - 101 + 181 40 From 028d1cf237881c582df787bd859e38af653d75d0 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 25 Oct 2018 13:36:15 -0700 Subject: [PATCH 076/182] Minor cleanup. --- tools/auto-tester/src/Downloader.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/auto-tester/src/Downloader.h b/tools/auto-tester/src/Downloader.h index 6d1029698f..742a88b890 100644 --- a/tools/auto-tester/src/Downloader.h +++ b/tools/auto-tester/src/Downloader.h @@ -37,7 +37,7 @@ public: signals: void downloaded(); - private slots: +private slots: void fileDownloaded(QNetworkReply* pReply); private: From 47ce1573eb5494d5107d1967d899d1779c9b4009 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 25 Oct 2018 15:17:07 -0700 Subject: [PATCH 077/182] Corrected use of _snapshotFolder. --- tools/auto-tester/src/TestRunner.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index 674cf6f8e8..94e65d0c8b 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -327,7 +327,6 @@ void TestRunner::startLocalServerProcesses() { void TestRunner::runInterfaceWithTestScript() { QString exeFile = QString("\"") + QDir::toNativeSeparators(_installationFolder) + "\\interface.exe\""; - QString snapshotFolder = QString("\"") + QDir::toNativeSeparators(_snapshotFolder) + "\""; QString url = QString("hifi://localhost"); if (_runServerless->isChecked()) { @@ -340,8 +339,11 @@ void TestRunner::runInterfaceWithTestScript() { QString testScript = QString("https://raw.githubusercontent.com/") + _user + "/hifi_tests/" + _branch + "/tests/testRecursive.js"; - QString commandLine = exeFile + " --url " + url + " --no-updater --no-login" + " --testScript " + testScript + - " quitWhenFinished --testResultsLocation " + snapshotFolder; + QString commandLine = exeFile + " --url " + url + " --no-updater" + " --testScript " + testScript + + " quitWhenFinished --testResultsLocation " + _snapshotFolder; + + // Helpful for debugging + appendLog(commandLine); interfaceWorker->setCommandLine(commandLine); emit startInterface(); From d2e31b3f6715092a48558f1ad3da54ce05670d4d Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 25 Oct 2018 15:18:29 -0700 Subject: [PATCH 078/182] Use `fromPercentEncoding` to download URL (attempting to get download to run on Mac). --- tools/auto-tester/src/Downloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/auto-tester/src/Downloader.cpp b/tools/auto-tester/src/Downloader.cpp index cb9863f34d..3c07d8c3a3 100644 --- a/tools/auto-tester/src/Downloader.cpp +++ b/tools/auto-tester/src/Downloader.cpp @@ -17,7 +17,7 @@ Downloader::Downloader(QUrl fileURL, QObject *parent) : QObject(parent) { this, SLOT (fileDownloaded(QNetworkReply*)) ); - QNetworkRequest request(fileURL); + QNetworkRequest request(QUrl::fromPercentEncoding(fileURL.toString().toLatin1())); _networkAccessManager.get(request); } From 7bf6e9cda918a1c2f93fb74455e9f8b3e8c49694 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 25 Oct 2018 16:19:25 -0700 Subject: [PATCH 079/182] Simplified, and seems to work --- tools/auto-tester/src/Downloader.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/auto-tester/src/Downloader.cpp b/tools/auto-tester/src/Downloader.cpp index 3c07d8c3a3..de768398b0 100644 --- a/tools/auto-tester/src/Downloader.cpp +++ b/tools/auto-tester/src/Downloader.cpp @@ -17,8 +17,7 @@ Downloader::Downloader(QUrl fileURL, QObject *parent) : QObject(parent) { this, SLOT (fileDownloaded(QNetworkReply*)) ); - QNetworkRequest request(QUrl::fromPercentEncoding(fileURL.toString().toLatin1())); - _networkAccessManager.get(request); + _networkAccessManager.get(QNetworkRequest(fileURL)); } void Downloader::fileDownloaded(QNetworkReply* reply) { @@ -37,4 +36,4 @@ void Downloader::fileDownloaded(QNetworkReply* reply) { QByteArray Downloader::downloadedData() const { return _downloadedData; -} \ No newline at end of file +} From c3b1f8c332d48a75fa042046d760f237b5ff41f9 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 25 Oct 2018 17:22:45 -0700 Subject: [PATCH 080/182] Should be able to download Mac installer --- tools/auto-tester/src/TestRunner.cpp | 69 +++++++++++++++------------- tools/auto-tester/src/TestRunner.h | 6 +++ 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index 94e65d0c8b..89d9867784 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -538,6 +538,7 @@ void TestRunner::parseBuildInformation() { #elif defined(Q_OS_MAC) platformOfInterest = "mac"; #endif + QDomElement element = domDocument.documentElement(); // Verify first element is "projects" @@ -554,42 +555,48 @@ void TestRunner::parseBuildInformation() { throw("File is not from 'interface' build"); } - // Now loop over the platforms + // Now loop over the platforms, looking for ours + bool platformFound{ false }; + element = element.firstChild().toElement(); while (!element.isNull()) { - element = element.firstChild().toElement(); - if (element.tagName() != "platform" || element.attribute("name") != platformOfInterest) { - continue; + if (element.attribute("name") == platformOfInterest) { + platformFound = true; + break; } - - // Next element should be the build - element = element.firstChild().toElement(); - if (element.tagName() != "build") { - throw("File seems to be in wrong format"); - } - - // Next element should be the version - element = element.firstChild().toElement(); - if (element.tagName() != "version") { - throw("File seems to be in wrong format"); - } - - // Add the build number to the end of the filename - _buildInformation.build = element.text(); - - // First sibling should be stable_version element = element.nextSibling().toElement(); - if (element.tagName() != "stable_version") { - throw("File seems to be in wrong format"); - } - - // Next sibling should be url - element = element.nextSibling().toElement(); - if (element.tagName() != "url") { - throw("File seems to be in wrong format"); - } - _buildInformation.url = element.text(); } + if (!platformFound) { + throw("File seems to be in wrong format - platform " + platformOfInterest + " not found"); + } + + element = element.firstChild().toElement(); + if (element.tagName() != "build") { + throw("File seems to be in wrong format"); + } + + // Next element should be the version + element = element.firstChild().toElement(); + if (element.tagName() != "version") { + throw("File seems to be in wrong format"); + } + + // Add the build number to the end of the filename + _buildInformation.build = element.text(); + + // First sibling should be stable_version + element = element.nextSibling().toElement(); + if (element.tagName() != "stable_version") { + throw("File seems to be in wrong format"); + } + + // Next sibling should be url + element = element.nextSibling().toElement(); + if (element.tagName() != "url") { + throw("File seems to be in wrong format"); + } + _buildInformation.url = element.text(); + } catch (QString errorMessage) { QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), errorMessage); exit(-1); diff --git a/tools/auto-tester/src/TestRunner.h b/tools/auto-tester/src/TestRunner.h index e6cb7cd764..5b2d55959f 100644 --- a/tools/auto-tester/src/TestRunner.h +++ b/tools/auto-tester/src/TestRunner.h @@ -88,7 +88,13 @@ signals: private: bool _automatedTestIsRunning{ false }; +#ifndef Q_OS_WIN const QString INSTALLER_FILENAME_LATEST{ "HighFidelity-Beta-latest-dev.exe" }; +#elif defined(Q_OS_MAC) + const QString INSTALLER_FILENAME_LATEST{ "HighFidelity-Beta-latest-dev.dmg" }; +#else + const QString INSTALLER_FILENAME_LATEST{ "just to pass compilation" }; +#endif QString _installerURL; QString _installerFilename; From e9310415012a33f2869d341af59fa2ed06b0b289 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 25 Oct 2018 17:39:06 -0700 Subject: [PATCH 081/182] Corrected #ifdef --- tools/auto-tester/src/TestRunner.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.h b/tools/auto-tester/src/TestRunner.h index 5b2d55959f..340ede9bf7 100644 --- a/tools/auto-tester/src/TestRunner.h +++ b/tools/auto-tester/src/TestRunner.h @@ -88,7 +88,7 @@ signals: private: bool _automatedTestIsRunning{ false }; -#ifndef Q_OS_WIN +#ifdef Q_OS_WIN const QString INSTALLER_FILENAME_LATEST{ "HighFidelity-Beta-latest-dev.exe" }; #elif defined(Q_OS_MAC) const QString INSTALLER_FILENAME_LATEST{ "HighFidelity-Beta-latest-dev.dmg" }; @@ -154,4 +154,5 @@ signals: private: QString _commandLine; }; -#endif // hifi_testRunner_h \ No newline at end of file +#endif // hifi_testRunner_h + From 28338a83071d36f40ab7f0473eb262b449d1201c Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 25 Oct 2018 17:40:39 -0700 Subject: [PATCH 082/182] Minor cleanup. --- tools/auto-tester/src/TestRunner.h | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/auto-tester/src/TestRunner.h b/tools/auto-tester/src/TestRunner.h index 340ede9bf7..8267a042b7 100644 --- a/tools/auto-tester/src/TestRunner.h +++ b/tools/auto-tester/src/TestRunner.h @@ -155,4 +155,3 @@ private: QString _commandLine; }; #endif // hifi_testRunner_h - From 98441b2328f91c64f19fa283f256d62f00231ef2 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 29 Oct 2018 15:49:46 -0700 Subject: [PATCH 083/182] WIP - installing High Fidelity from command line. --- tools/auto-tester/src/TestRunner.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index 89d9867784..2d5b013f31 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -176,10 +176,26 @@ void TestRunner::runInstaller() { QString installerFullPath = _workingFolder + "/" + _installerFilename; +#ifdef Q_OS_WIN QString commandLine = "\"" + QDir::toNativeSeparators(installerFullPath) + "\"" + " /S /D=" + QDir::toNativeSeparators(_installationFolder); installerWorker->setCommandLine(commandLine); +#elif defined Q_OS_MAC + QFile script; + script.setFileName(_workingFolder + "/install_app.sh"); + if (!script.open(QIODevice::Append | QIODevice::Text)) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), + "Could not open 'install_app.sh'"); + exit(-1); + } + + script.write("#/bin/sh\n\n"); + script.write("VOLUME=`hdiutil attach \"$1\" | grep Volumes | awk '{print $3}'`"); + script.write((QString("#cp -rf \"$VOLUME/") + _installerFilename + "High Fidelity/interface.app\"").toStdString().c_str()); + + QString commandLine = "yes | ../install_app.sh HighFidelity-Beta-latest-dev.dmg"; +#endif emit startInstaller(); } @@ -614,4 +630,4 @@ int Worker::runCommand() { int result = system(_commandLine.toStdString().c_str()); emit commandComplete(); return result; -} \ No newline at end of file +} From 1213f3f658b4e646863e06716e1c92630ba4a453 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 29 Oct 2018 17:51:41 -0700 Subject: [PATCH 084/182] Can run the installer --- tools/auto-tester/src/TestRunner.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index 2d5b013f31..09de31120e 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -179,23 +179,31 @@ void TestRunner::runInstaller() { #ifdef Q_OS_WIN QString commandLine = "\"" + QDir::toNativeSeparators(installerFullPath) + "\"" + " /S /D=" + QDir::toNativeSeparators(_installationFolder); - - installerWorker->setCommandLine(commandLine); #elif defined Q_OS_MAC QFile script; script.setFileName(_workingFolder + "/install_app.sh"); - if (!script.open(QIODevice::Append | QIODevice::Text)) { + if (!script.open(QIODevice::WriteOnly | QIODevice::Text)) { QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Could not open 'install_app.sh'"); exit(-1); } script.write("#/bin/sh\n\n"); - script.write("VOLUME=`hdiutil attach \"$1\" | grep Volumes | awk '{print $3}'`"); - script.write((QString("#cp -rf \"$VOLUME/") + _installerFilename + "High Fidelity/interface.app\"").toStdString().c_str()); + script.write("VOLUME=`hdiutil attach \"$1\" | grep Volumes | awk '{print $3}'`\n"); + script.write((QString("mkdir \"") + _workingFolder + "/High Fidelity\"\n").toStdString().c_str()); - QString commandLine = "yes | ../install_app.sh HighFidelity-Beta-latest-dev.dmg"; + QStringList urlParts = _buildInformation.url.split('/'); + QString installerFileName = urlParts[urlParts.length() - 1].split('.')[0]; + script.write((QString("cp -rf \"$VOLUME/") + "/High Fidelity/interface.app\" \"" + _workingFolder + "/High Fidelity/\"\n").toStdString().c_str()); + + script.write("hdiutil detach \"$VOLUME\"\n"); + script.close(); + script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); + + QString commandLine = "yes | " + _workingFolder + "/install_app.sh " + _workingFolder + "/HighFidelity-Beta-latest-dev.dmg"; #endif + + installerWorker->setCommandLine(commandLine); emit startInstaller(); } From 418a578e288238a2ff3765b80fa7f6a30c4187eb Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 30 Oct 2018 13:02:13 -0700 Subject: [PATCH 085/182] Can start Interface --- tools/auto-tester/src/TestRunner.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index 09de31120e..9c38fee4c4 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -188,15 +188,21 @@ void TestRunner::runInstaller() { exit(-1); } + QString installFolder = QString("\"") + _workingFolder + "/High Fidelity\""; + if (!QDir().exists(installFolder)) { + QDir().mkdir(installFolder); + } + + // This script installs High Fidelity. It is run as "yes | install_app.sh... so "yes" is killed at the end script.write("#/bin/sh\n\n"); script.write("VOLUME=`hdiutil attach \"$1\" | grep Volumes | awk '{print $3}'`\n"); - script.write((QString("mkdir \"") + _workingFolder + "/High Fidelity\"\n").toStdString().c_str()); QStringList urlParts = _buildInformation.url.split('/'); QString installerFileName = urlParts[urlParts.length() - 1].split('.')[0]; script.write((QString("cp -rf \"$VOLUME/") + "/High Fidelity/interface.app\" \"" + _workingFolder + "/High Fidelity/\"\n").toStdString().c_str()); script.write("hdiutil detach \"$VOLUME\"\n"); + script.write("killall yes\n"); script.close(); script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); @@ -350,8 +356,6 @@ void TestRunner::startLocalServerProcesses() { } void TestRunner::runInterfaceWithTestScript() { - QString exeFile = QString("\"") + QDir::toNativeSeparators(_installationFolder) + "\\interface.exe\""; - QString url = QString("hifi://localhost"); if (_runServerless->isChecked()) { // Move to an empty area @@ -363,9 +367,14 @@ void TestRunner::runInterfaceWithTestScript() { QString testScript = QString("https://raw.githubusercontent.com/") + _user + "/hifi_tests/" + _branch + "/tests/testRecursive.js"; +#ifdef Q_OS_WIN + QString exeFile = QString("\"") + QDir::toNativeSeparators(_installationFolder) + "\\interface.exe\""; QString commandLine = exeFile + " --url " + url + " --no-updater" + " --testScript " + testScript + " quitWhenFinished --testResultsLocation " + _snapshotFolder; - +#elif defined Q_OS_MAC + QString commandLine = "open -a \"" +_installationFolder + "/interface.app\""; +#endif + // Helpful for debugging appendLog(commandLine); From 41b70ffab5681f14d27e756627f851bf79c28b33 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 30 Oct 2018 16:30:56 -0700 Subject: [PATCH 086/182] Installs both interface and Sandbox. Runs interface. --- tools/auto-tester/src/TestRunner.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index 9c38fee4c4..d74073c164 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -84,7 +84,12 @@ void TestRunner::setWorkingFolder() { return; } +#ifdef Q_OS_WIN _installationFolder = _workingFolder + "/High Fidelity"; +#elif defined Q_OS_MAC + _installationFolder = _workingFolder + "/High_Fidelity"; +#endif + _logFile.setFileName(_workingFolder + "/log.txt"); autoTester->enableRunTabControls(); @@ -188,7 +193,7 @@ void TestRunner::runInstaller() { exit(-1); } - QString installFolder = QString("\"") + _workingFolder + "/High Fidelity\""; + QString installFolder = QString("\"") + _workingFolder + "/High_Fidelity\""; if (!QDir().exists(installFolder)) { QDir().mkdir(installFolder); } @@ -197,10 +202,9 @@ void TestRunner::runInstaller() { script.write("#/bin/sh\n\n"); script.write("VOLUME=`hdiutil attach \"$1\" | grep Volumes | awk '{print $3}'`\n"); - QStringList urlParts = _buildInformation.url.split('/'); - QString installerFileName = urlParts[urlParts.length() - 1].split('.')[0]; - script.write((QString("cp -rf \"$VOLUME/") + "/High Fidelity/interface.app\" \"" + _workingFolder + "/High Fidelity/\"\n").toStdString().c_str()); - + script.write((QString("cp -rf \"$VOLUME/") + "/High Fidelity/interface.app\" \"" + _workingFolder + "/High_Fidelity/\"\n").toStdString().c_str()); + script.write((QString("cp -rf \"$VOLUME/") + "/High Fidelity/Sandbox.app\" \"" + _workingFolder + "/High_Fidelity/\"\n").toStdString().c_str()); + script.write("hdiutil detach \"$VOLUME\"\n"); script.write("killall yes\n"); script.close(); From 263a831fc4dc5b2f3e3cc52aa5f20848d8d7e331 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 30 Oct 2018 18:41:10 -0700 Subject: [PATCH 087/182] Runs Interface with Sandbox --- tools/auto-tester/src/TestRunner.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index d74073c164..315ac732e0 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -345,16 +345,21 @@ void TestRunner::killProcesses() { } void TestRunner::startLocalServerProcesses() { -#ifdef Q_OS_WIN QString commandLine; - + +#ifdef Q_OS_WIN commandLine = "start \"domain-server.exe\" \"" + QDir::toNativeSeparators(_installationFolder) + "\\domain-server.exe\""; system(commandLine.toStdString().c_str()); commandLine = "start \"assignment-client.exe\" \"" + QDir::toNativeSeparators(_installationFolder) + "\\assignment-client.exe\" -n 6"; system(commandLine.toStdString().c_str()); + +#elif defined Q_OS_MAC + commandLine = "open -a \"" +_installationFolder + "/Sandbox.app\""; + system(commandLine.toStdString().c_str()); #endif + // Give server processes time to stabilize QThread::sleep(20); } From 5e58da8ec10c18494dffb7a39e2a697a1bf59cee Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 30 Oct 2018 22:29:50 -0700 Subject: [PATCH 088/182] Interface runs, but AutoTester doesn't wait for completion. --- tools/auto-tester/src/TestRunner.cpp | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index 315ac732e0..2bf304943b 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -20,7 +20,7 @@ extern AutoTester* autoTester; #include #include #endif - +#include TestRunner::TestRunner(std::vector dayCheckboxes, std::vector timeEditCheckboxes, std::vector timeEdits, @@ -247,11 +247,10 @@ void TestRunner::verifyInstallationSucceeded() { } void TestRunner::saveExistingHighFidelityAppDataFolder() { +#ifdef Q_OS_WIN QString dataDirectory{ "NOT FOUND" }; -#ifdef Q_OS_WIN dataDirectory = qgetenv("USERPROFILE") + "\\AppData\\Roaming"; -#endif if (_runLatest->isChecked()) { _appDataFolder = dataDirectory + "\\High Fidelity"; @@ -272,6 +271,9 @@ void TestRunner::saveExistingHighFidelityAppDataFolder() { // Copy an "empty" AppData folder (i.e. no entities) copyFolder(QDir::currentPath() + "/AppDataHighFidelity", _appDataFolder.path()); +#elif defined Q_OS_MAC + // TODO: find Mac equivalent of AppData +#endif } void TestRunner::createSnapshotFolder() { @@ -341,6 +343,13 @@ void TestRunner::killProcesses() { QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "unknown error"); exit(-1); } +#elif defined Q_OS_MAC + // TODO: this doesn't allow interface to run + //QString commandLine = "killall interface\n"; + //system(commandLine.toStdString().c_str()); + + //commandLine = "killall Sandbox\n"; + //system(commandLine.toStdString().c_str()); #endif } @@ -370,7 +379,12 @@ void TestRunner::runInterfaceWithTestScript() { // Move to an empty area url = "file:///~serverless/tutorial.json"; } else { +#ifdef Q_OS_WIN url = "hifi://localhost"; +#elif defined Q_OS_MAC + // TODO: Find out Mac equivalent of AppData, then this win't be needed + url = "hifi://localhost/9999,9999,9999"; +#endif } QString testScript = @@ -381,7 +395,8 @@ void TestRunner::runInterfaceWithTestScript() { QString commandLine = exeFile + " --url " + url + " --no-updater" + " --testScript " + testScript + " quitWhenFinished --testResultsLocation " + _snapshotFolder; #elif defined Q_OS_MAC - QString commandLine = "open -a \"" +_installationFolder + "/interface.app\""; + QString commandLine = "open -a \"" +_installationFolder + "/interface.app\"" + " --args --url " + url + " --no-updater" + " --testScript " + testScript + + " quitWhenFinished --testResultsLocation " + _snapshotFolder; #endif // Helpful for debugging @@ -448,11 +463,15 @@ void TestRunner::addBuildNumberToResults(QString zippedFolderName) { } void TestRunner::restoreHighFidelityAppDataFolder() { +#ifdef Q_OS_WIN _appDataFolder.removeRecursively(); if (_savedAppDataFolder != QDir()) { _appDataFolder.rename(_savedAppDataFolder.path(), _appDataFolder.path()); } +#elif defined Q_OS_MAC + // TODO: find Mac equivalent of AppData +#endif } // Copies a folder recursively From 675334a105248363800fd3840dd95e1ccff49551 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 30 Oct 2018 22:47:11 -0700 Subject: [PATCH 089/182] Do not need `-a` when using open with full path to app --- tools/auto-tester/src/TestRunner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index 2bf304943b..1beebe29b1 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -365,7 +365,7 @@ void TestRunner::startLocalServerProcesses() { system(commandLine.toStdString().c_str()); #elif defined Q_OS_MAC - commandLine = "open -a \"" +_installationFolder + "/Sandbox.app\""; + commandLine = "open \"" +_installationFolder + "/Sandbox.app\""; system(commandLine.toStdString().c_str()); #endif @@ -395,7 +395,7 @@ void TestRunner::runInterfaceWithTestScript() { QString commandLine = exeFile + " --url " + url + " --no-updater" + " --testScript " + testScript + " quitWhenFinished --testResultsLocation " + _snapshotFolder; #elif defined Q_OS_MAC - QString commandLine = "open -a \"" +_installationFolder + "/interface.app\"" + " --args --url " + url + " --no-updater" + " --testScript " + testScript + + QString commandLine = "open \"" +_installationFolder + "/interface.app\"" + " --args --url " + url + " --no-updater" + " --testScript " + testScript + " quitWhenFinished --testResultsLocation " + _snapshotFolder; #endif From 40a31b63a980eb4e34a54b87e4d0442e68dd245b Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 31 Oct 2018 14:48:27 -0700 Subject: [PATCH 090/182] Waits for Interface to finish --- tools/auto-tester/src/PythonInterface.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/tools/auto-tester/src/PythonInterface.cpp b/tools/auto-tester/src/PythonInterface.cpp index c5878939cc..2866ca0b87 100644 --- a/tools/auto-tester/src/PythonInterface.cpp +++ b/tools/auto-tester/src/PythonInterface.cpp @@ -14,19 +14,6 @@ #include PythonInterface::PythonInterface() { - if (QProcessEnvironment::systemEnvironment().contains("PYTHON_PATH")) { - QString _pythonPath = QProcessEnvironment::systemEnvironment().value("PYTHON_PATH"); - if (!QFile::exists(_pythonPath + "/" + _pythonExe)) { - QMessageBox::critical(0, _pythonExe, QString("Python executable not found in ") + _pythonPath); - exit(-1); - } - - _pythonCommand = _pythonPath + "/" + _pythonExe; - } else { - QMessageBox::critical(0, "PYTHON_PATH not defined", - "Please set PYTHON_PATH to directory containing the Python executable"); - exit(-1); - } } QString PythonInterface::getPythonCommand() { From 1d67531a87b26832167b746a70e6e3fb3c0c9f90 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 31 Oct 2018 22:45:12 -0700 Subject: [PATCH 091/182] Improve UI --- tools/auto-tester/src/ui/AutoTester.ui | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/auto-tester/src/ui/AutoTester.ui b/tools/auto-tester/src/ui/AutoTester.ui index cf2ffd35cd..08f4b46723 100644 --- a/tools/auto-tester/src/ui/AutoTester.ui +++ b/tools/auto-tester/src/ui/AutoTester.ui @@ -43,7 +43,7 @@ - 3 + 0 @@ -198,7 +198,7 @@ 10 160 161 - 28 + 51 @@ -525,7 +525,7 @@ 128 95 - 21 + 31 31 @@ -539,7 +539,7 @@ - 160 + 170 100 451 21 @@ -554,9 +554,9 @@ - 200 + 190 180 - 120 + 131 20 @@ -573,7 +573,7 @@ 330 170 181 - 40 + 51 @@ -684,10 +684,10 @@ - 240 + 270 30 160 - 40 + 51 @@ -699,7 +699,7 @@ 150 42 - 81 + 111 17 @@ -803,7 +803,7 @@ 0 0 720 - 21 + 22 From 716bd8ebd2ffaa7fb183f74526ca042cc5e10171 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 31 Oct 2018 22:45:52 -0700 Subject: [PATCH 092/182] WIP - starting on AWS Interface --- tools/auto-tester/src/TestRunner.cpp | 93 ++++++++++++++++++---------- 1 file changed, 60 insertions(+), 33 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index 1beebe29b1..1f31004b2f 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -20,7 +20,10 @@ extern AutoTester* autoTester; #include #include #endif + +// TODO: for debug #include + TestRunner::TestRunner(std::vector dayCheckboxes, std::vector timeEditCheckboxes, std::vector timeEdits, @@ -98,6 +101,51 @@ void TestRunner::setWorkingFolder() { _timer = new QTimer(this); connect(_timer, SIGNAL(timeout()), this, SLOT(checkTime())); _timer->start(30 * 1000); //time specified in ms + +#ifdef Q_OS_MAC + // Create MAC shell scripts + QFile script; + script.setFileName(_workingFolder + "/install_app.sh"); + if (!script.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), + "Could not open 'install_app.sh'"); + exit(-1); + } + + QString installFolder = QString("\"") + _workingFolder + "/High_Fidelity\""; + if (!QDir().exists(installFolder)) { + QDir().mkdir(installFolder); + } + + // This script installs High Fidelity. It is run as "yes | install_app.sh... so "yes" is killed at the end + script.write("#/bin/sh\n\n"); + script.write("VOLUME=`hdiutil attach \"$1\" | grep Volumes | awk '{print $3}'`\n"); + + script.write((QString("cp -rf \"$VOLUME/") + "/High Fidelity/interface.app\" \"" + _workingFolder + "/High_Fidelity/\"\n").toStdString().c_str()); + script.write((QString("cp -rf \"$VOLUME/") + "/High Fidelity/Sandbox.app\" \"" + _workingFolder + "/High_Fidelity/\"\n").toStdString().c_str()); + + script.write("hdiutil detach \"$VOLUME\"\n"); + script.write("killall yes\n"); + script.close(); + script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); + + // The Mac shell command returns immediately. This little script waits for a process to complete + script.setFileName(_workingFolder + "/waitForCompletion.sh"); + if (!script.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), + "Could not open 'install_app.sh'"); + exit(-1); + } + + script.write("#/bin/sh\n\n"); + script.write("PROCESS=\"$1\"\n"); + script.write("while (pgrep $PROCESS)\n"); + script.write("do\n"); + script.write("\tsleep 2\n"); + script.write("done\n"); + script.close(); + script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); + #endif } void TestRunner::run() { @@ -185,31 +233,6 @@ void TestRunner::runInstaller() { QString commandLine = "\"" + QDir::toNativeSeparators(installerFullPath) + "\"" + " /S /D=" + QDir::toNativeSeparators(_installationFolder); #elif defined Q_OS_MAC - QFile script; - script.setFileName(_workingFolder + "/install_app.sh"); - if (!script.open(QIODevice::WriteOnly | QIODevice::Text)) { - QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), - "Could not open 'install_app.sh'"); - exit(-1); - } - - QString installFolder = QString("\"") + _workingFolder + "/High_Fidelity\""; - if (!QDir().exists(installFolder)) { - QDir().mkdir(installFolder); - } - - // This script installs High Fidelity. It is run as "yes | install_app.sh... so "yes" is killed at the end - script.write("#/bin/sh\n\n"); - script.write("VOLUME=`hdiutil attach \"$1\" | grep Volumes | awk '{print $3}'`\n"); - - script.write((QString("cp -rf \"$VOLUME/") + "/High Fidelity/interface.app\" \"" + _workingFolder + "/High_Fidelity/\"\n").toStdString().c_str()); - script.write((QString("cp -rf \"$VOLUME/") + "/High Fidelity/Sandbox.app\" \"" + _workingFolder + "/High_Fidelity/\"\n").toStdString().c_str()); - - script.write("hdiutil detach \"$VOLUME\"\n"); - script.write("killall yes\n"); - script.close(); - script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); - QString commandLine = "yes | " + _workingFolder + "/install_app.sh " + _workingFolder + "/HighFidelity-Beta-latest-dev.dmg"; #endif @@ -344,12 +367,11 @@ void TestRunner::killProcesses() { exit(-1); } #elif defined Q_OS_MAC - // TODO: this doesn't allow interface to run - //QString commandLine = "killall interface\n"; - //system(commandLine.toStdString().c_str()); + QString commandLine = QString("killall interface") + "; " + _workingFolder +"/waitForCompletion.sh interface"; + system(commandLine.toStdString().c_str()); - //commandLine = "killall Sandbox\n"; - //system(commandLine.toStdString().c_str()); + commandLine = QString("killall Sandbox") + "; " + _workingFolder +"/waitForCompletion.sh interface"; + system(commandLine.toStdString().c_str()); #endif } @@ -357,7 +379,8 @@ void TestRunner::startLocalServerProcesses() { QString commandLine; #ifdef Q_OS_WIN - commandLine = "start \"domain-server.exe\" \"" + QDir::toNativeSeparators(_installationFolder) + "\\domain-server.exe\""; + commandLine = + "start \"domain-server.exe\" \"" + QDir::toNativeSeparators(_installationFolder) + "\\domain-server.exe\""; system(commandLine.toStdString().c_str()); commandLine = @@ -395,8 +418,12 @@ void TestRunner::runInterfaceWithTestScript() { QString commandLine = exeFile + " --url " + url + " --no-updater" + " --testScript " + testScript + " quitWhenFinished --testResultsLocation " + _snapshotFolder; #elif defined Q_OS_MAC - QString commandLine = "open \"" +_installationFolder + "/interface.app\"" + " --args --url " + url + " --no-updater" + " --testScript " + testScript + - " quitWhenFinished --testResultsLocation " + _snapshotFolder; + QString commandLine = "open \"" +_installationFolder + "/interface.app\" --args" + + " --url " + url + + " --no-updater" + + " --testScript " + testScript + " quitWhenFinished" + + " --testResultsLocation " + _snapshotFolder + + "; " + _workingFolder +"/waitForCompletion.sh interface"; #endif // Helpful for debugging From 1c7c0dd0a02680fb80215587aff0154470733fb2 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 31 Oct 2018 23:07:44 -0700 Subject: [PATCH 093/182] Booboo... --- tools/auto-tester/src/PythonInterface.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/auto-tester/src/PythonInterface.cpp b/tools/auto-tester/src/PythonInterface.cpp index 2866ca0b87..c5878939cc 100644 --- a/tools/auto-tester/src/PythonInterface.cpp +++ b/tools/auto-tester/src/PythonInterface.cpp @@ -14,6 +14,19 @@ #include PythonInterface::PythonInterface() { + if (QProcessEnvironment::systemEnvironment().contains("PYTHON_PATH")) { + QString _pythonPath = QProcessEnvironment::systemEnvironment().value("PYTHON_PATH"); + if (!QFile::exists(_pythonPath + "/" + _pythonExe)) { + QMessageBox::critical(0, _pythonExe, QString("Python executable not found in ") + _pythonPath); + exit(-1); + } + + _pythonCommand = _pythonPath + "/" + _pythonExe; + } else { + QMessageBox::critical(0, "PYTHON_PATH not defined", + "Please set PYTHON_PATH to directory containing the Python executable"); + exit(-1); + } } QString PythonInterface::getPythonCommand() { From 6121d7022c302cc87223171e7c6de76629785a30 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Nov 2018 07:49:36 -0700 Subject: [PATCH 094/182] Renamed folder. Removed useless 'mkdir'. --- tools/auto-tester/src/AWSInterface.cpp | 51 +++++++++++++++++--------- tools/auto-tester/src/AWSInterface.h | 4 +- tools/auto-tester/src/Test.cpp | 6 +-- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/tools/auto-tester/src/AWSInterface.cpp b/tools/auto-tester/src/AWSInterface.cpp index 628db5329c..a5a72288de 100644 --- a/tools/auto-tester/src/AWSInterface.cpp +++ b/tools/auto-tester/src/AWSInterface.cpp @@ -22,11 +22,11 @@ AWSInterface::AWSInterface(QObject* parent) : QObject(parent) { } void AWSInterface::createWebPageFromResults(const QString& testResults, - const QString& workingDirectory, + const QString& snapshotDirectory, QCheckBox* updateAWSCheckBox, QLineEdit* urlLineEdit) { _testResults = testResults; - _workingDirectory = workingDirectory; + _snapshotDirectory = snapshotDirectory; _urlLineEdit = urlLineEdit; _urlLineEdit->setEnabled(false); @@ -44,14 +44,13 @@ void AWSInterface::extractTestFailuresFromZippedFolder() { // the folder will be called `TestResults--2018-10-02_16-54-11(9426)[DESKTOP-PMKNLSQ]` // and, this folder will be in the workign directory QStringList parts =_testResults.split('/'); - QString zipFolderName = _workingDirectory + "/" + parts[parts.length() - 1].split('.')[0]; + QString zipFolderName = _snapshotDirectory + "/" + parts[parts.length() - 1].split('.')[0]; if (QDir(zipFolderName).exists()) { QDir dir = zipFolderName; dir.removeRecursively(); } - QDir().mkdir(_workingDirectory); - JlCompress::extractDir(_testResults, _workingDirectory); + JlCompress::extractDir(_testResults, _snapshotDirectory); } void AWSInterface::createHTMLFile() { @@ -61,7 +60,7 @@ void AWSInterface::createHTMLFile() { QString filename = pathComponents[pathComponents.length() - 1]; _resultsFolder = filename.left(filename.length() - 4); - QString resultsPath = _workingDirectory + "/" + _resultsFolder + "/"; + QString resultsPath = _snapshotDirectory + "/" + _resultsFolder + "/"; QDir().mkdir(resultsPath); _htmlFilename = resultsPath + HTML_FILENAME; @@ -157,7 +156,7 @@ void AWSInterface::writeTable(QTextStream& stream) { // Note that failures are processed first, then successes QStringList originalNamesFailures; QStringList originalNamesSuccesses; - QDirIterator it1(_workingDirectory.toStdString().c_str()); + QDirIterator it1(_snapshotDirectory.toStdString().c_str()); while (it1.hasNext()) { QString nextDirectory = it1.next(); @@ -191,10 +190,10 @@ void AWSInterface::writeTable(QTextStream& stream) { newNamesSuccesses.append(originalNamesSuccesses[i].split("--tests.")[1]); } - _htmlFailuresFolder = _workingDirectory + "/" + _resultsFolder + "/" + FAILURES_FOLDER; + _htmlFailuresFolder = _snapshotDirectory + "/" + _resultsFolder + "/" + FAILURES_FOLDER; QDir().mkdir(_htmlFailuresFolder); - _htmlSuccessesFolder = _workingDirectory + "/" + _resultsFolder + "/" + SUCCESSES_FOLDER; + _htmlSuccessesFolder = _snapshotDirectory + "/" + _resultsFolder + "/" + SUCCESSES_FOLDER; QDir().mkdir(_htmlSuccessesFolder); for (int i = 0; i < newNamesFailures.length(); ++i) { @@ -321,7 +320,7 @@ void AWSInterface::createEntry(int index, const QString& testResult, QTextStream } void AWSInterface::updateAWS() { - QString filename = _workingDirectory + "/updateAWS.py"; + QString filename = _snapshotDirectory + "/updateAWS.py"; if (QFile::exists(filename)) { QFile::remove(filename); } @@ -352,14 +351,23 @@ void AWSInterface::updateAWS() { QStringList parts = nextDirectory.split('/'); QString filename = parts[parts.length() - 3] + "/" + parts[parts.length() - 2] + "/" + parts[parts.length() - 1]; - stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Actual Image.png" << "', 'rb')\n"; + stream << "data = open('" << _snapshotDirectory << "/" << filename << "/" + << "Actual Image.png" + << "', 'rb')\n"; + stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Actual Image.png" << "', Body=data)\n\n"; - stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Expected Image.png" << "', 'rb')\n"; + stream << "data = open('" << _snapshotDirectory << "/" << filename << "/" + << "Expected Image.png" + << "', 'rb')\n"; + stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Expected Image.png" << "', Body=data)\n\n"; if (QFile::exists(_htmlFailuresFolder + "/" + parts[parts.length() - 1] + "/Difference Image.png")) { - stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Difference Image.png" << "', 'rb')\n"; + stream << "data = open('" << _snapshotDirectory << "/" << filename << "/" + << "Difference Image.png" + << "', 'rb')\n"; + stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Difference Image.png" << "', Body=data)\n\n"; } } @@ -378,19 +386,28 @@ void AWSInterface::updateAWS() { QStringList parts = nextDirectory.split('/'); QString filename = parts[parts.length() - 3] + "/" + parts[parts.length() - 2] + "/" + parts[parts.length() - 1]; - stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Actual Image.png" << "', 'rb')\n"; + stream << "data = open('" << _snapshotDirectory << "/" << filename << "/" + << "Actual Image.png" + << "', 'rb')\n"; + stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Actual Image.png" << "', Body=data)\n\n"; - stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Expected Image.png" << "', 'rb')\n"; + stream << "data = open('" << _snapshotDirectory << "/" << filename << "/" + << "Expected Image.png" + << "', 'rb')\n"; + stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Expected Image.png" << "', Body=data)\n\n"; if (QFile::exists(_htmlSuccessesFolder + "/" + parts[parts.length() - 1] + "/Difference Image.png")) { - stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Difference Image.png" << "', 'rb')\n"; + stream << "data = open('" << _snapshotDirectory << "/" << filename << "/" + << "Difference Image.png" + << "', 'rb')\n"; + stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Difference Image.png" << "', Body=data)\n\n"; } } - stream << "data = open('" << _workingDirectory << "/" << _resultsFolder << "/" << HTML_FILENAME << "', 'rb')\n"; + stream << "data = open('" << _snapshotDirectory << "/" << _resultsFolder << "/" << HTML_FILENAME << "', 'rb')\n"; stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << _resultsFolder << "/" << HTML_FILENAME << "', Body=data, ContentType='text/html')\n"; diff --git a/tools/auto-tester/src/AWSInterface.h b/tools/auto-tester/src/AWSInterface.h index c5be5f35bb..43299bd888 100644 --- a/tools/auto-tester/src/AWSInterface.h +++ b/tools/auto-tester/src/AWSInterface.h @@ -26,7 +26,7 @@ public: explicit AWSInterface(QObject* parent = 0); void createWebPageFromResults(const QString& testResults, - const QString& workingDirectory, + const QString& testDirectory, QCheckBox* updateAWSCheckBox, QLineEdit* urlLineEdit); @@ -49,7 +49,7 @@ public: private: QString _testResults; - QString _workingDirectory; + QString _snapshotDirectory; QString _resultsFolder; QString _htmlFailuresFolder; QString _htmlSuccessesFolder; diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 582f6209af..2c262bec1e 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -1052,11 +1052,11 @@ void Test::createWebPage(QCheckBox* updateAWSCheckBox, QLineEdit* urlLineEdit) { return; } - QString tempDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select a folder to store temporary files in", + QString snapshotDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select a folder to store temporary files in", nullptr, QFileDialog::ShowDirsOnly); - if (tempDirectory.isNull()) { + if (snapshotDirectory.isNull()) { return; } - _awsInterface.createWebPageFromResults(testResults, tempDirectory, updateAWSCheckBox, urlLineEdit); + _awsInterface.createWebPageFromResults(testResults, snapshotDirectory, updateAWSCheckBox, urlLineEdit); } \ No newline at end of file From 8e3f2d360170a96c01e92c69fe8fb8b3fe420bef Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Nov 2018 08:17:35 -0700 Subject: [PATCH 095/182] Minor clean-up. --- tools/auto-tester/src/AWSInterface.cpp | 2 +- tools/auto-tester/src/AWSInterface.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/auto-tester/src/AWSInterface.cpp b/tools/auto-tester/src/AWSInterface.cpp index a5a72288de..b6eef39b1d 100644 --- a/tools/auto-tester/src/AWSInterface.cpp +++ b/tools/auto-tester/src/AWSInterface.cpp @@ -42,7 +42,7 @@ void AWSInterface::createWebPageFromResults(const QString& testResults, void AWSInterface::extractTestFailuresFromZippedFolder() { // For a test results zip file called `D:/tt/TestResults--2018-10-02_16-54-11(9426)[DESKTOP-PMKNLSQ].zip` // the folder will be called `TestResults--2018-10-02_16-54-11(9426)[DESKTOP-PMKNLSQ]` - // and, this folder will be in the workign directory + // and, this folder will be in the working directory QStringList parts =_testResults.split('/'); QString zipFolderName = _snapshotDirectory + "/" + parts[parts.length() - 1].split('.')[0]; if (QDir(zipFolderName).exists()) { diff --git a/tools/auto-tester/src/AWSInterface.h b/tools/auto-tester/src/AWSInterface.h index 43299bd888..f4084f1a14 100644 --- a/tools/auto-tester/src/AWSInterface.h +++ b/tools/auto-tester/src/AWSInterface.h @@ -26,7 +26,7 @@ public: explicit AWSInterface(QObject* parent = 0); void createWebPageFromResults(const QString& testResults, - const QString& testDirectory, + const QString& snapshotDirectory, QCheckBox* updateAWSCheckBox, QLineEdit* urlLineEdit); From 701f3274ce3ffe30efd0acc56f362c54cd593e09 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Nov 2018 08:47:56 -0700 Subject: [PATCH 096/182] Updated IMPORTANT information for running Python3 on Mac. --- tools/auto-tester/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/auto-tester/README.md b/tools/auto-tester/README.md index e029955edc..8851524ffd 100644 --- a/tools/auto-tester/README.md +++ b/tools/auto-tester/README.md @@ -14,7 +14,7 @@ Auto-tester has 5 functions, separated into 4 tabs: ## Installation ### Executable -1. Download the installer by browsing to [here](). +1. On Windows: download the installer by browsing to [here](). 2. Double click on the installer and install to a convenient location ![](./setup_7z.PNG) 3. To run the auto-tester, double click **auto-tester.exe**. @@ -26,7 +26,9 @@ Python 3 can be downloaded from: 2. Linux (source) (**Gzipped source tarball**) 3. Mac (**macOS 64-bit/32-bit installer** or **macOS 64-bit/32-bit installer**) -After installation - create an environment variable called PYTHON_PATH and set it to the folder containing the Python executable. +On Windows: after installation - create an environment variable called PYTHON_PATH and set it to the folder containing the Python executable. + +On Mac: after installation - run `open "/Applications/Python 3.6/Install Certificates.command"`. This is needed because the Mac Python supplied no longer links with the deprecated Apple-supplied system OpenSSL libraries but rather supplies a private copy of OpenSSL 1.0.2 which does not automatically access the system default root certificates. ### AWS interface #### Windows 1. Download the AWS CLI from `https://aws.amazon.com/cli/` From 61ba685022e2d9764c6df00a4a5a41795f014330 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Nov 2018 12:17:53 -0700 Subject: [PATCH 097/182] Set Python command to `usr/local/python3`. --- tools/auto-tester/src/PythonInterface.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/auto-tester/src/PythonInterface.cpp b/tools/auto-tester/src/PythonInterface.cpp index c5878939cc..9832ac9f8d 100644 --- a/tools/auto-tester/src/PythonInterface.cpp +++ b/tools/auto-tester/src/PythonInterface.cpp @@ -14,6 +14,7 @@ #include PythonInterface::PythonInterface() { +#ifdef Q_OS_WIN if (QProcessEnvironment::systemEnvironment().contains("PYTHON_PATH")) { QString _pythonPath = QProcessEnvironment::systemEnvironment().value("PYTHON_PATH"); if (!QFile::exists(_pythonPath + "/" + _pythonExe)) { @@ -27,6 +28,14 @@ PythonInterface::PythonInterface() { "Please set PYTHON_PATH to directory containing the Python executable"); exit(-1); } +#elif defined Q_OS_MAC + _pythonCommand = "/usr/local/bin/python3"; + if (!QFile::exists(_pythonCommand)) { + QMessageBox::critical(0, "PYTHON_PATH not defined", + "python3 not found at " + _pythonCommand); + exit(-1); + } +#endif } QString PythonInterface::getPythonCommand() { From c1a01caeb8b97aef24ff1a4d3149ceff36395551 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Nov 2018 12:18:55 -0700 Subject: [PATCH 098/182] Added missing `!` --- tools/auto-tester/src/TestRunner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index 1f31004b2f..7d2d57b0bc 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -118,7 +118,7 @@ void TestRunner::setWorkingFolder() { } // This script installs High Fidelity. It is run as "yes | install_app.sh... so "yes" is killed at the end - script.write("#/bin/sh\n\n"); + script.write("#!/bin/sh\n\n"); script.write("VOLUME=`hdiutil attach \"$1\" | grep Volumes | awk '{print $3}'`\n"); script.write((QString("cp -rf \"$VOLUME/") + "/High Fidelity/interface.app\" \"" + _workingFolder + "/High_Fidelity/\"\n").toStdString().c_str()); @@ -137,7 +137,7 @@ void TestRunner::setWorkingFolder() { exit(-1); } - script.write("#/bin/sh\n\n"); + script.write("#!/bin/sh\n\n"); script.write("PROCESS=\"$1\"\n"); script.write("while (pgrep $PROCESS)\n"); script.write("do\n"); From 7d9b6a3f1052f523344527a37f50d2d56575bdf1 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Nov 2018 12:19:25 -0700 Subject: [PATCH 099/182] Can read runs from TestRail. --- tools/auto-tester/src/TestRailInterface.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/auto-tester/src/TestRailInterface.cpp b/tools/auto-tester/src/TestRailInterface.cpp index f943935539..912f72492c 100644 --- a/tools/auto-tester/src/TestRailInterface.cpp +++ b/tools/auto-tester/src/TestRailInterface.cpp @@ -1117,9 +1117,14 @@ void TestRailInterface::getRunsFromTestRail() { [=](int exitCode, QProcess::ExitStatus exitStatus) { updateRunsComboData(exitCode, exitStatus); }); connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater())); +#ifdef Q_OS_WIN QStringList parameters = QStringList() << filename; - process->start(_pythonCommand, parameters); +#elif defined Q_OS_MAC + QStringList parameters = QStringList() << "-c" << _pythonCommand + " " + filename; + process->start("sh", parameters); + process->waitForFinished(); +#endif } void TestRailInterface::createTestRailRun(const QString& outputDirectory) { @@ -1164,4 +1169,4 @@ void TestRailInterface::extractTestFailuresFromZippedFolder(const QString& testR QDir dir = tempSubDirectory; dir.mkdir(tempSubDirectory); JlCompress::extractDir(testResults, tempSubDirectory); -} \ No newline at end of file +} From 6e8338fade6c7f131a23eed7c7d91a9daae9443f Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Nov 2018 12:55:28 -0700 Subject: [PATCH 100/182] Completed Python commands for Mac. --- tools/auto-tester/src/TestRailInterface.cpp | 26 ++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tools/auto-tester/src/TestRailInterface.cpp b/tools/auto-tester/src/TestRailInterface.cpp index 912f72492c..a0c0d74526 100644 --- a/tools/auto-tester/src/TestRailInterface.cpp +++ b/tools/auto-tester/src/TestRailInterface.cpp @@ -357,8 +357,13 @@ void TestRailInterface::createAddTestCasesPythonScript(const QString& testDirect connect(process, static_cast(&QProcess::finished), this, [=](int exitCode, QProcess::ExitStatus exitStatus) { _busyWindow.hide(); }); +#ifdef Q_OS_WIN QStringList parameters = QStringList() << _outputDirectory + "/addTestCases.py"; process->start(_pythonCommand, parameters); +#elif defined Q_OS_MAC + QStringList parameters = QStringList() << "-c" << _pythonCommand + " " + _outputDirectory + "/addTestCases.py"; + process->start("sh", parameters); +#endif } } @@ -482,8 +487,13 @@ void TestRailInterface::addRun() { connect(process, static_cast(&QProcess::finished), this, [=](int exitCode, QProcess::ExitStatus exitStatus) { _busyWindow.hide(); }); +#ifdef Q_OS_WIN QStringList parameters = QStringList() << _outputDirectory + "/addRun.py"; process->start(_pythonCommand, parameters); +#elif defined Q_OS_MAC + QStringList parameters = QStringList() << "-c" << _pythonCommand + " " + _outputDirectory + "/addRun.py"; + process->start("sh", parameters); +#endif } } @@ -586,8 +596,13 @@ void TestRailInterface::updateRunWithResults() { connect(process, static_cast(&QProcess::finished), this, [=](int exitCode, QProcess::ExitStatus exitStatus) { _busyWindow.hide(); }); +#ifdef Q_OS_WIN QStringList parameters = QStringList() << _outputDirectory + "/updateRunWithResults.py"; process->start(_pythonCommand, parameters); +#elif defined Q_OS_MAC + QStringList parameters = QStringList() << "-c" << _pythonCommand + " " + _outputDirectory + "/updateRunWithResults.py"; + process->start("sh", parameters); +#endif } } @@ -759,8 +774,13 @@ void TestRailInterface::getReleasesFromTestRail() { [=](int exitCode, QProcess::ExitStatus exitStatus) { updateReleasesComboData(exitCode, exitStatus); }); connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater())); +#ifdef Q_OS_WIN QStringList parameters = QStringList() << filename; process->start(_pythonCommand, parameters); +#elif defined Q_OS_MAC + QStringList parameters = QStringList() << "-c" << _pythonCommand + " " + filename; + process->start("sh", parameters); +#endif } void TestRailInterface::createTestSuitePython(const QString& testDirectory, @@ -1078,8 +1098,13 @@ void TestRailInterface::getTestSectionsFromTestRail() { [=](int exitCode, QProcess::ExitStatus exitStatus) { updateSectionsComboData(exitCode, exitStatus); }); connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater())); +#ifdef Q_OS_WIN QStringList parameters = QStringList() << filename; process->start(_pythonCommand, parameters); +#elif defined Q_OS_MAC + QStringList parameters = QStringList() << "-c" << _pythonCommand + " " + filename; + process->start("sh", parameters); +#endif } void TestRailInterface::getRunsFromTestRail() { @@ -1123,7 +1148,6 @@ void TestRailInterface::getRunsFromTestRail() { #elif defined Q_OS_MAC QStringList parameters = QStringList() << "-c" << _pythonCommand + " " + filename; process->start("sh", parameters); - process->waitForFinished(); #endif } From 22ae1114b5cfc7f071bd9793e3783831618fa4cf Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Nov 2018 14:20:05 -0700 Subject: [PATCH 101/182] Updated Python command for Mac. --- tools/auto-tester/src/AWSInterface.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/auto-tester/src/AWSInterface.cpp b/tools/auto-tester/src/AWSInterface.cpp index b6eef39b1d..e43ef8dc75 100644 --- a/tools/auto-tester/src/AWSInterface.cpp +++ b/tools/auto-tester/src/AWSInterface.cpp @@ -425,6 +425,11 @@ void AWSInterface::updateAWS() { connect(process, static_cast(&QProcess::finished), this, [=](int exitCode, QProcess::ExitStatus exitStatus) { _busyWindow.hide(); }); +#ifdef Q_OS_WIN QStringList parameters = QStringList() << filename ; process->start(_pythonCommand, parameters); +#elif defined Q_OS_MAC + QStringList parameters = QStringList() << "-c" << _pythonCommand + " " + filename; + process->start("sh", parameters); +#endif } From ebc37610d3f450675bc7fc7eaf48ac1aed11d36e Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Nov 2018 15:07:19 -0700 Subject: [PATCH 102/182] Updated for MAC. --- tools/auto-tester/README.md | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/tools/auto-tester/README.md b/tools/auto-tester/README.md index 8851524ffd..0bec83d703 100644 --- a/tools/auto-tester/README.md +++ b/tools/auto-tester/README.md @@ -26,9 +26,13 @@ Python 3 can be downloaded from: 2. Linux (source) (**Gzipped source tarball**) 3. Mac (**macOS 64-bit/32-bit installer** or **macOS 64-bit/32-bit installer**) -On Windows: after installation - create an environment variable called PYTHON_PATH and set it to the folder containing the Python executable. +#### Windows +After installation - create an environment variable called PYTHON_PATH and set it to the folder containing the Python executable. + +#### Mac +After installation - run `open "/Applications/Python 3.6/Install Certificates.command"`. This is needed because the Mac Python supplied no longer links with the deprecated Apple-supplied system OpenSSL libraries but rather supplies a private copy of OpenSSL 1.0.2 which does not automatically access the system default root certificates. +Verify that `/usr/local/bin/python3` exists. -On Mac: after installation - run `open "/Applications/Python 3.6/Install Certificates.command"`. This is needed because the Mac Python supplied no longer links with the deprecated Apple-supplied system OpenSSL libraries but rather supplies a private copy of OpenSSL 1.0.2 which does not automatically access the system default root certificates. ### AWS interface #### Windows 1. Download the AWS CLI from `https://aws.amazon.com/cli/` @@ -38,8 +42,23 @@ On Mac: after installation - run `open "/Applications/Python 3.6/Install Certifi 1. Enter the secret key 1. Leave region name and ouput format as default [None] -1. Install the latest release of Boto3 via pip: ->pip install boto3 +1. Install the latest release of Boto3 via pip: +pip install boto3 +#### Mac +1. Install pip with the script provided by the Python Packaging Authority: +$ curl -O https://bootstrap.pypa.io/get-pip.py +$ python3 get-pip.py --user + +1. Use pip to install the AWS CLI. +$ pip3 install awscli --upgrade --user +This will install aws in your user. For user XXX, aws will be located in /Users/XXX/Library/Python/3.7/bin +1. Open a new command prompt and run `aws configure` +1. Enter the AWS account number +1. Enter the secret key +1. Leave region name and ouput format as default [None] +1. Install the latest release of Boto3 via pip: +pip3 install boto3 + # Create ![](./Create.PNG) From d851720cb01cc63566e1d741aaf52f49f0b8299c Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Nov 2018 16:57:28 -0700 Subject: [PATCH 103/182] Added method to detect OS type. Needed for testing. --- interface/src/scripting/TestScriptingInterface.cpp | 10 ++++++++++ interface/src/scripting/TestScriptingInterface.h | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index 52f6a3ebc0..36846a1fef 100644 --- a/interface/src/scripting/TestScriptingInterface.cpp +++ b/interface/src/scripting/TestScriptingInterface.cpp @@ -198,4 +198,14 @@ void TestScriptingInterface::setOtherAvatarsReplicaCount(int count) { int TestScriptingInterface::getOtherAvatarsReplicaCount() { return qApp->getOtherAvatarsReplicaCount(); +} + +QString TestScriptingInterface::getOperatingSystemType() { +#ifdef Q_OS_WIN + return "WINDOWS"; +#elif #defined Q_MAC_OS + return "MACOS"; +#else + return "UNKNOWN"; +#endif } \ No newline at end of file diff --git a/interface/src/scripting/TestScriptingInterface.h b/interface/src/scripting/TestScriptingInterface.h index 4a1d1a3eeb..a40826bd25 100644 --- a/interface/src/scripting/TestScriptingInterface.h +++ b/interface/src/scripting/TestScriptingInterface.h @@ -163,6 +163,12 @@ public slots: */ Q_INVOKABLE int getOtherAvatarsReplicaCount(); + /**jsdoc + * Returns the Operating Sytem type + * @function Test.getOperatingSystemType + */ + QString getOperatingSystemType(); + private: bool waitForCondition(qint64 maxWaitMs, std::function condition); QString _testResultsLocation; From 470a4904948d16fba5a6944a0045aef7c252d722 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Nov 2018 17:31:10 -0700 Subject: [PATCH 104/182] Typo. --- interface/src/scripting/TestScriptingInterface.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index 36846a1fef..a31e43d6c6 100644 --- a/interface/src/scripting/TestScriptingInterface.cpp +++ b/interface/src/scripting/TestScriptingInterface.cpp @@ -203,9 +203,9 @@ int TestScriptingInterface::getOtherAvatarsReplicaCount() { QString TestScriptingInterface::getOperatingSystemType() { #ifdef Q_OS_WIN return "WINDOWS"; -#elif #defined Q_MAC_OS +#elif defined Q_MAC_OS return "MACOS"; #else return "UNKNOWN"; #endif -} \ No newline at end of file +} From cd2194ad539467285e4b800c0f9863a6e75adbef Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Nov 2018 17:56:45 -0700 Subject: [PATCH 105/182] Correction for Linux --- tools/auto-tester/src/TestRunner.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index 7d2d57b0bc..906cb3ab06 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -229,11 +229,11 @@ void TestRunner::runInstaller() { QString installerFullPath = _workingFolder + "/" + _installerFilename; + QString commandLine; #ifdef Q_OS_WIN - QString commandLine = - "\"" + QDir::toNativeSeparators(installerFullPath) + "\"" + " /S /D=" + QDir::toNativeSeparators(_installationFolder); + commandLine = "\"" + QDir::toNativeSeparators(installerFullPath) + "\"" + " /S /D=" + QDir::toNativeSeparators(_installationFolder); #elif defined Q_OS_MAC - QString commandLine = "yes | " + _workingFolder + "/install_app.sh " + _workingFolder + "/HighFidelity-Beta-latest-dev.dmg"; + commandLine = "yes | " + _workingFolder + "/install_app.sh " + _workingFolder + "/HighFidelity-Beta-latest-dev.dmg"; #endif installerWorker->setCommandLine(commandLine); From 58bac436babc728a45b7a75a35c2c8143c4522fe Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Nov 2018 18:14:29 -0700 Subject: [PATCH 106/182] Fixed Linux error --- tools/auto-tester/src/TestRunner.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index 906cb3ab06..b2ef00647f 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -405,7 +405,7 @@ void TestRunner::runInterfaceWithTestScript() { #ifdef Q_OS_WIN url = "hifi://localhost"; #elif defined Q_OS_MAC - // TODO: Find out Mac equivalent of AppData, then this win't be needed + // TODO: Find out Mac equivalent of AppData, then this won't be needed url = "hifi://localhost/9999,9999,9999"; #endif } @@ -413,12 +413,13 @@ void TestRunner::runInterfaceWithTestScript() { QString testScript = QString("https://raw.githubusercontent.com/") + _user + "/hifi_tests/" + _branch + "/tests/testRecursive.js"; + QString commandLine; #ifdef Q_OS_WIN QString exeFile = QString("\"") + QDir::toNativeSeparators(_installationFolder) + "\\interface.exe\""; - QString commandLine = exeFile + " --url " + url + " --no-updater" + " --testScript " + testScript + + commandLine = exeFile + " --url " + url + " --no-updater" + " --testScript " + testScript + " quitWhenFinished --testResultsLocation " + _snapshotFolder; #elif defined Q_OS_MAC - QString commandLine = "open \"" +_installationFolder + "/interface.app\" --args" + + commandLine = "open \"" +_installationFolder + "/interface.app\" --args" + " --url " + url + " --no-updater" + " --testScript " + testScript + " quitWhenFinished" + From c7353e6c590c033e57c13ff8d49cbd992d9357f2 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 2 Nov 2018 09:57:58 -0700 Subject: [PATCH 107/182] Added `setWindowSize` - FOR TESTING ON MAC --- interface/src/scripting/TestScriptingInterface.cpp | 4 ++++ interface/src/scripting/TestScriptingInterface.h | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index a31e43d6c6..968c5b8001 100644 --- a/interface/src/scripting/TestScriptingInterface.cpp +++ b/interface/src/scripting/TestScriptingInterface.cpp @@ -209,3 +209,7 @@ QString TestScriptingInterface::getOperatingSystemType() { return "UNKNOWN"; #endif } + +void TestScriptingInterface::setWindowSize(int width, int height) { + qApp->getWindow()->resize(width, height); +} \ No newline at end of file diff --git a/interface/src/scripting/TestScriptingInterface.h b/interface/src/scripting/TestScriptingInterface.h index a40826bd25..8dbfded39c 100644 --- a/interface/src/scripting/TestScriptingInterface.h +++ b/interface/src/scripting/TestScriptingInterface.h @@ -166,9 +166,16 @@ public slots: /**jsdoc * Returns the Operating Sytem type * @function Test.getOperatingSystemType + * @returns {string} "WINDOWS", "MACOS" or "UNKNOWN" */ QString getOperatingSystemType(); + /**jsdoc + * Sets the size of the Window on desktop + * @function Test.getOperatingSystemType + */ + void setWindowSize(int width, int height); + private: bool waitForCondition(qint64 maxWaitMs, std::function condition); QString _testResultsLocation; From 70c0addc3f7c306e5fbd36485348291ca173612b Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 2 Nov 2018 10:47:17 -0700 Subject: [PATCH 108/182] Removed `setWindowSize` - crashes on both Windows and Mac. Fixed typo. --- interface/src/scripting/TestScriptingInterface.cpp | 6 +----- interface/src/scripting/TestScriptingInterface.h | 6 ------ 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index 968c5b8001..a9ba165037 100644 --- a/interface/src/scripting/TestScriptingInterface.cpp +++ b/interface/src/scripting/TestScriptingInterface.cpp @@ -203,13 +203,9 @@ int TestScriptingInterface::getOtherAvatarsReplicaCount() { QString TestScriptingInterface::getOperatingSystemType() { #ifdef Q_OS_WIN return "WINDOWS"; -#elif defined Q_MAC_OS +#elif defined Q_OS_MAC return "MACOS"; #else return "UNKNOWN"; #endif } - -void TestScriptingInterface::setWindowSize(int width, int height) { - qApp->getWindow()->resize(width, height); -} \ No newline at end of file diff --git a/interface/src/scripting/TestScriptingInterface.h b/interface/src/scripting/TestScriptingInterface.h index 8dbfded39c..26e967c9b5 100644 --- a/interface/src/scripting/TestScriptingInterface.h +++ b/interface/src/scripting/TestScriptingInterface.h @@ -170,12 +170,6 @@ public slots: */ QString getOperatingSystemType(); - /**jsdoc - * Sets the size of the Window on desktop - * @function Test.getOperatingSystemType - */ - void setWindowSize(int width, int height); - private: bool waitForCondition(qint64 maxWaitMs, std::function condition); QString _testResultsLocation; From 51272d8fec68d8831f4c591ddee328fa24405ed7 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 2 Nov 2018 13:09:07 -0700 Subject: [PATCH 109/182] Added setGeometry script command. --- interface/src/Application.cpp | 12 ++++++++++++ interface/src/Application.h | 6 ++++++ interface/src/scripting/TestScriptingInterface.cpp | 4 ++++ interface/src/scripting/TestScriptingInterface.h | 10 ++++++++++ 4 files changed, 32 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7cd91d76a0..30b5e3ed5f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3636,6 +3636,12 @@ void Application::onPresent(quint32 frameCount) { if (_renderEventHandler && !isAboutToQuit() && _pendingRenderEvent.compare_exchange_strong(expected, true)) { postEvent(_renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render)); } + + // This is done here so it won't be during a resize/move event + if (_setGeometryRequested) { + _setGeometryRequested = false; + _window->setGeometry(requestedGeometry); + } } static inline bool isKeyEvent(QEvent::Type type) { @@ -8578,6 +8584,12 @@ void Application::copyToClipboard(const QString& text) { QApplication::clipboard()->setText(text); } +void Application::setGeometry(int x, int y, int width, int height) { + // Note that calling setGeometry inside resizeEvent() or moveEvent() can cause infinite recursion + requestedGeometry = QRect(x, y, width, height); + _setGeometryRequested = true; +} + #if defined(Q_OS_ANDROID) void Application::beforeEnterBackground() { auto nodeList = DependencyManager::get(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 14e30b8006..cd5d62c106 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -315,6 +315,8 @@ public: Q_INVOKABLE void copyToClipboard(const QString& text); + void setGeometry(int x, int y, int width, int height); + int getOtherAvatarsReplicaCount() { return DependencyManager::get()->getReplicaCount(); } void setOtherAvatarsReplicaCount(int count) { DependencyManager::get()->setReplicaCount(count); } @@ -784,5 +786,9 @@ private: bool _showTrackedObjects { false }; bool _prevShowTrackedObjects { false }; + + // Data for the setGeometry script command + bool _setGeometryRequested{ false }; + QRect requestedGeometry; }; #endif // hifi_Application_h diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index a9ba165037..74b03faf83 100644 --- a/interface/src/scripting/TestScriptingInterface.cpp +++ b/interface/src/scripting/TestScriptingInterface.cpp @@ -209,3 +209,7 @@ QString TestScriptingInterface::getOperatingSystemType() { return "UNKNOWN"; #endif } + +void TestScriptingInterface::setGeometry(int x, int y, int width, int height) { + qApp->setGeometry(x, y, width, height); +} \ No newline at end of file diff --git a/interface/src/scripting/TestScriptingInterface.h b/interface/src/scripting/TestScriptingInterface.h index 26e967c9b5..6c2c542f33 100644 --- a/interface/src/scripting/TestScriptingInterface.h +++ b/interface/src/scripting/TestScriptingInterface.h @@ -170,6 +170,16 @@ public slots: */ QString getOperatingSystemType(); + /**jsdoc + * Sets the position and size of the window on desktop. All units are pixels + * @function Test.setGeometry + * @param {int} x - Distance of window from left edge + * @param {int} y - Distance of window from top edge + * @param {int} width - Width of window + * @param {int} height - Height of window + */ + void setGeometry(int x, int y, int width, int height); + private: bool waitForCondition(qint64 maxWaitMs, std::function condition); QString _testResultsLocation; From 562c9b11964dccfb53712653591ef6a59a869630 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 2 Nov 2018 13:35:38 -0700 Subject: [PATCH 110/182] "works" on Mac --- interface/src/Application.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 30b5e3ed5f..d5d99a34b5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3636,12 +3636,6 @@ void Application::onPresent(quint32 frameCount) { if (_renderEventHandler && !isAboutToQuit() && _pendingRenderEvent.compare_exchange_strong(expected, true)) { postEvent(_renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render)); } - - // This is done here so it won't be during a resize/move event - if (_setGeometryRequested) { - _setGeometryRequested = false; - _window->setGeometry(requestedGeometry); - } } static inline bool isKeyEvent(QEvent::Type type) { @@ -4810,6 +4804,12 @@ void Application::idle() { } } + // This is done here so it won't be during a resize/move event + if (_setGeometryRequested) { + _setGeometryRequested = false; + _window->setGeometry(requestedGeometry); + } + _overlayConductor.update(secondsSinceLastUpdate); _gameLoopCounter.increment(); From c0e7a4348bf1ce30a00a86ccc036fc7a8f75de12 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 5 Nov 2018 22:10:20 -0500 Subject: [PATCH 111/182] Reverted changes to Interface. --- interface/src/Application.cpp | 14 +------------- interface/src/Application.h | 6 ------ .../src/scripting/TestScriptingInterface.cpp | 14 -------------- .../src/scripting/TestScriptingInterface.h | 17 ----------------- 4 files changed, 1 insertion(+), 50 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d5d99a34b5..9f69bab82c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4803,13 +4803,7 @@ void Application::idle() { _idleLoopStdev.reset(); } } - - // This is done here so it won't be during a resize/move event - if (_setGeometryRequested) { - _setGeometryRequested = false; - _window->setGeometry(requestedGeometry); - } - + _overlayConductor.update(secondsSinceLastUpdate); _gameLoopCounter.increment(); @@ -8584,12 +8578,6 @@ void Application::copyToClipboard(const QString& text) { QApplication::clipboard()->setText(text); } -void Application::setGeometry(int x, int y, int width, int height) { - // Note that calling setGeometry inside resizeEvent() or moveEvent() can cause infinite recursion - requestedGeometry = QRect(x, y, width, height); - _setGeometryRequested = true; -} - #if defined(Q_OS_ANDROID) void Application::beforeEnterBackground() { auto nodeList = DependencyManager::get(); diff --git a/interface/src/Application.h b/interface/src/Application.h index cd5d62c106..14e30b8006 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -315,8 +315,6 @@ public: Q_INVOKABLE void copyToClipboard(const QString& text); - void setGeometry(int x, int y, int width, int height); - int getOtherAvatarsReplicaCount() { return DependencyManager::get()->getReplicaCount(); } void setOtherAvatarsReplicaCount(int count) { DependencyManager::get()->setReplicaCount(count); } @@ -786,9 +784,5 @@ private: bool _showTrackedObjects { false }; bool _prevShowTrackedObjects { false }; - - // Data for the setGeometry script command - bool _setGeometryRequested{ false }; - QRect requestedGeometry; }; #endif // hifi_Application_h diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index 74b03faf83..c3aeb2643b 100644 --- a/interface/src/scripting/TestScriptingInterface.cpp +++ b/interface/src/scripting/TestScriptingInterface.cpp @@ -199,17 +199,3 @@ void TestScriptingInterface::setOtherAvatarsReplicaCount(int count) { int TestScriptingInterface::getOtherAvatarsReplicaCount() { return qApp->getOtherAvatarsReplicaCount(); } - -QString TestScriptingInterface::getOperatingSystemType() { -#ifdef Q_OS_WIN - return "WINDOWS"; -#elif defined Q_OS_MAC - return "MACOS"; -#else - return "UNKNOWN"; -#endif -} - -void TestScriptingInterface::setGeometry(int x, int y, int width, int height) { - qApp->setGeometry(x, y, width, height); -} \ No newline at end of file diff --git a/interface/src/scripting/TestScriptingInterface.h b/interface/src/scripting/TestScriptingInterface.h index 6c2c542f33..4a1d1a3eeb 100644 --- a/interface/src/scripting/TestScriptingInterface.h +++ b/interface/src/scripting/TestScriptingInterface.h @@ -163,23 +163,6 @@ public slots: */ Q_INVOKABLE int getOtherAvatarsReplicaCount(); - /**jsdoc - * Returns the Operating Sytem type - * @function Test.getOperatingSystemType - * @returns {string} "WINDOWS", "MACOS" or "UNKNOWN" - */ - QString getOperatingSystemType(); - - /**jsdoc - * Sets the position and size of the window on desktop. All units are pixels - * @function Test.setGeometry - * @param {int} x - Distance of window from left edge - * @param {int} y - Distance of window from top edge - * @param {int} width - Width of window - * @param {int} height - Height of window - */ - void setGeometry(int x, int y, int width, int height); - private: bool waitForCondition(qint64 maxWaitMs, std::function condition); QString _testResultsLocation; From e9a636d751f15c677a1baf4dfc33fd24190070e4 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 5 Nov 2018 22:13:02 -0500 Subject: [PATCH 112/182] Revert... --- interface/src/Application.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9f69bab82c..69d114e51b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4803,7 +4803,6 @@ void Application::idle() { _idleLoopStdev.reset(); } } - _overlayConductor.update(secondsSinceLastUpdate); _gameLoopCounter.increment(); From ebdd443646cfc38849e285d8ab6efdd8f7bb71b5 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 6 Nov 2018 10:19:27 -0500 Subject: [PATCH 113/182] New resize method for Mac. --- tools/auto-tester/src/TestRunner.cpp | 62 ++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index b2ef00647f..3781024a63 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -129,11 +129,11 @@ void TestRunner::setWorkingFolder() { script.close(); script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); - // The Mac shell command returns immediately. This little script waits for a process to complete - script.setFileName(_workingFolder + "/waitForCompletion.sh"); + // This script waits for a process to start + script.setFileName(_workingFolder + "/waitForStart.sh"); if (!script.open(QIODevice::WriteOnly | QIODevice::Text)) { QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), - "Could not open 'install_app.sh'"); + "Could not open 'waitForStart.sh'"); exit(-1); } @@ -145,7 +145,55 @@ void TestRunner::setWorkingFolder() { script.write("done\n"); script.close(); script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); - #endif + + // The Mac shell command returns immediately. This little script waits for a process to complete + script.setFileName(_workingFolder + "/waitForCompletion.sh"); + if (!script.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), + "Could not open 'waitForCompletion.sh'"); + exit(-1); + } + + script.write("#!/bin/sh\n\n"); + script.write("PROCESS=\"$1\"\n"); + script.write("while (pgrep $PROCESS)\n"); + script.write("do\n"); + script.write("\tsleep 2\n"); + script.write("done\n"); + script.close(); + script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); + + // Create an AppleScript to resize Interface. This is needed so that snapshots taken + // with the primary camera will be the correct size. + // This will be run from a normal shell script + script.setFileName(_workingFolder + "/setInterfaceSizeAndPosition.scpt"); + if (!script.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), + "Could not open 'setInterfaceSizeAndPosition.scpt'"); + exit(-1); + } + + script.write("set width to 960\n"); + script.write("set height to 540\n"); + script.write("set x to 100\n"); + script.write("set y to 100\n\n"); + script.write("tell application \"System Events\" to tell application process \"interface\" to tell window 1 to set {size, position} to {{width, height}, {x, y}})\n"); + + script.close(); + script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); + + script.setFileName(_workingFolder + "/setInterfaceSizeAndPosition.sh"); + if (!script.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), + "Could not open 'setInterfaceSizeAndPosition.sh'"); + exit(-1); + } + + script.write("#!/bin/sh\n\n"); + script.write((_workingFolder + "/osascript " + _workingFolder + "/setInterfaceSizeAndPosition.scpt\n").toStdString().c_str()); + script.close(); + script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); +#endif } void TestRunner::run() { @@ -419,11 +467,17 @@ void TestRunner::runInterfaceWithTestScript() { commandLine = exeFile + " --url " + url + " --no-updater" + " --testScript " + testScript + " quitWhenFinished --testResultsLocation " + _snapshotFolder; #elif defined Q_OS_MAC + // On The Mac, we need to resize Interface. The Interface window opens a few seconds after the process has started, + // so we wait another 10 seconds + // The shell closes if we don't wait for completion, hence the final line commandLine = "open \"" +_installationFolder + "/interface.app\" --args" + " --url " + url + " --no-updater" + " --testScript " + testScript + " quitWhenFinished" + " --testResultsLocation " + _snapshotFolder + + "; " + _workingFolder +"/waitForStart.sh interface" + + "; " + "sleep 10" + + "; " + _workingFolder +"/setInterfaceSizeAndPosition.sh" + "; " + _workingFolder +"/waitForCompletion.sh interface"; #endif From 189a799a3a1f8a672983b48b782a933683f00d36 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 7 Nov 2018 08:58:38 -0800 Subject: [PATCH 114/182] Added method to detect OS type. Needed for running automated tests. --- interface/src/scripting/TestScriptingInterface.cpp | 10 ++++++++++ interface/src/scripting/TestScriptingInterface.h | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index c3aeb2643b..a9ba165037 100644 --- a/interface/src/scripting/TestScriptingInterface.cpp +++ b/interface/src/scripting/TestScriptingInterface.cpp @@ -199,3 +199,13 @@ void TestScriptingInterface::setOtherAvatarsReplicaCount(int count) { int TestScriptingInterface::getOtherAvatarsReplicaCount() { return qApp->getOtherAvatarsReplicaCount(); } + +QString TestScriptingInterface::getOperatingSystemType() { +#ifdef Q_OS_WIN + return "WINDOWS"; +#elif defined Q_OS_MAC + return "MACOS"; +#else + return "UNKNOWN"; +#endif +} diff --git a/interface/src/scripting/TestScriptingInterface.h b/interface/src/scripting/TestScriptingInterface.h index 4a1d1a3eeb..26e967c9b5 100644 --- a/interface/src/scripting/TestScriptingInterface.h +++ b/interface/src/scripting/TestScriptingInterface.h @@ -163,6 +163,13 @@ public slots: */ Q_INVOKABLE int getOtherAvatarsReplicaCount(); + /**jsdoc + * Returns the Operating Sytem type + * @function Test.getOperatingSystemType + * @returns {string} "WINDOWS", "MACOS" or "UNKNOWN" + */ + QString getOperatingSystemType(); + private: bool waitForCondition(qint64 maxWaitMs, std::function condition); QString _testResultsLocation; From f0dd07294e0132eb8ffb83f3f10ecd84da226d4b Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 7 Nov 2018 15:10:01 -0800 Subject: [PATCH 115/182] Added the no-login option. --- interface/src/Application.cpp | 40 ++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5caf58e992..155ef3549b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2337,23 +2337,29 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(&AndroidHelper::instance(), &AndroidHelper::enterForeground, this, &Application::enterForeground); AndroidHelper::instance().notifyLoadComplete(); #else - static int CHECK_LOGIN_TIMER = 3000; - QTimer* checkLoginTimer = new QTimer(this); - checkLoginTimer->setInterval(CHECK_LOGIN_TIMER); - checkLoginTimer->setSingleShot(true); - connect(checkLoginTimer, &QTimer::timeout, this, []() { - auto accountManager = DependencyManager::get(); - auto dialogsManager = DependencyManager::get(); - if (!accountManager->isLoggedIn()) { - Setting::Handle{"loginDialogPoppedUp", false}.set(true); - dialogsManager->showLoginDialog(); - QJsonObject loginData = {}; - loginData["action"] = "login dialog shown"; - UserActivityLogger::getInstance().logAction("encourageLoginDialog", loginData); - } - }); - Setting::Handle{"loginDialogPoppedUp", false}.set(false); - checkLoginTimer->start(); + // Do not show login dialog if requested not to on the command line + const QString HIFI_NO_LOGIN_COMMAND_LINE_KEY = "--no-login-suggestion"; + int index = arguments().indexOf(HIFI_NO_LOGIN_COMMAND_LINE_KEY); + if (index == -1) { + // request not found + static int CHECK_LOGIN_TIMER = 3000; + QTimer* checkLoginTimer = new QTimer(this); + checkLoginTimer->setInterval(CHECK_LOGIN_TIMER); + checkLoginTimer->setSingleShot(true); + connect(checkLoginTimer, &QTimer::timeout, this, []() { + auto accountManager = DependencyManager::get(); + auto dialogsManager = DependencyManager::get(); + if (!accountManager->isLoggedIn()) { + Setting::Handle{"loginDialogPoppedUp", false}.set(true); + dialogsManager->showLoginDialog(); + QJsonObject loginData = {}; + loginData["action"] = "login dialog shown"; + UserActivityLogger::getInstance().logAction("encourageLoginDialog", loginData); + } + }); + Setting::Handle{"loginDialogPoppedUp", false}.set(false); + checkLoginTimer->start(); + } #endif } From 7e93d91bfa841cb4b35cba92eb58aef8f9bc7fb6 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 8 Nov 2018 09:29:02 +0100 Subject: [PATCH 116/182] 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 117/182] 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 118/182] 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 119/182] 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 120/182] 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 121/182] 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 122/182] 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 123/182] 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 124/182] 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 125/182] 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 126/182] 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 127/182] 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 dd7ce2cfffbdc5693ab7c4e256d92a00a464306e Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 8 Nov 2018 08:37:44 -0800 Subject: [PATCH 128/182] Enable GitHub fields correctly on MAC --- tools/auto-tester/src/ui/AutoTester.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index d49f3aaa1c..9eac1a35e5 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -97,7 +97,12 @@ void AutoTester::startTestsEvaluation(const bool isRunningFromCommandLine, } void AutoTester::on_tabWidget_currentChanged(int index) { +// Enable the GitHub edit boxes as required +#ifdef Q_OS_WIN if (index == 0 || index == 2 || index == 3) { +#elif defined Q_OS_MAC + if (index == 0 || index == 1 || index == 2) { +#endif _ui.userLineEdit->setDisabled(false); _ui.branchLineEdit->setDisabled(false); } else { @@ -307,4 +312,4 @@ void AutoTester::updateStatusLabel(const QString& status) { void AutoTester::appendLogWindow(const QString& message) { _ui.plainTextEdit->appendPlainText(message); -} \ No newline at end of file +} From 8b2287126af908a12609e21e559bb2334e4c54d1 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 8 Nov 2018 08:38:44 -0800 Subject: [PATCH 129/182] WIP - working on MAC --- tools/auto-tester/src/TestRunner.cpp | 180 +++++++++++++++++---------- tools/auto-tester/src/TestRunner.h | 14 ++- 2 files changed, 123 insertions(+), 71 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index 3781024a63..b947f2544a 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -43,27 +43,29 @@ TestRunner::TestRunner(std::vector dayCheckboxes, _url = url; _runNow = runNow; - installerThread = new QThread(); - installerWorker = new Worker(); - installerWorker->moveToThread(installerThread); - installerThread->start(); - connect(this, SIGNAL(startInstaller()), installerWorker, SLOT(runCommand())); - connect(installerWorker, SIGNAL(commandComplete()), this, SLOT(installationComplete())); + _installerThread = new QThread(); + _installerWorker = new Worker(); + + _installerWorker->moveToThread(_installerThread); + _installerThread->start(); + connect(this, SIGNAL(startInstaller()), _installerWorker, SLOT(runCommand())); + connect(_installerWorker, SIGNAL(commandComplete()), this, SLOT(installationComplete())); - interfaceThread = new QThread(); - interfaceWorker = new Worker(); - interfaceThread->start(); - interfaceWorker->moveToThread(interfaceThread); - connect(this, SIGNAL(startInterface()), interfaceWorker, SLOT(runCommand())); - connect(interfaceWorker, SIGNAL(commandComplete()), this, SLOT(interfaceExecutionComplete())); + _interfaceThread = new QThread(); + _interfaceWorker = new Worker(); + + _interfaceThread->start(); + _interfaceWorker->moveToThread(_interfaceThread); + connect(this, SIGNAL(startInterface()), _interfaceWorker, SLOT(runCommand())); + connect(_interfaceWorker, SIGNAL(commandComplete()), this, SLOT(interfaceExecutionComplete())); } TestRunner::~TestRunner() { - delete installerThread; - delete interfaceThread; + delete _installerThread; + delete _installerWorker; - delete interfaceThread; - delete interfaceWorker; + delete _interfaceThread; + delete _interfaceWorker; if (_timer) { delete _timer; @@ -105,30 +107,7 @@ void TestRunner::setWorkingFolder() { #ifdef Q_OS_MAC // Create MAC shell scripts QFile script; - script.setFileName(_workingFolder + "/install_app.sh"); - if (!script.open(QIODevice::WriteOnly | QIODevice::Text)) { - QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), - "Could not open 'install_app.sh'"); - exit(-1); - } - QString installFolder = QString("\"") + _workingFolder + "/High_Fidelity\""; - if (!QDir().exists(installFolder)) { - QDir().mkdir(installFolder); - } - - // This script installs High Fidelity. It is run as "yes | install_app.sh... so "yes" is killed at the end - script.write("#!/bin/sh\n\n"); - script.write("VOLUME=`hdiutil attach \"$1\" | grep Volumes | awk '{print $3}'`\n"); - - script.write((QString("cp -rf \"$VOLUME/") + "/High Fidelity/interface.app\" \"" + _workingFolder + "/High_Fidelity/\"\n").toStdString().c_str()); - script.write((QString("cp -rf \"$VOLUME/") + "/High Fidelity/Sandbox.app\" \"" + _workingFolder + "/High_Fidelity/\"\n").toStdString().c_str()); - - script.write("hdiutil detach \"$VOLUME\"\n"); - script.write("killall yes\n"); - script.close(); - script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); - // This script waits for a process to start script.setFileName(_workingFolder + "/waitForStart.sh"); if (!script.open(QIODevice::WriteOnly | QIODevice::Text)) { @@ -139,27 +118,31 @@ void TestRunner::setWorkingFolder() { script.write("#!/bin/sh\n\n"); script.write("PROCESS=\"$1\"\n"); - script.write("while (pgrep $PROCESS)\n"); + script.write("until (pgrep $PROCESS >nul)\n"); script.write("do\n"); + script.write("\techo waiting for \"$1\" to start\n"); script.write("\tsleep 2\n"); script.write("done\n"); + script.write("echo \"$1\" \"started\"\n"); script.close(); script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); - // The Mac shell command returns immediately. This little script waits for a process to complete - script.setFileName(_workingFolder + "/waitForCompletion.sh"); + // The Mac shell command returns immediately. This little script waits for a process to finish + script.setFileName(_workingFolder + "/waitForFinish.sh"); if (!script.open(QIODevice::WriteOnly | QIODevice::Text)) { QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), - "Could not open 'waitForCompletion.sh'"); + "Could not open 'waitForFinish.sh'"); exit(-1); } script.write("#!/bin/sh\n\n"); script.write("PROCESS=\"$1\"\n"); - script.write("while (pgrep $PROCESS)\n"); + script.write("while (pgrep $PROCESS >nul)\n"); script.write("do\n"); + script.write("\techo waiting for \"$1\" to finish\n"); script.write("\tsleep 2\n"); script.write("done\n"); + script.write("echo \"$1\" \"finished\"\n"); script.close(); script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); @@ -177,7 +160,7 @@ void TestRunner::setWorkingFolder() { script.write("set height to 540\n"); script.write("set x to 100\n"); script.write("set y to 100\n\n"); - script.write("tell application \"System Events\" to tell application process \"interface\" to tell window 1 to set {size, position} to {{width, height}, {x, y}})\n"); + script.write("tell application \"System Events\" to tell application process \"interface\" to tell window 1 to set {size, position} to {{width, height}, {x, y}}\n"); script.close(); script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); @@ -190,7 +173,7 @@ void TestRunner::setWorkingFolder() { } script.write("#!/bin/sh\n\n"); - script.write((_workingFolder + "/osascript " + _workingFolder + "/setInterfaceSizeAndPosition.scpt\n").toStdString().c_str()); + script.write(("osascript " + _workingFolder + "/setInterfaceSizeAndPosition.scpt\n").toStdString().c_str()); script.close(); script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); #endif @@ -281,10 +264,39 @@ void TestRunner::runInstaller() { #ifdef Q_OS_WIN commandLine = "\"" + QDir::toNativeSeparators(installerFullPath) + "\"" + " /S /D=" + QDir::toNativeSeparators(_installationFolder); #elif defined Q_OS_MAC - commandLine = "yes | " + _workingFolder + "/install_app.sh " + _workingFolder + "/HighFidelity-Beta-latest-dev.dmg"; -#endif + // Create installation shell script + QFile script; + script.setFileName(_workingFolder + "/install_app.sh"); + if (!script.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), + "Could not open 'install_app.sh'"); + exit(-1); + } + + if (!QDir().exists(_installationFolder)) { + QDir().mkdir(_installationFolder); + } + + // This script installs High Fidelity. It is run as "yes | install_app.sh... so "yes" is killed at the end + script.write("#!/bin/sh\n\n"); + script.write("VOLUME=`hdiutil attach \"$1\" | grep Volumes | awk '{print $3}'`\n"); + + QString folderName {"High Fidelity"}; + if (!_runLatest->isChecked()) { + folderName += QString(" - ") + getPRNumberFromURL(_url->text()); + } - installerWorker->setCommandLine(commandLine); + script.write((QString("cp -rf \"$VOLUME/") + folderName + "/interface.app\" \"" + _workingFolder + "/High_Fidelity/\"\n").toStdString().c_str()); + script.write((QString("cp -rf \"$VOLUME/") + folderName + "/Sandbox.app\" \"" + _workingFolder + "/High_Fidelity/\"\n").toStdString().c_str()); + + script.write("hdiutil detach \"$VOLUME\"\n"); + script.write("killall yes\n"); + script.close(); + script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); + commandLine = "yes | " + _workingFolder + "/install_app.sh " + installerFullPath; +#endif + appendLog(commandLine); + _installerWorker->setCommandLine(commandLine); emit startInstaller(); } @@ -415,10 +427,15 @@ void TestRunner::killProcesses() { exit(-1); } #elif defined Q_OS_MAC - QString commandLine = QString("killall interface") + "; " + _workingFolder +"/waitForCompletion.sh interface"; + QString commandLine; + + commandLine = QString("killall interface") + "; " + _workingFolder +"/waitForFinish.sh interface"; system(commandLine.toStdString().c_str()); - - commandLine = QString("killall Sandbox") + "; " + _workingFolder +"/waitForCompletion.sh interface"; + + commandLine = QString("killall Sandbox") + "; " + _workingFolder +"/waitForFinish.sh Sandbox"; + system(commandLine.toStdString().c_str()); + + commandLine = QString("killall Console") + "; " + _workingFolder +"/waitForFinish.sh Console"; system(commandLine.toStdString().c_str()); #endif } @@ -464,28 +481,56 @@ void TestRunner::runInterfaceWithTestScript() { QString commandLine; #ifdef Q_OS_WIN QString exeFile = QString("\"") + QDir::toNativeSeparators(_installationFolder) + "\\interface.exe\""; - commandLine = exeFile + " --url " + url + " --no-updater" + " --testScript " + testScript + - " quitWhenFinished --testResultsLocation " + _snapshotFolder; + commandLine = exeFile + + " --url " + url + + " --no-updater" + + " --no-login-suggestion" + " --testScript " + testScript + " quitWhenFinished" + + " --testResultsLocation " + _snapshotFolder; + + interfaceWorker->setCommandLine(commandLine); + emit startInterface(); #elif defined Q_OS_MAC - // On The Mac, we need to resize Interface. The Interface window opens a few seconds after the process has started, - // so we wait another 10 seconds - // The shell closes if we don't wait for completion, hence the final line - commandLine = "open \"" +_installationFolder + "/interface.app\" --args" + + // On The Mac, we need to resize Interface. The Interface window opens a few seconds after the process + // has started. + // Before starting interface, start a process that will resize interface 10s after it opens + // This is performed by creating a bash script that runs to processes + QFile script; + script.setFileName(_workingFolder + "/runInterfaceTests.sh"); + if (!script.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), + "Could not open 'runInterfaceTests.sh'"); + exit(-1); + } + + script.write("#!/bin/sh\n\n"); + + commandLine = _workingFolder +"/waitForStart.sh interface && sleep 10 && " + _workingFolder +"/setInterfaceSizeAndPosition.sh &\n"; + script.write(commandLine.toStdString().c_str()); + + commandLine = + "open \"" +_installationFolder + "/interface.app\" --args" + " --url " + url + " --no-updater" + + " --no-login-suggestion" " --testScript " + testScript + " quitWhenFinished" + " --testResultsLocation " + _snapshotFolder + - "; " + _workingFolder +"/waitForStart.sh interface" + - "; " + "sleep 10" + - "; " + _workingFolder +"/setInterfaceSizeAndPosition.sh" + - "; " + _workingFolder +"/waitForCompletion.sh interface"; + " && " + _workingFolder +"/waitForStart.sh interface" + + " && " + _workingFolder +"/waitForFinish.sh interface"; + + script.write(commandLine.toStdString().c_str()); + + script.close(); + script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); + + commandLine = _workingFolder + "/runInterfaceTests.sh"; + _interfaceWorker->setCommandLine(commandLine); + + emit startInterface(); #endif // Helpful for debugging appendLog(commandLine); - - interfaceWorker->setCommandLine(commandLine); - emit startInterface(); } void TestRunner::interfaceExecutionComplete() { @@ -637,6 +682,7 @@ void TestRunner::appendLog(const QString& message) { QString TestRunner::getInstallerNameFromURL(const QString& url) { // An example URL: https://deployment.highfidelity.com/jobs/pr-build/label%3Dwindows/13023/HighFidelity-Beta-Interface-PR14006-be76c43.exe + // On Mac, replace `exe` with `dmg` try { QStringList urlParts = url.split("/"); return urlParts[urlParts.size() - 1]; @@ -654,7 +700,11 @@ QString TestRunner::getPRNumberFromURL(const QString& url) { QStringList urlParts = url.split("/"); QStringList filenameParts = urlParts[urlParts.size() - 1].split("-"); if (filenameParts.size() <= 3) { +#ifdef Q_OS_WIN throw "URL not in expected format, should look like `https://deployment.highfidelity.com/jobs/pr-build/label%3Dwindows/13023/HighFidelity-Beta-Interface-PR14006-be76c43.exe`"; +#elif defined Q_OS_MAC + throw "URL not in expected format, should look like `https://deployment.highfidelity.com/jobs/pr-build/label%3Dwindows/13023/HighFidelity-Beta-Interface-PR14006-be76c43.dmg`"; +#endif } return filenameParts[filenameParts.size() - 2]; } catch (QString errorMessage) { diff --git a/tools/auto-tester/src/TestRunner.h b/tools/auto-tester/src/TestRunner.h index 8267a042b7..11129d2f36 100644 --- a/tools/auto-tester/src/TestRunner.h +++ b/tools/auto-tester/src/TestRunner.h @@ -84,7 +84,8 @@ private slots: signals: void startInstaller(); void startInterface(); - + void startResize(); + private: bool _automatedTestIsRunning{ false }; @@ -130,11 +131,12 @@ private: QDateTime _testStartDateTime; - QThread* installerThread; - QThread* interfaceThread; - Worker* installerWorker; - Worker* interfaceWorker; + QThread* _installerThread; + QThread* _interfaceThread; + Worker* _installerWorker; + Worker* _interfaceWorker; + BuildInformation _buildInformation; }; @@ -150,7 +152,7 @@ signals: void commandComplete(); void startInstaller(); void startInterface(); - + private: QString _commandLine; }; From 05939f8a7c81fef1dc86fdd165d8bb1b4197be25 Mon Sep 17 00:00:00 2001 From: r3tk0n Date: Thu, 8 Nov 2018 11:09:19 -0800 Subject: [PATCH 130/182] Fix settings to only show relevant HMD controls. --- interface/resources/html/tabletHelp.html | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/interface/resources/html/tabletHelp.html b/interface/resources/html/tabletHelp.html index 279213bbcb..68a34245c7 100644 --- a/interface/resources/html/tabletHelp.html +++ b/interface/resources/html/tabletHelp.html @@ -66,7 +66,7 @@ From 1bd978e4c3a0695532a00d0573f0ef0f0d488ef4 Mon Sep 17 00:00:00 2001 From: r3tk0n Date: Thu, 8 Nov 2018 11:22:43 -0800 Subject: [PATCH 131/182] Clean up code in tabletHelp.html --- interface/resources/html/tabletHelp.html | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/interface/resources/html/tabletHelp.html b/interface/resources/html/tabletHelp.html index 68a34245c7..a1739b3d67 100644 --- a/interface/resources/html/tabletHelp.html +++ b/interface/resources/html/tabletHelp.html @@ -137,29 +137,24 @@ switch (params.handControllerName) { case "oculus": handControllerImageURL = "img/tablet-help-oculus.jpg"; - index = 0; break; case "windowsMR": handControllerImageURL = "img/tablet-help-windowsMR.jpg"; - index = 0; break; case "vive": handControllerImageURL = "img/tablet-help-vive.jpg"; - index = 0; default: - } switch (params.defaultTab) { + case "handControllers": + showHandControllers(); + index = 0; + break; case "gamepad": showGamepad(); index = 1; break; - - case "handControllers": - showHandControllers(); - break; - case "kbm": default: showKbm(); From a6494bf379eaaf20ace3b81c677b4d2a57af70c4 Mon Sep 17 00:00:00 2001 From: r3tk0n Date: Thu, 8 Nov 2018 11:25:55 -0800 Subject: [PATCH 132/182] Fix edge case with Oculus. --- interface/resources/html/tabletHelp.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/resources/html/tabletHelp.html b/interface/resources/html/tabletHelp.html index a1739b3d67..f3e60ff16f 100644 --- a/interface/resources/html/tabletHelp.html +++ b/interface/resources/html/tabletHelp.html @@ -135,15 +135,15 @@ } switch (params.handControllerName) { - case "oculus": - handControllerImageURL = "img/tablet-help-oculus.jpg"; - break; case "windowsMR": handControllerImageURL = "img/tablet-help-windowsMR.jpg"; break; case "vive": handControllerImageURL = "img/tablet-help-vive.jpg"; + break; + case "oculus": default: + handControllerImageURL = "img/tablet-help-oculus.jpg"; } switch (params.defaultTab) { From b4be7544b9fedd28b95334ed1f811b2a4c054407 Mon Sep 17 00:00:00 2001 From: Jason Najera <39922250+r3tk0n@users.noreply.github.com> Date: Thu, 8 Nov 2018 13:15:19 -0800 Subject: [PATCH 133/182] Attempt to fix spacing Weird thing is it still looked fine in GitHub's editor... --- interface/resources/html/tabletHelp.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/html/tabletHelp.html b/interface/resources/html/tabletHelp.html index f3e60ff16f..a48ee9d6d1 100644 --- a/interface/resources/html/tabletHelp.html +++ b/interface/resources/html/tabletHelp.html @@ -147,7 +147,7 @@ } switch (params.defaultTab) { - case "handControllers": + case "handControllers": showHandControllers(); index = 0; break; From 59bba5b6e69c9487f4a01b58f97b43d7e3f10129 Mon Sep 17 00:00:00 2001 From: Jason Najera <39922250+r3tk0n@users.noreply.github.com> Date: Thu, 8 Nov 2018 13:16:24 -0800 Subject: [PATCH 134/182] More attempt to fix indentation. Still looked fine in github's editor and N++. --- interface/resources/html/tabletHelp.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/html/tabletHelp.html b/interface/resources/html/tabletHelp.html index a48ee9d6d1..1399c98f9f 100644 --- a/interface/resources/html/tabletHelp.html +++ b/interface/resources/html/tabletHelp.html @@ -149,7 +149,7 @@ switch (params.defaultTab) { case "handControllers": showHandControllers(); - index = 0; + index = 0; break; case "gamepad": showGamepad(); From 84209c0e5319a1b7cfbb23c65b2f30a0834a50fd Mon Sep 17 00:00:00 2001 From: r3tk0n Date: Thu, 8 Nov 2018 13:18:25 -0800 Subject: [PATCH 135/182] Finally fix all indentation. --- interface/resources/html/tabletHelp.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/html/tabletHelp.html b/interface/resources/html/tabletHelp.html index 1399c98f9f..cc931580c3 100644 --- a/interface/resources/html/tabletHelp.html +++ b/interface/resources/html/tabletHelp.html @@ -139,11 +139,11 @@ handControllerImageURL = "img/tablet-help-windowsMR.jpg"; break; case "vive": - handControllerImageURL = "img/tablet-help-vive.jpg"; - break; - case "oculus": + handControllerImageURL = "img/tablet-help-vive.jpg"; + break; + case "oculus": default: - handControllerImageURL = "img/tablet-help-oculus.jpg"; + handControllerImageURL = "img/tablet-help-oculus.jpg"; } switch (params.defaultTab) { From 8aea237ad755ebee312e80d06505769019fd5bd6 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 8 Nov 2018 14:26:27 -0800 Subject: [PATCH 136/182] Fixed endless wait --- tools/auto-tester/src/TestRunner.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp index b947f2544a..740b3f4087 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/auto-tester/src/TestRunner.cpp @@ -118,7 +118,7 @@ void TestRunner::setWorkingFolder() { script.write("#!/bin/sh\n\n"); script.write("PROCESS=\"$1\"\n"); - script.write("until (pgrep $PROCESS >nul)\n"); + script.write("until (pgrep -x $PROCESS >nul)\n"); script.write("do\n"); script.write("\techo waiting for \"$1\" to start\n"); script.write("\tsleep 2\n"); @@ -137,7 +137,7 @@ void TestRunner::setWorkingFolder() { script.write("#!/bin/sh\n\n"); script.write("PROCESS=\"$1\"\n"); - script.write("while (pgrep $PROCESS >nul)\n"); + script.write("while (pgrep -x $PROCESS >nul)\n"); script.write("do\n"); script.write("\techo waiting for \"$1\" to finish\n"); script.write("\tsleep 2\n"); @@ -515,7 +515,6 @@ void TestRunner::runInterfaceWithTestScript() { " --no-login-suggestion" " --testScript " + testScript + " quitWhenFinished" + " --testResultsLocation " + _snapshotFolder + - " && " + _workingFolder +"/waitForStart.sh interface" + " && " + _workingFolder +"/waitForFinish.sh interface"; script.write(commandLine.toStdString().c_str()); From 9b60103f47c1d38b177817e7600b57feb998a08a Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 8 Nov 2018 15:07:32 -0800 Subject: [PATCH 137/182] Renaming auto-tester ==> nitpick --- tools/CMakeLists.txt | 4 +- .../AppDataHighFidelity/Interface.json | 0 .../Interface/AccountInfo.bin | Bin .../Interface/avatarbookmarks.json | 0 .../assignment-client/entities/models.json.gz | Bin .../domain-server/AccountInfo.bin | Bin .../domain-server/config.json | 0 .../domain-server/entities/models.json.gz | Bin tools/{auto-tester => nitpick}/CMakeLists.txt | 4 +- tools/{auto-tester => nitpick}/Create.PNG | Bin tools/{auto-tester => nitpick}/Evaluate.PNG | Bin tools/{auto-tester => nitpick}/README.md | 29 +++--- tools/{auto-tester => nitpick}/Run.PNG | Bin .../TestRailSelector.PNG | Bin .../Web Interface.PNG | Bin .../{auto-tester => nitpick}/WebInterface.PNG | Bin tools/{auto-tester => nitpick}/Windows.PNG | Bin .../nitpickMismatchExample.PNG} | Bin tools/{auto-tester => nitpick}/setup_7z.PNG | Bin .../src/AWSInterface.cpp | 0 .../src/AWSInterface.h | 0 .../src/Downloader.cpp | 0 .../{auto-tester => nitpick}/src/Downloader.h | 0 .../src/ImageComparer.cpp | 0 .../src/ImageComparer.h | 0 .../src/PythonInterface.cpp | 0 .../src/PythonInterface.h | 0 tools/{auto-tester => nitpick}/src/Test.cpp | 64 ++++++------ tools/{auto-tester => nitpick}/src/Test.h | 2 +- .../src/TestRailInterface.cpp | 0 .../src/TestRailInterface.h | 0 .../src/TestRunner.cpp | 20 ++-- .../{auto-tester => nitpick}/src/TestRunner.h | 0 tools/{auto-tester => nitpick}/src/common.h | 0 tools/{auto-tester => nitpick}/src/main.cpp | 12 +-- .../src/ui/BusyWindow.cpp | 0 .../src/ui/BusyWindow.h | 0 .../src/ui/BusyWindow.ui | 0 .../src/ui/HelpWindow.cpp | 0 .../src/ui/HelpWindow.h | 0 .../src/ui/HelpWindow.ui | 2 +- .../src/ui/MismatchWindow.cpp | 0 .../src/ui/MismatchWindow.h | 0 .../src/ui/MismatchWindow.ui | 0 .../src/ui/Nitpick.cpp} | 92 +++++++++--------- .../AutoTester.h => nitpick/src/ui/Nitpick.h} | 18 ++-- .../src/ui/Nitpick.ui} | 6 +- .../src/ui/TestRailResultsSelectorWindow.cpp | 0 .../src/ui/TestRailResultsSelectorWindow.h | 0 .../src/ui/TestRailResultsSelectorWindow.ui | 0 .../src/ui/TestRailRunSelectorWindow.cpp | 0 .../src/ui/TestRailRunSelectorWindow.h | 0 .../src/ui/TestRailRunSelectorWindow.ui | 0 .../ui/TestRailTestCasesSelectorWindow.cpp | 0 .../src/ui/TestRailTestCasesSelectorWindow.h | 0 .../src/ui/TestRailTestCasesSelectorWindow.ui | 0 56 files changed, 126 insertions(+), 127 deletions(-) rename tools/{auto-tester => nitpick}/AppDataHighFidelity/Interface.json (100%) rename tools/{auto-tester => nitpick}/AppDataHighFidelity/Interface/AccountInfo.bin (100%) rename tools/{auto-tester => nitpick}/AppDataHighFidelity/Interface/avatarbookmarks.json (100%) rename tools/{auto-tester => nitpick}/AppDataHighFidelity/assignment-client/entities/models.json.gz (100%) rename tools/{auto-tester => nitpick}/AppDataHighFidelity/domain-server/AccountInfo.bin (100%) rename tools/{auto-tester => nitpick}/AppDataHighFidelity/domain-server/config.json (100%) rename tools/{auto-tester => nitpick}/AppDataHighFidelity/domain-server/entities/models.json.gz (100%) rename tools/{auto-tester => nitpick}/CMakeLists.txt (95%) rename tools/{auto-tester => nitpick}/Create.PNG (100%) rename tools/{auto-tester => nitpick}/Evaluate.PNG (100%) rename tools/{auto-tester => nitpick}/README.md (93%) rename tools/{auto-tester => nitpick}/Run.PNG (100%) rename tools/{auto-tester => nitpick}/TestRailSelector.PNG (100%) rename tools/{auto-tester => nitpick}/Web Interface.PNG (100%) rename tools/{auto-tester => nitpick}/WebInterface.PNG (100%) rename tools/{auto-tester => nitpick}/Windows.PNG (100%) rename tools/{auto-tester/autoTesterMismatchExample.PNG => nitpick/nitpickMismatchExample.PNG} (100%) rename tools/{auto-tester => nitpick}/setup_7z.PNG (100%) rename tools/{auto-tester => nitpick}/src/AWSInterface.cpp (100%) rename tools/{auto-tester => nitpick}/src/AWSInterface.h (100%) rename tools/{auto-tester => nitpick}/src/Downloader.cpp (100%) rename tools/{auto-tester => nitpick}/src/Downloader.h (100%) rename tools/{auto-tester => nitpick}/src/ImageComparer.cpp (100%) rename tools/{auto-tester => nitpick}/src/ImageComparer.h (100%) rename tools/{auto-tester => nitpick}/src/PythonInterface.cpp (100%) rename tools/{auto-tester => nitpick}/src/PythonInterface.h (100%) rename tools/{auto-tester => nitpick}/src/Test.cpp (94%) rename tools/{auto-tester => nitpick}/src/Test.h (98%) rename tools/{auto-tester => nitpick}/src/TestRailInterface.cpp (100%) rename tools/{auto-tester => nitpick}/src/TestRailInterface.h (100%) rename tools/{auto-tester => nitpick}/src/TestRunner.cpp (98%) rename tools/{auto-tester => nitpick}/src/TestRunner.h (100%) rename tools/{auto-tester => nitpick}/src/common.h (100%) rename tools/{auto-tester => nitpick}/src/main.cpp (89%) rename tools/{auto-tester => nitpick}/src/ui/BusyWindow.cpp (100%) rename tools/{auto-tester => nitpick}/src/ui/BusyWindow.h (100%) rename tools/{auto-tester => nitpick}/src/ui/BusyWindow.ui (100%) rename tools/{auto-tester => nitpick}/src/ui/HelpWindow.cpp (100%) rename tools/{auto-tester => nitpick}/src/ui/HelpWindow.h (100%) rename tools/{auto-tester => nitpick}/src/ui/HelpWindow.ui (96%) rename tools/{auto-tester => nitpick}/src/ui/MismatchWindow.cpp (100%) rename tools/{auto-tester => nitpick}/src/ui/MismatchWindow.h (100%) rename tools/{auto-tester => nitpick}/src/ui/MismatchWindow.ui (100%) rename tools/{auto-tester/src/ui/AutoTester.cpp => nitpick/src/ui/Nitpick.cpp} (72%) rename tools/{auto-tester/src/ui/AutoTester.h => nitpick/src/ui/Nitpick.h} (92%) rename tools/{auto-tester/src/ui/AutoTester.ui => nitpick/src/ui/Nitpick.ui} (99%) rename tools/{auto-tester => nitpick}/src/ui/TestRailResultsSelectorWindow.cpp (100%) rename tools/{auto-tester => nitpick}/src/ui/TestRailResultsSelectorWindow.h (100%) rename tools/{auto-tester => nitpick}/src/ui/TestRailResultsSelectorWindow.ui (100%) rename tools/{auto-tester => nitpick}/src/ui/TestRailRunSelectorWindow.cpp (100%) rename tools/{auto-tester => nitpick}/src/ui/TestRailRunSelectorWindow.h (100%) rename tools/{auto-tester => nitpick}/src/ui/TestRailRunSelectorWindow.ui (100%) rename tools/{auto-tester => nitpick}/src/ui/TestRailTestCasesSelectorWindow.cpp (100%) rename tools/{auto-tester => nitpick}/src/ui/TestRailTestCasesSelectorWindow.h (100%) rename tools/{auto-tester => nitpick}/src/ui/TestRailTestCasesSelectorWindow.ui (100%) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 1c36306410..8ab84372cb 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -33,6 +33,6 @@ if (BUILD_TOOLS) add_subdirectory(oven) set_target_properties(oven PROPERTIES FOLDER "Tools") - add_subdirectory(auto-tester) - set_target_properties(auto-tester PROPERTIES FOLDER "Tools") + add_subdirectory(nitpick) + set_target_properties(nitpick PROPERTIES FOLDER "Tools") endif() diff --git a/tools/auto-tester/AppDataHighFidelity/Interface.json b/tools/nitpick/AppDataHighFidelity/Interface.json similarity index 100% rename from tools/auto-tester/AppDataHighFidelity/Interface.json rename to tools/nitpick/AppDataHighFidelity/Interface.json diff --git a/tools/auto-tester/AppDataHighFidelity/Interface/AccountInfo.bin b/tools/nitpick/AppDataHighFidelity/Interface/AccountInfo.bin similarity index 100% rename from tools/auto-tester/AppDataHighFidelity/Interface/AccountInfo.bin rename to tools/nitpick/AppDataHighFidelity/Interface/AccountInfo.bin diff --git a/tools/auto-tester/AppDataHighFidelity/Interface/avatarbookmarks.json b/tools/nitpick/AppDataHighFidelity/Interface/avatarbookmarks.json similarity index 100% rename from tools/auto-tester/AppDataHighFidelity/Interface/avatarbookmarks.json rename to tools/nitpick/AppDataHighFidelity/Interface/avatarbookmarks.json diff --git a/tools/auto-tester/AppDataHighFidelity/assignment-client/entities/models.json.gz b/tools/nitpick/AppDataHighFidelity/assignment-client/entities/models.json.gz similarity index 100% rename from tools/auto-tester/AppDataHighFidelity/assignment-client/entities/models.json.gz rename to tools/nitpick/AppDataHighFidelity/assignment-client/entities/models.json.gz diff --git a/tools/auto-tester/AppDataHighFidelity/domain-server/AccountInfo.bin b/tools/nitpick/AppDataHighFidelity/domain-server/AccountInfo.bin similarity index 100% rename from tools/auto-tester/AppDataHighFidelity/domain-server/AccountInfo.bin rename to tools/nitpick/AppDataHighFidelity/domain-server/AccountInfo.bin diff --git a/tools/auto-tester/AppDataHighFidelity/domain-server/config.json b/tools/nitpick/AppDataHighFidelity/domain-server/config.json similarity index 100% rename from tools/auto-tester/AppDataHighFidelity/domain-server/config.json rename to tools/nitpick/AppDataHighFidelity/domain-server/config.json diff --git a/tools/auto-tester/AppDataHighFidelity/domain-server/entities/models.json.gz b/tools/nitpick/AppDataHighFidelity/domain-server/entities/models.json.gz similarity index 100% rename from tools/auto-tester/AppDataHighFidelity/domain-server/entities/models.json.gz rename to tools/nitpick/AppDataHighFidelity/domain-server/entities/models.json.gz diff --git a/tools/auto-tester/CMakeLists.txt b/tools/nitpick/CMakeLists.txt similarity index 95% rename from tools/auto-tester/CMakeLists.txt rename to tools/nitpick/CMakeLists.txt index c8c0a336d2..543b9c9b47 100644 --- a/tools/auto-tester/CMakeLists.txt +++ b/tools/nitpick/CMakeLists.txt @@ -1,4 +1,4 @@ -set (TARGET_NAME auto-tester) +set (TARGET_NAME nitpick) project(${TARGET_NAME}) # Automatically run UIC and MOC. This replaces the older WRAP macros @@ -22,7 +22,7 @@ set (QT_LIBRARIES Qt5::Core Qt5::Widgets QT::Gui Qt5::Xml) if (WIN32) # Do not show Console - set_property (TARGET auto-tester PROPERTY WIN32_EXECUTABLE true) + set_property (TARGET nitpick PROPERTY WIN32_EXECUTABLE true) endif() target_zlib() diff --git a/tools/auto-tester/Create.PNG b/tools/nitpick/Create.PNG similarity index 100% rename from tools/auto-tester/Create.PNG rename to tools/nitpick/Create.PNG diff --git a/tools/auto-tester/Evaluate.PNG b/tools/nitpick/Evaluate.PNG similarity index 100% rename from tools/auto-tester/Evaluate.PNG rename to tools/nitpick/Evaluate.PNG diff --git a/tools/auto-tester/README.md b/tools/nitpick/README.md similarity index 93% rename from tools/auto-tester/README.md rename to tools/nitpick/README.md index 0bec83d703..d21614f5f5 100644 --- a/tools/auto-tester/README.md +++ b/tools/nitpick/README.md @@ -1,11 +1,11 @@ -# Auto Tester +# nitpick -The auto-tester is a stand alone application that provides a mechanism for regression testing. The general idea is simple: +Nitpick is a stand alone application that provides a mechanism for regression testing. The general idea is simple: * Each test folder has a script that produces a set of snapshots. * The snapshots are compared to a 'canonical' set of images that have been produced beforehand. * The result, if any test failed, is a zipped folder describing the failure. -Auto-tester has 5 functions, separated into 4 tabs: +Nitpick has 5 functions, separated into 4 tabs: 1. Creating tests, MD files and recursive scripts 1. Windows task bar utility (Windows only) 1. Running tests @@ -14,12 +14,12 @@ Auto-tester has 5 functions, separated into 4 tabs: ## Installation ### Executable -1. On Windows: download the installer by browsing to [here](). +1. On Windows: download the installer by browsing to [here](). 2. Double click on the installer and install to a convenient location ![](./setup_7z.PNG) -3. To run the auto-tester, double click **auto-tester.exe**. +3. To run nitpick, double click **nitpick.exe**. ### Python -The TestRail interface requires Python 3 to be installed. Auto-Tester has been tested with Python 3.7.0 but should work with newer versions. +The TestRail interface requires Python 3 to be installed. Nitpick has been tested with Python 3.7.0 but should work with newer versions. Python 3 can be downloaded from: 1. Windows installer @@ -41,7 +41,6 @@ Verify that `/usr/local/bin/python3` exists. 1. Enter the AWS account number 1. Enter the secret key 1. Leave region name and ouput format as default [None] - 1. Install the latest release of Boto3 via pip: pip install boto3 #### Mac @@ -78,7 +77,7 @@ This function creates an MD file in the (user-selected) tests root folder. The This function creates a file named `test.md` from a `test.js` script. The user will be asked for the folder containing the test script: ### Details The process to produce the MD file is a simplistic parse of the test script. -- The string in the `autoTester.perform(...)` function call will be the title of the file +- The string in the `nitpick.perform(...)` function call will be the title of the file - Instructions to run the script are then provided: @@ -110,26 +109,26 @@ The various scripts are called in alphabetical order. An example of a recursive script is as follows: ``` -// This is an automatically generated file, created by auto-tester on Jul 5 2018, 10:19 +// This is an automatically generated file, created by nitpick on Jul 5 2018, 10:19 PATH_TO_THE_REPO_PATH_UTILS_FILE = "https://raw.githubusercontent.com/highfidelity/hifi_tests/master/tests/utils/branchUtils.js"; Script.include(PATH_TO_THE_REPO_PATH_UTILS_FILE); -var autoTester = createAutoTester(Script.resolvePath(".")); +var nitpick = createNitpick(Script.resolvePath(".")); -var testsRootPath = autoTester.getTestsRootPath(); +var testsRootPath = nitpick.getTestsRootPath(); if (typeof Test !== 'undefined') { Test.wait(10000); }; -autoTester.enableRecursive(); -autoTester.enableAuto(); +nitpick.enableRecursive(); +nitpick.enableAuto(); Script.include(testsRootPath + "content/overlay/layer/drawInFront/shape/test.js"); Script.include(testsRootPath + "content/overlay/layer/drawInFront/model/test.js"); Script.include(testsRootPath + "content/overlay/layer/drawHUDLayer/test.js"); -autoTester.runRecursive(); +nitpick.runRecursive(); ``` ## Create all Recursive Scripts ### Usage @@ -186,7 +185,7 @@ Evaluation proceeds in a number of steps: 1. The images are then pair-wise compared, using the SSIM algorithm. A fixed threshold is used to define a mismatch. 1. In interactive mode - a window is opened showing the expected image, actual image, difference image and error: -![](./autoTesterMismatchExample.PNG) +![](./nitpickMismatchExample.PNG) 1. If not in interactive mode, or the user has defined the results as an error, an error is written into the error folder. The error itself is a folder with the 3 images and a small text file containing details. diff --git a/tools/auto-tester/Run.PNG b/tools/nitpick/Run.PNG similarity index 100% rename from tools/auto-tester/Run.PNG rename to tools/nitpick/Run.PNG diff --git a/tools/auto-tester/TestRailSelector.PNG b/tools/nitpick/TestRailSelector.PNG similarity index 100% rename from tools/auto-tester/TestRailSelector.PNG rename to tools/nitpick/TestRailSelector.PNG diff --git a/tools/auto-tester/Web Interface.PNG b/tools/nitpick/Web Interface.PNG similarity index 100% rename from tools/auto-tester/Web Interface.PNG rename to tools/nitpick/Web Interface.PNG diff --git a/tools/auto-tester/WebInterface.PNG b/tools/nitpick/WebInterface.PNG similarity index 100% rename from tools/auto-tester/WebInterface.PNG rename to tools/nitpick/WebInterface.PNG diff --git a/tools/auto-tester/Windows.PNG b/tools/nitpick/Windows.PNG similarity index 100% rename from tools/auto-tester/Windows.PNG rename to tools/nitpick/Windows.PNG diff --git a/tools/auto-tester/autoTesterMismatchExample.PNG b/tools/nitpick/nitpickMismatchExample.PNG similarity index 100% rename from tools/auto-tester/autoTesterMismatchExample.PNG rename to tools/nitpick/nitpickMismatchExample.PNG diff --git a/tools/auto-tester/setup_7z.PNG b/tools/nitpick/setup_7z.PNG similarity index 100% rename from tools/auto-tester/setup_7z.PNG rename to tools/nitpick/setup_7z.PNG diff --git a/tools/auto-tester/src/AWSInterface.cpp b/tools/nitpick/src/AWSInterface.cpp similarity index 100% rename from tools/auto-tester/src/AWSInterface.cpp rename to tools/nitpick/src/AWSInterface.cpp diff --git a/tools/auto-tester/src/AWSInterface.h b/tools/nitpick/src/AWSInterface.h similarity index 100% rename from tools/auto-tester/src/AWSInterface.h rename to tools/nitpick/src/AWSInterface.h diff --git a/tools/auto-tester/src/Downloader.cpp b/tools/nitpick/src/Downloader.cpp similarity index 100% rename from tools/auto-tester/src/Downloader.cpp rename to tools/nitpick/src/Downloader.cpp diff --git a/tools/auto-tester/src/Downloader.h b/tools/nitpick/src/Downloader.h similarity index 100% rename from tools/auto-tester/src/Downloader.h rename to tools/nitpick/src/Downloader.h diff --git a/tools/auto-tester/src/ImageComparer.cpp b/tools/nitpick/src/ImageComparer.cpp similarity index 100% rename from tools/auto-tester/src/ImageComparer.cpp rename to tools/nitpick/src/ImageComparer.cpp diff --git a/tools/auto-tester/src/ImageComparer.h b/tools/nitpick/src/ImageComparer.h similarity index 100% rename from tools/auto-tester/src/ImageComparer.h rename to tools/nitpick/src/ImageComparer.h diff --git a/tools/auto-tester/src/PythonInterface.cpp b/tools/nitpick/src/PythonInterface.cpp similarity index 100% rename from tools/auto-tester/src/PythonInterface.cpp rename to tools/nitpick/src/PythonInterface.cpp diff --git a/tools/auto-tester/src/PythonInterface.h b/tools/nitpick/src/PythonInterface.h similarity index 100% rename from tools/auto-tester/src/PythonInterface.h rename to tools/nitpick/src/PythonInterface.h diff --git a/tools/auto-tester/src/Test.cpp b/tools/nitpick/src/Test.cpp similarity index 94% rename from tools/auto-tester/src/Test.cpp rename to tools/nitpick/src/Test.cpp index 2c262bec1e..13a03c32e8 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/nitpick/src/Test.cpp @@ -19,8 +19,8 @@ #include #include -#include "ui/AutoTester.h" -extern AutoTester* autoTester; +#include "ui/Nitpick.h" +extern Nitpick* nitpick; #include @@ -30,9 +30,9 @@ Test::Test(QProgressBar* progressBar, QCheckBox* checkBoxInteractiveMode) { _mismatchWindow.setModal(true); - if (autoTester) { - autoTester->setUserText(GIT_HUB_DEFAULT_USER); - autoTester->setBranchText(GIT_HUB_DEFAULT_BRANCH); + if (nitpick) { + nitpick->setUserText(GIT_HUB_DEFAULT_USER); + nitpick->setBranchText(GIT_HUB_DEFAULT_BRANCH); } } @@ -240,8 +240,8 @@ void Test::startTestsEvaluation(const bool isRunningFromCommandLine, _expectedImagesFilenames.clear(); _expectedImagesFullFilenames.clear(); - QString branch = (branchFromCommandLine.isNull()) ? autoTester->getSelectedBranch() : branchFromCommandLine; - QString user = (userFromCommandLine.isNull()) ? autoTester->getSelectedUser() : userFromCommandLine; + QString branch = (branchFromCommandLine.isNull()) ? nitpick->getSelectedBranch() : branchFromCommandLine; + QString user = (userFromCommandLine.isNull()) ? nitpick->getSelectedUser() : userFromCommandLine; foreach(QString currentFilename, sortedTestResultsFilenames) { QString fullCurrentFilename = _snapshotDirectory + "/" + currentFilename; @@ -268,7 +268,7 @@ void Test::startTestsEvaluation(const bool isRunningFromCommandLine, } } - autoTester->downloadFiles(expectedImagesURLs, _snapshotDirectory, _expectedImagesFilenames, (void *)this); + nitpick->downloadFiles(expectedImagesURLs, _snapshotDirectory, _expectedImagesFilenames, (void *)this); } void Test::finishTestsEvaluation() { int numberOfFailures = compareImageLists(); @@ -288,7 +288,7 @@ void Test::finishTestsEvaluation() { } if (_isRunningInAutomaticTestRun) { - autoTester->automaticTestRunEvaluationComplete(zippedFolderName, numberOfFailures); + nitpick->automaticTestRunEvaluationComplete(zippedFolderName, numberOfFailures); } } @@ -429,22 +429,22 @@ ExtractedText Test::getTestScriptLines(QString testFileName) { QString line = stream.readLine(); // Name of test is the string in the following line: - // autoTester.perform("Apply Material Entities to Avatars", Script.resolvePath("."), function(testType) {... + // nitpick.perform("Apply Material Entities to Avatars", Script.resolvePath("."), function(testType) {... const QString ws("\\h*"); //white-space character - const QString functionPerformName(ws + "autoTester" + ws + "\\." + ws + "perform"); + const QString functionPerformName(ws + "nitpick" + ws + "\\." + ws + "perform"); const QString quotedString("\\\".+\\\""); QString regexTestTitle(ws + functionPerformName + "\\(" + quotedString); QRegularExpression lineContainingTitle = QRegularExpression(regexTestTitle); // Each step is either of the following forms: - // autoTester.addStepSnapshot("Take snapshot"... - // autoTester.addStep("Clean up after test"... - const QString functionAddStepSnapshotName(ws + "autoTester" + ws + "\\." + ws + "addStepSnapshot"); + // nitpick.addStepSnapshot("Take snapshot"... + // nitpick.addStep("Clean up after test"... + const QString functionAddStepSnapshotName(ws + "nitpick" + ws + "\\." + ws + "addStepSnapshot"); const QString regexStepSnapshot(ws + functionAddStepSnapshotName + ws + "\\(" + ws + quotedString + ".*"); const QRegularExpression lineStepSnapshot = QRegularExpression(regexStepSnapshot); - const QString functionAddStepName(ws + "autoTester" + ws + "\\." + ws + "addStep"); + const QString functionAddStepName(ws + "nitpick" + ws + "\\." + ws + "addStep"); const QString regexStep(ws + functionAddStepName + ws + "\\(" + ws + quotedString + ".*"); const QRegularExpression lineStep = QRegularExpression(regexStep); @@ -620,7 +620,7 @@ void Test::createTestAutoScript() { } if (createTestAutoScript(_testDirectory)) { - QMessageBox::information(0, "Success", "'autoTester.js` script has been created"); + QMessageBox::information(0, "Success", "'nitpick.js` script has been created"); } } @@ -653,7 +653,7 @@ void Test::createAllTestAutoScripts() { } } - QMessageBox::information(0, "Success", "'autoTester.js' scripts have been created"); + QMessageBox::information(0, "Success", "'nitpick.js' scripts have been created"); } bool Test::createTestAutoScript(const QString& directory) { @@ -677,8 +677,8 @@ bool Test::createTestAutoScript(const QString& directory) { stream << "if (typeof PATH_TO_THE_REPO_PATH_UTILS_FILE === 'undefined') PATH_TO_THE_REPO_PATH_UTILS_FILE = 'https://raw.githubusercontent.com/highfidelity/hifi_tests/master/tests/utils/branchUtils.js';\n"; stream << "Script.include(PATH_TO_THE_REPO_PATH_UTILS_FILE);\n"; - stream << "var autoTester = createAutoTester(Script.resolvePath('.'));\n\n"; - stream << "autoTester.enableAuto();\n\n"; + stream << "var nitpick = createAutoTester(Script.resolvePath('.'));\n\n"; + stream << "nitpick.enableAuto();\n\n"; stream << "Script.include('./test.js?raw=true');\n"; testAutoScriptFile.close(); @@ -751,29 +751,29 @@ void Test::createRecursiveScript(const QString& topLevelDirectory, bool interact textStream << "// This is an automatically generated file, created by auto-tester" << endl; // Include 'autoTest.js' - QString branch = autoTester->getSelectedBranch(); - QString user = autoTester->getSelectedUser(); + QString branch = nitpick->getSelectedBranch(); + QString user = nitpick->getSelectedUser(); textStream << "PATH_TO_THE_REPO_PATH_UTILS_FILE = \"https://raw.githubusercontent.com/" + user + "/hifi_tests/" + branch + "/tests/utils/branchUtils.js\";" << endl; textStream << "Script.include(PATH_TO_THE_REPO_PATH_UTILS_FILE);" << endl; - textStream << "var autoTester = createAutoTester(Script.resolvePath(\".\"));" << endl << endl; + textStream << "var nitpick = createAutoTester(Script.resolvePath(\".\"));" << endl << endl; - textStream << "var testsRootPath = autoTester.getTestsRootPath();" << endl << endl; + textStream << "var testsRootPath = nitpick.getTestsRootPath();" << endl << endl; // Wait 10 seconds before starting textStream << "if (typeof Test !== 'undefined') {" << endl; textStream << " Test.wait(10000);" << endl; textStream << "};" << endl << endl; - textStream << "autoTester.enableRecursive();" << endl; - textStream << "autoTester.enableAuto();" << endl << endl; + textStream << "nitpick.enableRecursive();" << endl; + textStream << "nitpick.enableAuto();" << endl << endl; // This is used to verify that the recursive test contains at least one test bool testFound{ false }; - // Directories are included in reverse order. The autoTester scripts use a stack mechanism, + // Directories are included in reverse order. The nitpick scripts use a stack mechanism, // so this ensures that the tests run in alphabetical order (a convenience when debugging) QStringList directories; @@ -819,7 +819,7 @@ void Test::createRecursiveScript(const QString& topLevelDirectory, bool interact } textStream << endl; - textStream << "autoTester.runRecursive();" << endl; + textStream << "nitpick.runRecursive();" << endl; allTestsFilename.close(); } @@ -881,7 +881,7 @@ void Test::createTestsOutline() { // The directory name appears after the last slash (we are assured there is at least 1). QString directoryName = directory.right(directory.length() - directory.lastIndexOf("/") - 1); - // autoTester is run on a clone of the repository. We use relative paths, so we can use both local disk and GitHub + // nitpick is run on a clone of the repository. We use relative paths, so we can use both local disk and GitHub // For a test in "D:/GitHub/hifi_tests/tests/content/entity/zone/ambientLightInheritance" the // GitHub URL is "./content/entity/zone/ambientLightInheritance?raw=true" QString partialPath = directory.right(directory.length() - (directory.lastIndexOf("/tests/") + QString("/tests").length() + 1)); @@ -937,11 +937,11 @@ void Test::createTestRailTestCases() { } if (_testRailCreateMode == PYTHON) { - _testRailInterface.createTestSuitePython(_testDirectory, outputDirectory, autoTester->getSelectedUser(), - autoTester->getSelectedBranch()); + _testRailInterface.createTestSuitePython(_testDirectory, outputDirectory, nitpick->getSelectedUser(), + nitpick->getSelectedBranch()); } else { - _testRailInterface.createTestSuiteXML(_testDirectory, outputDirectory, autoTester->getSelectedUser(), - autoTester->getSelectedBranch()); + _testRailInterface.createTestSuiteXML(_testDirectory, outputDirectory, nitpick->getSelectedUser(), + nitpick->getSelectedBranch()); } } diff --git a/tools/auto-tester/src/Test.h b/tools/nitpick/src/Test.h similarity index 98% rename from tools/auto-tester/src/Test.h rename to tools/nitpick/src/Test.h index f653a91782..a79252b92a 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/nitpick/src/Test.h @@ -146,7 +146,7 @@ private: const QString DATETIME_FORMAT{ "yyyy-MM-dd_hh-mm-ss" }; - // NOTE: these need to match the appropriate var's in autoTester.js + // NOTE: these need to match the appropriate var's in nitpick.js // var advanceKey = "n"; // var pathSeparator = "."; const QString ADVANCE_KEY{ "n" }; diff --git a/tools/auto-tester/src/TestRailInterface.cpp b/tools/nitpick/src/TestRailInterface.cpp similarity index 100% rename from tools/auto-tester/src/TestRailInterface.cpp rename to tools/nitpick/src/TestRailInterface.cpp diff --git a/tools/auto-tester/src/TestRailInterface.h b/tools/nitpick/src/TestRailInterface.h similarity index 100% rename from tools/auto-tester/src/TestRailInterface.h rename to tools/nitpick/src/TestRailInterface.h diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp similarity index 98% rename from tools/auto-tester/src/TestRunner.cpp rename to tools/nitpick/src/TestRunner.cpp index 3781024a63..1387635b8f 100644 --- a/tools/auto-tester/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -13,8 +13,8 @@ #include #include -#include "ui/AutoTester.h" -extern AutoTester* autoTester; +#include "ui/Nitpick.h" +extern Nitpick* nitpick; #ifdef Q_OS_WIN #include @@ -95,7 +95,7 @@ void TestRunner::setWorkingFolder() { _logFile.setFileName(_workingFolder + "/log.txt"); - autoTester->enableRunTabControls(); + nitpick->enableRunTabControls(); _workingFolderLabel->setText(QDir::toNativeSeparators(_workingFolder)); _timer = new QTimer(this); @@ -203,8 +203,8 @@ void TestRunner::run() { _automatedTestIsRunning = true; // Initial setup - _branch = autoTester->getSelectedBranch(); - _user = autoTester->getSelectedUser(); + _branch = nitpick->getSelectedBranch(); + _user = nitpick->getSelectedUser(); // This will be restored at the end of the tests saveExistingHighFidelityAppDataFolder(); @@ -221,7 +221,7 @@ void TestRunner::run() { updateStatusLabel("Downloading Build XML"); buildXMLDownloaded = false; - autoTester->downloadFiles(urls, _workingFolder, filenames, (void*)this); + nitpick->downloadFiles(urls, _workingFolder, filenames, (void*)this); // `downloadComplete` will run after download has completed } @@ -250,7 +250,7 @@ void TestRunner::downloadComplete() { updateStatusLabel("Downloading installer"); - autoTester->downloadFiles(urls, _workingFolder, filenames, (void*)this); + nitpick->downloadFiles(urls, _workingFolder, filenames, (void*)this); // `downloadComplete` will run again after download has completed @@ -505,7 +505,7 @@ void TestRunner::interfaceExecutionComplete() { void TestRunner::evaluateResults() { updateStatusLabel("Evaluating results"); - autoTester->startTestsEvaluation(false, true, _snapshotFolder, _branch, _user); + nitpick->startTestsEvaluation(false, true, _snapshotFolder, _branch, _user); } void TestRunner::automaticTestRunEvaluationComplete(QString zippedFolder, int numberOfFailures) { @@ -618,7 +618,7 @@ void TestRunner::checkTime() { } void TestRunner::updateStatusLabel(const QString& message) { - autoTester->updateStatusLabel(message); + nitpick->updateStatusLabel(message); } void TestRunner::appendLog(const QString& message) { @@ -632,7 +632,7 @@ void TestRunner::appendLog(const QString& message) { _logFile.write("\n"); _logFile.close(); - autoTester->appendLogWindow(message); + nitpick->appendLogWindow(message); } QString TestRunner::getInstallerNameFromURL(const QString& url) { diff --git a/tools/auto-tester/src/TestRunner.h b/tools/nitpick/src/TestRunner.h similarity index 100% rename from tools/auto-tester/src/TestRunner.h rename to tools/nitpick/src/TestRunner.h diff --git a/tools/auto-tester/src/common.h b/tools/nitpick/src/common.h similarity index 100% rename from tools/auto-tester/src/common.h rename to tools/nitpick/src/common.h diff --git a/tools/auto-tester/src/main.cpp b/tools/nitpick/src/main.cpp similarity index 89% rename from tools/auto-tester/src/main.cpp rename to tools/nitpick/src/main.cpp index ac4b4593c5..089a72e6ce 100644 --- a/tools/auto-tester/src/main.cpp +++ b/tools/nitpick/src/main.cpp @@ -8,11 +8,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include -#include "ui/AutoTester.h" +#include "ui/Nitpick.h" #include -AutoTester* autoTester; +Nitpick* nitpick; int main(int argc, char *argv[]) { // If no parameters then run in interactive mode @@ -62,13 +62,13 @@ int main(int argc, char *argv[]) { QApplication application(argc, argv); - autoTester = new AutoTester(); - autoTester->setup(); + nitpick = new Nitpick(); + nitpick->setup(); if (!testFolder.isNull()) { - autoTester->startTestsEvaluation(true ,false, testFolder, branch, user); + nitpick->startTestsEvaluation(true ,false, testFolder, branch, user); } else { - autoTester->show(); + nitpick->show(); } return application.exec(); diff --git a/tools/auto-tester/src/ui/BusyWindow.cpp b/tools/nitpick/src/ui/BusyWindow.cpp similarity index 100% rename from tools/auto-tester/src/ui/BusyWindow.cpp rename to tools/nitpick/src/ui/BusyWindow.cpp diff --git a/tools/auto-tester/src/ui/BusyWindow.h b/tools/nitpick/src/ui/BusyWindow.h similarity index 100% rename from tools/auto-tester/src/ui/BusyWindow.h rename to tools/nitpick/src/ui/BusyWindow.h diff --git a/tools/auto-tester/src/ui/BusyWindow.ui b/tools/nitpick/src/ui/BusyWindow.ui similarity index 100% rename from tools/auto-tester/src/ui/BusyWindow.ui rename to tools/nitpick/src/ui/BusyWindow.ui diff --git a/tools/auto-tester/src/ui/HelpWindow.cpp b/tools/nitpick/src/ui/HelpWindow.cpp similarity index 100% rename from tools/auto-tester/src/ui/HelpWindow.cpp rename to tools/nitpick/src/ui/HelpWindow.cpp diff --git a/tools/auto-tester/src/ui/HelpWindow.h b/tools/nitpick/src/ui/HelpWindow.h similarity index 100% rename from tools/auto-tester/src/ui/HelpWindow.h rename to tools/nitpick/src/ui/HelpWindow.h diff --git a/tools/auto-tester/src/ui/HelpWindow.ui b/tools/nitpick/src/ui/HelpWindow.ui similarity index 96% rename from tools/auto-tester/src/ui/HelpWindow.ui rename to tools/nitpick/src/ui/HelpWindow.ui index d2aa0da0d4..1ce6e8c321 100644 --- a/tools/auto-tester/src/ui/HelpWindow.ui +++ b/tools/nitpick/src/ui/HelpWindow.ui @@ -14,7 +14,7 @@ - AutoTester Help + Nitpick Help diff --git a/tools/auto-tester/src/ui/MismatchWindow.cpp b/tools/nitpick/src/ui/MismatchWindow.cpp similarity index 100% rename from tools/auto-tester/src/ui/MismatchWindow.cpp rename to tools/nitpick/src/ui/MismatchWindow.cpp diff --git a/tools/auto-tester/src/ui/MismatchWindow.h b/tools/nitpick/src/ui/MismatchWindow.h similarity index 100% rename from tools/auto-tester/src/ui/MismatchWindow.h rename to tools/nitpick/src/ui/MismatchWindow.h diff --git a/tools/auto-tester/src/ui/MismatchWindow.ui b/tools/nitpick/src/ui/MismatchWindow.ui similarity index 100% rename from tools/auto-tester/src/ui/MismatchWindow.ui rename to tools/nitpick/src/ui/MismatchWindow.ui diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/nitpick/src/ui/Nitpick.cpp similarity index 72% rename from tools/auto-tester/src/ui/AutoTester.cpp rename to tools/nitpick/src/ui/Nitpick.cpp index d49f3aaa1c..185599538e 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/nitpick/src/ui/Nitpick.cpp @@ -1,5 +1,5 @@ // -// AutoTester.cpp +// Nitpick.cpp // zone/ambientLightInheritence // // Created by Nissim Hadar on 2 Nov 2017. @@ -8,14 +8,14 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "AutoTester.h" +#include "Nitpick.h" #ifdef Q_OS_WIN #include #include #endif -AutoTester::AutoTester(QWidget* parent) : QMainWindow(parent) { +Nitpick::Nitpick(QWidget* parent) : QMainWindow(parent) { _ui.setupUi(this); _ui.checkBoxInteractiveMode->setChecked(true); @@ -24,9 +24,9 @@ AutoTester::AutoTester(QWidget* parent) : QMainWindow(parent) { _signalMapper = new QSignalMapper(); - connect(_ui.actionClose, &QAction::triggered, this, &AutoTester::on_closeButton_clicked); - connect(_ui.actionAbout, &QAction::triggered, this, &AutoTester::about); - connect(_ui.actionContent, &QAction::triggered, this, &AutoTester::content); + connect(_ui.actionClose, &QAction::triggered, this, &Nitpick::on_closeButton_clicked); + connect(_ui.actionAbout, &QAction::triggered, this, &Nitpick::about); + connect(_ui.actionContent, &QAction::triggered, this, &Nitpick::content); // The second tab hides and shows the Windows task bar #ifndef Q_OS_WIN @@ -36,13 +36,13 @@ AutoTester::AutoTester(QWidget* parent) : QMainWindow(parent) { _ui.statusLabel->setText(""); _ui.plainTextEdit->setReadOnly(true); - setWindowTitle("Auto Tester - v7.0"); + setWindowTitle("Nitpick - v1.0"); - // Coming soon to an auto-tester near you... + // Coming soon to a nitpick near you... //// _helpWindow.textBrowser->setText() } -AutoTester::~AutoTester() { +Nitpick::~Nitpick() { delete _signalMapper; if (_test) { @@ -54,7 +54,7 @@ AutoTester::~AutoTester() { } } -void AutoTester::setup() { +void Nitpick::setup() { if (_test) { delete _test; } @@ -87,7 +87,7 @@ void AutoTester::setup() { _testRunner = new TestRunner(dayCheckboxes, timeEditCheckboxes, timeEdits, _ui.workingFolderLabel, _ui.checkBoxServerless, _ui.checkBoxRunLatest, _ui.urlLineEdit, _ui.runNowButton); } -void AutoTester::startTestsEvaluation(const bool isRunningFromCommandLine, +void Nitpick::startTestsEvaluation(const bool isRunningFromCommandLine, const bool isRunningInAutomaticTestRun, const QString& snapshotDirectory, const QString& branch, @@ -96,7 +96,7 @@ void AutoTester::startTestsEvaluation(const bool isRunningFromCommandLine, _test->startTestsEvaluation(isRunningFromCommandLine, isRunningInAutomaticTestRun, snapshotDirectory, branch, user); } -void AutoTester::on_tabWidget_currentChanged(int index) { +void Nitpick::on_tabWidget_currentChanged(int index) { if (index == 0 || index == 2 || index == 3) { _ui.userLineEdit->setDisabled(false); _ui.branchLineEdit->setDisabled(false); @@ -106,73 +106,73 @@ void AutoTester::on_tabWidget_currentChanged(int index) { } } -void AutoTester::on_evaluateTestsButton_clicked() { +void Nitpick::on_evaluateTestsButton_clicked() { _test->startTestsEvaluation(false, false); } -void AutoTester::on_createRecursiveScriptButton_clicked() { +void Nitpick::on_createRecursiveScriptButton_clicked() { _test->createRecursiveScript(); } -void AutoTester::on_createAllRecursiveScriptsButton_clicked() { +void Nitpick::on_createAllRecursiveScriptsButton_clicked() { _test->createAllRecursiveScripts(); } -void AutoTester::on_createTestsButton_clicked() { +void Nitpick::on_createTestsButton_clicked() { _test->createTests(); } -void AutoTester::on_createMDFileButton_clicked() { +void Nitpick::on_createMDFileButton_clicked() { _test->createMDFile(); } -void AutoTester::on_createAllMDFilesButton_clicked() { +void Nitpick::on_createAllMDFilesButton_clicked() { _test->createAllMDFiles(); } -void AutoTester::on_createTestAutoScriptButton_clicked() { +void Nitpick::on_createTestAutoScriptButton_clicked() { _test->createTestAutoScript(); } -void AutoTester::on_createAllTestAutoScriptsButton_clicked() { +void Nitpick::on_createAllTestAutoScriptsButton_clicked() { _test->createAllTestAutoScripts(); } -void AutoTester::on_createTestsOutlineButton_clicked() { +void Nitpick::on_createTestsOutlineButton_clicked() { _test->createTestsOutline(); } -void AutoTester::on_createTestRailTestCasesButton_clicked() { +void Nitpick::on_createTestRailTestCasesButton_clicked() { _test->createTestRailTestCases(); } -void AutoTester::on_createTestRailRunButton_clicked() { +void Nitpick::on_createTestRailRunButton_clicked() { _test->createTestRailRun(); } -void AutoTester::on_setWorkingFolderButton_clicked() { +void Nitpick::on_setWorkingFolderButton_clicked() { _testRunner->setWorkingFolder(); } -void AutoTester::enableRunTabControls() { +void Nitpick::enableRunTabControls() { _ui.runNowButton->setEnabled(true); _ui.daysGroupBox->setEnabled(true); _ui.timesGroupBox->setEnabled(true); } -void AutoTester::on_runNowButton_clicked() { +void Nitpick::on_runNowButton_clicked() { _testRunner->run(); } -void AutoTester::on_checkBoxRunLatest_clicked() { +void Nitpick::on_checkBoxRunLatest_clicked() { _ui.urlLineEdit->setEnabled(!_ui.checkBoxRunLatest->isChecked()); } -void AutoTester::automaticTestRunEvaluationComplete(QString zippedFolderName, int numberOfFailures) { +void Nitpick::automaticTestRunEvaluationComplete(QString zippedFolderName, int numberOfFailures) { _testRunner->automaticTestRunEvaluationComplete(zippedFolderName, numberOfFailures); } -void AutoTester::on_updateTestRailRunResultsButton_clicked() { +void Nitpick::on_updateTestRailRunResultsButton_clicked() { _test->updateTestRailRunResult(); } @@ -180,7 +180,7 @@ void AutoTester::on_updateTestRailRunResultsButton_clicked() { // if (uState & ABS_AUTOHIDE) on_showTaskbarButton_clicked(); // else on_hideTaskbarButton_clicked(); // -void AutoTester::on_hideTaskbarButton_clicked() { +void Nitpick::on_hideTaskbarButton_clicked() { #ifdef Q_OS_WIN APPBARDATA abd = { sizeof abd }; UINT uState = (UINT)SHAppBarMessage(ABM_GETSTATE, &abd); @@ -190,7 +190,7 @@ void AutoTester::on_hideTaskbarButton_clicked() { #endif } -void AutoTester::on_showTaskbarButton_clicked() { +void Nitpick::on_showTaskbarButton_clicked() { #ifdef Q_OS_WIN APPBARDATA abd = { sizeof abd }; UINT uState = (UINT)SHAppBarMessage(ABM_GETSTATE, &abd); @@ -200,23 +200,23 @@ void AutoTester::on_showTaskbarButton_clicked() { #endif } -void AutoTester::on_closeButton_clicked() { +void Nitpick::on_closeButton_clicked() { exit(0); } -void AutoTester::on_createPythonScriptRadioButton_clicked() { +void Nitpick::on_createPythonScriptRadioButton_clicked() { _test->setTestRailCreateMode(PYTHON); } -void AutoTester::on_createXMLScriptRadioButton_clicked() { +void Nitpick::on_createXMLScriptRadioButton_clicked() { _test->setTestRailCreateMode(XML); } -void AutoTester::on_createWebPagePushButton_clicked() { +void Nitpick::on_createWebPagePushButton_clicked() { _test->createWebPage(_ui.updateAWSCheckBox, _ui.awsURLLineEdit); } -void AutoTester::downloadFile(const QUrl& url) { +void Nitpick::downloadFile(const QUrl& url) { _downloaders.emplace_back(new Downloader(url, this)); connect(_downloaders[_index], SIGNAL(downloaded()), _signalMapper, SLOT(map())); @@ -225,7 +225,7 @@ void AutoTester::downloadFile(const QUrl& url) { ++_index; } -void AutoTester::downloadFiles(const QStringList& URLs, const QString& directoryName, const QStringList& filenames, void *caller) { +void Nitpick::downloadFiles(const QStringList& URLs, const QString& directoryName, const QStringList& filenames, void *caller) { connect(_signalMapper, SIGNAL(mapped(int)), this, SLOT(saveFile(int))); _directoryName = directoryName; @@ -251,7 +251,7 @@ void AutoTester::downloadFiles(const QStringList& URLs, const QString& directory } } -void AutoTester::saveFile(int index) { +void Nitpick::saveFile(int index) { try { QFile file(_directoryName + "/" + _filenames[index]); file.open(QIODevice::WriteOnly); @@ -277,34 +277,34 @@ void AutoTester::saveFile(int index) { } } -void AutoTester::about() { +void Nitpick::about() { QMessageBox::information(0, "About", QString("Built ") + __DATE__ + ", " + __TIME__); } -void AutoTester::content() { +void Nitpick::content() { _helpWindow.show(); } -void AutoTester::setUserText(const QString& user) { +void Nitpick::setUserText(const QString& user) { _ui.userLineEdit->setText(user); } -QString AutoTester::getSelectedUser() { +QString Nitpick::getSelectedUser() { return _ui.userLineEdit->text(); } -void AutoTester::setBranchText(const QString& branch) { +void Nitpick::setBranchText(const QString& branch) { _ui.branchLineEdit->setText(branch); } -QString AutoTester::getSelectedBranch() { +QString Nitpick::getSelectedBranch() { return _ui.branchLineEdit->text(); } -void AutoTester::updateStatusLabel(const QString& status) { +void Nitpick::updateStatusLabel(const QString& status) { _ui.statusLabel->setText(status); } -void AutoTester::appendLogWindow(const QString& message) { +void Nitpick::appendLogWindow(const QString& message) { _ui.plainTextEdit->appendPlainText(message); } \ No newline at end of file diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/nitpick/src/ui/Nitpick.h similarity index 92% rename from tools/auto-tester/src/ui/AutoTester.h rename to tools/nitpick/src/ui/Nitpick.h index 429a8b60e1..21b917654b 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/nitpick/src/ui/Nitpick.h @@ -1,5 +1,5 @@ // -// AutoTester.h +// Nitpick.h // // Created by Nissim Hadar on 2 Nov 2017. // Copyright 2013 High Fidelity, Inc. @@ -7,13 +7,13 @@ // 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_AutoTester_h -#define hifi_AutoTester_h +#ifndef hifi_Nitpick_h +#define hifi_Nitpick_h #include #include #include -#include "ui_AutoTester.h" +#include "ui_Nitpick.h" #include "../Downloader.h" #include "../Test.h" @@ -22,12 +22,12 @@ #include "../TestRunner.h" #include "../AWSInterface.h" -class AutoTester : public QMainWindow { +class Nitpick : public QMainWindow { Q_OBJECT public: - AutoTester(QWidget* parent = Q_NULLPTR); - ~AutoTester(); + Nitpick(QWidget* parent = Q_NULLPTR); + ~Nitpick(); void setup(); @@ -95,7 +95,7 @@ private slots: void content(); private: - Ui::AutoTesterClass _ui; + Ui::NitpickClass _ui; Test* _test{ nullptr }; TestRunner* _testRunner{ nullptr }; @@ -121,4 +121,4 @@ private: void* _caller; }; -#endif // hifi_AutoTester_h \ No newline at end of file +#endif // hifi_Nitpick_h \ No newline at end of file diff --git a/tools/auto-tester/src/ui/AutoTester.ui b/tools/nitpick/src/ui/Nitpick.ui similarity index 99% rename from tools/auto-tester/src/ui/AutoTester.ui rename to tools/nitpick/src/ui/Nitpick.ui index 08f4b46723..5e20e75553 100644 --- a/tools/auto-tester/src/ui/AutoTester.ui +++ b/tools/nitpick/src/ui/Nitpick.ui @@ -1,7 +1,7 @@ - AutoTesterClass - + NitpickClass + 0 @@ -17,7 +17,7 @@ - AutoTester + Nitpick diff --git a/tools/auto-tester/src/ui/TestRailResultsSelectorWindow.cpp b/tools/nitpick/src/ui/TestRailResultsSelectorWindow.cpp similarity index 100% rename from tools/auto-tester/src/ui/TestRailResultsSelectorWindow.cpp rename to tools/nitpick/src/ui/TestRailResultsSelectorWindow.cpp diff --git a/tools/auto-tester/src/ui/TestRailResultsSelectorWindow.h b/tools/nitpick/src/ui/TestRailResultsSelectorWindow.h similarity index 100% rename from tools/auto-tester/src/ui/TestRailResultsSelectorWindow.h rename to tools/nitpick/src/ui/TestRailResultsSelectorWindow.h diff --git a/tools/auto-tester/src/ui/TestRailResultsSelectorWindow.ui b/tools/nitpick/src/ui/TestRailResultsSelectorWindow.ui similarity index 100% rename from tools/auto-tester/src/ui/TestRailResultsSelectorWindow.ui rename to tools/nitpick/src/ui/TestRailResultsSelectorWindow.ui diff --git a/tools/auto-tester/src/ui/TestRailRunSelectorWindow.cpp b/tools/nitpick/src/ui/TestRailRunSelectorWindow.cpp similarity index 100% rename from tools/auto-tester/src/ui/TestRailRunSelectorWindow.cpp rename to tools/nitpick/src/ui/TestRailRunSelectorWindow.cpp diff --git a/tools/auto-tester/src/ui/TestRailRunSelectorWindow.h b/tools/nitpick/src/ui/TestRailRunSelectorWindow.h similarity index 100% rename from tools/auto-tester/src/ui/TestRailRunSelectorWindow.h rename to tools/nitpick/src/ui/TestRailRunSelectorWindow.h diff --git a/tools/auto-tester/src/ui/TestRailRunSelectorWindow.ui b/tools/nitpick/src/ui/TestRailRunSelectorWindow.ui similarity index 100% rename from tools/auto-tester/src/ui/TestRailRunSelectorWindow.ui rename to tools/nitpick/src/ui/TestRailRunSelectorWindow.ui diff --git a/tools/auto-tester/src/ui/TestRailTestCasesSelectorWindow.cpp b/tools/nitpick/src/ui/TestRailTestCasesSelectorWindow.cpp similarity index 100% rename from tools/auto-tester/src/ui/TestRailTestCasesSelectorWindow.cpp rename to tools/nitpick/src/ui/TestRailTestCasesSelectorWindow.cpp diff --git a/tools/auto-tester/src/ui/TestRailTestCasesSelectorWindow.h b/tools/nitpick/src/ui/TestRailTestCasesSelectorWindow.h similarity index 100% rename from tools/auto-tester/src/ui/TestRailTestCasesSelectorWindow.h rename to tools/nitpick/src/ui/TestRailTestCasesSelectorWindow.h diff --git a/tools/auto-tester/src/ui/TestRailTestCasesSelectorWindow.ui b/tools/nitpick/src/ui/TestRailTestCasesSelectorWindow.ui similarity index 100% rename from tools/auto-tester/src/ui/TestRailTestCasesSelectorWindow.ui rename to tools/nitpick/src/ui/TestRailTestCasesSelectorWindow.ui From d2a1b35f969027806483a8651a54af740232eb51 Mon Sep 17 00:00:00 2001 From: r3tk0n Date: Thu, 8 Nov 2018 16:50:11 -0800 Subject: [PATCH 138/182] Fix desktop case showing Vive controls. --- interface/resources/html/tabletHelp.html | 20 +++++++++++--------- interface/src/Application.cpp | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/interface/resources/html/tabletHelp.html b/interface/resources/html/tabletHelp.html index cc931580c3..8d4214d5af 100644 --- a/interface/resources/html/tabletHelp.html +++ b/interface/resources/html/tabletHelp.html @@ -94,15 +94,14 @@ switch (index) { case 0: - showHandControllers(); - break; - case 1: showGamepad(); break; - case 2: + case 1: showKbm(); break; - + case 2: + showHandControllers(); + break; default: } } @@ -142,23 +141,26 @@ handControllerImageURL = "img/tablet-help-vive.jpg"; break; case "oculus": + handControllerImageURL = "img/tablet-help-oculus.jpg"; + break; default: - handControllerImageURL = "img/tablet-help-oculus.jpg"; + handControllerImageURL = null; + count = 2; } switch (params.defaultTab) { case "handControllers": showHandControllers(); - index = 0; + index = 2; break; case "gamepad": showGamepad(); - index = 1; + index = 0; break; case "kbm": default: showKbm(); - index = 2; + index = 1; } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 245e6c0017..ecb738c7c4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3366,7 +3366,7 @@ void Application::showHelp() { static const QString TAB_GAMEPAD = "gamepad"; static const QString TAB_HAND_CONTROLLERS = "handControllers"; - QString handControllerName = HAND_CONTROLLER_NAME_VIVE; + QString handControllerName = ""; QString defaultTab = TAB_KEYBOARD_MOUSE; if (PluginUtils::isViveControllerAvailable()) { From 8d4d0beebd9138f8256fd63903d4290341c6f1ee Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 8 Nov 2018 17:52:07 -0800 Subject: [PATCH 139/182] Cleanup --- interface/src/Application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5844462497..368f4d4d9a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4834,6 +4834,7 @@ void Application::idle() { _idleLoopStdev.reset(); } } + _overlayConductor.update(secondsSinceLastUpdate); _gameLoopCounter.increment(); From 4e89e9ed2a3a91d84c7327bfdc2d67d48ff6e3c3 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 9 Nov 2018 09:58:17 +0100 Subject: [PATCH 140/182] 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; From a535519fbcd8441076c87c03500a7bf7ff9472cd Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 12 Nov 2018 11:00:24 -0800 Subject: [PATCH 141/182] Typo. --- tools/nitpick/src/TestRunner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/nitpick/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp index 0e6acf073e..20f419a356 100644 --- a/tools/nitpick/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -488,7 +488,7 @@ void TestRunner::runInterfaceWithTestScript() { " --testScript " + testScript + " quitWhenFinished" + " --testResultsLocation " + _snapshotFolder; - interfaceWorker->setCommandLine(commandLine); + _interfaceWorker->setCommandLine(commandLine); emit startInterface(); #elif defined Q_OS_MAC // On The Mac, we need to resize Interface. The Interface window opens a few seconds after the process From 4a158ea789d3380f92cf2c0716e297185c372942 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 12 Nov 2018 11:07:18 -0800 Subject: [PATCH 142/182] Fixed Linux compilation error. --- tools/nitpick/src/ui/Nitpick.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/nitpick/src/ui/Nitpick.cpp b/tools/nitpick/src/ui/Nitpick.cpp index 9ae21d0233..a4aef8fad5 100644 --- a/tools/nitpick/src/ui/Nitpick.cpp +++ b/tools/nitpick/src/ui/Nitpick.cpp @@ -100,7 +100,7 @@ void Nitpick::on_tabWidget_currentChanged(int index) { // Enable the GitHub edit boxes as required #ifdef Q_OS_WIN if (index == 0 || index == 2 || index == 3) { -#elif defined Q_OS_MAC +#else if (index == 0 || index == 1 || index == 2) { #endif _ui.userLineEdit->setDisabled(false); From 05033b7da1c5343d35aff316444c861e56edecb8 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 12 Nov 2018 12:19:32 -0800 Subject: [PATCH 143/182] Echo status to screen --- tools/nitpick/src/TestRunner.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/nitpick/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp index 0e6acf073e..70321e088e 100644 --- a/tools/nitpick/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -173,7 +173,9 @@ void TestRunner::setWorkingFolder() { } script.write("#!/bin/sh\n\n"); + script.write("echo resizing interface"); script.write(("osascript " + _workingFolder + "/setInterfaceSizeAndPosition.scpt\n").toStdString().c_str()); + script.write("echo resize complete"); script.close(); script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); #endif From a9ff1f4ecd6356f77f794fc1d6cc9d49f36e2ae2 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Fri, 7 Sep 2018 17:53:45 +0300 Subject: [PATCH 144/182] add onscreen keyboard into 'Calibration' tab of Settings=>Controls dialog --- .../qml/hifi/tablet/ControllerSettings.qml | 31 +++++++++++++++++++ .../qml/hifi/tablet/OpenVrConfiguration.qml | 14 +++++++++ 2 files changed, 45 insertions(+) diff --git a/interface/resources/qml/hifi/tablet/ControllerSettings.qml b/interface/resources/qml/hifi/tablet/ControllerSettings.qml index b8bbd71f33..6727047eb0 100644 --- a/interface/resources/qml/hifi/tablet/ControllerSettings.qml +++ b/interface/resources/qml/hifi/tablet/ControllerSettings.qml @@ -9,6 +9,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 +import QtQuick.Window 2.2 import QtGraphicalEffects 1.0 import Qt.labs.settings 1.0 import stylesUit 1.0 @@ -72,6 +73,11 @@ Item { initialItem: inputConfiguration property alias messageVisible: imageMessageBox.visible property string selectedPlugin: "" + + property bool keyboardEnabled: false + property bool keyboardRaised: false + property bool punctuationMode: false + Rectangle { id: inputConfiguration anchors { @@ -227,6 +233,8 @@ Item { anchors.right: parent.right anchors.top: inputConfiguration.bottom anchors.bottom: parent.bottom + anchors.bottomMargin: keyboard.height + Loader { id: loader asynchronous: false @@ -248,6 +256,29 @@ Item { } } + HifiControls.Keyboard { + id: keyboard + raised: parent.keyboardEnabled && parent.keyboardRaised + onRaisedChanged: { + if (raised) { + // delayed execution to allow loader and its content to adjust size + Qt.callLater(function() { + loader.item.bringToView(Window.activeFocusItem); + }) + } + } + + numeric: parent.punctuationMode + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + + Component.onCompleted: { + parent.keyboardEnabled = HMD.active; + } + } function inputPlugins() { if (checkBox.checked) { diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 2fc5cc4196..1c629349d8 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -32,6 +32,18 @@ Flickable { } } + function bringToView(item) { + var yTop = item.mapToItem(contentItem, 0, 0).y; + var yBottom = yTop + item.height; + + var surfaceTop = contentY; + var surfaceBottom = contentY + height; + + if(yTop < surfaceTop || yBottom > surfaceBottom) { + contentY = yTop - height / 2 + item.height + } + } + Component.onCompleted: { page = config.createObject(flick.contentItem); } @@ -39,6 +51,8 @@ Flickable { id: config Rectangle { id: openVrConfiguration + anchors.fill: parent + property int leftMargin: 75 property int countDown: 0 property string pluginName: "" From 37bb3586eaee91eb0b1e6f202888e0ed196e0e75 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Tue, 13 Nov 2018 19:05:16 +0530 Subject: [PATCH 145/182] show spinbox suffix in separate control to: disallow editing it & allow to pass validator --- .../resources/qml/controlsUit/SpinBox.qml | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/controlsUit/SpinBox.qml b/interface/resources/qml/controlsUit/SpinBox.qml index d24c7c5e8c..34794d80c7 100644 --- a/interface/resources/qml/controlsUit/SpinBox.qml +++ b/interface/resources/qml/controlsUit/SpinBox.qml @@ -83,8 +83,10 @@ SpinBox { } validator: DoubleValidator { - bottom: Math.min(spinBox.from, spinBox.to) - top: Math.max(spinBox.from, spinBox.to) + decimals: spinBox.decimals + bottom: Math.min(spinBox.realFrom, spinBox.realTo) + top: Math.max(spinBox.realFrom, spinBox.realTo) + notation: DoubleValidator.StandardNotation } textFromValue: function(value, locale) { @@ -97,20 +99,37 @@ SpinBox { contentItem: TextInput { + id: spinboxText z: 2 color: isLightColorScheme ? (spinBox.activeFocus ? hifi.colors.black : hifi.colors.lightGray) : (spinBox.activeFocus ? hifi.colors.white : hifi.colors.lightGrayText) selectedTextColor: hifi.colors.black selectionColor: hifi.colors.primaryHighlight - text: spinBox.textFromValue(spinBox.value, spinBox.locale) + suffix + text: spinBox.textFromValue(spinBox.value, spinBox.locale) inputMethodHints: spinBox.inputMethodHints validator: spinBox.validator verticalAlignment: Qt.AlignVCenter leftPadding: spinBoxLabelInside.visible ? 30 : hifi.dimensions.textPadding - //rightPadding: hifi.dimensions.spinnerSize width: spinBox.width - hifi.dimensions.spinnerSize onEditingFinished: spinBox.editingFinished() + + Text { + id: suffixText + x: metrics.advanceWidth(spinboxText.text + '*') + height: spinboxText.height + + FontMetrics { + id: metrics + font: spinboxText.font + } + + color: isLightColorScheme + ? (spinBox.activeFocus ? hifi.colors.black : hifi.colors.lightGray) + : (spinBox.activeFocus ? hifi.colors.white : hifi.colors.lightGrayText) + text: suffix + verticalAlignment: Qt.AlignVCenter + } } up.indicator: Item { From 95c51c2ffac2fcdd5e8ca58d58ced4220019b033 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Fri, 7 Sep 2018 20:46:27 +0300 Subject: [PATCH 146/182] unfocus spinboxes on finishing editing --- .../resources/qml/hifi/tablet/OpenVrConfiguration.qml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 1c629349d8..eccf456b5e 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -214,6 +214,7 @@ Flickable { onEditingFinished: { sendConfigurationSettings(); + openVrConfiguration.forceActiveFocus(); } } @@ -231,6 +232,7 @@ Flickable { onEditingFinished: { sendConfigurationSettings(); + openVrConfiguration.forceActiveFocus(); } } } @@ -323,6 +325,7 @@ Flickable { onEditingFinished: { sendConfigurationSettings(); + openVrConfiguration.forceActiveFocus(); } } @@ -339,6 +342,7 @@ Flickable { onEditingFinished: { sendConfigurationSettings(); + openVrConfiguration.forceActiveFocus(); } } } @@ -571,6 +575,7 @@ Flickable { onEditingFinished: { sendConfigurationSettings(); + openVrConfiguration.forceActiveFocus(); } } @@ -587,6 +592,7 @@ Flickable { onEditingFinished: { sendConfigurationSettings(); + openVrConfiguration.forceActiveFocus(); } } } @@ -765,6 +771,7 @@ Flickable { calibrationTimer.interval = realValue * 1000; openVrConfiguration.countDown = realValue; numberAnimation.duration = calibrationTimer.interval; + openVrConfiguration.forceActiveFocus(); } } From 3a62184afd227f41f6fe584a5653a63137f660b0 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Wed, 12 Sep 2018 02:12:05 +0300 Subject: [PATCH 147/182] specify min/max/stepsize --- .../resources/qml/hifi/tablet/OpenVrConfiguration.qml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index eccf456b5e..b68a094846 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -568,7 +568,8 @@ Flickable { width: 160 suffix: " cm" label: "Arm Circumference" - minimumValue: 0 + minimumValue: 10.0 + maximumValue: 50.0 realStepSize: 1.0 colorScheme: hifi.colorSchemes.dark realValue: 33.0 @@ -585,6 +586,7 @@ Flickable { label: "Shoulder Width" suffix: " cm" minimumValue: 0 + maximumValue: 50.0 realStepSize: 1.0 decimals: 1 colorScheme: hifi.colorSchemes.dark @@ -763,8 +765,10 @@ Flickable { anchors.left: parent.left anchors.leftMargin: leftMargin - minimumValue: 5 + minimumValue: 0 + maximumValue: 5 realValue: 5 + realStepSize: 1.0 colorScheme: hifi.colorSchemes.dark onEditingFinished: { From b16efb2afbda71e9f54cae7971ee30f24d8b467f Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Wed, 12 Sep 2018 02:45:30 +0300 Subject: [PATCH 148/182] set minimum shoulder width to 25 cm (based on discussion with Tony) --- interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index b68a094846..e18fdea444 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -585,7 +585,7 @@ Flickable { width: 160 label: "Shoulder Width" suffix: " cm" - minimumValue: 0 + minimumValue: 25.0 maximumValue: 50.0 realStepSize: 1.0 decimals: 1 From e378a1b79cbea8c811af2472422c1d581545ba33 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 13 Nov 2018 08:39:52 -0800 Subject: [PATCH 149/182] Added missing CR --- tools/nitpick/src/TestRunner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/nitpick/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp index 868e608982..db6ce6cece 100644 --- a/tools/nitpick/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -173,9 +173,9 @@ void TestRunner::setWorkingFolder() { } script.write("#!/bin/sh\n\n"); - script.write("echo resizing interface"); + script.write("echo resizing interface\n"); script.write(("osascript " + _workingFolder + "/setInterfaceSizeAndPosition.scpt\n").toStdString().c_str()); - script.write("echo resize complete"); + script.write("echo resize complete\n"); script.close(); script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); #endif From c7e0cb1757b1d906a72b9624c799abb86b868f15 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 13 Nov 2018 10:11:22 -0800 Subject: [PATCH 150/182] Moved downloader deletion to after completion of download. --- tools/nitpick/src/ui/Nitpick.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/nitpick/src/ui/Nitpick.cpp b/tools/nitpick/src/ui/Nitpick.cpp index a4aef8fad5..8893173284 100644 --- a/tools/nitpick/src/ui/Nitpick.cpp +++ b/tools/nitpick/src/ui/Nitpick.cpp @@ -246,10 +246,6 @@ void Nitpick::downloadFiles(const QStringList& URLs, const QString& directoryNam _ui.progressBar->setValue(0); _ui.progressBar->setVisible(true); - foreach (auto downloader, _downloaders) { - delete downloader; - } - _downloaders.clear(); for (int i = 0; i < _numberOfFilesToDownload; ++i) { downloadFile(URLs[i]); @@ -277,6 +273,10 @@ void Nitpick::saveFile(int index) { } else if (_caller == _testRunner) { _testRunner->downloadComplete(); } + + foreach (auto downloader, _downloaders) { + delete downloader; + } } else { _ui.progressBar->setValue(_numberOfFilesDownloaded); } From 234a46bd4316f641d1d6c3356808a0acecf68cd0 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 13 Nov 2018 10:12:06 -0800 Subject: [PATCH 151/182] Evaluate results even if Interface crashed midway. --- tools/nitpick/src/TestRunner.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/nitpick/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp index 868e608982..8667852032 100644 --- a/tools/nitpick/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -539,9 +539,7 @@ void TestRunner::interfaceExecutionComplete() { QFileInfo testCompleted(QDir::toNativeSeparators(_snapshotFolder) +"/tests_completed.txt"); if (!testCompleted.exists()) { - QMessageBox::critical(0, "Tests not completed", "Interface seems to have crashed before completion of the test scripts"); - _runNow->setEnabled(true); - return; + QMessageBox::critical(0, "Tests not completed", "Interface seems to have crashed before completion of the test scripts\nExisting images will be evaluated"); } evaluateResults(); From 10d045b11b0dfe78eda1dcb82260dfe3dcf0503f Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 8 Nov 2018 17:16:34 -0800 Subject: [PATCH 152/182] fix infinate loading if entity server is not running --- interface/src/Application.cpp | 1 + interface/src/octree/SafeLanding.cpp | 15 ++++++++++++++- interface/src/octree/SafeLanding.h | 1 + scripts/system/interstitialPage.js | 2 +- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 75a9f598f7..a9d75e745c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5705,6 +5705,7 @@ void Application::update(float deltaTime) { quint64 now = usecTimestampNow(); if (isServerlessMode() || _octreeProcessor.isLoadSequenceComplete()) { bool enableInterstitial = DependencyManager::get()->getDomainHandler().getInterstitialModeEnabled(); + if (gpuTextureMemSizeStable() || !enableInterstitial) { // we've received a new full-scene octree stats packet, or it's been long enough to try again anyway _lastPhysicsCheckTime = now; diff --git a/interface/src/octree/SafeLanding.cpp b/interface/src/octree/SafeLanding.cpp index db381d5350..224ef064b6 100644 --- a/interface/src/octree/SafeLanding.cpp +++ b/interface/src/octree/SafeLanding.cpp @@ -11,6 +11,7 @@ #include "SafeLanding.h" +#include #include #include "EntityTreeRenderer.h" @@ -19,6 +20,8 @@ #include "Application.h" const int SafeLanding::SEQUENCE_MODULO = std::numeric_limits::max() + 1; +const quint64 MAX_ELAPSED_TIME = 1000; // msec +const quint64 MICRO_TO_MILI_SECONDS = 1000; namespace { template bool lessThanWraparound(int a, int b) { @@ -107,7 +110,9 @@ void SafeLanding::noteReceivedsequenceNumber(int sequenceNumber) { } bool SafeLanding::isLoadSequenceComplete() { - if (isEntityLoadingComplete() && isSequenceNumbersComplete()) { + quint64 elapsedTime = (usecTimestampNow() - _startTime) / MICRO_TO_MILI_SECONDS; + if ((isEntityLoadingComplete() && isSequenceNumbersComplete()) || + (elapsedTime >= MAX_ELAPSED_TIME && isEntityServerNotRunning() && _sequenceNumbers.empty())) { Locker lock(_lock); _initialStart = INVALID_SEQUENCE; _initialEnd = INVALID_SEQUENCE; @@ -119,6 +124,14 @@ bool SafeLanding::isLoadSequenceComplete() { return !_trackingEntities; } +bool SafeLanding::isEntityServerNotRunning() { + auto nodeList = DependencyManager::get(); + const auto& domainHandler = nodeList->getDomainHandler(); + auto entityServer = nodeList->soloNodeOfType(NodeType::EntityServer); + + return (domainHandler.isConnected() && !entityServer); +} + float SafeLanding::loadingProgressPercentage() { Locker lock(_lock); static const int MINIMUM_TRACKED_ENTITY_STABILITY_COUNT = 15; diff --git a/interface/src/octree/SafeLanding.h b/interface/src/octree/SafeLanding.h index 51357b60ff..157fda53aa 100644 --- a/interface/src/octree/SafeLanding.h +++ b/interface/src/octree/SafeLanding.h @@ -40,6 +40,7 @@ private: bool isSequenceNumbersComplete(); void debugDumpSequenceIDs() const; bool isEntityLoadingComplete(); + bool isEntityServerNotRunning(); std::mutex _lock; using Locker = std::lock_guard; diff --git a/scripts/system/interstitialPage.js b/scripts/system/interstitialPage.js index b7c5809b3a..9a67964801 100644 --- a/scripts/system/interstitialPage.js +++ b/scripts/system/interstitialPage.js @@ -15,7 +15,7 @@ (function() { Script.include("/~/system/libraries/Xform.js"); Script.include("/~/system/libraries/globals.js"); - var DEBUG = false; + var DEBUG = true; var TOTAL_LOADING_PROGRESS = 3.7; var EPSILON = 0.05; var TEXTURE_EPSILON = 0.01; From 1a95ee2b31fcb3b0dcb77d758ce17d9d4d9fb14a Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 9 Nov 2018 09:27:55 -0800 Subject: [PATCH 153/182] making requested changes --- interface/src/octree/SafeLanding.cpp | 4 ++-- scripts/system/interstitialPage.js | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/src/octree/SafeLanding.cpp b/interface/src/octree/SafeLanding.cpp index 224ef064b6..ff32e03006 100644 --- a/interface/src/octree/SafeLanding.cpp +++ b/interface/src/octree/SafeLanding.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "EntityTreeRenderer.h" #include "RenderableModelEntityItem.h" @@ -21,7 +22,6 @@ const int SafeLanding::SEQUENCE_MODULO = std::numeric_limits::max() + 1; const quint64 MAX_ELAPSED_TIME = 1000; // msec -const quint64 MICRO_TO_MILI_SECONDS = 1000; namespace { template bool lessThanWraparound(int a, int b) { @@ -110,7 +110,7 @@ void SafeLanding::noteReceivedsequenceNumber(int sequenceNumber) { } bool SafeLanding::isLoadSequenceComplete() { - quint64 elapsedTime = (usecTimestampNow() - _startTime) / MICRO_TO_MILI_SECONDS; + quint64 elapsedTime = (usecTimestampNow() - _startTime) / USECS_PER_MSEC; if ((isEntityLoadingComplete() && isSequenceNumbersComplete()) || (elapsedTime >= MAX_ELAPSED_TIME && isEntityServerNotRunning() && _sequenceNumbers.empty())) { Locker lock(_lock); diff --git a/scripts/system/interstitialPage.js b/scripts/system/interstitialPage.js index 9a67964801..cd8869d805 100644 --- a/scripts/system/interstitialPage.js +++ b/scripts/system/interstitialPage.js @@ -15,7 +15,7 @@ (function() { Script.include("/~/system/libraries/Xform.js"); Script.include("/~/system/libraries/globals.js"); - var DEBUG = true; + var DEBUG = false; var TOTAL_LOADING_PROGRESS = 3.7; var EPSILON = 0.05; var TEXTURE_EPSILON = 0.01; @@ -197,7 +197,7 @@ var loadingBarProgress = Overlays.addOverlay("image3d", { name: "Loading-Bar-Progress", - localPosition: { x: 0.0, y: -0.86, z: 0.0 }, + localPosition: { x: 0.0, y: -0.91, z: 0.0 }, url: LOADING_BAR_PROGRESS, alpha: 1, dimensions: { x: TOTAL_LOADING_PROGRESS, y: 0.3}, @@ -482,7 +482,7 @@ var end = 0; var xLocalPosition = (progressPercentage * (end - start)) + start; var properties = { - localPosition: { x: xLocalPosition, y: -0.93, z: 0.0 }, + localPosition: { x: xLocalPosition, y: -0.91, z: 0.0 }, dimensions: { x: progress, y: 0.3 From 812373cdabe1f8aa81fd3f427bbc58b6326c84c9 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 9 Nov 2018 10:37:21 -0800 Subject: [PATCH 154/182] fixing loading bar visual --- scripts/system/interstitialPage.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/system/interstitialPage.js b/scripts/system/interstitialPage.js index cd8869d805..e4dc778985 100644 --- a/scripts/system/interstitialPage.js +++ b/scripts/system/interstitialPage.js @@ -274,6 +274,7 @@ previousCameraMode = Camera.mode; Camera.mode = "first person"; updateProgressBar(0.0); + scaleInterstitialPage(MyAvatar.sensorToWorldScale); timer = Script.setTimeout(update, 2000); } } @@ -482,7 +483,7 @@ var end = 0; var xLocalPosition = (progressPercentage * (end - start)) + start; var properties = { - localPosition: { x: xLocalPosition, y: -0.91, z: 0.0 }, + localPosition: { x: xLocalPosition, y: (HMD.active ? -0.93 : -0.91), z: 0.0 }, dimensions: { x: progress, y: 0.3 From c7b3b9c0d2313b416406212fcd976b4f66403c1d Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 13 Nov 2018 11:49:59 -0800 Subject: [PATCH 155/182] Reverted previous commit. --- tools/nitpick/src/ui/Nitpick.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/nitpick/src/ui/Nitpick.cpp b/tools/nitpick/src/ui/Nitpick.cpp index 8893173284..a4aef8fad5 100644 --- a/tools/nitpick/src/ui/Nitpick.cpp +++ b/tools/nitpick/src/ui/Nitpick.cpp @@ -246,6 +246,10 @@ void Nitpick::downloadFiles(const QStringList& URLs, const QString& directoryNam _ui.progressBar->setValue(0); _ui.progressBar->setVisible(true); + foreach (auto downloader, _downloaders) { + delete downloader; + } + _downloaders.clear(); for (int i = 0; i < _numberOfFilesToDownload; ++i) { downloadFile(URLs[i]); @@ -273,10 +277,6 @@ void Nitpick::saveFile(int index) { } else if (_caller == _testRunner) { _testRunner->downloadComplete(); } - - foreach (auto downloader, _downloaders) { - delete downloader; - } } else { _ui.progressBar->setValue(_numberOfFilesDownloaded); } From 620c9e2f93fd62fdfab33a6e73bb6c8035cebd90 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 13 Nov 2018 13:38:44 -0800 Subject: [PATCH 156/182] All results now logged, so don't mark as failed. --- tools/nitpick/src/Test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/nitpick/src/Test.cpp b/tools/nitpick/src/Test.cpp index 13a03c32e8..47458d00ee 100644 --- a/tools/nitpick/src/Test.cpp +++ b/tools/nitpick/src/Test.cpp @@ -167,7 +167,7 @@ void Test::appendTestResultsToFile(const QString& _testResultsFolderPath, TestRe // Create text file describing the failure QTextStream stream(&descriptionFile); - stream << "Test failed in folder " << testResult._pathname.left(testResult._pathname.length() - 1) << endl; // remove trailing '/' + stream << "Test in folder " << testResult._pathname.left(testResult._pathname.length() - 1) << endl; // remove trailing '/' stream << "Expected image was " << testResult._expectedImageFilename << endl; stream << "Actual image was " << testResult._actualImageFilename << endl; stream << "Similarity index was " << testResult._error << endl; From ecee31960299f71859d621568ccdfa029c778d8a Mon Sep 17 00:00:00 2001 From: r3tk0n Date: Tue, 13 Nov 2018 15:20:46 -0800 Subject: [PATCH 157/182] Get logic working correctly. --- interface/resources/html/tabletHelp.html | 2 +- interface/src/Application.cpp | 46 +++++++++++++++++++----- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/interface/resources/html/tabletHelp.html b/interface/resources/html/tabletHelp.html index 8d4214d5af..dd7931d0ed 100644 --- a/interface/resources/html/tabletHelp.html +++ b/interface/resources/html/tabletHelp.html @@ -144,7 +144,7 @@ handControllerImageURL = "img/tablet-help-oculus.jpg"; break; default: - handControllerImageURL = null; + handControllerImageURL = ""; count = 2; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e537d618e9..9430d15794 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3400,21 +3400,51 @@ void Application::showHelp() { static const QString TAB_GAMEPAD = "gamepad"; static const QString TAB_HAND_CONTROLLERS = "handControllers"; - QString handControllerName = ""; + QString handControllerName; QString defaultTab = TAB_KEYBOARD_MOUSE; - if (PluginUtils::isViveControllerAvailable()) { - defaultTab = TAB_HAND_CONTROLLERS; - handControllerName = HAND_CONTROLLER_NAME_VIVE; - } else if (PluginUtils::isOculusTouchControllerAvailable()) { - defaultTab = TAB_HAND_CONTROLLERS; - handControllerName = HAND_CONTROLLER_NAME_OCULUS_TOUCH; - } else if (qApp->getActiveDisplayPlugin()->getName() == "WindowMS") { + qDebug() << "Printing names..."; + for (auto& inputPlugin : PluginManager::getInstance()->getInputPlugins()) { + qDebug() << inputPlugin->getName(); + auto subdeviceNames = inputPlugin->getSubdeviceNames(); + for (auto& subdeviceName : subdeviceNames) { + qDebug() << " -|" << subdeviceName; + } + } + + qDebug() << "----------------------"; + + auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); + for (auto& displayPlugin : displayPlugins) { + qDebug() << displayPlugin->getName(); + } + + if (PluginUtils::isHMDAvailable("WindowsMR")) { defaultTab = TAB_HAND_CONTROLLERS; handControllerName = HAND_CONTROLLER_NAME_WINDOWS_MR; + //} else if (PluginUtils::isViveControllerAvailable()) { + } else if (PluginUtils::isHMDAvailable("HTC Vive")) { + defaultTab = TAB_HAND_CONTROLLERS; + handControllerName = HAND_CONTROLLER_NAME_VIVE; + } else if (PluginUtils::isHMDAvailable("Oculus Rift")) { + defaultTab = TAB_HAND_CONTROLLERS; + handControllerName = HAND_CONTROLLER_NAME_OCULUS_TOUCH; } else if (PluginUtils::isXboxControllerAvailable()) { defaultTab = TAB_GAMEPAD; } + //if (QString::compare(qApp->getActiveDisplayPlugin()->getName(), "WindowsMR") == 0) { + // defaultTab = TAB_HAND_CONTROLLERS; + // handControllerName = HAND_CONTROLLER_NAME_WINDOWS_MR; + ////} else if (PluginUtils::isViveControllerAvailable()) { + //} else if (QString::compare(qApp->getActiveDisplayPlugin()->getName(), "HTC Vive") == 0) { + // defaultTab = TAB_HAND_CONTROLLERS; + // handControllerName = HAND_CONTROLLER_NAME_VIVE; + //} else if (PluginUtils::isOculusTouchControllerAvailable()) { + // defaultTab = TAB_HAND_CONTROLLERS; + // handControllerName = HAND_CONTROLLER_NAME_OCULUS_TOUCH; + //} else if (PluginUtils::isXboxControllerAvailable()) { + // defaultTab = TAB_GAMEPAD; + //} // TODO need some way to detect windowsMR to load controls reference default tab in Help > Controls Reference menu. QUrlQuery queryString; From dd8bbeb0e5378c49d22db7b740a28cfe8e98abea Mon Sep 17 00:00:00 2001 From: r3tk0n Date: Tue, 13 Nov 2018 15:36:25 -0800 Subject: [PATCH 158/182] Clean up code and remove comments. --- interface/src/Application.cpp | 41 ++++++----------------------------- 1 file changed, 7 insertions(+), 34 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9430d15794..aec580ff9d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3396,6 +3396,10 @@ void Application::showHelp() { static const QString HAND_CONTROLLER_NAME_OCULUS_TOUCH = "oculus"; static const QString HAND_CONTROLLER_NAME_WINDOWS_MR = "windowsMR"; + static const QString VIVE_PLUGIN_NAME = "HTC Vive"; + static const QString OCULUS_RIFT_PLUGIN_NAME = "Oculus Rift"; + static const QString WINDOWS_MR_PLUGIN_NAME = "WindowsMR"; + static const QString TAB_KEYBOARD_MOUSE = "kbm"; static const QString TAB_GAMEPAD = "gamepad"; static const QString TAB_HAND_CONTROLLERS = "handControllers"; @@ -3403,49 +3407,18 @@ void Application::showHelp() { QString handControllerName; QString defaultTab = TAB_KEYBOARD_MOUSE; - qDebug() << "Printing names..."; - for (auto& inputPlugin : PluginManager::getInstance()->getInputPlugins()) { - qDebug() << inputPlugin->getName(); - auto subdeviceNames = inputPlugin->getSubdeviceNames(); - for (auto& subdeviceName : subdeviceNames) { - qDebug() << " -|" << subdeviceName; - } - } - - qDebug() << "----------------------"; - - auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); - for (auto& displayPlugin : displayPlugins) { - qDebug() << displayPlugin->getName(); - } - - if (PluginUtils::isHMDAvailable("WindowsMR")) { + if (PluginUtils::isHMDAvailable(WINDOWS_MR_PLUGIN_NAME)) { defaultTab = TAB_HAND_CONTROLLERS; handControllerName = HAND_CONTROLLER_NAME_WINDOWS_MR; - //} else if (PluginUtils::isViveControllerAvailable()) { - } else if (PluginUtils::isHMDAvailable("HTC Vive")) { + } else if (PluginUtils::isHMDAvailable(VIVE_PLUGIN_NAME)) { defaultTab = TAB_HAND_CONTROLLERS; handControllerName = HAND_CONTROLLER_NAME_VIVE; - } else if (PluginUtils::isHMDAvailable("Oculus Rift")) { + } else if (PluginUtils::isHMDAvailable(OCULUS_RIFT_PLUGIN_NAME)) { defaultTab = TAB_HAND_CONTROLLERS; handControllerName = HAND_CONTROLLER_NAME_OCULUS_TOUCH; } else if (PluginUtils::isXboxControllerAvailable()) { defaultTab = TAB_GAMEPAD; } - //if (QString::compare(qApp->getActiveDisplayPlugin()->getName(), "WindowsMR") == 0) { - // defaultTab = TAB_HAND_CONTROLLERS; - // handControllerName = HAND_CONTROLLER_NAME_WINDOWS_MR; - ////} else if (PluginUtils::isViveControllerAvailable()) { - //} else if (QString::compare(qApp->getActiveDisplayPlugin()->getName(), "HTC Vive") == 0) { - // defaultTab = TAB_HAND_CONTROLLERS; - // handControllerName = HAND_CONTROLLER_NAME_VIVE; - //} else if (PluginUtils::isOculusTouchControllerAvailable()) { - // defaultTab = TAB_HAND_CONTROLLERS; - // handControllerName = HAND_CONTROLLER_NAME_OCULUS_TOUCH; - //} else if (PluginUtils::isXboxControllerAvailable()) { - // defaultTab = TAB_GAMEPAD; - //} - // TODO need some way to detect windowsMR to load controls reference default tab in Help > Controls Reference menu. QUrlQuery queryString; queryString.addQueryItem("handControllerName", handControllerName); From 85a3938cbee6755eb0f56ab596efb31b285b9dfc Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 14 Nov 2018 11:55:11 +0100 Subject: [PATCH 159/182] Switch to app for ambient occlusion debug script --- .../render-utils/src/AmbientOcclusionEffect.h | 8 +- .../render/debugAmbientOcclusionPass.js | 104 +++++------------- 2 files changed, 33 insertions(+), 79 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index a5b3ec1fdb..864aef09e4 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -208,7 +208,7 @@ private: void updateJitterSamples(); int getDepthResolutionLevel() const; - + AOParametersBuffer _aoParametersBuffer; FrameParametersBuffer _aoFrameParametersBuffer[SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT]; BlurParametersBuffer _vblurParametersBuffer; @@ -216,13 +216,13 @@ private: float _blurEdgeSharpness{ 0.0f }; static const gpu::PipelinePointer& getOcclusionPipeline(); - static const gpu::PipelinePointer& getBilateralBlurPipeline(); - static const gpu::PipelinePointer& getMipCreationPipeline(); + 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 _bilateralBlurPipeline; + static gpu::PipelinePointer _bilateralBlurPipeline; static gpu::PipelinePointer _mipCreationPipeline; static gpu::PipelinePointer _gatherPipeline; static gpu::PipelinePointer _buildNormalsPipeline; diff --git a/scripts/developer/utilities/render/debugAmbientOcclusionPass.js b/scripts/developer/utilities/render/debugAmbientOcclusionPass.js index 409473511e..19c29c59a3 100644 --- a/scripts/developer/utilities/render/debugAmbientOcclusionPass.js +++ b/scripts/developer/utilities/render/debugAmbientOcclusionPass.js @@ -12,88 +12,42 @@ // (function() { - var TABLET_BUTTON_NAME = "AO"; - var QMLAPP_URL = Script.resolvePath("./ambientOcclusionPass.qml"); + var AppUi = Script.require('appUi'); - - var onLuciScreen = false; + var onMousePressEvent = function (e) { + }; + Controller.mousePressEvent.connect(onMousePressEvent); - function onClicked() { - if (onLuciScreen) { - tablet.gotoHomeScreen(); - } else { - tablet.loadQMLSource(QMLAPP_URL); - } - } + var onMouseReleaseEvent = function () { + }; + Controller.mouseReleaseEvent.connect(onMouseReleaseEvent); - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - var button = tablet.addButton({ - text: TABLET_BUTTON_NAME, - sortOrder: 1 - }); - - 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) { - onLuciScreen = true; - } else { - onLuciScreen = false; - } - - button.editProperties({isActive: onLuciScreen}); - wireEventBridge(onLuciScreen); - } + var onMouseMoveEvent = function (e) { + }; + Controller.mouseMoveEvent.connect(onMouseMoveEvent); function fromQml(message) { + } - - button.clicked.connect(onClicked); - tablet.screenChanged.connect(onScreenChanged); - - 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); }); - + var ui; + function startup() { + ui = new AppUi({ + buttonName: "AO", + home: Script.resolvePath("ambientOcclusionPass.qml"), + onMessage: fromQml, + //normalButton: Script.resolvePath("../../../system/assets/images/ao-i.svg"), + //activeButton: Script.resolvePath("../../../system/assets/images/ao-a.svg") + }); + } + startup(); Script.scriptEnding.connect(function () { - if (onLuciScreen) { - tablet.gotoHomeScreen(); - } - button.clicked.disconnect(onClicked); - tablet.screenChanged.disconnect(onScreenChanged); - tablet.removeButton(button); + Controller.mousePressEvent.disconnect(onMousePressEvent); + Controller.mouseReleaseEvent.disconnect(onMouseReleaseEvent); + Controller.mouseMoveEvent.disconnect(onMouseMoveEvent); + pages.clear(); + // killEngineInspectorView(); + // killCullInspectorView(); + // killEngineLODWindow(); }); - - function setDebugCursor(x, y) { - nx = ((x + 0.5) / Window.innerWidth); - ny = 1.0 - ((y + 0.5) / (Window.innerHeight)); - - Render.getConfig("RenderMainView").getConfig("DebugAmbientOcclusion").debugCursorTexcoord = { x: nx, y: ny }; - } - }()); From 7192aed131440b3eb9860f8ee95cbd2e43973081 Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 24 Oct 2018 15:46:54 -0700 Subject: [PATCH 160/182] Rework audio data memory ownership model --- assignment-client/src/Agent.cpp | 10 +- interface/src/Application.cpp | 3 +- interface/src/avatar/AvatarManager.cpp | 9 +- libraries/audio/src/AudioConstants.h | 2 +- libraries/audio/src/AudioInjector.cpp | 149 +++++---- libraries/audio/src/AudioInjector.h | 14 +- .../audio/src/AudioInjectorLocalBuffer.cpp | 20 +- .../audio/src/AudioInjectorLocalBuffer.h | 13 +- libraries/audio/src/Sound.cpp | 286 ++++++++++-------- libraries/audio/src/Sound.h | 93 ++++-- .../src/EntityTreeRenderer.cpp | 9 +- .../src/AudioScriptingInterface.cpp | 6 +- libraries/script-engine/src/ScriptEngine.h | 4 +- .../ui/src/ui/TabletScriptingInterface.cpp | 2 +- libraries/ui/src/ui/types/SoundEffect.cpp | 3 +- 15 files changed, 355 insertions(+), 268 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index d9a399c162..88897a0fed 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -754,13 +754,13 @@ void Agent::processAgentAvatarAudio() { const int16_t* nextSoundOutput = NULL; if (_avatarSound) { - const QByteArray& soundByteArray = _avatarSound->getByteArray(); - nextSoundOutput = reinterpret_cast(soundByteArray.data() + auto audioData = _avatarSound->getAudioData(); + nextSoundOutput = reinterpret_cast(audioData->rawData() + _numAvatarSoundSentBytes); - int numAvailableBytes = (soundByteArray.size() - _numAvatarSoundSentBytes) > AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL + int numAvailableBytes = (audioData->getNumBytes() - _numAvatarSoundSentBytes) > AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL ? AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL - : soundByteArray.size() - _numAvatarSoundSentBytes; + : audioData->getNumBytes() - _numAvatarSoundSentBytes; numAvailableSamples = (int16_t)numAvailableBytes / sizeof(int16_t); @@ -773,7 +773,7 @@ void Agent::processAgentAvatarAudio() { } _numAvatarSoundSentBytes += numAvailableBytes; - if (_numAvatarSoundSentBytes == soundByteArray.size()) { + if (_numAvatarSoundSentBytes == (int)audioData->getNumBytes()) { // we're done with this sound object - so set our pointer back to NULL // and our sent bytes back to zero _avatarSound.clear(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5256ef2c6a..4a1a18c470 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4050,8 +4050,7 @@ void Application::keyPressEvent(QKeyEvent* event) { _snapshotSoundInjector->setOptions(options); _snapshotSoundInjector->restart(); } else { - QByteArray samples = _snapshotSound->getByteArray(); - _snapshotSoundInjector = AudioInjector::playSound(samples, options); + _snapshotSoundInjector = AudioInjector::playSound(_snapshotSound, options); } } takeSnapshot(true); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 76ad49b1f4..7ca18ca258 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -562,8 +562,13 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents static const int MAX_INJECTOR_COUNT = 3; if (_collisionInjectors.size() < MAX_INJECTOR_COUNT) { - auto injector = AudioInjector::playSound(collisionSound, energyFactorOfFull, AVATAR_STRETCH_FACTOR, - myAvatar->getWorldPosition()); + AudioInjectorOptions options; + options.stereo = collisionSound->isStereo(); + options.position = myAvatar->getWorldPosition(); + options.volume = energyFactorOfFull; + options.pitch = 1.0f / AVATAR_STRETCH_FACTOR; + + auto injector = AudioInjector::playSoundAndDelete(collisionSound, options); _collisionInjectors.emplace_back(injector); } myAvatar->collisionWithEntity(collision); diff --git a/libraries/audio/src/AudioConstants.h b/libraries/audio/src/AudioConstants.h index 6d9678c368..f4235f42c5 100644 --- a/libraries/audio/src/AudioConstants.h +++ b/libraries/audio/src/AudioConstants.h @@ -22,7 +22,7 @@ namespace AudioConstants { const int STEREO = 2; const int AMBISONIC = 4; - typedef int16_t AudioSample; + using AudioSample = int16_t; const int SAMPLE_SIZE = sizeof(AudioSample); inline const char* getAudioFrameName() { return "com.highfidelity.recording.Audio"; } diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index d1b919292a..efd823c5b1 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -38,12 +38,14 @@ AudioInjectorState& operator|= (AudioInjectorState& lhs, AudioInjectorState rhs) return lhs; }; -AudioInjector::AudioInjector(const Sound& sound, const AudioInjectorOptions& injectorOptions) : - AudioInjector(sound.getByteArray(), injectorOptions) +AudioInjector::AudioInjector(SharedSoundPointer sound, const AudioInjectorOptions& injectorOptions) : + _sound(sound), + _audioData(sound->getAudioData()), + _options(injectorOptions) { } -AudioInjector::AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions) : +AudioInjector::AudioInjector(AudioDataPointer audioData, const AudioInjectorOptions& injectorOptions) : _audioData(audioData), _options(injectorOptions) { @@ -154,7 +156,7 @@ bool AudioInjector::inject(bool(AudioInjectorManager::*injection)(const AudioInj bool AudioInjector::injectLocally() { bool success = false; if (_localAudioInterface) { - if (_audioData.size() > 0) { + if (_audioData->getNumBytes() > 0) { _localBuffer = new AudioInjectorLocalBuffer(_audioData); @@ -220,22 +222,12 @@ int64_t AudioInjector::injectNextFrame() { if (!_currentPacket) { if (_currentSendOffset < 0 || - _currentSendOffset >= _audioData.size()) { + _currentSendOffset >= (int)_audioData->getNumBytes()) { _currentSendOffset = 0; } // make sure we actually have samples downloaded to inject - if (_audioData.size()) { - - int sampleSize = (_options.stereo ? 2 : 1) * sizeof(AudioConstants::AudioSample); - auto numSamples = static_cast(_audioData.size() / sampleSize); - auto targetSize = numSamples * sampleSize; - if (targetSize != _audioData.size()) { - qCDebug(audio) << "Resizing audio that doesn't end at multiple of sample size, resizing from " - << _audioData.size() << " to " << targetSize; - _audioData.resize(targetSize); - } - + if (_audioData && _audioData->getNumSamples() > 0) { _outgoingSequenceNumber = 0; _nextFrame = 0; @@ -307,19 +299,10 @@ int64_t AudioInjector::injectNextFrame() { _frameTimer->restart(); } - int totalBytesLeftToCopy = (_options.stereo ? 2 : 1) * AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL; - if (!_options.loop) { - // If we aren't looping, let's make sure we don't read past the end - totalBytesLeftToCopy = std::min(totalBytesLeftToCopy, _audioData.size() - _currentSendOffset); - } - - // Measure the loudness of this frame - _loudness = 0.0f; - for (int i = 0; i < totalBytesLeftToCopy; i += sizeof(int16_t)) { - _loudness += abs(*reinterpret_cast(_audioData.data() + ((_currentSendOffset + i) % _audioData.size()))) / - (AudioConstants::MAX_SAMPLE_VALUE / 2.0f); - } - _loudness /= (float)(totalBytesLeftToCopy/ sizeof(int16_t)); + assert(loopbackOptionOffset != -1); + assert(positionOptionOffset != -1); + assert(volumeOptionOffset != -1); + assert(audioDataOffset != -1); _currentPacket->seek(0); @@ -339,19 +322,37 @@ int64_t AudioInjector::injectNextFrame() { _currentPacket->seek(audioDataOffset); - // This code is copying bytes from the _audioData directly into the packet, handling looping appropriately. + // This code is copying bytes from the _sound directly into the packet, handling looping appropriately. // Might be a reasonable place to do the encode step here. QByteArray decodedAudio; - while (totalBytesLeftToCopy > 0) { - int bytesToCopy = std::min(totalBytesLeftToCopy, _audioData.size() - _currentSendOffset); - decodedAudio.append(_audioData.data() + _currentSendOffset, bytesToCopy); - _currentSendOffset += bytesToCopy; - totalBytesLeftToCopy -= bytesToCopy; - if (_options.loop && _currentSendOffset >= _audioData.size()) { - _currentSendOffset = 0; - } + int totalBytesLeftToCopy = (_options.stereo ? 2 : 1) * AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL; + if (!_options.loop) { + // If we aren't looping, let's make sure we don't read past the end + int bytesLeftToRead = _audioData->getNumBytes() - _currentSendOffset; + totalBytesLeftToCopy = std::min(totalBytesLeftToCopy, bytesLeftToRead); } + + auto samples = _audioData->data(); + auto currentSample = _currentSendOffset / AudioConstants::SAMPLE_SIZE; + auto samplesLeftToCopy = totalBytesLeftToCopy / AudioConstants::SAMPLE_SIZE; + + using AudioConstants::AudioSample; + decodedAudio.resize(totalBytesLeftToCopy); + auto samplesOut = reinterpret_cast(decodedAudio.data()); + + // Copy and Measure the loudness of this frame + _loudness = 0.0f; + for (int i = 0; i < samplesLeftToCopy; ++i) { + auto index = (currentSample + i) % _audioData->getNumSamples(); + auto sample = samples[index]; + samplesOut[i] = sample; + _loudness += abs(sample) / (AudioConstants::MAX_SAMPLE_VALUE / 2.0f); + } + _loudness /= (float)samplesLeftToCopy; + _currentSendOffset = (_currentSendOffset + totalBytesLeftToCopy) % + _audioData->getNumBytes(); + // FIXME -- good place to call codec encode here. We need to figure out how to tell the AudioInjector which // codec to use... possible through AbstractAudioInterface. QByteArray encodedAudio = decodedAudio; @@ -370,7 +371,7 @@ int64_t AudioInjector::injectNextFrame() { _outgoingSequenceNumber++; } - if (_currentSendOffset >= _audioData.size() && !_options.loop) { + if (_currentSendOffset == 0 && !_options.loop) { finishNetworkInjection(); return NEXT_FRAME_DELTA_ERROR_OR_FINISHED; } @@ -390,7 +391,7 @@ int64_t AudioInjector::injectNextFrame() { // If we are falling behind by more frames than our threshold, let's skip the frames ahead qCDebug(audio) << this << "injectNextFrame() skipping ahead, fell behind by " << (currentFrameBasedOnElapsedTime - _nextFrame) << " frames"; _nextFrame = currentFrameBasedOnElapsedTime; - _currentSendOffset = _nextFrame * AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL * (_options.stereo ? 2 : 1) % _audioData.size(); + _currentSendOffset = _nextFrame * AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL * (_options.stereo ? 2 : 1) % _audioData->getNumBytes(); } int64_t playNextFrameAt = ++_nextFrame * AudioConstants::NETWORK_FRAME_USECS; @@ -417,38 +418,25 @@ void AudioInjector::triggerDeleteAfterFinish() { } } -AudioInjectorPointer AudioInjector::playSound(SharedSoundPointer sound, const float volume, - const float stretchFactor, const glm::vec3 position) { +AudioInjectorPointer AudioInjector::playSoundAndDelete(SharedSoundPointer sound, const AudioInjectorOptions& options) { + AudioInjectorPointer injector = playSound(sound, options); + + if (injector) { + injector->_state |= AudioInjectorState::PendingDelete; + } + + return injector; +} + + +AudioInjectorPointer AudioInjector::playSound(SharedSoundPointer sound, const AudioInjectorOptions& options) { if (!sound || !sound->isReady()) { return AudioInjectorPointer(); } - AudioInjectorOptions options; - options.stereo = sound->isStereo(); - options.position = position; - options.volume = volume; - options.pitch = 1.0f / stretchFactor; - - QByteArray samples = sound->getByteArray(); - - return playSoundAndDelete(samples, options); -} - -AudioInjectorPointer AudioInjector::playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options) { - AudioInjectorPointer sound = playSound(buffer, options); - - if (sound) { - sound->_state |= AudioInjectorState::PendingDelete; - } - - return sound; -} - -AudioInjectorPointer AudioInjector::playSound(const QByteArray& buffer, const AudioInjectorOptions options) { - if (options.pitch == 1.0f) { - AudioInjectorPointer injector = AudioInjectorPointer::create(buffer, options); + AudioInjectorPointer injector = AudioInjectorPointer::create(sound, options); if (!injector->inject(&AudioInjectorManager::threadInjector)) { qWarning() << "AudioInjector::playSound failed to thread injector"; @@ -456,24 +444,31 @@ AudioInjectorPointer AudioInjector::playSound(const QByteArray& buffer, const Au return injector; } else { + using AudioConstants::AudioSample; + using AudioConstants::SAMPLE_RATE; + const int standardRate = SAMPLE_RATE; + // limit to 4 octaves + const int pitch = glm::clamp(options.pitch, 1 / 16.0f, 16.0f); + const int resampledRate = SAMPLE_RATE / pitch; - const int standardRate = AudioConstants::SAMPLE_RATE; - const int resampledRate = AudioConstants::SAMPLE_RATE / glm::clamp(options.pitch, 1/16.0f, 16.0f); // limit to 4 octaves - const int numChannels = options.ambisonic ? AudioConstants::AMBISONIC : - (options.stereo ? AudioConstants::STEREO : AudioConstants::MONO); + auto audioData = sound->getAudioData(); + auto numChannels = audioData->getNumChannels(); + auto numFrames = audioData->getNumFrames(); AudioSRC resampler(standardRate, resampledRate, numChannels); // create a resampled buffer that is guaranteed to be large enough - const int nInputFrames = buffer.size() / (numChannels * sizeof(int16_t)); - const int maxOutputFrames = resampler.getMaxOutput(nInputFrames); - QByteArray resampledBuffer(maxOutputFrames * numChannels * sizeof(int16_t), '\0'); + const int maxOutputFrames = resampler.getMaxOutput(numFrames); + const int maxOutputSize = maxOutputFrames * numChannels * sizeof(AudioSample); + QByteArray resampledBuffer(maxOutputSize, '\0'); + auto bufferPtr = reinterpret_cast(resampledBuffer.data()); - resampler.render(reinterpret_cast(buffer.data()), - reinterpret_cast(resampledBuffer.data()), - nInputFrames); + resampler.render(audioData->data(), bufferPtr, numFrames); - AudioInjectorPointer injector = AudioInjectorPointer::create(resampledBuffer, options); + int numSamples = maxOutputFrames * numChannels; + auto newAudioData = AudioData::make(numSamples, numChannels, bufferPtr); + + AudioInjectorPointer injector = AudioInjectorPointer::create(newAudioData, options); if (!injector->inject(&AudioInjectorManager::threadInjector)) { qWarning() << "AudioInjector::playSound failed to thread pitch-shifted injector"; diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index fc197f7ba0..37e4cbd66c 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -52,8 +52,8 @@ AudioInjectorState& operator|= (AudioInjectorState& lhs, AudioInjectorState rhs) class AudioInjector : public QObject, public QEnableSharedFromThis { Q_OBJECT public: - AudioInjector(const Sound& sound, const AudioInjectorOptions& injectorOptions); - AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions); + AudioInjector(SharedSoundPointer sound, const AudioInjectorOptions& injectorOptions); + AudioInjector(AudioDataPointer audioData, const AudioInjectorOptions& injectorOptions); ~AudioInjector(); bool isFinished() const { return (stateHas(AudioInjectorState::Finished)); } @@ -74,10 +74,9 @@ public: bool stateHas(AudioInjectorState state) const ; static void setLocalAudioInterface(AbstractAudioInterface* audioInterface) { _localAudioInterface = audioInterface; } - static AudioInjectorPointer playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options); - static AudioInjectorPointer playSound(const QByteArray& buffer, const AudioInjectorOptions options); - static AudioInjectorPointer playSound(SharedSoundPointer sound, const float volume, - const float stretchFactor, const glm::vec3 position); + + static AudioInjectorPointer playSoundAndDelete(SharedSoundPointer sound, const AudioInjectorOptions& options); + static AudioInjectorPointer playSound(SharedSoundPointer sound, const AudioInjectorOptions& options); public slots: void restart(); @@ -106,7 +105,8 @@ private: static AbstractAudioInterface* _localAudioInterface; - QByteArray _audioData; + const SharedSoundPointer _sound; + AudioDataPointer _audioData; AudioInjectorOptions _options; AudioInjectorState _state { AudioInjectorState::NotFinished }; bool _hasSentFirstFrame { false }; diff --git a/libraries/audio/src/AudioInjectorLocalBuffer.cpp b/libraries/audio/src/AudioInjectorLocalBuffer.cpp index 7834644baf..015d87e03b 100644 --- a/libraries/audio/src/AudioInjectorLocalBuffer.cpp +++ b/libraries/audio/src/AudioInjectorLocalBuffer.cpp @@ -11,13 +11,9 @@ #include "AudioInjectorLocalBuffer.h" -AudioInjectorLocalBuffer::AudioInjectorLocalBuffer(const QByteArray& rawAudioArray) : - _rawAudioArray(rawAudioArray), - _shouldLoop(false), - _isStopped(false), - _currentOffset(0) +AudioInjectorLocalBuffer::AudioInjectorLocalBuffer(AudioDataPointer audioData) : + _audioData(audioData) { - } void AudioInjectorLocalBuffer::stop() { @@ -39,7 +35,7 @@ qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) { if (!_isStopped) { // first copy to the end of the raw audio - int bytesToEnd = _rawAudioArray.size() - _currentOffset; + int bytesToEnd = (int)_audioData->getNumBytes() - _currentOffset; int bytesRead = maxSize; @@ -47,7 +43,7 @@ qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) { bytesRead = bytesToEnd; } - memcpy(data, _rawAudioArray.data() + _currentOffset, bytesRead); + memcpy(data, _audioData->rawData() + _currentOffset, bytesRead); // now check if we are supposed to loop and if we can copy more from the beginning if (_shouldLoop && maxSize != bytesRead) { @@ -56,7 +52,7 @@ qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) { _currentOffset += bytesRead; } - if (_shouldLoop && _currentOffset == _rawAudioArray.size()) { + if (_shouldLoop && _currentOffset == (int)_audioData->getNumBytes()) { _currentOffset = 0; } @@ -70,12 +66,12 @@ qint64 AudioInjectorLocalBuffer::recursiveReadFromFront(char* data, qint64 maxSi // see how much we can get in this pass int bytesRead = maxSize; - if (bytesRead > _rawAudioArray.size()) { - bytesRead = _rawAudioArray.size(); + if (bytesRead > (int)_audioData->getNumBytes()) { + bytesRead = _audioData->getNumBytes(); } // copy that amount - memcpy(data, _rawAudioArray.data(), bytesRead); + memcpy(data, _audioData->rawData(), bytesRead); // check if we need to call ourselves again and pull from the front again if (bytesRead < maxSize) { diff --git a/libraries/audio/src/AudioInjectorLocalBuffer.h b/libraries/audio/src/AudioInjectorLocalBuffer.h index 3065de5199..e0f8847883 100644 --- a/libraries/audio/src/AudioInjectorLocalBuffer.h +++ b/libraries/audio/src/AudioInjectorLocalBuffer.h @@ -16,10 +16,12 @@ #include +#include "Sound.h" + class AudioInjectorLocalBuffer : public QIODevice { Q_OBJECT public: - AudioInjectorLocalBuffer(const QByteArray& rawAudioArray); + AudioInjectorLocalBuffer(AudioDataPointer audioData); void stop(); @@ -34,11 +36,10 @@ public: private: qint64 recursiveReadFromFront(char* data, qint64 maxSize); - QByteArray _rawAudioArray; - bool _shouldLoop; - bool _isStopped; - - int _currentOffset; + AudioDataPointer _audioData; + bool _shouldLoop { false }; + bool _isStopped { false }; + int _currentOffset { 0 }; }; #endif // hifi_AudioInjectorLocalBuffer_h diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 3807882b00..3cc32333f6 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -33,48 +33,59 @@ #include "flump3dec.h" -QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, const SharedSoundPointer& in) { - return engine->newQObject(new SoundScriptingInterface(in), QScriptEngine::ScriptOwnership); +int audioDataPointerMetaTypeID = qRegisterMetaType("AudioDataPointer"); + +using AudioConstants::AudioSample; + +AudioDataPointer AudioData::make(uint32_t numSamples, uint32_t numChannels, + const AudioSample* samples) { + // Compute the amount of memory required for the audio data object + const size_t bufferSize = numSamples * sizeof(AudioSample); + const size_t memorySize = sizeof(AudioData) + bufferSize; + + // Allocate the memory for the audio data object and the buffer + void* memory = ::malloc(memorySize); + auto audioData = reinterpret_cast(memory); + auto buffer = reinterpret_cast(audioData + 1); + assert(((char*)buffer - (char*)audioData) == sizeof(AudioData)); + + // Use placement new to construct the audio data object at the memory allocated + ::new(audioData) AudioData(numSamples, numChannels, buffer); + + // Copy the samples to the buffer + memcpy(buffer, samples, bufferSize); + + // Return shared_ptr that properly destruct the object and release the memory + return AudioDataPointer(audioData, [](AudioData* ptr) { + ptr->~AudioData(); + ::free(ptr); + }); } -void soundSharedPointerFromScriptValue(const QScriptValue& object, SharedSoundPointer& out) { - if (auto soundInterface = qobject_cast(object.toQObject())) { - out = soundInterface->getSound(); - } -} -SoundScriptingInterface::SoundScriptingInterface(const SharedSoundPointer& sound) : _sound(sound) { - // During shutdown we can sometimes get an empty sound pointer back - if (_sound) { - QObject::connect(_sound.data(), &Sound::ready, this, &SoundScriptingInterface::ready); - } -} - -Sound::Sound(const QUrl& url, bool isStereo, bool isAmbisonic) : - Resource(url), - _isStereo(isStereo), - _isAmbisonic(isAmbisonic), - _isReady(false) -{ -} +AudioData::AudioData(uint32_t numSamples, uint32_t numChannels, const AudioSample* samples) + : _numSamples(numSamples), + _numChannels(numChannels), + _data(samples) +{} void Sound::downloadFinished(const QByteArray& data) { + if (!_self) { + soundProcessError(301, "Sound object has gone out of scope"); + return; + } + // this is a QRunnable, will delete itself after it has finished running - SoundProcessor* soundProcessor = new SoundProcessor(_url, data, _isStereo, _isAmbisonic); + auto soundProcessor = new SoundProcessor(_self, data); connect(soundProcessor, &SoundProcessor::onSuccess, this, &Sound::soundProcessSuccess); connect(soundProcessor, &SoundProcessor::onError, this, &Sound::soundProcessError); QThreadPool::globalInstance()->start(soundProcessor); } -void Sound::soundProcessSuccess(QByteArray data, bool stereo, bool ambisonic, float duration) { +void Sound::soundProcessSuccess(AudioDataPointer audioData) { + qCDebug(audio) << "Setting ready state for sound file" << _url.fileName(); - qCDebug(audio) << "Setting ready state for sound file"; - - _byteArray = data; - _isStereo = stereo; - _isAmbisonic = ambisonic; - _duration = duration; - _isReady = true; + _audioData = std::move(audioData); finishedLoading(true); emit ready(); @@ -86,91 +97,102 @@ void Sound::soundProcessError(int error, QString str) { finishedLoading(false); } -void SoundProcessor::run() { - qCDebug(audio) << "Processing sound file"; +SoundProcessor::SoundProcessor(QWeakPointer sound, QByteArray data) : + _sound(sound), + _data(data) +{ +} + +void SoundProcessor::run() { + auto sound = qSharedPointerCast(_sound.lock()); + if (!sound) { + emit onError(301, "Sound object has gone out of scope"); + return; + } + + QString fileName = sound->getURL().fileName().toLower(); + qCDebug(audio) << "Processing sound file" << fileName; // replace our byte array with the downloaded data - QByteArray rawAudioByteArray = QByteArray(_data); - QString fileName = _url.fileName().toLower(); static const QString WAV_EXTENSION = ".wav"; static const QString MP3_EXTENSION = ".mp3"; static const QString RAW_EXTENSION = ".raw"; + static const QString STEREO_RAW_EXTENSION = ".stereo.raw"; + QString fileType; + + QByteArray outputAudioByteArray; + AudioProperties properties; if (fileName.endsWith(WAV_EXTENSION)) { - - QByteArray outputAudioByteArray; - - int sampleRate = interpretAsWav(rawAudioByteArray, outputAudioByteArray); - if (sampleRate == 0) { - qCWarning(audio) << "Unsupported WAV file type"; - emit onError(300, "Failed to load sound file, reason: unsupported WAV file type"); - return; - } - - downSample(outputAudioByteArray, sampleRate); - + fileType = "WAV"; + properties = interpretAsWav(_data, outputAudioByteArray); } else if (fileName.endsWith(MP3_EXTENSION)) { - - QByteArray outputAudioByteArray; - - int sampleRate = interpretAsMP3(rawAudioByteArray, outputAudioByteArray); - if (sampleRate == 0) { - qCWarning(audio) << "Unsupported MP3 file type"; - emit onError(300, "Failed to load sound file, reason: unsupported MP3 file type"); - return; - } - - downSample(outputAudioByteArray, sampleRate); - - } else if (fileName.endsWith(RAW_EXTENSION)) { + fileType = "MP3"; + properties = interpretAsMP3(_data, outputAudioByteArray); + } else if (fileName.endsWith(STEREO_RAW_EXTENSION)) { // check if this was a stereo raw file // since it's raw the only way for us to know that is if the file was called .stereo.raw - if (fileName.toLower().endsWith("stereo.raw")) { - _isStereo = true; - qCDebug(audio) << "Processing sound of" << rawAudioByteArray.size() << "bytes as stereo audio file."; - } - + qCDebug(audio) << "Processing sound of" << _data.size() << "bytes from" << fileName << "as stereo audio file."; // Process as 48khz RAW file - downSample(rawAudioByteArray, 48000); - + properties.numChannels = 2; + properties.sampleRate = 48000; + outputAudioByteArray = _data; + } else if (fileName.endsWith(RAW_EXTENSION)) { + // Process as 48khz RAW file + properties.numChannels = 1; + properties.sampleRate = 48000; + outputAudioByteArray = _data; } else { qCWarning(audio) << "Unknown sound file type"; emit onError(300, "Failed to load sound file, reason: unknown sound file type"); return; } - emit onSuccess(_data, _isStereo, _isAmbisonic, _duration); + if (properties.sampleRate == 0) { + qCWarning(audio) << "Unsupported" << fileType << "file type"; + emit onError(300, "Failed to load sound file, reason: unsupported " + fileType + " file type"); + return; + } + + auto data = downSample(outputAudioByteArray, properties); + + int numSamples = data.size() / AudioConstants::SAMPLE_SIZE; + auto audioData = AudioData::make(numSamples, properties.numChannels, + (const AudioSample*)data.constData()); + emit onSuccess(audioData); } -void SoundProcessor::downSample(const QByteArray& rawAudioByteArray, int sampleRate) { +QByteArray SoundProcessor::downSample(const QByteArray& rawAudioByteArray, + AudioProperties properties) { // we want to convert it to the format that the audio-mixer wants // which is signed, 16-bit, 24Khz - if (sampleRate == AudioConstants::SAMPLE_RATE) { + if (properties.sampleRate == AudioConstants::SAMPLE_RATE) { // no resampling needed - _data = rawAudioByteArray; - } else { - - int numChannels = _isAmbisonic ? AudioConstants::AMBISONIC : (_isStereo ? AudioConstants::STEREO : AudioConstants::MONO); - AudioSRC resampler(sampleRate, AudioConstants::SAMPLE_RATE, numChannels); - - // resize to max possible output - int numSourceFrames = rawAudioByteArray.size() / (numChannels * sizeof(AudioConstants::AudioSample)); - int maxDestinationFrames = resampler.getMaxOutput(numSourceFrames); - int maxDestinationBytes = maxDestinationFrames * numChannels * sizeof(AudioConstants::AudioSample); - _data.resize(maxDestinationBytes); - - int numDestinationFrames = resampler.render((int16_t*)rawAudioByteArray.data(), - (int16_t*)_data.data(), - numSourceFrames); - - // truncate to actual output - int numDestinationBytes = numDestinationFrames * numChannels * sizeof(AudioConstants::AudioSample); - _data.resize(numDestinationBytes); + return rawAudioByteArray; } + + AudioSRC resampler(properties.sampleRate, AudioConstants::SAMPLE_RATE, + properties.numChannels); + + // resize to max possible output + int numSourceFrames = rawAudioByteArray.size() / (properties.numChannels * AudioConstants::SAMPLE_SIZE); + int maxDestinationFrames = resampler.getMaxOutput(numSourceFrames); + int maxDestinationBytes = maxDestinationFrames * properties.numChannels * AudioConstants::SAMPLE_SIZE; + QByteArray data(maxDestinationBytes, Qt::Uninitialized); + + int numDestinationFrames = resampler.render((int16_t*)rawAudioByteArray.data(), + (int16_t*)data.data(), + numSourceFrames); + + // truncate to actual output + int numDestinationBytes = numDestinationFrames * properties.numChannels * sizeof(AudioSample); + data.resize(numDestinationBytes); + + return data; } // @@ -218,7 +240,9 @@ struct WAVEFormat { }; // returns wavfile sample rate, used for resampling -int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray) { +SoundProcessor::AudioProperties SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, + QByteArray& outputAudioByteArray) { + AudioProperties properties; // Create a data stream to analyze the data QDataStream waveStream(const_cast(&inputAudioByteArray), QIODevice::ReadOnly); @@ -227,7 +251,7 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA RIFFHeader riff; if (waveStream.readRawData((char*)&riff, sizeof(RIFFHeader)) != sizeof(RIFFHeader)) { qCWarning(audio) << "Not a valid WAVE file."; - return 0; + return AudioProperties(); } // Parse the "RIFF" chunk @@ -235,11 +259,11 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA waveStream.setByteOrder(QDataStream::LittleEndian); } else { qCWarning(audio) << "Currently not supporting big-endian audio files."; - return 0; + return AudioProperties(); } if (strncmp(riff.type, "WAVE", 4) != 0) { qCWarning(audio) << "Not a valid WAVE file."; - return 0; + return AudioProperties(); } // Read chunks until the "fmt " chunk is found @@ -247,7 +271,7 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA while (true) { if (waveStream.readRawData((char*)&fmt, sizeof(chunk)) != sizeof(chunk)) { qCWarning(audio) << "Not a valid WAVE file."; - return 0; + return AudioProperties(); } if (strncmp(fmt.id, "fmt ", 4) == 0) { break; @@ -259,26 +283,26 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA WAVEFormat wave; if (waveStream.readRawData((char*)&wave, sizeof(WAVEFormat)) != sizeof(WAVEFormat)) { qCWarning(audio) << "Not a valid WAVE file."; - return 0; + return AudioProperties(); } // Parse the "fmt " chunk if (qFromLittleEndian(wave.audioFormat) != WAVEFORMAT_PCM && qFromLittleEndian(wave.audioFormat) != WAVEFORMAT_EXTENSIBLE) { qCWarning(audio) << "Currently not supporting non PCM audio files."; - return 0; + return AudioProperties(); } - if (qFromLittleEndian(wave.numChannels) == 2) { - _isStereo = true; - } else if (qFromLittleEndian(wave.numChannels) == 4) { - _isAmbisonic = true; - } else if (qFromLittleEndian(wave.numChannels) != 1) { + + properties.numChannels = qFromLittleEndian(wave.numChannels); + if (properties.numChannels != 1 && + properties.numChannels != 2 && + properties.numChannels != 4) { qCWarning(audio) << "Currently not supporting audio files with other than 1/2/4 channels."; - return 0; + return AudioProperties(); } if (qFromLittleEndian(wave.bitsPerSample) != 16) { qCWarning(audio) << "Currently not supporting non 16bit audio files."; - return 0; + return AudioProperties(); } // Skip any extra data in the "fmt " chunk @@ -289,7 +313,7 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA while (true) { if (waveStream.readRawData((char*)&data, sizeof(chunk)) != sizeof(chunk)) { qCWarning(audio) << "Not a valid WAVE file."; - return 0; + return AudioProperties(); } if (strncmp(data.id, "data", 4) == 0) { break; @@ -300,17 +324,21 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA // Read the "data" chunk quint32 outputAudioByteArraySize = qFromLittleEndian(data.size); outputAudioByteArray.resize(outputAudioByteArraySize); - if (waveStream.readRawData(outputAudioByteArray.data(), outputAudioByteArraySize) != (int)outputAudioByteArraySize) { + auto bytesRead = waveStream.readRawData(outputAudioByteArray.data(), outputAudioByteArraySize); + if (bytesRead != (int)outputAudioByteArraySize) { qCWarning(audio) << "Error reading WAV file"; - return 0; + return AudioProperties(); } - _duration = (float)(outputAudioByteArraySize / (wave.sampleRate * wave.numChannels * wave.bitsPerSample / 8.0f)); - return wave.sampleRate; + properties.sampleRate = wave.sampleRate; + return properties; } // returns MP3 sample rate, used for resampling -int SoundProcessor::interpretAsMP3(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray) { +SoundProcessor::AudioProperties SoundProcessor::interpretAsMP3(const QByteArray& inputAudioByteArray, + QByteArray& outputAudioByteArray) { + AudioProperties properties; + using namespace flump3dec; static const int MP3_SAMPLES_MAX = 1152; @@ -321,21 +349,19 @@ int SoundProcessor::interpretAsMP3(const QByteArray& inputAudioByteArray, QByteA // create bitstream Bit_stream_struc *bitstream = bs_new(); if (bitstream == nullptr) { - return 0; + return AudioProperties(); } // create decoder mp3tl *decoder = mp3tl_new(bitstream, MP3TL_MODE_16BIT); if (decoder == nullptr) { bs_free(bitstream); - return 0; + return AudioProperties(); } // initialize bs_set_data(bitstream, (uint8_t*)inputAudioByteArray.data(), inputAudioByteArray.size()); int frameCount = 0; - int sampleRate = 0; - int numChannels = 0; // skip ID3 tag, if present Mp3TlRetcode result = mp3tl_skip_id3(decoder); @@ -357,8 +383,8 @@ int SoundProcessor::interpretAsMP3(const QByteArray& inputAudioByteArray, QByteA << "channels =" << header->channels; // save header info - sampleRate = header->sample_rate; - numChannels = header->channels; + properties.sampleRate = header->sample_rate; + properties.numChannels = header->channels; // skip Xing header, if present result = mp3tl_skip_xing(decoder, header); @@ -388,14 +414,32 @@ int SoundProcessor::interpretAsMP3(const QByteArray& inputAudioByteArray, QByteA // free bitstream bs_free(bitstream); - int outputAudioByteArraySize = outputAudioByteArray.size(); - if (outputAudioByteArraySize == 0) { + if (outputAudioByteArray.isEmpty()) { qCWarning(audio) << "Error decoding MP3 file"; - return 0; + return AudioProperties(); } - _isStereo = (numChannels == 2); - _isAmbisonic = false; - _duration = (float)outputAudioByteArraySize / (sampleRate * numChannels * sizeof(int16_t)); - return sampleRate; + return properties; +} + + +QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, const SharedSoundPointer& in) { + return engine->newQObject(new SoundScriptingInterface(in), QScriptEngine::ScriptOwnership); +} + +void soundSharedPointerFromScriptValue(const QScriptValue& object, SharedSoundPointer& out) { + if (auto soundInterface = qobject_cast(object.toQObject())) { + out = soundInterface->getSound(); + } +} + +SoundScriptingInterface::SoundScriptingInterface(const SharedSoundPointer& sound) : _sound(sound) { + // During shutdown we can sometimes get an empty sound pointer back + if (_sound) { + QObject::connect(_sound.data(), &Sound::ready, this, &SoundScriptingInterface::ready); + } +} + +Sound::Sound(const QUrl& url, bool isStereo, bool isAmbisonic) : Resource(url) { + _numChannels = isAmbisonic ? 4 : (isStereo ? 2 : 1); } diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index a0544870d0..36bc9c72ac 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -19,61 +19,102 @@ #include +#include "AudioConstants.h" + +class AudioData; +using AudioDataPointer = std::shared_ptr; + +Q_DECLARE_METATYPE(AudioDataPointer); + +// AudioData is designed to be immutable +// All of its members and methods are const +// This makes it perfectly safe to access from multiple threads at once +class AudioData { +public: + using AudioSample = AudioConstants::AudioSample; + + // Allocates the buffer memory contiguous with the object + static AudioDataPointer make(uint32_t numSamples, uint32_t numChannels, + const AudioSample* samples); + + AudioData(uint32_t numSamples, uint32_t numChannels, const AudioSample* samples); + + uint32_t getNumSamples() const { return _numSamples; } + uint32_t getNumChannels() const { return _numChannels; } + const AudioSample* data() const { return _data; } + const char* rawData() const { return reinterpret_cast(_data); } + + float isStereo() const { return _numChannels == 2; } + float isAmbisonic() const { return _numChannels == 4; } + float getDuration() const { return (float)_numSamples / (_numChannels * AudioConstants::SAMPLE_RATE); } + uint32_t getNumFrames() const { return _numSamples / _numChannels; } + uint32_t getNumBytes() const { return _numSamples * sizeof(AudioSample); } + +private: + const uint32_t _numSamples { 0 }; + const uint32_t _numChannels { 0 }; + const AudioSample* const _data { nullptr }; +}; + class Sound : public Resource { Q_OBJECT public: Sound(const QUrl& url, bool isStereo = false, bool isAmbisonic = false); - bool isStereo() const { return _isStereo; } - bool isAmbisonic() const { return _isAmbisonic; } - bool isReady() const { return _isReady; } - float getDuration() const { return _duration; } - - const QByteArray& getByteArray() const { return _byteArray; } + bool isReady() const { return (bool)_audioData; } + + bool isStereo() const { return _audioData ? _audioData->isStereo() : false; } + bool isAmbisonic() const { return _audioData ? _audioData->isAmbisonic() : false; } + float getDuration() const { return _audioData ? _audioData->getDuration() : 0.0f; } + + AudioDataPointer getAudioData() const { return _audioData; } + + int getNumChannels() const { return _numChannels; } signals: void ready(); protected slots: - void soundProcessSuccess(QByteArray data, bool stereo, bool ambisonic, float duration); + void soundProcessSuccess(AudioDataPointer audioData); void soundProcessError(int error, QString str); private: - QByteArray _byteArray; - bool _isStereo; - bool _isAmbisonic; - bool _isReady; - float _duration; // In seconds - virtual void downloadFinished(const QByteArray& data) override; + + AudioDataPointer _audioData; + + // Only used for caching until the download has finished + int _numChannels { 0 }; }; class SoundProcessor : public QObject, public QRunnable { Q_OBJECT public: - SoundProcessor(const QUrl& url, const QByteArray& data, bool stereo, bool ambisonic) - : _url(url), _data(data), _isStereo(stereo), _isAmbisonic(ambisonic) - { - } + struct AudioProperties { + uint8_t numChannels { 0 }; + uint32_t sampleRate { 0 }; + }; + + SoundProcessor(QWeakPointer sound, QByteArray data); virtual void run() override; - void downSample(const QByteArray& rawAudioByteArray, int sampleRate); - int interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray); - int interpretAsMP3(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray); + QByteArray downSample(const QByteArray& rawAudioByteArray, + AudioProperties properties); + AudioProperties interpretAsWav(const QByteArray& inputAudioByteArray, + QByteArray& outputAudioByteArray); + AudioProperties interpretAsMP3(const QByteArray& inputAudioByteArray, + QByteArray& outputAudioByteArray); signals: - void onSuccess(QByteArray data, bool stereo, bool ambisonic, float duration); + void onSuccess(AudioDataPointer audioData); void onError(int error, QString str); private: - QUrl _url; - QByteArray _data; - bool _isStereo; - bool _isAmbisonic; - float _duration; + const QWeakPointer _sound; + const QByteArray _data; }; typedef QSharedPointer SharedSoundPointer; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 6e82d26f29..980ff8834c 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -1031,7 +1031,14 @@ void EntityTreeRenderer::playEntityCollisionSound(const EntityItemPointer& entit // Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2) const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f; const float stretchFactor = logf(1.0f + (minAACube.getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / logf(2.0f); - AudioInjector::playSound(collisionSound, volume, stretchFactor, collision.contactPoint); + + AudioInjectorOptions options; + options.stereo = collisionSound->isStereo(); + options.position = collision.contactPoint; + options.volume = volume; + options.pitch = 1.0f / stretchFactor; + + AudioInjector::playSoundAndDelete(collisionSound, options); } void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, diff --git a/libraries/script-engine/src/AudioScriptingInterface.cpp b/libraries/script-engine/src/AudioScriptingInterface.cpp index 72918e33f6..0c4a593487 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.cpp +++ b/libraries/script-engine/src/AudioScriptingInterface.cpp @@ -63,15 +63,15 @@ ScriptAudioInjector* AudioScriptingInterface::playSound(SharedSoundPointer sound optionsCopy.ambisonic = sound->isAmbisonic(); optionsCopy.localOnly = optionsCopy.localOnly || sound->isAmbisonic(); // force localOnly when Ambisonic - auto injector = AudioInjector::playSound(sound->getByteArray(), optionsCopy); + auto injector = AudioInjector::playSound(sound, optionsCopy); if (!injector) { - return NULL; + return nullptr; } return new ScriptAudioInjector(injector); } else { qCDebug(scriptengine) << "AudioScriptingInterface::playSound called with null Sound object."; - return NULL; + return nullptr; } } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 17afd3dbbd..fe8396bc50 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -766,8 +766,8 @@ protected: */ Q_INVOKABLE void entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success, const QString& status); - EntityItemID currentEntityIdentifier {}; // Contains the defining entity script entity id during execution, if any. Empty for interface script execution. - QUrl currentSandboxURL {}; // The toplevel url string for the entity script that loaded the code being executed, else empty. + EntityItemID currentEntityIdentifier; // Contains the defining entity script entity id during execution, if any. Empty for interface script execution. + QUrl currentSandboxURL; // The toplevel url string for the entity script that loaded the code being executed, else empty. void doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function operation); void callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args); diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 52d359ad0d..8fc2d069ec 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -211,7 +211,7 @@ void TabletScriptingInterface::playSound(TabletAudioEvents aEvent) { options.ambisonic = sound->isAmbisonic(); options.localOnly = true; - AudioInjectorPointer injector = AudioInjector::playSoundAndDelete(sound->getByteArray(), options); + AudioInjectorPointer injector = AudioInjector::playSoundAndDelete(sound, options); } } diff --git a/libraries/ui/src/ui/types/SoundEffect.cpp b/libraries/ui/src/ui/types/SoundEffect.cpp index e35d009ef6..dc2328b33e 100644 --- a/libraries/ui/src/ui/types/SoundEffect.cpp +++ b/libraries/ui/src/ui/types/SoundEffect.cpp @@ -37,7 +37,6 @@ void SoundEffect::play(QVariant position) { _injector->setOptions(options); _injector->restart(); } else { - QByteArray samples = _sound->getByteArray(); - _injector = AudioInjector::playSound(samples, options); + _injector = AudioInjector::playSound(_sound, options); } } From d2a1bb4806a26f9cb3d3e5249814a2633ba4b272 Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 8 Nov 2018 11:29:20 -0800 Subject: [PATCH 161/182] CR --- libraries/audio/src/Sound.cpp | 7 +++---- libraries/audio/src/Sound.h | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 3cc32333f6..7c5dd3813b 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -111,11 +111,10 @@ void SoundProcessor::run() { return; } - QString fileName = sound->getURL().fileName().toLower(); + auto url = sound->getURL(); + QString fileName = url.fileName().toLower(); qCDebug(audio) << "Processing sound file" << fileName; - // replace our byte array with the downloaded data - static const QString WAV_EXTENSION = ".wav"; static const QString MP3_EXTENSION = ".mp3"; static const QString RAW_EXTENSION = ".raw"; @@ -165,7 +164,7 @@ void SoundProcessor::run() { } QByteArray SoundProcessor::downSample(const QByteArray& rawAudioByteArray, - AudioProperties properties) { + AudioProperties properties) { // we want to convert it to the format that the audio-mixer wants // which is signed, 16-bit, 24Khz diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 36bc9c72ac..836e28d582 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -37,8 +37,6 @@ public: static AudioDataPointer make(uint32_t numSamples, uint32_t numChannels, const AudioSample* samples); - AudioData(uint32_t numSamples, uint32_t numChannels, const AudioSample* samples); - uint32_t getNumSamples() const { return _numSamples; } uint32_t getNumChannels() const { return _numChannels; } const AudioSample* data() const { return _data; } @@ -51,6 +49,8 @@ public: uint32_t getNumBytes() const { return _numSamples * sizeof(AudioSample); } private: + AudioData(uint32_t numSamples, uint32_t numChannels, const AudioSample* samples); + const uint32_t _numSamples { 0 }; const uint32_t _numChannels { 0 }; const AudioSample* const _data { nullptr }; From 7f910a38e3810608ae7976e657b57e38c8382bf1 Mon Sep 17 00:00:00 2001 From: Clement Date: Mon, 12 Nov 2018 16:06:22 -0800 Subject: [PATCH 162/182] Update keyboard injector to new interface --- interface/src/ui/Keyboard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/Keyboard.cpp b/interface/src/ui/Keyboard.cpp index 773253f85c..5f83c095c8 100644 --- a/interface/src/ui/Keyboard.cpp +++ b/interface/src/ui/Keyboard.cpp @@ -485,7 +485,7 @@ void Keyboard::handleTriggerBegin(const OverlayID& overlayID, const PointerEvent audioOptions.position = keyWorldPosition; audioOptions.volume = 0.1f; - AudioInjector::playSound(_keySound->getByteArray(), audioOptions); + AudioInjector::playSoundAndDelete(_keySound, audioOptions); int scanCode = key.getScanCode(_capsEnabled); QString keyString = key.getKeyString(_capsEnabled); From f17723c216520c481b30db69676fe57c35b71d54 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 14 Nov 2018 14:50:38 -0800 Subject: [PATCH 163/182] disable interstitial for master --- libraries/networking/src/DomainHandler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index c0c5a4d059..620ffb9641 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -234,7 +234,7 @@ private: #ifdef Q_OS_ANDROID Setting::Handle _enableInterstitialMode{ "enableInterstitialMode", false }; #else - Setting::Handle _enableInterstitialMode { "enableInterstitialMode", true }; + Setting::Handle _enableInterstitialMode { "enableInterstitialMode", false }; #endif QSet _domainConnectionRefusals; From 31033ad68589658ead1e75f3293b589755ff744f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 13 Nov 2018 12:12:48 -0800 Subject: [PATCH 164/182] Update TTS audio API use --- .../src/scripting/TTSScriptingInterface.cpp | 6 ++- libraries/audio/src/AudioInjector.cpp | 46 +++++++++++++++++++ libraries/audio/src/AudioInjector.h | 2 + 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/interface/src/scripting/TTSScriptingInterface.cpp b/interface/src/scripting/TTSScriptingInterface.cpp index 6b1677aecb..6589769ece 100644 --- a/interface/src/scripting/TTSScriptingInterface.cpp +++ b/interface/src/scripting/TTSScriptingInterface.cpp @@ -147,7 +147,11 @@ void TTSScriptingInterface::speakText(const QString& textToSpeak) { _lastSoundAudioInjectorUpdateTimer.stop(); } - _lastSoundAudioInjector = AudioInjector::playSoundAndDelete(_lastSoundByteArray, options); + uint32_t numChannels = 1; + uint32_t numSamples = (uint32_t)_lastSoundByteArray.size() / sizeof(AudioData::AudioSample); + auto samples = reinterpret_cast(_lastSoundByteArray.data()); + auto newAudioData = AudioData::make(numSamples, numChannels, samples); + _lastSoundAudioInjector = AudioInjector::playSoundAndDelete(newAudioData, options); _lastSoundAudioInjectorUpdateTimer.start(INJECTOR_INTERVAL_MS); #else diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index efd823c5b1..4af6e79caf 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -476,3 +476,49 @@ AudioInjectorPointer AudioInjector::playSound(SharedSoundPointer sound, const A return injector; } } + +AudioInjectorPointer AudioInjector::playSoundAndDelete(AudioDataPointer audioData, const AudioInjectorOptions& options) { + AudioInjectorPointer injector = playSound(audioData, options); + + if (injector) { + injector->_state |= AudioInjectorState::PendingDelete; + } + + return injector; +} + +AudioInjectorPointer AudioInjector::playSound(AudioDataPointer audioData, const AudioInjectorOptions& options) { + if (options.pitch == 1.0f) { + AudioInjectorPointer injector = AudioInjectorPointer::create(audioData, options); + + if (!injector->inject(&AudioInjectorManager::threadInjector)) { + qWarning() << "AudioInjector::playSound failed to thread pitch-shifted injector"; + } + return injector; + } else { + using AudioConstants::AudioSample; + using AudioConstants::SAMPLE_RATE; + const int standardRate = SAMPLE_RATE; + // limit to 4 octaves + const int pitch = glm::clamp(options.pitch, 1 / 16.0f, 16.0f); + const int resampledRate = SAMPLE_RATE / pitch; + + auto numChannels = audioData->getNumChannels(); + auto numFrames = audioData->getNumFrames(); + + AudioSRC resampler(standardRate, resampledRate, numChannels); + + // create a resampled buffer that is guaranteed to be large enough + const int maxOutputFrames = resampler.getMaxOutput(numFrames); + const int maxOutputSize = maxOutputFrames * numChannels * sizeof(AudioSample); + QByteArray resampledBuffer(maxOutputSize, '\0'); + auto bufferPtr = reinterpret_cast(resampledBuffer.data()); + + resampler.render(audioData->data(), bufferPtr, numFrames); + + int numSamples = maxOutputFrames * numChannels; + auto newAudioData = AudioData::make(numSamples, numChannels, bufferPtr); + + return AudioInjector::playSound(newAudioData, options); + } +} \ No newline at end of file diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 37e4cbd66c..49faa61b91 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -77,6 +77,8 @@ public: static AudioInjectorPointer playSoundAndDelete(SharedSoundPointer sound, const AudioInjectorOptions& options); static AudioInjectorPointer playSound(SharedSoundPointer sound, const AudioInjectorOptions& options); + static AudioInjectorPointer playSoundAndDelete(AudioDataPointer audioData, const AudioInjectorOptions& options); + static AudioInjectorPointer playSound(AudioDataPointer audioData, const AudioInjectorOptions& options); public slots: void restart(); From d0e4c6297874d9fc726656e66bc45f2b17bc7a89 Mon Sep 17 00:00:00 2001 From: humbletim Date: Wed, 14 Nov 2018 23:50:02 -0500 Subject: [PATCH 165/182] fix merge conflict --- interface/src/ModelPropertiesDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ModelPropertiesDialog.cpp b/interface/src/ModelPropertiesDialog.cpp index a32d8adefb..1bdb170b60 100644 --- a/interface/src/ModelPropertiesDialog.cpp +++ b/interface/src/ModelPropertiesDialog.cpp @@ -26,7 +26,7 @@ #include -ModelPropertiesDialog::ModelPropertiesDialog(FSTReader::ModelType modelType, const QVariantHash& originalMapping, +ModelPropertiesDialog::ModelPropertiesDialog(const QVariantHash& originalMapping, const QString& basePath, const HFMModel& hfmModel) : _originalMapping(originalMapping), _basePath(basePath), From 1e17b878e70d3e7dd90a10c0c0a0708ab6a72ed8 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 15 Nov 2018 07:32:26 -0800 Subject: [PATCH 166/182] CR updates. --- tools/nitpick/src/PythonInterface.h | 3 +-- tools/nitpick/src/TestRunner.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/nitpick/src/PythonInterface.h b/tools/nitpick/src/PythonInterface.h index a218b68039..a6e954f356 100644 --- a/tools/nitpick/src/PythonInterface.h +++ b/tools/nitpick/src/PythonInterface.h @@ -21,8 +21,7 @@ public: private: #ifdef Q_OS_WIN const QString _pythonExe{ "python.exe" }; -#endif -#ifdef Q_OS_MACOS +#elif const QString _pythonExe{ "python" }; #endif diff --git a/tools/nitpick/src/TestRunner.h b/tools/nitpick/src/TestRunner.h index 11129d2f36..00f0f66ecf 100644 --- a/tools/nitpick/src/TestRunner.h +++ b/tools/nitpick/src/TestRunner.h @@ -94,7 +94,7 @@ private: #elif defined(Q_OS_MAC) const QString INSTALLER_FILENAME_LATEST{ "HighFidelity-Beta-latest-dev.dmg" }; #else - const QString INSTALLER_FILENAME_LATEST{ "just to pass compilation" }; + const QString INSTALLER_FILENAME_LATEST{ "" }; #endif QString _installerURL; From fb0a84e80047c05bf788a31253c4f9026546797f Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 15 Nov 2018 07:54:56 -0800 Subject: [PATCH 167/182] CR updates. --- tools/nitpick/src/PythonInterface.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/nitpick/src/PythonInterface.h b/tools/nitpick/src/PythonInterface.h index a6e954f356..947b359037 100644 --- a/tools/nitpick/src/PythonInterface.h +++ b/tools/nitpick/src/PythonInterface.h @@ -21,7 +21,8 @@ public: private: #ifdef Q_OS_WIN const QString _pythonExe{ "python.exe" }; -#elif +#else + // Both Mac and Linux use "python" const QString _pythonExe{ "python" }; #endif From 0401858129b2c1d14ad735853c80630cf41fcaa4 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 15 Nov 2018 18:34:41 +0100 Subject: [PATCH 168/182] Cleaned up do_draw in GLESBackend --- .../gpu-gl-common/src/gpu/gl/GLBackend.cpp | 9 -------- .../gpu-gl-common/src/gpu/gl/GLBackend.h | 2 +- libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp | 9 ++++++++ libraries/gpu-gl/src/gpu/gl41/GL41Backend.h | 1 + libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp | 9 ++++++++ libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 1 + .../gpu-gles/src/gpu/gles/GLESBackend.cpp | 23 +------------------ 7 files changed, 22 insertions(+), 32 deletions(-) diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index d5124e82a4..c1ce05c18b 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -177,15 +177,6 @@ void GLBackend::shutdown() { killShaderBinaryCache(); } -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 ae3a7ce5fd..37dde5b08e 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -275,7 +275,7 @@ public: size_t getMaxNumResourceTextureTables() const { return MAX_NUM_RESOURCE_TABLE_TEXTURES; } // Draw Stage - virtual void do_draw(const Batch& batch, size_t paramOffset); + virtual void do_draw(const Batch& batch, size_t paramOffset) = 0; 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; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp index ea884fe125..cb0950c06d 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp @@ -43,6 +43,15 @@ 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; + + draw(mode, numVertices, startVertex); +} + 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 23e49773ae..881487c9db 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -147,6 +147,7 @@ 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 29c2a230a0..385ddca065 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp @@ -66,6 +66,15 @@ 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; + + draw(mode, numVertices, startVertex); +} + 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 391fec45ce..c1ce074188 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -248,6 +248,7 @@ 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-gles/src/gpu/gles/GLESBackend.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackend.cpp index cb40b4fc9b..12c1346c7b 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackend.cpp +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackend.cpp @@ -49,28 +49,7 @@ void GLESBackend::do_draw(const Batch& batch, size_t paramOffset) { 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(); + draw(mode, numVertices, startVertex); } void GLESBackend::do_drawIndexed(const Batch& batch, size_t paramOffset) { From 597ff773e1ff065792d5b6beb168a1ea24a25528 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 14 Nov 2018 18:00:56 -0800 Subject: [PATCH 169/182] fix for avatar flashing --- libraries/render/src/render/Item.h | 4 ++-- libraries/render/src/render/Scene.cpp | 7 ++++++- libraries/render/src/render/Scene.h | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index a87e2031f9..79557e3e44 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -480,8 +480,8 @@ public: protected: PayloadPointer _payload; ItemKey _key; - ItemCell _cell{ INVALID_CELL }; - Index _transitionId{ INVALID_INDEX }; + ItemCell _cell { INVALID_CELL }; + Index _transitionId { INVALID_INDEX }; friend class Scene; }; diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index 8d12cfae25..1850261c99 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -391,7 +391,12 @@ void Scene::transitionItems(const Transaction::TransitionAdds& transactions) { // Remove pre-existing transition, if need be if (!TransitionStage::isIndexInvalid(transitionId)) { - resetItemTransition(itemId); + // Only remove if: + // transitioning to something other than none or we're transitioning to none from ELEMENT_LEAVE_DOMAIN or USER_LEAVE_DOMAIN + const auto& oldTransitionType = transitionStage->getTransition(transitionId).eventType; + if (transitionType != Transition::NONE || !(oldTransitionType == Transition::ELEMENT_LEAVE_DOMAIN || oldTransitionType == Transition::USER_LEAVE_DOMAIN)) { + resetItemTransition(itemId); + } } // Add a new one. diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 68acfe8d0f..e05cb04532 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -157,7 +157,7 @@ public: // This next call are NOT threadsafe, you have to call them from the correct thread to avoid any potential issues - // Access a particular item form its ID + // Access a particular item from its ID // WARNING, There is No check on the validity of the ID, so this could return a bad Item const Item& getItem(const ItemID& id) const { return _items[id]; } From 20ad05726efd0d86dac24f924f36d741b76cd014 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 13 Nov 2018 15:13:30 -0800 Subject: [PATCH 170/182] entity server timout --- .../qml/hifi/tablet/TabletAddressDialog.qml | 2 +- interface/src/Application.cpp | 26 ++++++++++++++++++- interface/src/Application.h | 4 +++ interface/src/octree/SafeLanding.cpp | 15 +---------- interface/src/octree/SafeLanding.h | 1 - 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index b8972378ad..ab0a98a8c5 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -56,7 +56,7 @@ StackView { Qt.callLater(function() { addressBarDialog.keyboardEnabled = HMD.active; addressLine.forceActiveFocus(); - addressBarDialog.raised = true; + addressBarDialog.keyboardRaised = true; }) } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a9d75e745c..47a73cee57 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -371,6 +371,8 @@ static const QString INFO_HELP_PATH = "html/tabletHelp.html"; static const unsigned int THROTTLED_SIM_FRAMERATE = 15; static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE; +static const int ENTITY_SERVER_ADDED_TIMEOUT = 5000; +static const int ENTITY_SERVER_CONNECTION_TIMEOUT = 5000; static const uint32_t INVALID_FRAME = UINT32_MAX; @@ -1224,6 +1226,18 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo getOverlays().deleteOverlay(getTabletScreenID()); getOverlays().deleteOverlay(getTabletHomeButtonID()); getOverlays().deleteOverlay(getTabletFrameID()); + _failedToConnectToEntityServer = false; + }); + + _entityServerConnectionTimer.setSingleShot(true); + connect(&_entityServerConnectionTimer, &QTimer::timeout, this, &Application::setFailedToConnectToEntityServer); + + connect(&domainHandler, &DomainHandler::connectedToDomain, this, [this]() { + if (!isServerlessMode()) { + _entityServerConnectionTimer.setInterval(ENTITY_SERVER_ADDED_TIMEOUT); + _entityServerConnectionTimer.start(); + _failedToConnectToEntityServer = false; + } }); connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &Application::domainConnectionRefused); @@ -6630,7 +6644,13 @@ void Application::resettingDomain() { } void Application::nodeAdded(SharedNodePointer node) const { - // nothing to do here + if (node->getType() == NodeType::EntityServer) { + if (!_failedToConnectToEntityServer) { + _entityServerConnectionTimer.stop(); + _entityServerConnectionTimer.setInterval(ENTITY_SERVER_CONNECTION_TIMEOUT); + _entityServerConnectionTimer.start(); + } + } } void Application::nodeActivated(SharedNodePointer node) { @@ -6658,6 +6678,10 @@ void Application::nodeActivated(SharedNodePointer node) { if (node->getType() == NodeType::EntityServer) { _queryExpiry = SteadyClock::now(); _octreeQuery.incrementConnectionID(); + + if (!_failedToConnectToEntityServer) { + _entityServerConnectionTimer.stop(); + } } if (node->getType() == NodeType::AudioMixer && !isInterstitialMode()) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 14e30b8006..053cb158e0 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -307,6 +307,7 @@ public: bool isServerlessMode() const; bool isInterstitialMode() const { return _interstitialMode; } + bool failedToConnectToEntityServer() const { return _failedToConnectToEntityServer; } void replaceDomainContent(const QString& url); @@ -460,6 +461,7 @@ private slots: void loadSettings(); void saveSettings() const; + void setFailedToConnectToEntityServer() { _failedToConnectToEntityServer = true; } bool acceptSnapshot(const QString& urlString); bool askToSetAvatarUrl(const QString& url); @@ -710,6 +712,7 @@ private: bool _isForeground = true; // starts out assumed to be in foreground bool _isGLInitialized { false }; bool _physicsEnabled { false }; + bool _failedToConnectToEntityServer { false }; bool _reticleClickPressed { false }; @@ -756,6 +759,7 @@ private: QStringList _addAssetToWorldInfoMessages; // Info message QTimer _addAssetToWorldInfoTimer; QTimer _addAssetToWorldErrorTimer; + mutable QTimer _entityServerConnectionTimer; FileScriptingInterface* _fileDownload; AudioInjectorPointer _snapshotSoundInjector; diff --git a/interface/src/octree/SafeLanding.cpp b/interface/src/octree/SafeLanding.cpp index ff32e03006..9efad22d09 100644 --- a/interface/src/octree/SafeLanding.cpp +++ b/interface/src/octree/SafeLanding.cpp @@ -11,9 +11,7 @@ #include "SafeLanding.h" -#include #include -#include #include "EntityTreeRenderer.h" #include "RenderableModelEntityItem.h" @@ -21,7 +19,6 @@ #include "Application.h" const int SafeLanding::SEQUENCE_MODULO = std::numeric_limits::max() + 1; -const quint64 MAX_ELAPSED_TIME = 1000; // msec namespace { template bool lessThanWraparound(int a, int b) { @@ -110,9 +107,7 @@ void SafeLanding::noteReceivedsequenceNumber(int sequenceNumber) { } bool SafeLanding::isLoadSequenceComplete() { - quint64 elapsedTime = (usecTimestampNow() - _startTime) / USECS_PER_MSEC; - if ((isEntityLoadingComplete() && isSequenceNumbersComplete()) || - (elapsedTime >= MAX_ELAPSED_TIME && isEntityServerNotRunning() && _sequenceNumbers.empty())) { + if ((isEntityLoadingComplete() && isSequenceNumbersComplete()) || qApp->failedToConnectToEntityServer()) { Locker lock(_lock); _initialStart = INVALID_SEQUENCE; _initialEnd = INVALID_SEQUENCE; @@ -124,14 +119,6 @@ bool SafeLanding::isLoadSequenceComplete() { return !_trackingEntities; } -bool SafeLanding::isEntityServerNotRunning() { - auto nodeList = DependencyManager::get(); - const auto& domainHandler = nodeList->getDomainHandler(); - auto entityServer = nodeList->soloNodeOfType(NodeType::EntityServer); - - return (domainHandler.isConnected() && !entityServer); -} - float SafeLanding::loadingProgressPercentage() { Locker lock(_lock); static const int MINIMUM_TRACKED_ENTITY_STABILITY_COUNT = 15; diff --git a/interface/src/octree/SafeLanding.h b/interface/src/octree/SafeLanding.h index 157fda53aa..51357b60ff 100644 --- a/interface/src/octree/SafeLanding.h +++ b/interface/src/octree/SafeLanding.h @@ -40,7 +40,6 @@ private: bool isSequenceNumbersComplete(); void debugDumpSequenceIDs() const; bool isEntityLoadingComplete(); - bool isEntityServerNotRunning(); std::mutex _lock; using Locker = std::lock_guard; From 34224c4f16382ae0a3faf311fca388302bc7067d Mon Sep 17 00:00:00 2001 From: r3tk0n Date: Thu, 15 Nov 2018 14:08:21 -0800 Subject: [PATCH 171/182] Fix XBox One controller detection. --- libraries/plugins/src/plugins/PluginUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/plugins/src/plugins/PluginUtils.cpp b/libraries/plugins/src/plugins/PluginUtils.cpp index ce67f7c585..f6419ccba0 100644 --- a/libraries/plugins/src/plugins/PluginUtils.cpp +++ b/libraries/plugins/src/plugins/PluginUtils.cpp @@ -65,6 +65,6 @@ bool PluginUtils::isOculusTouchControllerAvailable() { }; bool PluginUtils::isXboxControllerAvailable() { - return isSubdeviceContainingNameAvailable("X360 Controller"); + return isSubdeviceContainingNameAvailable("X360 Controller") || isSubdeviceContainingNameAvailable("XInput Controller"); }; From 60832b071cb8088ec432131b464807e9d3c56b33 Mon Sep 17 00:00:00 2001 From: r3tk0n Date: Thu, 15 Nov 2018 14:08:38 -0800 Subject: [PATCH 172/182] Fix logic for cases with rift headset but no touch controllers. --- interface/src/Application.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index aec580ff9d..a4277d6132 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3414,10 +3414,18 @@ void Application::showHelp() { defaultTab = TAB_HAND_CONTROLLERS; handControllerName = HAND_CONTROLLER_NAME_VIVE; } else if (PluginUtils::isHMDAvailable(OCULUS_RIFT_PLUGIN_NAME)) { - defaultTab = TAB_HAND_CONTROLLERS; - handControllerName = HAND_CONTROLLER_NAME_OCULUS_TOUCH; + if (PluginUtils::isOculusTouchControllerAvailable()) { + defaultTab = TAB_HAND_CONTROLLERS; + handControllerName = HAND_CONTROLLER_NAME_OCULUS_TOUCH; + } else if (PluginUtils::isXboxControllerAvailable()) { + defaultTab = TAB_GAMEPAD; + } else { + defaultTab = TAB_KEYBOARD_MOUSE; + } } else if (PluginUtils::isXboxControllerAvailable()) { defaultTab = TAB_GAMEPAD; + } else { + defaultTab = TAB_KEYBOARD_MOUSE; } QUrlQuery queryString; From de7f4a4a4d8d4578d38416d2308a91d80a545a25 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 15 Nov 2018 15:23:18 -0800 Subject: [PATCH 173/182] fix entity list resizing --- scripts/system/html/js/entityList.js | 2 +- scripts/system/html/js/listView.js | 20 +++++--------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/scripts/system/html/js/entityList.js b/scripts/system/html/js/entityList.js index 00c50169a6..39673b8f16 100644 --- a/scripts/system/html/js/entityList.js +++ b/scripts/system/html/js/entityList.js @@ -1219,7 +1219,7 @@ function loaded() { refreshSortOrder(); refreshEntities(); - window.onresize = updateColumnWidths; + window.addEventListener("resize", updateColumnWidths); }); augmentSpinButtons(); diff --git a/scripts/system/html/js/listView.js b/scripts/system/html/js/listView.js index 07aba53f1c..f775a4cb24 100644 --- a/scripts/system/html/js/listView.js +++ b/scripts/system/html/js/listView.js @@ -72,11 +72,6 @@ ListView.prototype = { } }, - onScroll: function() { - var that = this.listView; - that.scroll(); - }, - scroll: function() { let scrollTop = this.elTableScroll.scrollTop; let scrollHeight = this.getScrollHeight(); @@ -244,18 +239,13 @@ ListView.prototype = { } }, - onResize: function() { - var that = this.listView; - that.resize(); - }, - resize: function() { if (!this.elTableBody || !this.elTableScroll) { debugPrint("ListView.resize - no valid table body or table scroll element"); return; } - let prevScrollTop = this.elTableScroll.scrollTop; + let prevScrollTop = this.elTableScroll.scrollTop; // take up available window space this.elTableScroll.style.height = window.innerHeight - WINDOW_NONVARIABLE_HEIGHT; @@ -305,10 +295,10 @@ ListView.prototype = { this.elTableBody.appendChild(this.elBottomBuffer); this.elBottomBuffer.setAttribute("height", 0); - this.elTableScroll.listView = this; - this.elTableScroll.onscroll = this.onScroll; - window.listView = this; - window.onresize = this.onResize; + this.onScroll = this.scroll.bind(this); + this.elTableScroll.addEventListener("scroll", this.onScroll); + this.onResize = this.resize.bind(this); + window.addEventListener("resize", this.onResize); // initialize all row elements this.resize(); From 8e1785bd909f4f2173b35d418d201c37be5a3966 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 15 Nov 2018 15:59:52 -0800 Subject: [PATCH 174/182] security settings post-oculus-store wording --- interface/resources/qml/hifi/dialogs/security/Security.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/dialogs/security/Security.qml b/interface/resources/qml/hifi/dialogs/security/Security.qml index b754cb06ab..5c52af1c05 100644 --- a/interface/resources/qml/hifi/dialogs/security/Security.qml +++ b/interface/resources/qml/hifi/dialogs/security/Security.qml @@ -256,7 +256,7 @@ Rectangle { color: hifi.colors.baseGrayHighlight; HifiStylesUit.RalewaySemiBold { - text: "Wallet"; + text: "Secure Transactions"; anchors.fill: parent; anchors.leftMargin: 20; color: hifi.colors.white; @@ -287,7 +287,7 @@ Rectangle { HifiStylesUit.RalewaySemiBold { id: securityPictureText; - text: "Wallet Security Picture"; + text: "Security Picture"; // Anchors anchors.top: parent.top; anchors.bottom: parent.bottom; From bb0f046a728bd30d4f157adb80bf791c5483d93e Mon Sep 17 00:00:00 2001 From: birarda Date: Thu, 15 Nov 2018 17:28:34 -0800 Subject: [PATCH 175/182] add throttle start and backoff to DS settings --- assignment-client/src/audio/AudioMixer.cpp | 15 ++++++++++----- assignment-client/src/audio/AudioMixer.h | 4 +++- domain-server/resources/describe-settings.json | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index d6f893c42e..5d203595c2 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -488,11 +488,8 @@ void AudioMixer::throttle(chrono::microseconds duration, int frame) { // target different mix and backoff ratios (they also have different backoff rates) // this is to prevent oscillation, and encourage throttling to find a steady state - const float TARGET = 0.9f; - // on a "regular" machine with 100 avatars, this is the largest value where - // - overthrottling can be recovered - // - oscillations will not occur after the recovery - const float BACKOFF_TARGET = 0.44f; + const float TARGET = _throttleStartTarget; + const float BACKOFF_TARGET = _throttleBackoffTarget; // the mixer is known to struggle at about 80 on a "regular" machine // so throttle 2/80 the streams to ensure smooth audio (throttling is linear) @@ -551,6 +548,14 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { _slavePool.setNumThreads(numThreads); } } + + const QString THROTTLE_START_KEY = "throttle_start"; + const QString THROTTLE_BACKOFF_KEY = "throttle_backoff"; + + _throttleStartTarget = audioThreadingGroupObject[THROTTLE_START_KEY].toDouble(_throttleStartTarget); + _throttleBackoffTarget = audioThreadingGroupObject[THROTTLE_BACKOFF_KEY].toDouble(_throttleBackoffTarget); + + qCDebug(audio) << "Throttle Start:" << _throttleStartTarget << "Throttle Backoff:" << _throttleBackoffTarget; } if (settingsObject.contains(AUDIO_BUFFER_GROUP_KEY)) { diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index b8ea0d5c58..c7726d2fea 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -144,11 +144,13 @@ private: static std::map _availableCodecs; static QStringList _codecPreferenceOrder; - static std::vector _audioZones; static std::vector _zoneSettings; static std::vector _zoneReverbSettings; + float _throttleStartTarget = 0.9f; + float _throttleBackoffTarget = 0.44f; + AudioMixerSlave::SharedData _workerSharedData; }; diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 5d1f725ab4..49023c9af8 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1012,6 +1012,24 @@ "placeholder": "1", "default": "1", "advanced": true + }, + { + "name": "throttle_start", + "type": "double", + "label": "Throttle Start Target", + "help": "Target percentage of frame time to start throttling", + "placeholder": "0.9", + "default": 0.9, + "advanced": true + }, + { + "name": "throttle_backoff", + "type": "double", + "label": "Throttle Backoff Target", + "help": "Target percentage of frame time to backoff throttling", + "placeholder": "0.44", + "default": 0.44, + "advanced": true } ] }, From 7fba4c467322a937762db20e905ce62fba315a8f Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 15 Nov 2018 17:41:01 -0800 Subject: [PATCH 176/182] Deleted unneeded file. --- .../AppDataHighFidelity/Interface/AccountInfo.bin | Bin 489 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tools/nitpick/AppDataHighFidelity/Interface/AccountInfo.bin diff --git a/tools/nitpick/AppDataHighFidelity/Interface/AccountInfo.bin b/tools/nitpick/AppDataHighFidelity/Interface/AccountInfo.bin deleted file mode 100644 index 65c971ea793926e8f7518d36c6079a59b4cc08e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 489 zcmZwDIZgvX6a>(RL`XzHz#(8ZGh;F&5@N{FEZx`=U}O(SWQ3fJvv3Dcw;T{q(O;|T ze;nZ2%53&x=hC@zPl8$RO|Z2SoLO0WuoA6Jf=6q!cV|W$PaH}(x$fuwHf-O*_G%nA zug~+%bKIoPhf&apCcROkQCf8hNg_vhkUa5_0l~HGDQko1ZiyTL-sL>kK znJMirv{|oHyD*6y#LuteZyXr}y=^`)c}q-5WyrjPP9q9hg-($@q>Wmg)jJm&efAoZ zd-b5o4i}jz`AWUYq}a!$LZQw-XjJ){#)wl_Ud=Y{-3fN)?CxIqvq%2$AEff1^k1Zz EU+;ia(EtDd From 6440c13bfe9a6ad70549d53246dff5a0a92c9d40 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 15 Nov 2018 18:50:56 -0800 Subject: [PATCH 177/182] Updated manual. --- tools/nitpick/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/nitpick/README.md b/tools/nitpick/README.md index d21614f5f5..e8129ae29e 100644 --- a/tools/nitpick/README.md +++ b/tools/nitpick/README.md @@ -14,7 +14,7 @@ Nitpick has 5 functions, separated into 4 tabs: ## Installation ### Executable -1. On Windows: download the installer by browsing to [here](). +1. On Windows: download the installer by browsing to [here](). 2. Double click on the installer and install to a convenient location ![](./setup_7z.PNG) 3. To run nitpick, double click **nitpick.exe**. From 6daac008ff660ce8a6db9651d6257441802b7812 Mon Sep 17 00:00:00 2001 From: birarda Date: Fri, 16 Nov 2018 11:50:13 -0800 Subject: [PATCH 178/182] sanitize throttle start and backoff values from DS settings --- assignment-client/src/audio/AudioMixer.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 5d203595c2..e8568a7ff3 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -552,8 +552,18 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { const QString THROTTLE_START_KEY = "throttle_start"; const QString THROTTLE_BACKOFF_KEY = "throttle_backoff"; - _throttleStartTarget = audioThreadingGroupObject[THROTTLE_START_KEY].toDouble(_throttleStartTarget); - _throttleBackoffTarget = audioThreadingGroupObject[THROTTLE_BACKOFF_KEY].toDouble(_throttleBackoffTarget); + float settingsThrottleStart = audioThreadingGroupObject[THROTTLE_START_KEY].toDouble(_throttleStartTarget); + float settingsThrottleBackoff = audioThreadingGroupObject[THROTTLE_BACKOFF_KEY].toDouble(_throttleBackoffTarget); + + if (settingsThrottleBackoff > settingsThrottleStart) { + qCWarning(audio) << "Throttle backoff target cannot be higher than throttle start target. Using default values."; + } else if (settingsThrottleBackoff < 0.0f || settingsThrottleStart > 1.0f) { + qCWarning(audio) << "Throttle start and backoff targets must be greater than or equal to 0.0" + << "and lesser than or equal to 1.0. Using default values."; + } else { + _throttleStartTarget = settingsThrottleStart; + _throttleBackoffTarget = settingsThrottleBackoff; + } qCDebug(audio) << "Throttle Start:" << _throttleStartTarget << "Throttle Backoff:" << _throttleBackoffTarget; } From 31d37e7e75569d1c5c33ef97085539ea1b4afa0a Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 15 Nov 2018 02:38:39 +0100 Subject: [PATCH 179/182] Fix entity list double click rename / highlight issue --- scripts/system/html/js/entityList.js | 32 +++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/scripts/system/html/js/entityList.js b/scripts/system/html/js/entityList.js index 39673b8f16..ac2a4132ae 100644 --- a/scripts/system/html/js/entityList.js +++ b/scripts/system/html/js/entityList.js @@ -153,6 +153,9 @@ const ICON_FOR_TYPE = { Text: "l", }; +const DOUBLE_CLICK_TIMEOUT = 300; // ms +const RENAME_COOLDOWN = 400; // ms + // List of all entities let entities = []; // List of all entities, indexed by Entity ID @@ -181,6 +184,9 @@ let currentResizeEl = null; let startResizeEvent = null; let resizeColumnIndex = 0; let startThClick = null; +let renameTimeout = null; +let renameLastBlur = null; +let renameLastEntityID = null; let elEntityTable, elEntityTableHeader, @@ -394,6 +400,7 @@ function loaded() { entityListContextMenu = new EntityListContextMenu(); function startRenamingEntity(entityID) { + renameLastEntityID = entityID; let entity = entitiesByID[entityID]; if (!entity || entity.locked || !entity.elRow) { return; @@ -423,6 +430,8 @@ function loaded() { })); entity.name = value; elCell.innerText = value; + + renameLastBlur = Date.now(); }; elCell.innerHTML = ""; @@ -478,6 +487,13 @@ function loaded() { entityListContextMenu.open(clickEvent, entityID, enabledContextMenuItems); } + let clearRenameTimeout = () => { + if (renameTimeout !== null) { + window.clearTimeout(renameTimeout); + renameTimeout = null; + } + }; + function onRowClicked(clickEvent) { let entityID = this.dataset.entityID; let selection = [entityID]; @@ -516,7 +532,15 @@ function loaded() { } else if (!clickEvent.ctrlKey && !clickEvent.shiftKey && selectedEntities.length === 1) { // if reselecting the same entity then start renaming it if (selectedEntities[0] === entityID) { - startRenamingEntity(entityID); + if (renameLastBlur && renameLastEntityID === entityID && (Date.now() - renameLastBlur) < RENAME_COOLDOWN) { + + return; + } + clearRenameTimeout(); + renameTimeout = window.setTimeout(() => { + renameTimeout = null; + startRenamingEntity(entityID); + }, DOUBLE_CLICK_TIMEOUT); } } @@ -530,6 +554,8 @@ function loaded() { } function onRowDoubleClicked() { + clearRenameTimeout(); + let selection = [this.dataset.entityID]; updateSelectedEntities(selection, false); @@ -1100,12 +1126,12 @@ function loaded() { startResizeEvent = ev; } } - } + }; document.onmouseup = function(ev) { startResizeEvent = null; ev.stopPropagation(); - } + }; function setSpaceMode(spaceMode) { if (spaceMode === "local") { From e89346c146386a17cc08143fcd113a569152690d Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Fri, 16 Nov 2018 20:02:16 +0100 Subject: [PATCH 180/182] making rename functionality list refresh proof --- scripts/system/html/js/entityList.js | 45 +++++++++++++++++++++++--- scripts/system/html/js/listView.js | 8 +++-- scripts/system/libraries/entityList.js | 2 +- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/scripts/system/html/js/entityList.js b/scripts/system/html/js/entityList.js index ac2a4132ae..328c8c76e1 100644 --- a/scripts/system/html/js/entityList.js +++ b/scripts/system/html/js/entityList.js @@ -187,6 +187,7 @@ let startThClick = null; let renameTimeout = null; let renameLastBlur = null; let renameLastEntityID = null; +let isRenameFieldIsBeingMoved = false; let elEntityTable, elEntityTableHeader, @@ -210,7 +211,8 @@ let elEntityTable, elNoEntitiesMessage, elColumnsMultiselectBox, elColumnsOptions, - elToggleSpaceMode; + elToggleSpaceMode, + elRenameInput; const ENABLE_PROFILING = false; let profileIndent = ''; @@ -395,7 +397,7 @@ function loaded() { elEntityTableHeaderRow = document.querySelectorAll("#entity-table thead th"); entityList = new ListView(elEntityTableBody, elEntityTableScroll, elEntityTableHeaderRow, - createRow, updateRow, clearRow, WINDOW_NONVARIABLE_HEIGHT); + createRow, updateRow, clearRow, beforeUpdate, afterUpdate, WINDOW_NONVARIABLE_HEIGHT); entityListContextMenu = new EntityListContextMenu(); @@ -407,7 +409,7 @@ function loaded() { } let elCell = entity.elRow.childNodes[getColumnIndex("name")]; - let elRenameInput = document.createElement("input"); + elRenameInput = document.createElement("input"); elRenameInput.setAttribute('class', 'rename-entity'); elRenameInput.value = entity.name; let ignoreClicks = function(event) { @@ -422,6 +424,9 @@ function loaded() { }; elRenameInput.onblur = function(event) { + if (isRenameFieldIsBeingMoved) { + return; + } let value = elRenameInput.value; EventBridge.emitWebEvent(JSON.stringify({ type: 'rename', @@ -429,9 +434,10 @@ function loaded() { name: value })); entity.name = value; - elCell.innerText = value; + elRenameInput.parentElement.innerText = value; renameLastBlur = Date.now(); + elRenameInput = null; }; elCell.innerHTML = ""; @@ -440,6 +446,32 @@ function loaded() { elRenameInput.select(); } + function beforeUpdate() { + // move the rename input to the body + if (elRenameInput) { + isRenameFieldIsBeingMoved = true; + document.body.appendChild(elRenameInput); + // keep the focus + elRenameInput.select(); + } + } + + function afterUpdate() { + if (!elRenameInput || !isRenameFieldIsBeingMoved) { + return; + } + let entity = entitiesByID[renameLastEntityID]; + if (!entity || entity.locked || !entity.elRow) { + return; + } + let elCell = entity.elRow.childNodes[getColumnIndex("name")]; + elCell.innerHTML = ""; + elCell.appendChild(elRenameInput); + // keep the focus + elRenameInput.select(); + isRenameFieldIsBeingMoved = false; + } + entityListContextMenu.setOnSelectedCallback(function(optionName, selectedEntityID) { switch (optionName) { case "Cut": @@ -464,6 +496,11 @@ function loaded() { }); function onRowContextMenu(clickEvent) { + if (elRenameInput) { + // disallow the context menu from popping up while renaming + return; + } + let entityID = this.dataset.entityID; if (!selectedEntities.includes(entityID)) { diff --git a/scripts/system/html/js/listView.js b/scripts/system/html/js/listView.js index f775a4cb24..4336698688 100644 --- a/scripts/system/html/js/listView.js +++ b/scripts/system/html/js/listView.js @@ -14,7 +14,7 @@ debugPrint = function (message) { }; function ListView(elTableBody, elTableScroll, elTableHeaderRow, createRowFunction, - updateRowFunction, clearRowFunction, WINDOW_NONVARIABLE_HEIGHT) { + updateRowFunction, clearRowFunction, beforeRefreshFunction, afterRefreshFunction, WINDOW_NONVARIABLE_HEIGHT) { this.elTableBody = elTableBody; this.elTableScroll = elTableScroll; this.elTableHeaderRow = elTableHeaderRow; @@ -25,6 +25,8 @@ function ListView(elTableBody, elTableScroll, elTableHeaderRow, createRowFunctio this.createRowFunction = createRowFunction; this.updateRowFunction = updateRowFunction; this.clearRowFunction = clearRowFunction; + this.beforeRefreshFunction = beforeRefreshFunction; + this.afterRefreshFunction = afterRefreshFunction; // the list of row elements created in the table up to max viewable height plus SCROLL_ROWS rows for scrolling buffer this.elRows = []; @@ -173,6 +175,7 @@ ListView.prototype = { }, refresh: function() { + this.beforeRefreshFunction(); // block refreshing before rows are initialized let numRows = this.getNumRows(); if (numRows === 0) { @@ -211,6 +214,7 @@ ListView.prototype = { this.lastRowShiftScrollTop = 0; } } + this.afterRefreshFunction(); }, refreshBuffers: function() { @@ -230,7 +234,7 @@ ListView.prototype = { refreshRowOffset: function() { // make sure the row offset isn't causing visible rows to pass the end of the item list and is clamped to 0 - var numRows = this.getNumRows(); + let numRows = this.getNumRows(); if (this.rowOffset + numRows > this.itemData.length) { this.rowOffset = this.itemData.length - numRows; } diff --git a/scripts/system/libraries/entityList.js b/scripts/system/libraries/entityList.js index 8942c84f33..eeb16fd60d 100644 --- a/scripts/system/libraries/entityList.js +++ b/scripts/system/libraries/entityList.js @@ -17,7 +17,7 @@ var profileIndent = ''; const PROFILE_NOOP = function(_name, fn, args) { fn.apply(this, args); }; -PROFILE = !PROFILING_ENABLED ? PROFILE_NOOP : function(name, fn, args) { +const PROFILE = !PROFILING_ENABLED ? PROFILE_NOOP : function(name, fn, args) { console.log("PROFILE-Script " + profileIndent + "(" + name + ") Begin"); var previousIndent = profileIndent; profileIndent += ' '; From 7b3d2bed15a61caf4a2fef24612e6ca32ba01efb Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Fri, 16 Nov 2018 20:49:25 +0100 Subject: [PATCH 181/182] CR fixes --- scripts/system/html/js/entityList.js | 16 ++++++++-------- scripts/system/html/js/listView.js | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/scripts/system/html/js/entityList.js b/scripts/system/html/js/entityList.js index 328c8c76e1..fe657cd8b5 100644 --- a/scripts/system/html/js/entityList.js +++ b/scripts/system/html/js/entityList.js @@ -187,7 +187,7 @@ let startThClick = null; let renameTimeout = null; let renameLastBlur = null; let renameLastEntityID = null; -let isRenameFieldIsBeingMoved = false; +let isRenameFieldBeingMoved = false; let elEntityTable, elEntityTableHeader, @@ -397,7 +397,7 @@ function loaded() { elEntityTableHeaderRow = document.querySelectorAll("#entity-table thead th"); entityList = new ListView(elEntityTableBody, elEntityTableScroll, elEntityTableHeaderRow, - createRow, updateRow, clearRow, beforeUpdate, afterUpdate, WINDOW_NONVARIABLE_HEIGHT); + createRow, updateRow, clearRow, preRefresh, postRefresh, WINDOW_NONVARIABLE_HEIGHT); entityListContextMenu = new EntityListContextMenu(); @@ -424,7 +424,7 @@ function loaded() { }; elRenameInput.onblur = function(event) { - if (isRenameFieldIsBeingMoved) { + if (isRenameFieldBeingMoved) { return; } let value = elRenameInput.value; @@ -446,18 +446,18 @@ function loaded() { elRenameInput.select(); } - function beforeUpdate() { + function preRefresh() { // move the rename input to the body if (elRenameInput) { - isRenameFieldIsBeingMoved = true; + isRenameFieldBeingMoved = true; document.body.appendChild(elRenameInput); // keep the focus elRenameInput.select(); } } - function afterUpdate() { - if (!elRenameInput || !isRenameFieldIsBeingMoved) { + function postRefresh() { + if (!elRenameInput || !isRenameFieldBeingMoved) { return; } let entity = entitiesByID[renameLastEntityID]; @@ -469,7 +469,7 @@ function loaded() { elCell.appendChild(elRenameInput); // keep the focus elRenameInput.select(); - isRenameFieldIsBeingMoved = false; + isRenameFieldBeingMoved = false; } entityListContextMenu.setOnSelectedCallback(function(optionName, selectedEntityID) { diff --git a/scripts/system/html/js/listView.js b/scripts/system/html/js/listView.js index 4336698688..482576e2fe 100644 --- a/scripts/system/html/js/listView.js +++ b/scripts/system/html/js/listView.js @@ -14,7 +14,7 @@ debugPrint = function (message) { }; function ListView(elTableBody, elTableScroll, elTableHeaderRow, createRowFunction, - updateRowFunction, clearRowFunction, beforeRefreshFunction, afterRefreshFunction, WINDOW_NONVARIABLE_HEIGHT) { + updateRowFunction, clearRowFunction, preRefreshFunction, postRefreshFunction, WINDOW_NONVARIABLE_HEIGHT) { this.elTableBody = elTableBody; this.elTableScroll = elTableScroll; this.elTableHeaderRow = elTableHeaderRow; @@ -25,8 +25,8 @@ function ListView(elTableBody, elTableScroll, elTableHeaderRow, createRowFunctio this.createRowFunction = createRowFunction; this.updateRowFunction = updateRowFunction; this.clearRowFunction = clearRowFunction; - this.beforeRefreshFunction = beforeRefreshFunction; - this.afterRefreshFunction = afterRefreshFunction; + this.preRefreshFunction = preRefreshFunction; + this.postRefreshFunction = postRefreshFunction; // the list of row elements created in the table up to max viewable height plus SCROLL_ROWS rows for scrolling buffer this.elRows = []; @@ -175,7 +175,7 @@ ListView.prototype = { }, refresh: function() { - this.beforeRefreshFunction(); + this.preRefreshFunction(); // block refreshing before rows are initialized let numRows = this.getNumRows(); if (numRows === 0) { @@ -214,7 +214,7 @@ ListView.prototype = { this.lastRowShiftScrollTop = 0; } } - this.afterRefreshFunction(); + this.postRefreshFunction(); }, refreshBuffers: function() { From ba790ae47013470e9bce78a87e07c060e1a1c5b8 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Sat, 17 Nov 2018 01:20:36 +0100 Subject: [PATCH 182/182] fix behavior after merge. --- scripts/system/html/js/entityList.js | 6 +++--- scripts/system/html/js/listView.js | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/system/html/js/entityList.js b/scripts/system/html/js/entityList.js index fe657cd8b5..84ad59df36 100644 --- a/scripts/system/html/js/entityList.js +++ b/scripts/system/html/js/entityList.js @@ -396,8 +396,8 @@ function loaded() { elEntityTableHeaderRow = document.querySelectorAll("#entity-table thead th"); - entityList = new ListView(elEntityTableBody, elEntityTableScroll, elEntityTableHeaderRow, - createRow, updateRow, clearRow, preRefresh, postRefresh, WINDOW_NONVARIABLE_HEIGHT); + entityList = new ListView(elEntityTableBody, elEntityTableScroll, elEntityTableHeaderRow, createRow, updateRow, + clearRow, preRefresh, postRefresh, preRefresh, WINDOW_NONVARIABLE_HEIGHT); entityListContextMenu = new EntityListContextMenu(); @@ -448,7 +448,7 @@ function loaded() { function preRefresh() { // move the rename input to the body - if (elRenameInput) { + if (!isRenameFieldBeingMoved && elRenameInput) { isRenameFieldBeingMoved = true; document.body.appendChild(elRenameInput); // keep the focus diff --git a/scripts/system/html/js/listView.js b/scripts/system/html/js/listView.js index 482576e2fe..49a91388a5 100644 --- a/scripts/system/html/js/listView.js +++ b/scripts/system/html/js/listView.js @@ -13,8 +13,8 @@ debugPrint = function (message) { console.log(message); }; -function ListView(elTableBody, elTableScroll, elTableHeaderRow, createRowFunction, - updateRowFunction, clearRowFunction, preRefreshFunction, postRefreshFunction, WINDOW_NONVARIABLE_HEIGHT) { +function ListView(elTableBody, elTableScroll, elTableHeaderRow, createRowFunction, updateRowFunction, clearRowFunction, + preRefreshFunction, postRefreshFunction, preResizeFunction, WINDOW_NONVARIABLE_HEIGHT) { this.elTableBody = elTableBody; this.elTableScroll = elTableScroll; this.elTableHeaderRow = elTableHeaderRow; @@ -27,6 +27,7 @@ function ListView(elTableBody, elTableScroll, elTableHeaderRow, createRowFunctio this.clearRowFunction = clearRowFunction; this.preRefreshFunction = preRefreshFunction; this.postRefreshFunction = postRefreshFunction; + this.preResizeFunction = preResizeFunction; // the list of row elements created in the table up to max viewable height plus SCROLL_ROWS rows for scrolling buffer this.elRows = []; @@ -248,7 +249,7 @@ ListView.prototype = { debugPrint("ListView.resize - no valid table body or table scroll element"); return; } - + this.preResizeFunction(); let prevScrollTop = this.elTableScroll.scrollTop; // take up available window space