Using UVs for buildNormals

This commit is contained in:
Olivier Prat 2018-09-24 14:38:03 +02:00
parent 9f0201878d
commit 2e40a5f3ff
5 changed files with 97 additions and 57 deletions

View file

@ -109,8 +109,8 @@ void AmbientOcclusionFramebuffer::allocate() {
}
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));
auto format = gpu::Element::COLOR_RGBA_32;
_normalTexture = gpu::Texture::createRenderBuffer(format, 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);
}
@ -561,8 +561,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte
}
// _frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT;
gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) {
PROFILE_RANGE_BATCH(batch, "AmbientOcclusion");
gpu::doInBatch("AmbientOcclusionEffect::Depth mip creation", args->_context, [=](gpu::Batch& batch) {
PROFILE_RANGE_BATCH(batch, "AO::Depth mip creation");
batch.enableStereo(false);
_gpuTimer->begin(batch);
@ -574,29 +574,57 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte
batch.setModelTransform(model);
// We need this with the mips levels
batch.pushProfileRange("Depth mip creation");
#if SSAO_USE_HORIZON_BASED
batch.setPipeline(mipCreationPipeline);
batch.generateTextureMipsWithPipeline(occlusionDepthTexture);
batch.setPipeline(mipCreationPipeline);
batch.generateTextureMipsWithPipeline(occlusionDepthTexture);
#else
batch.generateTextureMips(occlusionDepthTexture);
batch.generateTextureMips(occlusionDepthTexture);
#endif
batch.popProfileRange();
_gpuTimer->end(batch);
});
#if SSAO_USE_QUAD_SPLIT
gpu::doInBatch("AmbientOcclusionEffect::Build Normals", args->_context, [=](gpu::Batch& batch) {
PROFILE_RANGE_BATCH(batch, "AO::Build Normals");
batch.enableStereo(false);
_gpuTimer->begin(batch);
batch.resetViewTransform();
batch.setProjectionTransform(glm::mat4());
Transform model;
auto depthTextureSize = linearDepthTexture->getDimensions();
model.setScale( glm::vec3(occlusionViewport.z / (depthTextureSize.x * resolutionScale), occlusionViewport.w / (depthTextureSize.y * resolutionScale), 1.0f) );
batch.setModelTransform(model);
// Build face normals pass
batch.pushProfileRange("Build Normals");
batch.setViewportTransform(occlusionViewport);
batch.setPipeline(buildNormalsPipeline);
batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture);
batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, nullptr);
batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer());
batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer);
batch.setFramebuffer(occlusionNormalFramebuffer);
batch.draw(gpu::TRIANGLE_STRIP, 4);
batch.popProfileRange();
batch.setViewportTransform(occlusionViewport);
batch.setPipeline(buildNormalsPipeline);
batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, linearDepthTexture);
batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, nullptr);
batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer());
batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer);
batch.setFramebuffer(occlusionNormalFramebuffer);
batch.draw(gpu::TRIANGLE_STRIP, 4);
_gpuTimer->end(batch);
});
#endif
gpu::doInBatch("AmbientOcclusionEffect::Occlusion", args->_context, [=](gpu::Batch& batch) {
PROFILE_RANGE_BATCH(batch, "AO::Occlusion");
batch.enableStereo(false);
_gpuTimer->begin(batch);
batch.resetViewTransform();
Transform model;
batch.setProjectionTransform(glm::mat4());
batch.setModelTransform(model);
// Occlusion pass
batch.pushProfileRange("Occlusion");

View file

@ -73,19 +73,20 @@ void LinearDepthFramebuffer::allocate() {
auto height = _frameSize.y;
// For Linear Depth:
const uint16_t LINEAR_DEPTH_MAX_MIP_LEVEL = 5;
// 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);
const uint16_t LINEAR_DEPTH_MAX_MIP_LEVEL = 1;
const auto depthSamplerFull = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_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);
depthSamplerFull);
_linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("linearDepth"));
_linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture);
_linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat());
// For Downsampling:
const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = LINEAR_DEPTH_MAX_MIP_LEVEL;
const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = 5;
// Point sampling of the depth, as well as the clamp to edge, are needed for the AmbientOcclusionEffect with HBAO
const auto depthSamplerHalf = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP);
_halfLinearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), _halfFrameSize.x, _halfFrameSize.y, HALF_LINEAR_DEPTH_MAX_MIP_LEVEL,
depthSampler);
depthSamplerHalf);
_halfNormalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _halfFrameSize.x, _halfFrameSize.y, gpu::Texture::SINGLE_MIP,
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT));
@ -183,35 +184,47 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con
auto halfViewport = divideRoundUp(depthViewport, 2);
float clearLinearDepth = args->getViewFrustum().getFarClip() * 2.0f;
gpu::doInBatch("LinearDepthPass::run", args->_context, [=](gpu::Batch& batch) {
gpu::doInBatch("LinearDepthPass::ZtoLinearDepth", args->_context, [=](gpu::Batch& batch) {
PROFILE_RANGE_BATCH(batch, "ZtoLinearDepth");
_gpuTimer->begin(batch);
batch.enableStereo(false);
batch.setViewportTransform(depthViewport);
batch.setProjectionTransform(glm::mat4());
batch.resetViewTransform();
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(_linearDepthFramebuffer->getDepthFrameSize(), depthViewport));
batch.setUniformBuffer(ru::Buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer());
// LinearDepth
batch.setViewportTransform(depthViewport);
batch.setFramebuffer(linearDepthFBO);
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(clearLinearDepth, 0.0f, 0.0f, 0.0f));
batch.setPipeline(linearDepthPipeline);
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(_linearDepthFramebuffer->getDepthFrameSize(), depthViewport));
batch.setResourceTexture(ru::Texture::SurfaceGeometryDepth, depthBuffer);
batch.draw(gpu::TRIANGLE_STRIP, 4);
_gpuTimer->end(batch);
});
gpu::doInBatch("LinearDepthPass::halfDepth", args->_context, [=](gpu::Batch& batch) {
PROFILE_RANGE_BATCH(batch, "LinearDepthDownsample");
_gpuTimer->begin(batch);
batch.enableStereo(false);
batch.setProjectionTransform(glm::mat4());
batch.resetViewTransform();
batch.setUniformBuffer(ru::Buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer());
// 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);
batch.setPipeline(downsamplePipeline);
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(_linearDepthFramebuffer->getDepthFrameSize() >> 1, halfViewport));
batch.draw(gpu::TRIANGLE_STRIP, 4);
_gpuTimer->end(batch);
});

