diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 3fcf4ef656..8e2a25b3e6 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "RenderUtilsLogging.h" @@ -40,13 +41,18 @@ gpu::PipelinePointer AmbientOcclusionEffect::_buildNormalsPipeline; AmbientOcclusionFramebuffer::AmbientOcclusionFramebuffer() { } -bool AmbientOcclusionFramebuffer::updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer) { +bool AmbientOcclusionFramebuffer::update(const gpu::TexturePointer& linearDepthBuffer, int resolutionLevel, bool isStereo) { // If the depth buffer or size changed, we need to delete our FBOs bool reset = false; - if ((_linearDepthTexture != linearDepthBuffer)) { + if (_linearDepthTexture != linearDepthBuffer) { _linearDepthTexture = linearDepthBuffer; reset = true; } + if (_resolutionLevel != resolutionLevel || isStereo != _isStereo) { + _resolutionLevel = resolutionLevel; + _isStereo = isStereo; + reset = true; + } if (_linearDepthTexture) { auto newFrameSize = glm::ivec2(_linearDepthTexture->getDimensions()); if (_frameSize != newFrameSize) { @@ -76,17 +82,38 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getLinearDepthTexture() { } void AmbientOcclusionFramebuffer::allocate() { - auto width = _frameSize.x; - auto height = _frameSize.y; - auto format = gpu::Element::COLOR_R_8; + // Full frame + { + 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, gpu::Sampler::WRAP_CLAMP)); - _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); - _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); + _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, gpu::Sampler::WRAP_CLAMP)); - _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusionBlurred")); - _occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture); + _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); + } + + // Lower res frame + { + auto sideSize = _frameSize; + if (_isStereo) { + sideSize.x >>= 1; + } + sideSize = divideRoundUp(sideSize, 1 << _resolutionLevel); + if (_isStereo) { + sideSize.x <<= 1; + } + auto width = sideSize.x; + auto height = sideSize.y; + + _normalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, 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() { @@ -117,31 +144,17 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getOcclusionBlurredTexture() { return _occlusionBlurredTexture; } -void AmbientOcclusionFramebuffer::allocate(int resolutionLevel) { - auto width = _frameSize.x >> resolutionLevel; - auto height = _frameSize.y >> resolutionLevel; - - _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); - _resolutionLevel = resolutionLevel; -} - -gpu::FramebufferPointer AmbientOcclusionFramebuffer::getNormalFramebuffer(int resolutionLevel) { - if (!_normalFramebuffer || resolutionLevel != _resolutionLevel) { - allocate(resolutionLevel); +gpu::FramebufferPointer AmbientOcclusionFramebuffer::getNormalFramebuffer() { + if (!_normalFramebuffer) { + allocate(); } return _normalFramebuffer; } -gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture(int resolutionLevel) { - if (!_normalTexture || resolutionLevel != _resolutionLevel) { - allocate(resolutionLevel); - } - return _normalTexture; -} - gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() { + if (!_normalTexture) { + allocate(); + } return _normalTexture; } @@ -377,6 +390,28 @@ void AmbientOcclusionEffect::updateBlurParameters() { vblur.scaleHeight.z = frameSize.y; } +void AmbientOcclusionEffect::updateFramebufferSizes() { + auto& params = _aoParametersBuffer.edit(); + const int widthScale = _framebuffer->isStereo() & 1; + auto sourceFrameSize = _framebuffer->getSourceFrameSize(); + const int resolutionLevel = _aoParametersBuffer.get().getResolutionLevel(); + // Depth is at maximum half depth + const int depthResolutionLevel = std::min(1, resolutionLevel); + + sourceFrameSize.x >>= widthScale; + + params._sideSizes[0].x = _framebuffer->getNormalTexture()->getWidth() >> widthScale; + params._sideSizes[0].y = _framebuffer->getNormalTexture()->getHeight(); + params._sideSizes[0].z = resolutionLevel; + params._sideSizes[0].w = depthResolutionLevel; + + 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)); + params._sideSizes[1].z = occlusionSplitSize.x; + params._sideSizes[1].w = occlusionSplitSize.y; +} + const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { if (!_occlusionPipeline) { gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::ssao_makeOcclusion); @@ -466,11 +501,20 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte const auto& frameTransform = inputs.get0(); const auto& linearDepthFramebuffer = inputs.get2(); + const int resolutionLevel = _aoParametersBuffer->getResolutionLevel(); + const auto resolutionScale = powf(0.5f, resolutionLevel); + auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); auto occlusionDepthTexture = linearDepthTexture; auto sourceViewport = args->_viewport; - auto occlusionViewport = sourceViewport; + // divideRoundUp is used two compute the quarter or half resolution render sizes. + // We need to take the rounded up resolution. + auto occlusionViewport = divideRoundUp(sourceViewport, 1 << resolutionLevel); auto firstBlurViewport = sourceViewport; +#if SSAO_USE_QUAD_SPLIT + auto splitViewport = divideRoundUp(sourceViewport, 1 << (resolutionLevel + SSAO_USE_QUAD_SPLIT)); +#endif + firstBlurViewport.w = divideRoundUp(firstBlurViewport.w, 1 << resolutionLevel); if (!_gpuTimer) { _gpuTimer = std::make_shared < gpu::RangeTimer>(__FUNCTION__); @@ -480,16 +524,13 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte _framebuffer = std::make_shared(); } - const int resolutionLevel = _aoParametersBuffer->getResolutionLevel(); - const auto resolutionScale = powf(0.5f, resolutionLevel); if (resolutionLevel > 0) { - occlusionViewport = occlusionViewport >> resolutionLevel; - firstBlurViewport.w = firstBlurViewport.w >> resolutionLevel; occlusionDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); } - if (_framebuffer->updateLinearDepth(linearDepthTexture)) { + if (_framebuffer->update(linearDepthTexture, resolutionLevel, args->isStereo())) { updateBlurParameters(); + updateFramebufferSizes(); } auto occlusionFBO = _framebuffer->getOcclusionFramebuffer(); @@ -499,7 +540,6 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte outputs.edit1() = _aoParametersBuffer; auto framebufferSize = _framebuffer->getSourceFrameSize(); - auto occlusionPipeline = getOcclusionPipeline(); auto firstHBlurPipeline = getHBlurPipeline(); auto lastVBlurPipeline = getVBlurPipeline(); @@ -509,8 +549,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #if SSAO_USE_QUAD_SPLIT auto gatherPipeline = getGatherPipeline(); auto buildNormalsPipeline = getBuildNormalsPipeline(); - auto occlusionNormalFramebuffer = _framebuffer->getNormalFramebuffer(resolutionLevel); - auto occlusionNormalTexture = _framebuffer->getNormalTexture(resolutionLevel); + auto occlusionNormalFramebuffer = _framebuffer->getNormalFramebuffer(); + auto occlusionNormalTexture = _framebuffer->getNormalTexture(); #endif // Update sample rotation @@ -567,7 +607,6 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #else 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); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index b0752277c2..c9f5d42b14 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -31,20 +31,19 @@ public: gpu::FramebufferPointer getOcclusionBlurredFramebuffer(); gpu::TexturePointer getOcclusionBlurredTexture(); - gpu::FramebufferPointer getNormalFramebuffer(int resolutionLevel); - gpu::TexturePointer getNormalTexture(int resolutionLevel); + 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); + bool update(const gpu::TexturePointer& linearDepthBuffer, int resolutionLevel, bool isStereo); gpu::TexturePointer getLinearDepthTexture(); const glm::ivec2& getSourceFrameSize() const { return _frameSize; } - + bool isStereo() const { return _isStereo; } + protected: void clear(); void allocate(); - void allocate(int resolutionLevel); gpu::TexturePointer _linearDepthTexture; @@ -60,6 +59,7 @@ protected: glm::ivec2 _frameSize; int _resolutionLevel{ 0 }; + bool _isStereo{ false }; }; using AmbientOcclusionFramebufferPointer = std::shared_ptr; @@ -167,6 +167,7 @@ private: void updateGaussianDistribution(); void updateBlurParameters(); + void updateFramebufferSizes(); AOParametersBuffer _aoParametersBuffer; FrameParametersBuffer _aoFrameParametersBuffer[SSAO_SPLIT_COUNT]; diff --git a/libraries/render-utils/src/DeferredTransform.slh b/libraries/render-utils/src/DeferredTransform.slh index d9ced66edf..9b98029bd6 100644 --- a/libraries/render-utils/src/DeferredTransform.slh +++ b/libraries/render-utils/src/DeferredTransform.slh @@ -124,17 +124,18 @@ vec2 getStereoSideSize(int resolutionLevel) { return vec2(getStereoSideWidth(resolutionLevel), getStereoSideHeight(resolutionLevel)); } -ivec4 getStereoSideInfo(int xPos, int resolutionLevel) { - int sideWidth = int(getStereoSideWidth(resolutionLevel)); +ivec4 getStereoSideInfoFromWidth(int xPos, int sideWidth) { return ivec4(xPos < sideWidth ? ivec2(0, 0) : ivec2(1, sideWidth), sideWidth, isStereo()); } -int getStereoSide(ivec4 sideInfo) { - return sideInfo.x; +ivec4 getStereoSideInfo(int xPos, int resolutionLevel) { + int sideWidth = int(getStereoSideWidth(resolutionLevel)); + return getStereoSideInfoFromWidth(xPos, sideWidth); } -bool isStereoFromInfo(ivec4 sideInfo) { - return sideInfo.w != 0; + +int getStereoSide(ivec4 sideInfo) { + return sideInfo.x; } float evalZeyeFromZdb(float depth) { diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index 374a509c5a..8f337b66da 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -11,6 +11,7 @@ #include "SurfaceGeometryPass.h" #include +#include #include #include @@ -28,7 +29,7 @@ namespace ru { LinearDepthFramebuffer::LinearDepthFramebuffer() { } -void LinearDepthFramebuffer::update(const gpu::TexturePointer& depthBuffer, const gpu::TexturePointer& normalTexture) { +void LinearDepthFramebuffer::update(const gpu::TexturePointer& depthBuffer, const gpu::TexturePointer& normalTexture, bool isStereo) { //If the depth buffer or size changed, we need to delete our FBOs bool reset = false; if (_primaryDepthTexture != depthBuffer || _normalTexture != normalTexture) { @@ -38,10 +39,17 @@ void LinearDepthFramebuffer::update(const gpu::TexturePointer& depthBuffer, cons } if (_primaryDepthTexture) { auto newFrameSize = glm::ivec2(_primaryDepthTexture->getDimensions()); - if (_frameSize != newFrameSize) { + if (_frameSize != newFrameSize || _isStereo != isStereo) { _frameSize = newFrameSize; - _halfFrameSize = newFrameSize >> 1; - + _halfFrameSize = _frameSize; + if (isStereo) { + _halfFrameSize.x >>= 1; + } + _halfFrameSize = divideRoundUp(_halfFrameSize, 2); + if (isStereo) { + _halfFrameSize.x <<= 1; + } + _isStereo = isStereo; reset = true; } } @@ -66,7 +74,7 @@ void LinearDepthFramebuffer::allocate() { // For Linear Depth: const uint16_t LINEAR_DEPTH_MAX_MIP_LEVEL = 5; - // Point sampling of the depth is need for the AmbientOcclusionEffect in HBAO, as well as the clamp to edge + // Point sampling of the depth is needed for the AmbientOcclusionEffect in HBAO, as well as the clamp to edge const auto depthSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP); _linearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), width, height, LINEAR_DEPTH_MAX_MIP_LEVEL, depthSampler); @@ -153,7 +161,7 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con auto depthBuffer = deferredFramebuffer->getPrimaryDepthTexture(); auto normalTexture = deferredFramebuffer->getDeferredNormalTexture(); - _linearDepthFramebuffer->update(depthBuffer, normalTexture); + _linearDepthFramebuffer->update(depthBuffer, normalTexture, args->isStereo()); auto linearDepthFBO = _linearDepthFramebuffer->getLinearDepthFramebuffer(); auto linearDepthTexture = _linearDepthFramebuffer->getLinearDepthTexture(); @@ -172,7 +180,7 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con auto downsamplePipeline = getDownsamplePipeline(renderContext); auto depthViewport = args->_viewport; - auto halfViewport = depthViewport >> 1; + auto halfViewport = divideRoundUp(depthViewport, 2); float clearLinearDepth = args->getViewFrustum().getFarClip() * 2.0f; gpu::doInBatch("LinearDepthPass::run", args->_context, [=](gpu::Batch& batch) { @@ -195,7 +203,9 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con // Downsample batch.setViewportTransform(halfViewport); - + Transform model; + model.setScale( glm::vec3((depthViewport.z >> 1) / float(halfViewport.z), (depthViewport.w >> 1) / float(halfViewport.w), 1.0f) ); + batch.setModelTransform(model); batch.setFramebuffer(downsampleFBO); batch.setResourceTexture(ru::Texture::SurfaceGeometryDepth, linearDepthTexture); batch.setResourceTexture(ru::Texture::SurfaceGeometryNormal, normalTexture); diff --git a/libraries/render-utils/src/SurfaceGeometryPass.h b/libraries/render-utils/src/SurfaceGeometryPass.h index 5ada56521a..6ea03fbda5 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.h +++ b/libraries/render-utils/src/SurfaceGeometryPass.h @@ -35,7 +35,7 @@ public: 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, const gpu::TexturePointer& normalTexture); + void update(const gpu::TexturePointer& depthBuffer, const gpu::TexturePointer& normalTexture, bool isStereo); const glm::ivec2& getDepthFrameSize() const { return _frameSize; } void setResolutionLevel(int level) { _resolutionLevel = std::max(0, level); } @@ -59,6 +59,7 @@ protected: glm::ivec2 _frameSize; glm::ivec2 _halfFrameSize; int _resolutionLevel{ 0 }; + bool _isStereo{ false }; }; using LinearDepthFramebufferPointer = std::shared_ptr; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 56566c9b6f..3f4d361531 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -47,11 +47,32 @@ layout(binding=RENDER_UTILS_BUFFER_SSAO_FRAME_PARAMS) uniform ambientOcclusionFr float getPerspectiveScale() { return (params._resolutionInfo.z); } -int getResolutionLevel() { - +int getResolutionLevel() { return int(params._resolutionInfo.x); } +vec2 getNormalsSideSize() { + return params._sideSizes[0].xy; +} +int getNormalsResolutionLevel() { + return int(params._sideSizes[0].z); +} +int getDepthResolutionLevel() { + return int(params._sideSizes[0].w); +} +vec2 getOcclusionSideSize() { + return params._sideSizes[1].xy; +} +vec2 getOcclusionSplitSideSize() { + return params._sideSizes[1].zw; +} + +ivec2 getWidthHeightRoundUp(int resolutionLevel) { + ivec2 fullRes = ivec2(getWidthHeight(0)); + int resolutionDivisor = 1 << resolutionLevel; + return (fullRes + resolutionDivisor - 1) / resolutionDivisor; +} + float getRadius() { return params._radiusInfo.x; } @@ -205,6 +226,26 @@ layout(binding=RENDER_UTILS_TEXTURE_SSAO_NORMAL) uniform sampler2D normalTex; ivec2 getDepthTextureSize(int level) { return textureSize(depthPyramidTex, level); } +ivec2 getDepthTextureSideSize(int level) { + ivec2 size = getDepthTextureSize(level); + size.x >>= int(isStereo()) & 1; + return size; +} + +ivec2 getNormalTextureSize(int level) { + return textureSize(normalTex, level); +} +ivec2 getNormalTextureSideSize(int level) { + ivec2 size = getNormalTextureSize(level); + size.x >>= int(isStereo()) & 1; + return size; +} + +vec2 getStereoSideSizeRoundUp(int resolutionLevel) { + ivec2 fullRes = ivec2(getStereoSideSize(0)); + int resolutionDivisor = 1 << resolutionLevel; + return vec2((fullRes + resolutionDivisor - 1) / resolutionDivisor); +} float getZEyeAtPixel(ivec2 pixel, int level) { return -texelFetch(depthPyramidTex, pixel, level).x; @@ -254,8 +295,8 @@ vec3 getMinDelta(vec3 centralPoint, vec3 offsetPointPos, vec3 offsetPointNeg) { return dot(delta0, delta0) < dot(delta1, delta1) ? delta0 : delta1; } -vec3 buildNormal(ivec4 side, vec2 fragUVPos, ivec2 depthTexFragPixelPos, vec3 fragPosition, ivec2 depthTextureScale, vec2 sideImageSize) { - vec2 uvScale = vec2(1.0) / (sideImageSize * depthTextureScale); +vec3 buildNormal(ivec4 side, vec2 fragUVPos, ivec2 depthTexFragPixelPos, vec3 fragPosition, vec2 depthTextureSize) { + vec2 uvScale = vec2(1.0) / depthTextureSize; vec3 fragPositionDxPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(1, 0), uvScale); vec3 fragPositionDyPos = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(0, 1), uvScale); vec3 fragPositionDxNeg = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(-1, 0), uvScale); @@ -368,7 +409,7 @@ float computeHorizon(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, vec2 d float evalVisibilityHBAO(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, vec2 deltaTap, float diskPixelRadius, vec3 fragPositionES, vec3 fragNormalES) { vec2 searchVec = deltaTap * diskPixelRadius; - float obscurance; + float obscurance = 0.0; // Forward search for h1 obscurance = computeHorizon(side, shadedPixelPos, sideImageSize, deltaTap, fragPositionES, fragNormalES, searchVec, diskPixelRadius); @@ -376,7 +417,7 @@ float evalVisibilityHBAO(ivec4 side, vec2 shadedPixelPos, vec2 sideImageSize, ve // Backward search for h2 obscurance += computeHorizon(side, shadedPixelPos, sideImageSize, deltaTap, fragPositionES, fragNormalES, -searchVec, diskPixelRadius); - return obscurance * 0.5 / PI; + return obscurance; } <@endfunc@> diff --git a/libraries/render-utils/src/ssao_buildNormals.slf b/libraries/render-utils/src/ssao_buildNormals.slf index f3af324455..36066b87df 100644 --- a/libraries/render-utils/src/ssao_buildNormals.slf +++ b/libraries/render-utils/src/ssao_buildNormals.slf @@ -18,28 +18,30 @@ layout(location=0) out vec4 outFragColor; void main(void) { - vec2 sideImageSize = getStereoSideSize(getResolutionLevel()); - ivec2 renderSize = ivec2(sideImageSize) << ivec2(int(isStereo()) & 1, 0); - // Pixel being shaded vec2 fragCoord = gl_FragCoord.xy; ivec2 fragPixelPos = ivec2(fragCoord.xy); - // Fetch the z under the pixel (stereo or not) - ivec2 depthTextureScale = getDepthTextureSize(0) / renderSize; - ivec2 depthTexFragPixelPos = fragPixelPos * depthTextureScale; + // Fetch the z under the pixel (stereo or not) from full res depth + int depthTextureRatio = 1 << getNormalsResolutionLevel(); + ivec2 depthTexFragPixelPos = fragPixelPos * depthTextureRatio; float Zeye = getZEyeAtPixel(depthTexFragPixelPos, 0); - // Stereo side info - ivec4 side = getStereoSideInfo(fragPixelPos.x, getResolutionLevel()); + // Stereo side info based on the real viewport size of this pass + ivec2 sideNormalsSize = ivec2( getNormalsSideSize() ); + ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideNormalsSize.x); // From now on, fragPixelPos is the pixel pos in the side + vec2 depthSideSize = getDepthTextureSideSize(0); + vec2 sideImageSize = depthSideSize / float(depthTextureRatio); fragPixelPos.x -= side.y; vec2 fragUVPos = (vec2(fragPixelPos) + vec2(0.5)) / sideImageSize; // The position and normal of the pixel fragment in Eye space vec3 fragPositionES = evalEyePositionFromZeye(side.x, Zeye, fragUVPos); - vec3 fragNormalES = buildNormal(side, fragUVPos, depthTexFragPixelPos, fragPositionES, depthTextureScale, sideImageSize); + vec3 fragNormalES = buildNormal(side, fragUVPos, depthTexFragPixelPos, fragPositionES, depthSideSize); + vec3 absFragNormalES = abs(fragNormalES); + fragNormalES /= max(absFragNormalES.z, max(absFragNormalES.x, absFragNormalES.y)); outFragColor = vec4(vec3(fragNormalES)*0.5 + vec3(0.5), 1.0); } diff --git a/libraries/render-utils/src/ssao_gather.slf b/libraries/render-utils/src/ssao_gather.slf index 8f2282154a..6814498b38 100644 --- a/libraries/render-utils/src/ssao_gather.slf +++ b/libraries/render-utils/src/ssao_gather.slf @@ -26,7 +26,7 @@ void main(void) { // result (at the resolution level, of course) ivec2 destPixelCoord = ivec2(gl_FragCoord.xy); ivec2 sourcePixelCoord = destPixelCoord / 2; - ivec2 splitImageSize = ivec2(getWidthHeight(getResolutionLevel()+1)); + ivec2 splitImageSize = getWidthHeightRoundUp(getResolutionLevel()+1); sourcePixelCoord += (destPixelCoord & ivec2(1)) * splitImageSize; diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index cee5ef6fe3..f4962d8286 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -24,36 +24,36 @@ layout(location=0) out vec4 outFragColor; void main(void) { - vec2 sideImageSize = getStereoSideSize(getResolutionLevel()); - ivec2 renderSize = ivec2(sideImageSize) << ivec2(int(isStereo()) & 1, 0); - // Pixel being shaded vec2 fragCoord = gl_FragCoord.xy; ivec2 fragPixelPos = ivec2(fragCoord.xy); #if SSAO_USE_QUAD_SPLIT - ivec2 splitImageSize = ivec2(getWidthHeight(getResolutionLevel()+1)); + ivec2 splitImageSize = ivec2(getOcclusionSplitSideSize()); fragPixelPos = ((fragPixelPos - getPixelOffset()*splitImageSize) * 2) + getPixelOffset(); #endif // Fetch the z under the pixel (stereo or not) - ivec2 depthTextureScale = getDepthTextureSize(0) / renderSize; - ivec2 depthTexFragPixelPos = fragPixelPos * depthTextureScale; + int depthTextureRatio = 1 << (getResolutionLevel() - getDepthResolutionLevel()); + ivec2 depthTexFragPixelPos = fragPixelPos * depthTextureRatio; float Zeye = getZEyeAtPixel(depthTexFragPixelPos, 0); #if SSAO_USE_QUAD_SPLIT vec3 fragNormalES = getNormalEyeAtPixel(fragPixelPos, 0); #endif - // Stereo side info - ivec4 side = getStereoSideInfo(fragPixelPos.x, getResolutionLevel()); + // Stereo side info based on the real viewport size of this pass + ivec2 sideOcclusionSize = ivec2( getOcclusionSideSize() ); + ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideOcclusionSize.x); // From now on, fragPixelPos is the pixel pos in the side + vec2 depthSideSize = getDepthTextureSideSize(0); + vec2 sideImageSize = depthSideSize / float(depthTextureRatio); fragPixelPos.x -= side.y; vec2 fragUVPos = (vec2(fragPixelPos) + vec2(0.5)) / sideImageSize; // 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 = buildNormal(side, fragUVPos, depthTexFragPixelPos, fragPositionES, depthTextureScale, sideImageSize); + vec3 fragNormalES = buildNormal(side, fragUVPos, depthTexFragPixelPos, fragPositionES, depthSideSize); #endif // Choose the screen-space sample radius @@ -68,20 +68,28 @@ void main(void) { // Accumulate the obscurance for each samples float obscuranceSum = 0.0; int numSamples = int(getNumSamples()); + float invNumSamples = getInvNumSamples(); + + // Steps are in the depth texture resolution + depthTexFragPixelPos = fragPixelPos * depthTextureRatio; for (int i = 0; i < numSamples; ++i) { #if SSAO_USE_HORIZON_BASED vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); - obscuranceSum += evalVisibilityHBAO(side, vec2(fragPixelPos), sideImageSize, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); + obscuranceSum += evalVisibilityHBAO(side, vec2(depthTexFragPixelPos), depthSideSize, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES); #else - vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, fragPixelPos, sideImageSize); - vec2 tapPixelPos = vec2(fragPixelPos) + tap.xy; - vec3 tapUVZ = fetchTap(side, tapPixelPos, tap.z, sideImageSize); + vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, depthTexFragPixelPos, depthSideSize); + vec2 tapPixelPos = vec2(depthTexFragPixelPos) + tap.xy; + vec3 tapUVZ = fetchTap(side, tapPixelPos, tap.z, depthSideSize); vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES); #endif } - float occlusion = clamp(1.0 - obscuranceSum * getObscuranceScaling() * getInvNumSamples(), 0.0, 1.0); +#if SSAO_USE_HORIZON_BASED + obscuranceSum *= 0.5 / PI; +#endif + + float occlusion = clamp(1.0 - obscuranceSum * getObscuranceScaling() * invNumSamples, 0.0, 1.0); outFragColor = vec4(vec3(occlusion), 1.0); } diff --git a/libraries/render-utils/src/ssao_shared.h b/libraries/render-utils/src/ssao_shared.h index 89738fcea0..109d471964 100644 --- a/libraries/render-utils/src/ssao_shared.h +++ b/libraries/render-utils/src/ssao_shared.h @@ -40,6 +40,7 @@ struct AmbientOcclusionParams { SSAO_VEC4 _sampleInfo; SSAO_VEC4 _blurInfo; float _blurFilterTaps[SSAO_BLUR_GAUSSIAN_COEFS_COUNT]; + SSAO_VEC4 _sideSizes[2]; }; struct AmbientOcclusionFrameParams { diff --git a/libraries/shared/src/MathUtils.h b/libraries/shared/src/MathUtils.h new file mode 100644 index 0000000000..799890915e --- /dev/null +++ b/libraries/shared/src/MathUtils.h @@ -0,0 +1,21 @@ +// +// MathUtils.h +// libraries/shared/src +// +// Created by Olivier Prat on 9/21/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 +// + +#ifndef hifi_MathUtils_h +#define hifi_MathUtils_h + +template +T divideRoundUp(const T& numerator, int divisor) { + return (numerator + divisor - T(1)) / divisor; +} + +#endif // hifi_MathUtils_h +