Fixed bugs in stereo

This commit is contained in:
Olivier Prat 2018-09-28 19:22:20 +02:00
parent 086ba998c8
commit 9f9fe909b0
4 changed files with 56 additions and 42 deletions

View file

@ -92,12 +92,13 @@ void AmbientOcclusionFramebuffer::allocate() {
{ {
auto width = _frameSize.x; auto width = _frameSize.x;
auto height = _frameSize.y; auto height = _frameSize.y;
auto sampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP);
_occlusionTexture = gpu::Texture::createRenderBuffer(occlusionformat, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); _occlusionTexture = gpu::Texture::createRenderBuffer(occlusionformat, width, height, gpu::Texture::SINGLE_MIP, sampler);
_occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion")); _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusion"));
_occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture);
_occlusionBlurredTexture = gpu::Texture::createRenderBuffer(occlusionformat, width, height, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); _occlusionBlurredTexture = gpu::Texture::createRenderBuffer(occlusionformat, width, height, gpu::Texture::SINGLE_MIP, sampler);
_occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusionBlurred")); _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("occlusionBlurred"));
_occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture); _occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture);
} }
@ -108,7 +109,7 @@ void AmbientOcclusionFramebuffer::allocate() {
if (_isStereo) { if (_isStereo) {
sideSize.x >>= 1; sideSize.x >>= 1;
} }
sideSize = divideRoundUp(sideSize, 1 << _resolutionLevel); sideSize >>= _resolutionLevel;
if (_isStereo) { if (_isStereo) {
sideSize.x <<= 1; sideSize.x <<= 1;
} }
@ -127,7 +128,7 @@ void AmbientOcclusionFramebuffer::allocate() {
if (_isStereo) { if (_isStereo) {
splitSize.x >>= 1; splitSize.x >>= 1;
} }
splitSize = divideRoundUp(splitSize, SSAO_SPLIT_COUNT << _resolutionLevel); splitSize = divideRoundUp(_frameSize >> _resolutionLevel, SSAO_SPLIT_COUNT);
if (_isStereo) { if (_isStereo) {
splitSize.x <<= 1; splitSize.x <<= 1;
} }
@ -355,14 +356,13 @@ void AmbientOcclusionEffect::configure(const Config& config) {
void AmbientOcclusionEffect::updateBlurParameters() { void AmbientOcclusionEffect::updateBlurParameters() {
const auto resolutionLevel = _aoParametersBuffer->getResolutionLevel(); const auto resolutionLevel = _aoParametersBuffer->getResolutionLevel();
const auto resolutionScale = 1 << resolutionLevel;
auto& vblur = _vblurParametersBuffer.edit(); auto& vblur = _vblurParametersBuffer.edit();
auto& hblur = _hblurParametersBuffer.edit(); auto& hblur = _hblurParametersBuffer.edit();
auto frameSize = _framebuffer->getSourceFrameSize(); auto frameSize = _framebuffer->getSourceFrameSize();
if (_framebuffer->isStereo()) { if (_framebuffer->isStereo()) {
frameSize.x >>= 1; frameSize.x >>= 1;
} }
const auto occlusionSize = divideRoundUp(frameSize, resolutionScale); const auto occlusionSize = frameSize >> resolutionLevel;
// Occlusion UV limit // Occlusion UV limit
hblur._blurAxis.z = occlusionSize.x / float(frameSize.x); hblur._blurAxis.z = occlusionSize.x / float(frameSize.x);
@ -381,18 +381,17 @@ void AmbientOcclusionEffect::updateBlurParameters() {
void AmbientOcclusionEffect::updateFramebufferSizes() { void AmbientOcclusionEffect::updateFramebufferSizes() {
auto& params = _aoParametersBuffer.edit(); auto& params = _aoParametersBuffer.edit();
const int widthScale = _framebuffer->isStereo() & 1; const int stereoDivide = _framebuffer->isStereo() & 1;
auto sourceFrameSideSize = _framebuffer->getSourceFrameSize(); auto sourceFrameSideSize = _framebuffer->getSourceFrameSize();
sourceFrameSideSize.x >>= widthScale; sourceFrameSideSize.x >>= stereoDivide;
const int resolutionLevel = _aoParametersBuffer.get().getResolutionLevel(); const int resolutionLevel = _aoParametersBuffer.get().getResolutionLevel();
// Depth is at maximum half depth
const int depthResolutionLevel = getDepthResolutionLevel(); const int depthResolutionLevel = getDepthResolutionLevel();
const auto occlusionDepthFrameSize = divideRoundUp(sourceFrameSideSize, 1 << depthResolutionLevel); const auto occlusionDepthFrameSize = sourceFrameSideSize >> depthResolutionLevel;
const auto occlusionFrameSize = divideRoundUp(sourceFrameSideSize, 1 << resolutionLevel); const auto occlusionFrameSize = sourceFrameSideSize >> resolutionLevel;
auto normalTextureSize = _framebuffer->getNormalTexture()->getDimensions(); auto normalTextureSize = _framebuffer->getNormalTexture()->getDimensions();
normalTextureSize.x >>= widthScale; normalTextureSize.x >>= stereoDivide;
params._sideSizes[0].x = normalTextureSize.x; params._sideSizes[0].x = normalTextureSize.x;
params._sideSizes[0].y = normalTextureSize.y; params._sideSizes[0].y = normalTextureSize.y;
@ -485,12 +484,10 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte
const auto depthResolutionScale = powf(0.5f, depthResolutionLevel); const auto depthResolutionScale = powf(0.5f, depthResolutionLevel);
const auto isHorizonBased = _aoParametersBuffer->isHorizonBased(); const auto isHorizonBased = _aoParametersBuffer->isHorizonBased();
auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); auto fullResDepthTexture = linearDepthFramebuffer->getLinearDepthTexture();
auto occlusionDepthTexture = linearDepthTexture; auto occlusionDepthTexture = fullResDepthTexture;
auto sourceViewport = args->_viewport; auto sourceViewport = args->_viewport;
// divideRoundUp is used two compute the quarter or half resolution render sizes. auto occlusionViewport = sourceViewport >> resolutionLevel;
// We choose to take the rounded up resolution.
auto occlusionViewport = divideRoundUp(sourceViewport, 1 << resolutionLevel);
auto firstBlurViewport = sourceViewport; auto firstBlurViewport = sourceViewport;
firstBlurViewport.w = occlusionViewport.w; firstBlurViewport.w = occlusionViewport.w;
@ -506,7 +503,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte
occlusionDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); occlusionDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture();
} }
if (_framebuffer->update(linearDepthTexture, resolutionLevel, depthResolutionLevel, args->isStereo())) { if (_framebuffer->update(fullResDepthTexture, resolutionLevel, depthResolutionLevel, args->isStereo())) {
updateBlurParameters(); updateBlurParameters();
updateFramebufferSizes(); updateFramebufferSizes();
} }
@ -538,7 +535,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte
auto& sample = _aoFrameParametersBuffer[splitId].edit(); auto& sample = _aoFrameParametersBuffer[splitId].edit();
sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId]; sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId];
} }
// _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT; _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT;
gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) { gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) {
PROFILE_RANGE_BATCH(batch, "SSAO"); PROFILE_RANGE_BATCH(batch, "SSAO");
@ -567,7 +564,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte
batch.setModelTransform(Transform()); batch.setModelTransform(Transform());
batch.setViewportTransform(normalViewport); batch.setViewportTransform(normalViewport);
batch.setPipeline(buildNormalsPipeline); batch.setPipeline(buildNormalsPipeline);
batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, fullResDepthTexture);
batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, nullptr); batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, nullptr);
batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer()); batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer());
batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer); batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer);
@ -651,8 +648,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte
batch.setModelTransform(model); batch.setModelTransform(model);
} }
batch.setPipeline(bilateralBlurPipeline); batch.setPipeline(bilateralBlurPipeline);
// Use full resolution depth and normal for bilateral upscaling and blur // Use full resolution depth for bilateral upscaling and blur
batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, fullResDepthTexture);
#if SSAO_USE_QUAD_SPLIT #if SSAO_USE_QUAD_SPLIT
batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture); batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture);
#else #else
@ -742,18 +739,18 @@ void DebugAmbientOcclusion::run(const render::RenderContextPointer& renderContex
return; return;
} }
auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); auto fullResDepthTexture = linearDepthFramebuffer->getLinearDepthTexture();
auto sourceViewport = args->_viewport; auto sourceViewport = args->_viewport;
auto occlusionViewport = sourceViewport; auto occlusionViewport = sourceViewport;
auto resolutionLevel = ambientOcclusionUniforms->getResolutionLevel(); auto resolutionLevel = ambientOcclusionUniforms->getResolutionLevel();
if (resolutionLevel > 0) { if (resolutionLevel > 0) {
linearDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); fullResDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture();
occlusionViewport = occlusionViewport >> ambientOcclusionUniforms->getResolutionLevel(); occlusionViewport = occlusionViewport >> ambientOcclusionUniforms->getResolutionLevel();
} }
auto framebufferSize = glm::ivec2(linearDepthTexture->getDimensions()); auto framebufferSize = glm::ivec2(fullResDepthTexture->getDimensions());
float sMin = occlusionViewport.x / (float)framebufferSize.x; float sMin = occlusionViewport.x / (float)framebufferSize.x;
float sWidth = occlusionViewport.z / (float)framebufferSize.x; float sWidth = occlusionViewport.z / (float)framebufferSize.x;
@ -779,7 +776,7 @@ void DebugAmbientOcclusion::run(const render::RenderContextPointer& renderContex
batch.setUniformBuffer(render_utils::slot::buffer::SsaoDebugParams, _parametersBuffer); batch.setUniformBuffer(render_utils::slot::buffer::SsaoDebugParams, _parametersBuffer);
batch.setPipeline(debugPipeline); batch.setPipeline(debugPipeline);
batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture); batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, fullResDepthTexture);
batch.draw(gpu::TRIANGLE_STRIP, 4); batch.draw(gpu::TRIANGLE_STRIP, 4);

