From fec59e8b957a8e601d03b4566a423399c168690f Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 7 Sep 2018 16:12:03 +0200 Subject: [PATCH] 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); + }