From 45b4881edc75ff4d30cc006b7a5331a1fc5b7936 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 12 Sep 2018 17:59:57 +0200 Subject: [PATCH] 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); }