View file

@ -45,7 +45,7 @@ void LinearDepthFramebuffer::update(const gpu::TexturePointer& depthBuffer, cons
if (isStereo) { if (isStereo) {
_halfFrameSize.x >>= 1; _halfFrameSize.x >>= 1;
} }
_halfFrameSize = divideRoundUp(_halfFrameSize, 2); _halfFrameSize >>= 1;
if (isStereo) { if (isStereo) {
_halfFrameSize.x <<= 1; _halfFrameSize.x <<= 1;
} }
@ -182,7 +182,7 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con
auto downsamplePipeline = getDownsamplePipeline(renderContext); auto downsamplePipeline = getDownsamplePipeline(renderContext);
auto depthViewport = args->_viewport; auto depthViewport = args->_viewport;
auto halfViewport = divideRoundUp(depthViewport, 2); auto halfViewport = depthViewport >> 1;
float clearLinearDepth = args->getViewFrustum().getFarClip() * 2.0f; float clearLinearDepth = args->getViewFrustum().getFarClip() * 2.0f;
gpu::doInBatch("LinearDepthPass::run", args->_context, [=](gpu::Batch& batch) { gpu::doInBatch("LinearDepthPass::run", args->_context, [=](gpu::Batch& batch) {

View file

@ -260,11 +260,20 @@ float getZEyeAtUV(vec2 texCoord, int level) {
return -textureLod(depthPyramidTex, texCoord, level).x; return -textureLod(depthPyramidTex, texCoord, level).x;
} }
float getZEyeAtUV(vec2 texCoord, int level, ivec2 texelOffset) {
return -textureLodOffset(depthPyramidTex, texCoord, level, texelOffset).x;
}
float getZEyeAtUV(ivec4 side, vec2 texCoord, int level) { float getZEyeAtUV(ivec4 side, vec2 texCoord, int level) {
texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo());
return getZEyeAtUV(texCoord, level); return getZEyeAtUV(texCoord, level);
} }
float getZEyeAtUV(ivec4 side, vec2 texCoord, int level, ivec2 texelOffset) {
texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo());
return getZEyeAtUV(texCoord, level, texelOffset);
}
vec3 getNormalEyeAtUV(vec2 texCoord, int level) { vec3 getNormalEyeAtUV(vec2 texCoord, int level) {
return normalize(textureLod(normalTex, texCoord, level).xyz*2.0 - vec3(1.0)); return normalize(textureLod(normalTex, texCoord, level).xyz*2.0 - vec3(1.0));
} }
@ -301,20 +310,25 @@ vec3 buildPosition(ivec4 side, vec2 fragUVPos) {
return evalEyePositionFromZeye(side.x, Zeye, fragUVPos); return evalEyePositionFromZeye(side.x, Zeye, fragUVPos);
} }
vec3 buildPosition(ivec4 side, vec2 fragUVPos, ivec2 texelOffset, vec2 deltaUV) {
float Zeye = getZEyeAtUV(side, fragUVPos, 0, texelOffset);
return evalEyePositionFromZeye(side.x, Zeye, fragUVPos + texelOffset*deltaUV);
}
vec3 getMinDelta(vec3 centralPoint, vec3 offsetPointPos, vec3 offsetPointNeg) { vec3 getMinDelta(vec3 centralPoint, vec3 offsetPointPos, vec3 offsetPointNeg) {
vec3 delta0 = offsetPointPos - centralPoint; vec3 delta0 = offsetPointPos - centralPoint;
vec3 delta1 = centralPoint - offsetPointNeg; vec3 delta1 = centralPoint - offsetPointNeg;
float sqrLength0 = dot(delta0, delta0); float sqrLength0 = dot(delta0, delta0);
float sqrLength1 = dot(delta1, delta1); float sqrLength1 = dot(delta1, delta1);
float epsilon = 1e-6;
return sqrLength0 < sqrLength1 && sqrLength0>epsilon ? delta0 : delta1; return sqrLength0 < sqrLength1 ? delta0 : delta1;
} }
vec3 buildNormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec2 deltaDepthUV) { vec3 buildNormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec2 deltaDepthUV) {
vec3 fragPositionDxPos = buildPosition(side, fragUVPos + vec2(deltaDepthUV.x, 0)); vec3 fragPositionDxPos = buildPosition(side, fragUVPos, ivec2(1,0), deltaDepthUV);
vec3 fragPositionDxNeg = buildPosition(side, fragUVPos - vec2(deltaDepthUV.x, 0)); vec3 fragPositionDxNeg = buildPosition(side, fragUVPos, ivec2(-1,0), deltaDepthUV);
vec3 fragPositionDyPos = buildPosition(side, fragUVPos + vec2(0, deltaDepthUV.y)); vec3 fragPositionDyPos = buildPosition(side, fragUVPos, ivec2(0,1), deltaDepthUV);
vec3 fragPositionDyNeg = buildPosition(side, fragUVPos - vec2(0, deltaDepthUV.y)); vec3 fragPositionDyNeg = buildPosition(side, fragUVPos, ivec2(0,-1), deltaDepthUV);
vec3 fragPositionDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg); vec3 fragPositionDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg);
vec3 fragPositionDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg); vec3 fragPositionDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg);

