From 216c499d1472abecc29968bd9f2ba6b0aa7be7ac Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Thu, 23 Jul 2015 18:53:43 -0700 Subject: [PATCH] HAO (Horrendous Ambient Occlusion) --- .../src/AmbientOcclusionEffect.cpp | 114 ++++++++++++------ .../render-utils/src/AmbientOcclusionEffect.h | 17 +++ .../render-utils/src/ambient_occlusion.slf | 104 ++++++++++++---- .../render-utils/src/occlusion_blend.slf | 13 +- .../render-utils/src/occlusion_result.slf | 23 ++++ 5 files changed, 211 insertions(+), 60 deletions(-) create mode 100644 libraries/render-utils/src/occlusion_result.slf diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 2b1113d61b..e4220243ff 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -2,7 +2,7 @@ // AmbientOcclusionEffect.cpp // interface/src/renderer // -// Created by Andrzej Kapolka on 7/14/13. +// Created by Niraj Venkat on 7/14/13. // Copyright 2013 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. @@ -19,10 +19,11 @@ #include #include -#include "AbstractViewStateInterface.h" +#include "gpu/StandardShaderLib.h" #include "AmbientOcclusionEffect.h" #include "RenderUtil.h" #include "TextureCache.h" +#include "FramebufferCache.h" #include "DependencyManager.h" #include "ViewFrustum.h" #include "GeometryCache.h" @@ -34,9 +35,8 @@ #include "gaussian_blur_frag.h" #include "occlusion_blend_vert.h" #include "occlusion_blend_frag.h" - -const int ROTATION_WIDTH = 4; -const int ROTATION_HEIGHT = 4; +//#include "occlusion_result_vert.h" +#include "occlusion_result_frag.h" /* void AmbientOcclusionEffect::init(AbstractViewStateInterface* viewState) { @@ -197,6 +197,8 @@ const gpu::PipelinePointer& AmbientOcclusion::getOcclusionPipeline() { _gBiasLoc = program->getUniforms().findLocation("g_bias"); _gSampleRadiusLoc = program->getUniforms().findLocation("g_sample_rad"); _gIntensityLoc = program->getUniforms().findLocation("g_intensity"); + _bufferWidthLoc = program->getUniforms().findLocation("bufferWidth"); + _bufferHeightLoc = program->getUniforms().findLocation("bufferHeight"); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); @@ -209,7 +211,7 @@ const gpu::PipelinePointer& AmbientOcclusion::getOcclusionPipeline() { // Link the occlusion FBO to texture _occlusionBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, - DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); + DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); auto width = _occlusionBuffer->getWidth(); auto height = _occlusionBuffer->getHeight(); @@ -242,7 +244,7 @@ const gpu::PipelinePointer& AmbientOcclusion::getVBlurPipeline() { // Link the horizontal blur FBO to texture _vBlurBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, - DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); + DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); auto width = _vBlurBuffer->getWidth(); auto height = _vBlurBuffer->getHeight(); @@ -275,7 +277,7 @@ const gpu::PipelinePointer& AmbientOcclusion::getHBlurPipeline() { // Link the horizontal blur FBO to texture _hBlurBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, - DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); + DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); auto width = _hBlurBuffer->getWidth(); auto height = _hBlurBuffer->getHeight(); @@ -295,6 +297,9 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("blurredOcclusionTexture"), 0)); + slotBindings.insert(gpu::Shader::Binding(std::string("colorTexture"), 1)); + gpu::Shader::makeProgram(*program, slotBindings); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); @@ -303,17 +308,16 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { // Blend on transparent state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); - // Link the horizontal blur FBO to texture - _hBlurBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, - DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); + // Link the blend FBO to texture + _blendBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, + DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); - auto width = _hBlurBuffer->getWidth(); - auto height = _hBlurBuffer->getHeight(); + auto width = _blendBuffer->getWidth(); + auto height = _blendBuffer->getHeight(); auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); - _hBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); + _blendTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); // Good to go add the brand new pipeline _blendPipeline.reset(gpu::Pipeline::create(program, state)); @@ -321,38 +325,67 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { return _blendPipeline; } +const gpu::PipelinePointer& AmbientOcclusion::getAOResultPipeline() { + if (!_AOResultPipeline) { + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(ambient_occlusion_vert))); + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(occlusion_result_frag))); + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + //gpu::ShaderPointer program = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawTransformUnitQuadVS(), gpu::StandardShaderLib::getDrawTexturePS()); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + state->setDepthTest(false, false, gpu::LESS_EQUAL); + + // Blend on transparent + state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + + // Good to go add the brand new pipeline + _AOResultPipeline.reset(gpu::Pipeline::create(program, state)); + } + return _AOResultPipeline; +} + void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { - - // create a simple pipeline that does: - assert(renderContext->args); assert(renderContext->args->_viewFrustum); RenderArgs* args = renderContext->args; auto& scene = sceneContext->_scene; - // Allright, something to render let's do it gpu::Batch batch; glm::mat4 projMat; Transform viewMat; args->_viewFrustum->evalProjectionMatrix(projMat); args->_viewFrustum->evalViewTransform(viewMat); - if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { - viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); - } batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); batch.setModelTransform(Transform()); // Occlusion step getOcclusionPipeline(); - batch.setResourceTexture(0, DependencyManager::get()->getPrimaryDepthTexture()); - batch.setResourceTexture(1, DependencyManager::get()->getPrimaryNormalTexture()); + batch.setResourceTexture(0, DependencyManager::get()->getPrimaryDepthTexture()); + batch.setResourceTexture(1, DependencyManager::get()->getPrimaryNormalTexture()); _occlusionBuffer->setRenderBuffer(0, _occlusionTexture); batch.setFramebuffer(_occlusionBuffer); - // bind the first gpu::Pipeline we need - for calculating occlusion buffer + // Occlusion uniforms + g_scale = 1.0f; + g_bias = 1.0f; + g_sample_rad = 1.0f; + g_intensity = 1.0f; + + // Bind the first gpu::Pipeline we need - for calculating occlusion buffer batch.setPipeline(getOcclusionPipeline()); + batch._glUniform1f(_gScaleLoc, g_scale); + batch._glUniform1f(_gBiasLoc, g_bias); + batch._glUniform1f(_gSampleRadiusLoc, g_sample_rad); + batch._glUniform1f(_gIntensityLoc, g_intensity); + batch._glUniform1f(_bufferWidthLoc, DependencyManager::get()->getFrameBufferSize().width()); + batch._glUniform1f(_bufferHeightLoc, DependencyManager::get()->getFrameBufferSize().height()); glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f); glm::vec2 bottomLeft(-1.0f, -1.0f); @@ -367,7 +400,7 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons _vBlurBuffer->setRenderBuffer(0, _vBlurTexture); batch.setFramebuffer(_vBlurBuffer); - // bind the second gpu::Pipeline we need - for calculating blur buffer + // Bind the second gpu::Pipeline we need - for calculating blur buffer batch.setPipeline(getVBlurPipeline()); DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); @@ -378,29 +411,38 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons _hBlurBuffer->setRenderBuffer(0, _hBlurTexture); batch.setFramebuffer(_hBlurBuffer); - // bind the third gpu::Pipeline we need - for calculating blur buffer + // Bind the third gpu::Pipeline we need - for calculating blur buffer batch.setPipeline(getHBlurPipeline()); DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); - // "Blend" step - batch.setResourceTexture(0, _occlusionTexture); - batch.setFramebuffer(DependencyManager::get()->getPrimaryFramebuffer()); + // Blend step + getBlendPipeline(); + batch.setResourceTexture(0, _hBlurTexture); + batch.setResourceTexture(1, DependencyManager::get()->getPrimaryColorTexture()); + batch.setFramebuffer(_blendBuffer); - // bind the fourth gpu::Pipeline we need - for blending the primary framefuffer with blurred occlusion texture + // Bind the fourth gpu::Pipeline we need - for blending the primary color buffer with blurred occlusion texture batch.setPipeline(getBlendPipeline()); + DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); + + // Final AO result step + getAOResultPipeline(); + batch.setResourceTexture(0, _hBlurTexture); + batch.setFramebuffer(DependencyManager::get()->getPrimaryFramebuffer()); + + // Bind the fifth gpu::Pipeline we need - for displaying the blended texture + batch.setPipeline(getAOResultPipeline()); + glm::vec2 bottomLeftSmall(0.5f, -1.0f); glm::vec2 topRightSmall(1.0f, -0.5f); - DependencyManager::get()->renderQuad(batch, bottomLeftSmall, topRightSmall, texCoordTopLeft, texCoordBottomRight, color); + DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); // Ready to render args->_context->syncCache(); - renderContext->args->_context->syncCache(); args->_context->render((batch)); // need to fetch forom the z buffer and render something in a new render target a result that combine the z and produce a fake AO result - - } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index d38624f24c..ec0314016c 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -28,21 +28,38 @@ public: const gpu::PipelinePointer& getHBlurPipeline(); const gpu::PipelinePointer& getVBlurPipeline(); const gpu::PipelinePointer& getBlendPipeline(); + const gpu::PipelinePointer& getAOResultPipeline(); private: + // Uniforms for AO + gpu::int32 _gScaleLoc; + gpu::int32 _gBiasLoc; + gpu::int32 _gSampleRadiusLoc; + gpu::int32 _gIntensityLoc; + gpu::int32 _bufferWidthLoc; + gpu::int32 _bufferHeightLoc; + float g_scale; + float g_bias; + float g_sample_rad; + float g_intensity; + gpu::PipelinePointer _occlusionPipeline; gpu::PipelinePointer _hBlurPipeline; gpu::PipelinePointer _vBlurPipeline; gpu::PipelinePointer _blendPipeline; + gpu::PipelinePointer _AOResultPipeline; gpu::FramebufferPointer _occlusionBuffer; gpu::FramebufferPointer _hBlurBuffer; gpu::FramebufferPointer _vBlurBuffer; + gpu::FramebufferPointer _blendBuffer; gpu::TexturePointer _occlusionTexture; gpu::TexturePointer _hBlurTexture; gpu::TexturePointer _vBlurTexture; + gpu::TexturePointer _blendTexture; + }; #endif // hifi_AmbientOcclusionEffect_h diff --git a/libraries/render-utils/src/ambient_occlusion.slf b/libraries/render-utils/src/ambient_occlusion.slf index 10b687ad1f..023fe2552c 100644 --- a/libraries/render-utils/src/ambient_occlusion.slf +++ b/libraries/render-utils/src/ambient_occlusion.slf @@ -14,36 +14,96 @@ <@include DeferredBufferWrite.slh@> +<@include gpu/Transform.slh@> + +<$declareStandardTransform()$> + varying vec2 varTexcoord; uniform sampler2D depthTexture; uniform sampler2D normalTexture; -float getRandom(vec2 co) { - return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); +uniform float g_scale; +uniform float g_bias; +uniform float g_sample_rad; +uniform float g_intensity; +uniform float bufferWidth; +uniform float bufferHeight; + +#define SAMPLE_COUNT 4 + +float getRandom(vec2 uv) { + return fract(sin(dot(uv.xy ,vec2(12.9898,78.233))) * 43758.5453); } -/* -float doAmbientOcclusion(vec2 tcoord, vec2 uv, vec3 p, vec3 cnorm) { - vec3 diff = getPosition(tcoord + uv) - p; - vec3 v = normalize(diff); - float d = length(diff) * g_scale; - return max(0.0, dot(cnorm, v) - g_bias) * (1.0/(1.0 + d)) * g_intensity; -} -*/ + void main(void) { + vec3 sampleKernel[4] = { vec3(0.2, 0.0, 0.0), + vec3(0.0, 0.2, 0.0), + vec3(0.0, 0.0, 0.2), + vec3(0.2, 0.2, 0.2) }; - vec4 depthColor = texture2D(depthTexture, varTexcoord.xy); - vec4 normalColor = texture2D(normalTexture, varTexcoord.xy); - float z = depthColor.r; // fetch the z-value from our depth texture - float n = 1.0; // the near plane - float f = 30.0; // the far plane - float c = (2.0 * n) / (f + n - z * (f - n)); // convert to linear values + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); - vec4 linearizedDepthColor = vec4(c, c, c, 1.0); - gl_FragColor = mix(linearizedDepthColor, normalColor, 0.5); - //gl_FragColor = linearizedDepthColor; + vec3 eyeDir = vec3(0.0); + vec3 cameraPositionWorldSpace; + <$transformEyeToWorldDir(cam, eyeDir, cameraPositionWorldSpace)$> - //vec3 p = getPosition(i.uv); - //vec3 n = getNormal(i.uv); - //vec2 rand = vec2(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx)); + vec4 depthColor = texture2D(depthTexture, varTexcoord); + + // z in non linear range [0,1] + float depthVal = depthColor.r; + // conversion into NDC [-1,1] + float zNDC = depthVal * 2.0 - 1.0; + float n = 1.0; // the near plane + float f = 30.0; // the far plane + float l = -1.0; // left + float r = 1.0; // right + float b = -1.0; // bottom + float t = 1.0; // top + + // conversion into eye space + float zEye = 2*f*n / (zNDC*(f-n)-(f+n)); + // Converting from pixel coordinates to NDC + float xNDC = gl_FragCoord.x/bufferWidth * 2.0 - 1.0; + float yNDC = gl_FragCoord.y/bufferHeight * 2.0 - 1.0; + // Unprojecting X and Y from NDC to eye space + float xEye = -zEye*(xNDC*(r-l)+(r+l))/(2.0*n); + float yEye = -zEye*(yNDC*(t-b)+(t+b))/(2.0*n); + vec3 currentFragEyeSpace = vec3(xEye, yEye, zEye); + vec3 currentFragWorldSpace; + <$transformEyeToWorldDir(cam, currentFragEyeSpace, currentFragWorldSpace)$> + + vec3 cameraToPositionRay = normalize(currentFragWorldSpace - cameraPositionWorldSpace); + vec3 origin = cameraToPositionRay * depthVal + cameraPositionWorldSpace; + + vec3 normal = normalize(texture2D(normalTexture, varTexcoord).xyz); + //normal = normalize(normal * normalMatrix); + + vec3 rvec = vec3(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx), getRandom(varTexcoord.xx)) * 2.0 - 1.0; + vec3 tangent = normalize(rvec - normal * dot(rvec, normal)); + vec3 bitangent = cross(normal, tangent); + mat3 tbn = mat3(tangent, bitangent, normal); + + float occlusion = 0.0; + + for (int i = 0; i < SAMPLE_COUNT; ++i) { + vec3 samplePos = origin + (tbn * sampleKernel[i]) * g_sample_rad; + vec4 offset = cam._projectionViewUntranslated * vec4(samplePos, 1.0); + + offset.xy = (offset.xy / offset.w) * 0.5 + 0.5; + float depth = length(samplePos - cameraPositionWorldSpace); + + float sampleDepthVal = texture2D(depthTexture, offset.xy).r; + + float rangeDelta = abs(depthVal - sampleDepthVal); + float rangeCheck = smoothstep(0.0, 1.0, g_sample_rad / rangeDelta); + + occlusion += rangeCheck * step(sampleDepthVal, depth); + } + + occlusion = 1.0 - occlusion / float(SAMPLE_COUNT); + occlusion = clamp(pow(occlusion, g_intensity), 0.0, 1.0); + gl_FragColor = vec4(occlusion, occlusion, occlusion, 1.0); } + diff --git a/libraries/render-utils/src/occlusion_blend.slf b/libraries/render-utils/src/occlusion_blend.slf index 30d3173f90..64103e38c9 100644 --- a/libraries/render-utils/src/occlusion_blend.slf +++ b/libraries/render-utils/src/occlusion_blend.slf @@ -17,8 +17,17 @@ varying vec2 varTexcoord; uniform sampler2D blurredOcclusionTexture; +uniform sampler2D colorTexture; void main(void) { - vec4 depthColor = texture2D(blurredOcclusionTexture, varTexcoord.xy); - gl_FragColor = depthColor; + vec4 occlusionColor = texture2D(blurredOcclusionTexture, varTexcoord); + vec4 currentColor = texture2D(colorTexture, varTexcoord); + + if(occlusionColor.r == 1.0) { + gl_FragColor = currentColor; + } + else { + gl_FragColor = mix(occlusionColor, currentColor, 0.5); + } + gl_FragColor = occlusionColor; } diff --git a/libraries/render-utils/src/occlusion_result.slf b/libraries/render-utils/src/occlusion_result.slf new file mode 100644 index 0000000000..3b7e895dc6 --- /dev/null +++ b/libraries/render-utils/src/occlusion_result.slf @@ -0,0 +1,23 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// occlusion_result.frag +// fragment shader +// +// Created by Niraj Venkat on 7/23/15. +// Copyright 2015 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 +// + +<@include DeferredBufferWrite.slh@> + +varying vec2 varTexcoord; + +uniform sampler2D resultTexture; + +void main(void) { + gl_FragColor = texture2D(resultTexture, varTexcoord); +}