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@>