View file

@ -43,7 +43,7 @@ int getBlurRadius() {
} }
vec4 fetchOcclusionPacked(ivec4 side, vec2 texCoord) { vec4 fetchOcclusionPacked(ivec4 side, vec2 texCoord) {
texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side)) * 0.5, isStereo()); texCoord.x = mix(texCoord.x, (texCoord.x + getStereoSide(side) * getBlurOcclusionUVLimit().x) * 0.5, isStereo());
return textureLod(occlusionMap, texCoord, 0); return textureLod(occlusionMap, texCoord, 0);
} }
@ -54,12 +54,11 @@ float evalBlurCoefficient(vec3 blurScales, float radialDistance, float zDistance
const float BLUR_EDGE_NORMAL_LIMIT = 0.25; const float BLUR_EDGE_NORMAL_LIMIT = 0.25;
vec2 evalTapWeightedValue(vec3 blurScales, ivec4 side, int r, vec2 occlusionTexCoord, vec2 depthTexCoord, float fragDepth, vec3 fragNormal) { vec2 evalTapWeightedValue(vec3 blurScales, ivec4 side, int r, vec2 occlusionTexCoord, float fragDepth, vec3 fragNormal) {
vec2 tapOcclusionTexCoord = getBlurOcclusionAxis() * r + occlusionTexCoord; vec2 tapOcclusionTexCoord = getBlurOcclusionAxis() * r + occlusionTexCoord;
vec2 occlusionTexCoordLimits = getBlurOcclusionUVLimit(); vec2 occlusionTexCoordLimits = getBlurOcclusionUVLimit();
if (tapOcclusionTexCoord.x < side.x || tapOcclusionTexCoord.x >= (side.x + occlusionTexCoordLimits.x) if (any(lessThan(tapOcclusionTexCoord, vec2(0.0))) || any(greaterThanEqual(tapOcclusionTexCoord, occlusionTexCoordLimits)) ) {
|| tapOcclusionTexCoord.y < 0 || tapOcclusionTexCoord.y >= occlusionTexCoordLimits.y) {
return vec2(0.0); return vec2(0.0);
} }
@ -85,10 +84,10 @@ vec4 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 dept
// Stereo side info // Stereo side info
ivec4 side = getStereoSideInfo(destPixelCoord.x, 0); ivec4 side = getStereoSideInfo(destPixelCoord.x, 0);
float fragDepth = getZEyeAtUV(side, depthTexCoord, 0); float fragDepth = getZEyeAtUV(depthTexCoord, 0);
float fragDepthKey = CSZToDepthKey(fragDepth); float fragDepthKey = CSZToDepthKey(fragDepth);
#if SSAO_BILATERAL_BLUR_USE_NORMAL #if SSAO_BILATERAL_BLUR_USE_NORMAL
vec3 fragNormal = getNormalEyeAtUV(side, depthTexCoord, 0); vec3 fragNormal = getNormalEyeAtUV(depthTexCoord, 0);
#else #else
vec3 fragNormal = vec3(0, 0, 1); vec3 fragNormal = vec3(0, 0, 1);
#endif #endif
@ -98,9 +97,13 @@ vec4 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 dept
int blurRadius = getBlurRadius(); int blurRadius = getBlurRadius();
vec3 blurScales = getBlurScales(); vec3 blurScales = getBlurScales();
// From now on, occlusionTexCoord is the UV pos in the side
float sideTexCoord = occlusionTexCoord.x * 2.0 - getStereoSide(side) * getBlurOcclusionUVLimit().x;
occlusionTexCoord.x = mix(occlusionTexCoord.x, sideTexCoord, isStereo());
// negative side first // negative side first
for (int r = -blurRadius; r <= -1; ++r) { for (int r = -blurRadius; r <= -1; ++r) {
weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, depthTexCoord, fragDepthKey, fragNormal); weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, fragDepthKey, fragNormal);
} }
// Central pixel contribution // Central pixel contribution
@ -110,7 +113,7 @@ vec4 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 dept
// then positive side // then positive side
for (int r = 1; r <= blurRadius; ++r) { for (int r = 1; r <= blurRadius; ++r) {
weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, depthTexCoord, fragDepthKey, fragNormal); weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, fragDepthKey, fragNormal);
} }
// Final normalization // Final normalization