From 8a11d18f0d750451832fbd70718219a8217a63d2 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 19 Sep 2018 17:24:31 +0200 Subject: [PATCH] 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"