View file

@ -282,25 +282,26 @@ vec4 fetchTap(ivec4 side, vec2 tapSidePixelPos, float tapRadius, vec2 sideImageS
return P;
}
vec3 buildPosition(ivec4 side, vec2 fragUVPos, ivec2 depthTexFragPixelPos, ivec2 deltaDepthTexPixel, vec2 uvScale) {
depthTexFragPixelPos += deltaDepthTexPixel;
fragUVPos += deltaDepthTexPixel * uvScale;
float Zeye = getZEyeAtPixel(depthTexFragPixelPos, 0);
vec3 buildPosition(ivec4 side, vec2 fragUVPos) {
vec2 fetchUV = clamp(fragUVPos, vec2(0), vec2(1));
fetchUV = mix(fetchUV, vec2((fetchUV.x + getStereoSide(side)) * 0.5, fetchUV.y), isStereo());
float Zeye = getZEyeAtUV(fetchUV, 0);
return evalEyePositionFromZeye(side.x, Zeye, fragUVPos);
}
vec3 getMinDelta(vec3 centralPoint, vec3 offsetPointPos, vec3 offsetPointNeg) {
vec3 delta0 = offsetPointPos - centralPoint;
vec3 delta1 = centralPoint - offsetPointNeg;
return dot(delta0, delta0) < dot(delta1, delta1) ? delta0 : delta1;
float sqrLength0 = dot(delta0, delta0);
float sqrLength1 = dot(delta1, delta1);
return sqrLength0 < sqrLength1 ? delta0 : delta1;
}
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);
vec3 fragPositionDyNeg = buildPosition(side, fragUVPos, depthTexFragPixelPos, ivec2(0, -1), uvScale);
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 fragPositionDyNeg = buildPosition(side, fragUVPos - vec2(0, deltaDepthUV.y));
vec3 fragPositionDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg);
vec3 fragPositionDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg);

View file

@ -15,31 +15,28 @@
<$declareAmbientOcclusion()$>
<$declareFetchDepthPyramidMap()$>
layout(location=0) in vec2 varTexCoord0;
layout(location=0) out vec4 outFragColor;
void main(void) {
// Pixel being shaded
vec2 fragCoord = gl_FragCoord.xy;
ivec2 fragPixelPos = ivec2(fragCoord.xy);
// 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);
vec2 fragUVPos = varTexCoord0;
// 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;
// From now on, fragUVPos is the UV pos in the side
fragUVPos.x = mix(fragUVPos.x, fragUVPos.x - getStereoSide(side) * 0.5, isStereo());
vec2 deltaDepthUV = vec2(1.0) / vec2(getDepthTextureSideSize(0));
// 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, depthSideSize);
vec3 fragPositionES = buildPosition(side, fragUVPos);
vec3 fragNormalES = buildNormal(side, fragUVPos, fragPositionES, deltaDepthUV);
vec3 absFragNormalES = abs(fragNormalES);
fragNormalES /= max(absFragNormalES.z, max(absFragNormalES.x, absFragNormalES.y));

View file

@ -51,9 +51,10 @@ void main(void) {
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 fragPositionES = buildPosition(side, fragUVPos);
#if !SSAO_USE_QUAD_SPLIT
vec3 fragNormalES = buildNormal(side, fragUVPos, depthTexFragPixelPos, fragPositionES, depthSideSize);
vec2 deltaDepthUV = vec2(1.0) / depthSideSize;
vec3 fragNormalES = buildNormal(side, fragUVPos, fragPositionES, deltaDepthUV);
#endif
// Choose the screen-space sample radius