From dee0a6afa238ccebff133d4f755e6a77ea430f8c Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 26 Sep 2018 16:59:01 +0200 Subject: [PATCH] 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