From 0668fbc9e46dde5110d127f0261ddfbe0641c404 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 22 Dec 2015 18:39:44 -0800 Subject: [PATCH 01/32] starting on ao --- .../src/AmbientOcclusionEffect.cpp | 149 ++++++++++++++++++ .../render-utils/src/AmbientOcclusionEffect.h | 32 ++++ .../render-utils/src/RenderDeferredTask.cpp | 10 +- 3 files changed, 186 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index c32bf2654d..4b0ab241d0 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -284,3 +284,152 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); }); } + + + + +AmbientOcclusionEffect::AmbientOcclusionEffect() { + Parameters parameters; + _parametersBuffer = gpu::BufferView(std::make_shared(sizeof(Parameters), (const gpu::Byte*) ¶meters)); +} + +const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { + if (!_occlusionPipeline) { + auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); + auto ps = gpu::Shader::createPixel(std::string(ambient_occlusion_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("depthTexture"), 0)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalTexture"), 1)); + + 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, + gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); + + // 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())); + auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + auto width = _occlusionBuffer->getWidth(); + auto height = _occlusionBuffer->getHeight(); + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + _occlusionTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); + */ + // Good to go add the brand new pipeline + _occlusionPipeline = gpu::Pipeline::create(program, state); + } + return _occlusionPipeline; +} + +const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { + if (!_vBlurPipeline) { + auto vs = gpu::Shader::createVertex(std::string(gaussian_blur_vertical_vert)); + auto ps = gpu::Shader::createPixel(std::string(gaussian_blur_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + 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, + gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); + + // 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())); + auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + auto width = _vBlurBuffer->getWidth(); + auto height = _vBlurBuffer->getHeight(); + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + _vBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); + */ + // Good to go add the brand new pipeline + _vBlurPipeline = gpu::Pipeline::create(program, state); + } + return _vBlurPipeline; +} + +const gpu::PipelinePointer& AmbientOcclusionEffect::getHBlurPipeline() { + if (!_hBlurPipeline) { + auto vs = gpu::Shader::createVertex(std::string(gaussian_blur_horizontal_vert)); + auto ps = gpu::Shader::createPixel(std::string(gaussian_blur_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + 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, + gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); + + /* // 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())); + auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + auto width = _hBlurBuffer->getWidth(); + auto height = _hBlurBuffer->getHeight(); + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + _hBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); + */ + // Good to go add the brand new pipeline + _hBlurPipeline = gpu::Pipeline::create(program, state); + } + return _hBlurPipeline; +} + + +void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); + + RenderArgs* args = renderContext->getArgs(); + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + auto framebufferCache = DependencyManager::get(); + QSize framebufferSize = framebufferCache->getFrameBufferSize(); + float fbWidth = framebufferSize.width(); + float fbHeight = framebufferSize.height(); + float sMin = args->_viewport.x / fbWidth; + float sWidth = args->_viewport.z / fbWidth; + float tMin = args->_viewport.y / fbHeight; + float tHeight = args->_viewport.w / fbHeight; + + + glm::mat4 projMat; + Transform viewMat; + args->_viewFrustum->evalProjectionMatrix(projMat); + args->_viewFrustum->evalViewTransform(viewMat); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + batch.setModelTransform(Transform()); + + // Occlusion step + getOcclusionPipeline(); + batch.setResourceTexture(0, framebufferCache->getPrimaryDepthTexture()); + batch.setResourceTexture(1, framebufferCache->getDeferredNormalTexture()); + /*_occlusionBuffer->setRenderBuffer(0, _occlusionTexture); + batch.setFramebuffer(_occlusionBuffer); + */ + + + batch.draw(gpu::TRIANGLE_STRIP, 4); + }); +} diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 6153795ea6..d8766ed211 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -65,4 +65,36 @@ private: }; + +class AmbientOcclusionEffect { +public: + + AmbientOcclusionEffect(); + + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + typedef render::Job::Model JobModel; + + const gpu::PipelinePointer& getGenerateDepthPipeline(); + const gpu::PipelinePointer& getOcclusionPipeline(); + const gpu::PipelinePointer& getHBlurPipeline(); + const gpu::PipelinePointer& getVBlurPipeline(); + +private: + + // Class describing the uniform buffer with all the parameters common to the AO shaders + class Parameters { + public: + glm::vec4 spareB; + + Parameters() {} + }; + typedef gpu::BufferView UniformBufferView; + gpu::BufferView _parametersBuffer; + + gpu::PipelinePointer _generateDepthPipeline; + gpu::PipelinePointer _occlusionPipeline; + gpu::PipelinePointer _hBlurPipeline; + gpu::PipelinePointer _vBlurPipeline; +}; + #endif // hifi_AmbientOcclusionEffect_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index cf60fcfe37..860cecc6f6 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -83,17 +83,17 @@ RenderDeferredTask::RenderDeferredTask() : Task() { // Use Stencil and start drawing background in Lighting buffer _jobs.push_back(Job(new DrawBackgroundDeferred::JobModel("DrawBackgroundDeferred"))); + // AO job, to be revisited + _jobs.push_back(Job(new AmbientOcclusionEffect::JobModel("AmbientOcclusion"))); + _jobs.back().setEnabled(false); + _occlusionJobIndex = (int)_jobs.size() - 1; + // Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now. _jobs.push_back(Job(new DrawLight::JobModel("DrawLight"))); // DeferredBuffer is complete, now let's shade it into the LightingBuffer _jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred"))); - // AO job, to be revisited - _jobs.push_back(Job(new AmbientOcclusion::JobModel("AmbientOcclusion"))); - _jobs.back().setEnabled(false); - _occlusionJobIndex = (int)_jobs.size() - 1; - // AA job to be revisited _jobs.push_back(Job(new Antialiasing::JobModel("Antialiasing"))); _jobs.back().setEnabled(false); From dbc4506cee6126953b5b7ba2e144c9d6f36b6650 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 23 Dec 2015 17:27:20 -0800 Subject: [PATCH 02/32] Working on AO --- examples/utilities/tools/renderEngineDebug.js | 2 +- libraries/gpu/src/gpu/GLBackendTexture.cpp | 62 ++ .../src/AmbientOcclusionEffect.cpp | 565 +++++++++--------- .../render-utils/src/AmbientOcclusionEffect.h | 81 +-- .../render-utils/src/DebugDeferredBuffer.cpp | 13 +- .../render-utils/src/DebugDeferredBuffer.h | 1 + libraries/render-utils/src/DeferredBuffer.slh | 2 +- .../render-utils/src/FramebufferCache.cpp | 24 + libraries/render-utils/src/FramebufferCache.h | 7 +- .../render-utils/src/ToneMappingEffect.cpp | 9 +- .../src/debug_deferred_buffer.slf | 2 + 11 files changed, 409 insertions(+), 359 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index cc04ddd8a2..775bd352d9 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -12,7 +12,7 @@ Script.include("cookies.js"); var MENU = "Developer>Render>Debug Deferred Buffer"; -var ACTIONS = ["Off", "Diffuse", "Alpha", "Specular", "Roughness", "Normal", "Depth", "Lighting", "Custom"]; +var ACTIONS = ["Off", "Diffuse", "Alpha", "Specular", "Roughness", "Normal", "Depth", "Lighting", "AmbientOcclusion", "Custom"]; var SETTINGS_KEY = "EngineDebugScript.DebugMode"; Number.prototype.clamp = function(min, max) { diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 17802ae6ed..d84d3e3967 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -146,6 +146,68 @@ public: case gpu::RGB: case gpu::RGBA: texel.internalFormat = GL_RED; + switch (dstFormat.getType()) { + case gpu::UINT32: { + texel.internalFormat = GL_R32UI; + break; + } + case gpu::INT32: { + texel.internalFormat = GL_R32I; + break; + } + case gpu::NUINT32: { + texel.internalFormat = GL_RED; + break; + } + case gpu::NINT32: { + texel.internalFormat = GL_RED_SNORM; + break; + } + case gpu::FLOAT: { + texel.internalFormat = GL_R32F; + break; + } + case gpu::UINT16: { + texel.internalFormat = GL_R16UI; + break; + } + case gpu::INT16: { + texel.internalFormat = GL_R16I; + break; + } + case gpu::NUINT16: { + texel.internalFormat = GL_R16; + break; + } + case gpu::NINT16: { + texel.internalFormat = GL_R16_SNORM; + break; + } + case gpu::HALF: { + texel.internalFormat = GL_R16F; + break; + } + case gpu::UINT8: { + texel.internalFormat = GL_R8UI; + break; + } + case gpu::INT8: { + texel.internalFormat = GL_R8I; + break; + } + case gpu::NUINT8: { + texel.internalFormat = GL_R8; + break; + } + case gpu::NINT8: { + texel.internalFormat = GL_R8_SNORM; + break; + } + case gpu::NUM_TYPES: { // quiet compiler + Q_UNREACHABLE(); + } + + } break; case gpu::DEPTH: texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 4b0ab241d0..e2a732ddb7 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -32,298 +32,140 @@ #include "occlusion_blend_frag.h" -AmbientOcclusion::AmbientOcclusion() { -} - -const gpu::PipelinePointer& AmbientOcclusion::getOcclusionPipeline() { - if (!_occlusionPipeline) { - auto vs = gpu::Shader::createVertex(std::string(ambient_occlusion_vert)); - auto ps = gpu::Shader::createPixel(std::string(ambient_occlusion_frag)); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("depthTexture"), 0)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalTexture"), 1)); - - gpu::Shader::makeProgram(*program, slotBindings); - - _gScaleLoc = program->getUniforms().findLocation("g_scale"); - _gBiasLoc = program->getUniforms().findLocation("g_bias"); - _gSampleRadiusLoc = program->getUniforms().findLocation("g_sample_rad"); - _gIntensityLoc = program->getUniforms().findLocation("g_intensity"); - - _nearLoc = program->getUniforms().findLocation("near"); - _depthScaleLoc = program->getUniforms().findLocation("depthScale"); - _depthTexCoordOffsetLoc = program->getUniforms().findLocation("depthTexCoordOffset"); - _depthTexCoordScaleLoc = program->getUniforms().findLocation("depthTexCoordScale"); - _renderTargetResLoc = program->getUniforms().findLocation("renderTargetRes"); - _renderTargetResInvLoc = program->getUniforms().findLocation("renderTargetResInv"); - - 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, - gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); - - // 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())); - auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); - auto width = _occlusionBuffer->getWidth(); - auto height = _occlusionBuffer->getHeight(); - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); - _occlusionTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); - - // Good to go add the brand new pipeline - _occlusionPipeline = gpu::Pipeline::create(program, state); - } - return _occlusionPipeline; -} - -const gpu::PipelinePointer& AmbientOcclusion::getVBlurPipeline() { - if (!_vBlurPipeline) { - auto vs = gpu::Shader::createVertex(std::string(gaussian_blur_vertical_vert)); - auto ps = gpu::Shader::createPixel(std::string(gaussian_blur_frag)); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - - 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, - gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); - - // 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())); - auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); - auto width = _vBlurBuffer->getWidth(); - auto height = _vBlurBuffer->getHeight(); - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); - _vBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); - - // Good to go add the brand new pipeline - _vBlurPipeline = gpu::Pipeline::create(program, state); - } - return _vBlurPipeline; -} - -const gpu::PipelinePointer& AmbientOcclusion::getHBlurPipeline() { - if (!_hBlurPipeline) { - auto vs = gpu::Shader::createVertex(std::string(gaussian_blur_horizontal_vert)); - auto ps = gpu::Shader::createPixel(std::string(gaussian_blur_frag)); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - - 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, - gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); - - // 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())); - auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); - auto width = _hBlurBuffer->getWidth(); - auto height = _hBlurBuffer->getHeight(); - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); - _hBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); - - // Good to go add the brand new pipeline - _hBlurPipeline = gpu::Pipeline::create(program, state); - } - return _hBlurPipeline; -} - -const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { - if (!_blendPipeline) { - auto vs = gpu::Shader::createVertex(std::string(ambient_occlusion_vert)); - auto ps = gpu::Shader::createPixel(std::string(occlusion_blend_frag)); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("blurredOcclusionTexture"), 0)); - - 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(true, - gpu::State::INV_SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::SRC_ALPHA); - - // Good to go add the brand new pipeline - _blendPipeline = gpu::Pipeline::create(program, state); - } - return _blendPipeline; -} - -void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { - assert(renderContext->getArgs()); - assert(renderContext->getArgs()->_viewFrustum); - - RenderArgs* args = renderContext->getArgs(); - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { - auto framebufferCache = DependencyManager::get(); - QSize framebufferSize = framebufferCache->getFrameBufferSize(); - float fbWidth = framebufferSize.width(); - float fbHeight = framebufferSize.height(); - float sMin = args->_viewport.x / fbWidth; - float sWidth = args->_viewport.z / fbWidth; - float tMin = args->_viewport.y / fbHeight; - float tHeight = args->_viewport.w / fbHeight; - - - glm::mat4 projMat; - Transform viewMat; - args->_viewFrustum->evalProjectionMatrix(projMat); - args->_viewFrustum->evalViewTransform(viewMat); - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - batch.setModelTransform(Transform()); - - // Occlusion step - getOcclusionPipeline(); - batch.setResourceTexture(0, framebufferCache->getPrimaryDepthTexture()); - batch.setResourceTexture(1, framebufferCache->getDeferredNormalTexture()); - _occlusionBuffer->setRenderBuffer(0, _occlusionTexture); - batch.setFramebuffer(_occlusionBuffer); - - // 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); - - // setup uniforms for unpacking a view-space position from the depth buffer - // This is code taken from DeferredLightEffect.render() method in DeferredLightingEffect.cpp. - // DeferredBuffer.slh shows how the unpacking is done and what variables are needed. - - // initialize the view-space unpacking uniforms using frustum data - float left, right, bottom, top, nearVal, farVal; - glm::vec4 nearClipPlane, farClipPlane; - - args->_viewFrustum->computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); - - float depthScale = (farVal - nearVal) / farVal; - float nearScale = -1.0f / nearVal; - float depthTexCoordScaleS = (right - left) * nearScale / sWidth; - float depthTexCoordScaleT = (top - bottom) * nearScale / tHeight; - float depthTexCoordOffsetS = left * nearScale - sMin * depthTexCoordScaleS; - float depthTexCoordOffsetT = bottom * nearScale - tMin * depthTexCoordScaleT; - - // now set the position-unpacking unforms - batch._glUniform1f(_nearLoc, nearVal); - batch._glUniform1f(_depthScaleLoc, depthScale); - batch._glUniform2f(_depthTexCoordOffsetLoc, depthTexCoordOffsetS, depthTexCoordOffsetT); - batch._glUniform2f(_depthTexCoordScaleLoc, depthTexCoordScaleS, depthTexCoordScaleT); - - batch._glUniform2f(_renderTargetResLoc, fbWidth, fbHeight); - batch._glUniform2f(_renderTargetResInvLoc, 1.0f / fbWidth, 1.0f / fbHeight); - - glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f); - glm::vec2 bottomLeft(-1.0f, -1.0f); - glm::vec2 topRight(1.0f, 1.0f); - glm::vec2 texCoordTopLeft(0.0f, 0.0f); - glm::vec2 texCoordBottomRight(1.0f, 1.0f); - DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); - - // Vertical blur step - getVBlurPipeline(); - batch.setResourceTexture(0, _occlusionTexture); - _vBlurBuffer->setRenderBuffer(0, _vBlurTexture); - batch.setFramebuffer(_vBlurBuffer); - - // Bind the second gpu::Pipeline we need - for calculating blur buffer - batch.setPipeline(getVBlurPipeline()); - - DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); - - // Horizontal blur step - getHBlurPipeline(); - batch.setResourceTexture(0, _vBlurTexture); - _hBlurBuffer->setRenderBuffer(0, _hBlurTexture); - batch.setFramebuffer(_hBlurBuffer); - - // 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 - getBlendPipeline(); - batch.setResourceTexture(0, _hBlurTexture); - batch.setFramebuffer(framebufferCache->getDeferredFramebuffer()); - - // 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); - }); -} - - +const int AmbientOcclusionEffect_ParamsSlot = 0; +const int AmbientOcclusionEffect_DeferredTransformSlot = 1; +const int AmbientOcclusionEffect_DepthMapSlot = 0; +const int AmbientOcclusionEffect_PyramidMapSlot = 0; AmbientOcclusionEffect::AmbientOcclusionEffect() { Parameters parameters; _parametersBuffer = gpu::BufferView(std::make_shared(sizeof(Parameters), (const gpu::Byte*) ¶meters)); } -const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { - if (!_occlusionPipeline) { +const gpu::PipelinePointer& AmbientOcclusionEffect::getPyramidPipeline() { + if (!_pyramidPipeline) { + const char AO_frag[] = R"SCRIBE(#version 410 core + // + // Created by Sam Gateau on 12/23/2015 + // 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 + // + + struct AmbientOcclusionParams { + vec4 _clipInfo; + mat4 _projection; + }; + + uniform ambientOcclusionParamsBuffer { + AmbientOcclusionParams params; + }; + + float evalZeyeFromZdb(float depth) { + return params._clipInfo.x / (depth * params._clipInfo.y + params._clipInfo.z); + } + + // the depth texture + uniform sampler2D depthMap; + + in vec2 varTexCoord0; + out vec4 outFragColor; + + void main(void) { + float Zdb = texture(depthMap, varTexCoord0).x; + float Zeye = -evalZeyeFromZdb(Zdb); + outFragColor = vec4(Zeye, 0.0, 0.0, 1.0); + } + + )SCRIBE"; auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(ambient_occlusion_frag)); + auto ps = gpu::Shader::createPixel(std::string(AO_frag)); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("depthTexture"), 0)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalTexture"), 1)); + slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), AmbientOcclusionEffect_DeferredTransformSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), AmbientOcclusionEffect_DepthMapSlot)); gpu::Shader::makeProgram(*program, slotBindings); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(false, false, gpu::LESS_EQUAL); + // Stencil test all the ao passes for objects pixels only, not the background + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); - // Blend on transparent - state->setBlendFunction(false, - 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); + state->setColorWriteMask(true, false, false, false); + + // Good to go add the brand new pipeline + _pyramidPipeline = gpu::Pipeline::create(program, state); + } + return _pyramidPipeline; +} + +const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { + if (!_occlusionPipeline) { + const char AO_frag[] = R"SCRIBE(#version 410 core + // + // Created by Sam Gateau on 12/23/2015 + // 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 + // + + struct AmbientOcclusionParams { + vec4 _clipInfo; + mat4 _projection; + }; + + uniform ambientOcclusionParamsBuffer { + AmbientOcclusionParams params; + }; + + vec3 evalEyePositionFromZeye(float Zeye, vec2 texcoord, mat4 projection) { + // compute the view space position using the depth + // basically manually pick the proj matrix components to do the inverse + float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * projection[2][0] - projection[3][0]) / projection[0][0]; + float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * projection[2][1] - projection[3][1]) / projection[1][1]; + return vec3(Xe, Ye, Zeye); + } + + // the depth texture + uniform sampler2D pyramidMap; + + in vec2 varTexCoord0; + out vec4 outFragColor; + + void main(void) { + float Zeye = textureLod(pyramidMap, varTexCoord0, 0).x; + vec3 P = evalEyePositionFromZeye(-Zeye, varTexCoord0, params._projection); + + outFragColor = vec4(1.0, 0.0, 0.0, P.x / 100.0); + } + + )SCRIBE"; + auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); + auto ps = gpu::Shader::createPixel(std::string(AO_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), AmbientOcclusionEffect_DeferredTransformSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("pyramidMap"), AmbientOcclusionEffect_PyramidMapSlot)); + + gpu::Shader::makeProgram(*program, slotBindings); + + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + // Stencil test all the ao passes for objects pixels only, not the background + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); + + state->setColorWriteMask(false, false, false, true); - // 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())); - auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); - auto width = _occlusionBuffer->getWidth(); - auto height = _occlusionBuffer->getHeight(); - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); - _occlusionTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); - */ // Good to go add the brand new pipeline _occlusionPipeline = gpu::Pipeline::create(program, state); } @@ -396,40 +238,173 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getHBlurPipeline() { return _hBlurPipeline; } +void AmbientOcclusionEffect::setClipInfo(float nearZ, float farZ) { + _parametersBuffer.edit()._clipInfo = glm::vec4(nearZ*farZ, farZ -nearZ, -farZ, 0.0f); + +} + +void AmbientOcclusionEffect::updateDeferredTransformBuffer(const render::RenderContextPointer& renderContext) { + // Allocate the parameters buffer used by all the deferred shaders + if (!_deferredTransformBuffer[0]._buffer) { + DeferredTransform parameters; + _deferredTransformBuffer[0] = gpu::BufferView(std::make_shared(sizeof(DeferredTransform), (const gpu::Byte*) ¶meters)); + _deferredTransformBuffer[1] = gpu::BufferView(std::make_shared(sizeof(DeferredTransform), (const gpu::Byte*) ¶meters)); + } + + RenderArgs* args = renderContext->getArgs(); + + // THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport) + auto framebufferCache = DependencyManager::get(); + QSize framebufferSize = framebufferCache->getFrameBufferSize(); + auto monoViewport = args->_viewport; + float sMin = args->_viewport.x / (float)framebufferSize.width(); + float sWidth = args->_viewport.z / (float)framebufferSize.width(); + float tMin = args->_viewport.y / (float)framebufferSize.height(); + float tHeight = args->_viewport.w / (float)framebufferSize.height(); + + // The view frustum is the mono frustum base + auto viewFrustum = args->_viewFrustum; + + // Eval the mono projection + mat4 monoProjMat; + viewFrustum->evalProjectionMatrix(monoProjMat); + + // The mono view transform + Transform monoViewTransform; + viewFrustum->evalViewTransform(monoViewTransform); + + // THe mono view matrix coming from the mono view transform + glm::mat4 monoViewMat; + monoViewTransform.getMatrix(monoViewMat); + + // Running in stero ? + bool isStereo = args->_context->isStereo(); + int numPasses = 1; + + mat4 projMats[2]; + Transform viewTransforms[2]; + ivec4 viewports[2]; + vec4 clipQuad[2]; + vec2 screenBottomLeftCorners[2]; + vec2 screenTopRightCorners[2]; + vec4 fetchTexcoordRects[2]; + + DeferredTransform deferredTransforms[2]; + + if (isStereo) { + numPasses = 2; + + mat4 eyeViews[2]; + args->_context->getStereoProjections(projMats); + args->_context->getStereoViews(eyeViews); + + float halfWidth = 0.5f * sWidth; + + for (int i = 0; i < numPasses; i++) { + // In stereo, the 2 sides are layout side by side in the mono viewport and their width is half + int sideWidth = monoViewport.z >> 1; + viewports[i] = ivec4(monoViewport.x + (i * sideWidth), monoViewport.y, sideWidth, monoViewport.w); + + deferredTransforms[i].projection = projMats[i]; + + auto sideViewMat = monoViewMat * glm::inverse(eyeViews[i]); + viewTransforms[i].evalFromRawMatrix(sideViewMat); + deferredTransforms[i].viewInverse = sideViewMat; + + deferredTransforms[i].stereoSide = (i == 0 ? -1.0f : 1.0f); + + clipQuad[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight); + screenBottomLeftCorners[i] = glm::vec2(-1.0f + i * 1.0f, -1.0f); + screenTopRightCorners[i] = glm::vec2(i * 1.0f, 1.0f); + + fetchTexcoordRects[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight); + } + } else { + + viewports[0] = monoViewport; + projMats[0] = monoProjMat; + + deferredTransforms[0].projection = monoProjMat; + + deferredTransforms[0].viewInverse = monoViewMat; + viewTransforms[0] = monoViewTransform; + + deferredTransforms[0].stereoSide = 0.0f; + + clipQuad[0] = glm::vec4(sMin, tMin, sWidth, tHeight); + screenBottomLeftCorners[0] = glm::vec2(-1.0f, -1.0f); + screenTopRightCorners[0] = glm::vec2(1.0f, 1.0f); + + fetchTexcoordRects[0] = glm::vec4(sMin, tMin, sWidth, tHeight); + } + + _deferredTransformBuffer[0]._buffer->setSubData(0, sizeof(DeferredTransform), (const gpu::Byte*) &deferredTransforms[0]); + _deferredTransformBuffer[1]._buffer->setSubData(0, sizeof(DeferredTransform), (const gpu::Byte*) &deferredTransforms[1]); + +} void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { assert(renderContext->getArgs()); assert(renderContext->getArgs()->_viewFrustum); RenderArgs* args = renderContext->getArgs(); + auto framebufferCache = DependencyManager::get(); + auto depthBuffer = framebufferCache->getPrimaryDepthTexture(); + auto pyramidFBO = framebufferCache->getDepthPyramidFramebuffer(); + auto occlusionFBO = framebufferCache->getDeferredFramebufferDepthColor(); + + QSize framebufferSize = framebufferCache->getFrameBufferSize(); + float sMin = args->_viewport.x / (float)framebufferSize.width(); + float sWidth = args->_viewport.z / (float)framebufferSize.width(); + float tMin = args->_viewport.y / (float)framebufferSize.height(); + float tHeight = args->_viewport.w / (float)framebufferSize.height(); + + + updateDeferredTransformBuffer(renderContext); + + // Eval the mono projection + mat4 monoProjMat; + args->_viewFrustum->evalProjectionMatrix(monoProjMat); + + setClipInfo(args->_viewFrustum->getNearClip(), args->_viewFrustum->getFarClip()); + _parametersBuffer.edit()._projection = monoProjMat; + + + auto pyramidPipeline = getPyramidPipeline(); + auto occlusionPipeline = getOcclusionPipeline(); + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { - auto framebufferCache = DependencyManager::get(); - QSize framebufferSize = framebufferCache->getFrameBufferSize(); - float fbWidth = framebufferSize.width(); - float fbHeight = framebufferSize.height(); - float sMin = args->_viewport.x / fbWidth; - float sWidth = args->_viewport.z / fbWidth; - float tMin = args->_viewport.y / fbHeight; - float tHeight = args->_viewport.w / fbHeight; + batch.enableStereo(false); + + batch.setUniformBuffer(AmbientOcclusionEffect_DeferredTransformSlot, _deferredTransformBuffer[0]); - glm::mat4 projMat; - Transform viewMat; - args->_viewFrustum->evalProjectionMatrix(projMat); - args->_viewFrustum->evalViewTransform(viewMat); - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - batch.setModelTransform(Transform()); + batch.setViewportTransform(args->_viewport); + batch.setProjectionTransform(glm::mat4()); + batch.setViewTransform(Transform()); - // Occlusion step - getOcclusionPipeline(); - batch.setResourceTexture(0, framebufferCache->getPrimaryDepthTexture()); - batch.setResourceTexture(1, framebufferCache->getDeferredNormalTexture()); - /*_occlusionBuffer->setRenderBuffer(0, _occlusionTexture); - batch.setFramebuffer(_occlusionBuffer); - */ + Transform model; + model.setTranslation(glm::vec3(sMin, tMin, 0.0)); + model.setScale(glm::vec3(sWidth, tHeight, 1.0)); + batch.setModelTransform(model); + + batch.setUniformBuffer(AmbientOcclusionEffect_ParamsSlot, _parametersBuffer); + // Pyramid pass + batch.setFramebuffer(pyramidFBO); + batch.setPipeline(pyramidPipeline); + batch.setResourceTexture(AmbientOcclusionEffect_DepthMapSlot, depthBuffer); batch.draw(gpu::TRIANGLE_STRIP, 4); + + // + batch.setFramebuffer(occlusionFBO); + batch.generateTextureMips(pyramidFBO->getRenderBuffer(0)); + + // Occlusion pass + batch.setPipeline(occlusionPipeline); + batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot, pyramidFBO->getRenderBuffer(0)); + batch.draw(gpu::TRIANGLE_STRIP, 4); + }); } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index d8766ed211..cabd361136 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -16,56 +16,6 @@ #include "render/DrawTask.h" -class AmbientOcclusion { -public: - - AmbientOcclusion(); - - void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - typedef render::Job::Model JobModel; - - const gpu::PipelinePointer& getOcclusionPipeline(); - const gpu::PipelinePointer& getHBlurPipeline(); - const gpu::PipelinePointer& getVBlurPipeline(); - const gpu::PipelinePointer& getBlendPipeline(); - -private: - - // Uniforms for AO - gpu::int32 _gScaleLoc; - gpu::int32 _gBiasLoc; - gpu::int32 _gSampleRadiusLoc; - gpu::int32 _gIntensityLoc; - - gpu::int32 _nearLoc; - gpu::int32 _depthScaleLoc; - gpu::int32 _depthTexCoordOffsetLoc; - gpu::int32 _depthTexCoordScaleLoc; - gpu::int32 _renderTargetResLoc; - gpu::int32 _renderTargetResInvLoc; - - - 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::FramebufferPointer _occlusionBuffer; - gpu::FramebufferPointer _hBlurBuffer; - gpu::FramebufferPointer _vBlurBuffer; - - gpu::TexturePointer _occlusionTexture; - gpu::TexturePointer _hBlurTexture; - gpu::TexturePointer _vBlurTexture; - -}; - - class AmbientOcclusionEffect { public: @@ -74,24 +24,41 @@ public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); typedef render::Job::Model JobModel; - const gpu::PipelinePointer& getGenerateDepthPipeline(); - const gpu::PipelinePointer& getOcclusionPipeline(); - const gpu::PipelinePointer& getHBlurPipeline(); - const gpu::PipelinePointer& getVBlurPipeline(); - private: + void setClipInfo(float nearZ, float farZ); + // Class describing the uniform buffer with all the parameters common to the AO shaders class Parameters { public: - glm::vec4 spareB; + glm::vec4 _clipInfo; + glm::mat4 _projection; Parameters() {} }; typedef gpu::BufferView UniformBufferView; gpu::BufferView _parametersBuffer; - gpu::PipelinePointer _generateDepthPipeline; + // Class describing the uniform buffer with all the parameters common to the deferred shaders + class DeferredTransform { + public: + glm::mat4 projection; + glm::mat4 viewInverse; + float stereoSide{ 0.f }; + float spareA, spareB, spareC; + + DeferredTransform() {} + }; + UniformBufferView _deferredTransformBuffer[2]; + void updateDeferredTransformBuffer(const render::RenderContextPointer& renderContext); + + + const gpu::PipelinePointer& getPyramidPipeline(); + const gpu::PipelinePointer& getOcclusionPipeline(); + const gpu::PipelinePointer& getHBlurPipeline(); + const gpu::PipelinePointer& getVBlurPipeline(); + + gpu::PipelinePointer _pyramidPipeline; gpu::PipelinePointer _occlusionPipeline; gpu::PipelinePointer _hBlurPipeline; gpu::PipelinePointer _vBlurPipeline; diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index ca678770fb..fe71102a35 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -31,7 +31,8 @@ enum Slots { Normal, Specular, Depth, - Lighting + Lighting, + Pyramid }; static const std::string DEEFAULT_DIFFUSE_SHADER { @@ -69,6 +70,12 @@ static const std::string DEEFAULT_LIGHTING_SHADER { " return vec4(pow(texture(lightingMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);" " }" }; +static const std::string DEFAULT_AMBIENT_OCCLUSION_SHADER { + "vec4 getFragmentColor() {" + " return vec4(vec3(1.0 - texture(pyramidMap, uv).x * 0.01), 1.0);" + //" return vec4(vec3(1.0 - textureLod(pyramidMap, uv, 3).x * 0.01), 1.0);" + " }" +}; static const std::string DEEFAULT_CUSTOM_SHADER { "vec4 getFragmentColor() {" " return vec4(1.0, 0.0, 0.0, 1.0);" @@ -111,6 +118,8 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode, std::string cus return DEEFAULT_DEPTH_SHADER; case LightingMode: return DEEFAULT_LIGHTING_SHADER; + case AmbientOcclusionMode: + return DEFAULT_AMBIENT_OCCLUSION_SHADER; case CustomMode: return getFileContent(customFile, DEEFAULT_CUSTOM_SHADER); } @@ -158,6 +167,7 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode, std::st slotBindings.insert(gpu::Shader::Binding("specularMap", Specular)); slotBindings.insert(gpu::Shader::Binding("depthMap", Depth)); slotBindings.insert(gpu::Shader::Binding("lightingMap", Lighting)); + slotBindings.insert(gpu::Shader::Binding("pyramidMap", Pyramid)); gpu::Shader::makeProgram(*program, slotBindings); auto pipeline = gpu::Pipeline::create(program, std::make_shared()); @@ -205,6 +215,7 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setResourceTexture(Specular, framebufferCache->getDeferredSpecularTexture()); batch.setResourceTexture(Depth, framebufferCache->getPrimaryDepthTexture()); batch.setResourceTexture(Lighting, framebufferCache->getLightingTexture()); + batch.setResourceTexture(Pyramid, framebufferCache->getDepthPyramidTexture()); const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); const glm::vec2 bottomLeft(renderContext->_deferredDebugSize.x, renderContext->_deferredDebugSize.y); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index 682888b2af..abfdf682d9 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -33,6 +33,7 @@ private: NormalMode, DepthMode, LightingMode, + AmbientOcclusionMode, CustomMode // Needs to stay last }; diff --git a/libraries/render-utils/src/DeferredBuffer.slh b/libraries/render-utils/src/DeferredBuffer.slh index 18606f2525..0157fc1fda 100755 --- a/libraries/render-utils/src/DeferredBuffer.slh +++ b/libraries/render-utils/src/DeferredBuffer.slh @@ -92,7 +92,7 @@ DeferredFragment unpackDeferredFragment(DeferredTransform deferredTransform, vec frag.normal = normalize(frag.normalVal.xyz * 2.0 - vec3(1.0)); frag.diffuse = frag.diffuseVal.xyz; - frag.opacity = frag.diffuseVal.w; + frag.opacity = frag.normalVal.w; frag.specular = frag.specularVal.xyz; frag.gloss = frag.specularVal.w; diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 9f3d4ba0fe..58ee3f1170 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -45,6 +45,8 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) { _cachedFramebuffers.clear(); _lightingTexture.reset(); _lightingFramebuffer.reset(); + _depthPyramidFramebuffer.reset(); + _depthPyramidTexture.reset(); } } @@ -96,6 +98,14 @@ void FramebufferCache::createPrimaryFramebuffer() { _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _lightingFramebuffer->setRenderBuffer(0, _lightingTexture); _lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); + + + // For AO: + _depthPyramidTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::HALF, gpu::RGB), width, height, smoothSampler)); + _depthPyramidFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _depthPyramidFramebuffer->setRenderBuffer(0, _depthPyramidTexture); + _depthPyramidFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); + } gpu::FramebufferPointer FramebufferCache::getPrimaryFramebuffer() { @@ -197,3 +207,17 @@ gpu::FramebufferPointer FramebufferCache::getSelfieFramebuffer() { } return _selfieFramebuffer; } + +gpu::FramebufferPointer FramebufferCache::getDepthPyramidFramebuffer() { + if (!_depthPyramidFramebuffer) { + createPrimaryFramebuffer(); + } + return _depthPyramidFramebuffer; +} + +gpu::TexturePointer FramebufferCache::getDepthPyramidTexture() { + if (!_depthPyramidTexture) { + createPrimaryFramebuffer(); + } + return _depthPyramidTexture; +} \ No newline at end of file diff --git a/libraries/render-utils/src/FramebufferCache.h b/libraries/render-utils/src/FramebufferCache.h index 7ac5e4af63..4916882d9b 100644 --- a/libraries/render-utils/src/FramebufferCache.h +++ b/libraries/render-utils/src/FramebufferCache.h @@ -41,7 +41,9 @@ public: gpu::TexturePointer getDeferredNormalTexture(); gpu::TexturePointer getDeferredSpecularTexture(); - + gpu::FramebufferPointer getDepthPyramidFramebuffer(); + gpu::TexturePointer getDepthPyramidTexture(); + gpu::TexturePointer getLightingTexture(); gpu::FramebufferPointer getLightingFramebuffer(); @@ -83,6 +85,9 @@ private: gpu::FramebufferPointer _selfieFramebuffer; + gpu::FramebufferPointer _depthPyramidFramebuffer; + gpu::TexturePointer _depthPyramidTexture; + QSize _frameBufferSize{ 100, 100 }; }; diff --git a/libraries/render-utils/src/ToneMappingEffect.cpp b/libraries/render-utils/src/ToneMappingEffect.cpp index 2583719424..81c25bb4b8 100644 --- a/libraries/render-utils/src/ToneMappingEffect.cpp +++ b/libraries/render-utils/src/ToneMappingEffect.cpp @@ -18,6 +18,8 @@ #include "FramebufferCache.h" +const int ToneMappingEffect_ParamsSlot = 0; +const int ToneMappingEffect_LightingMapSlot = 0; ToneMappingEffect::ToneMappingEffect() { Parameters parameters; @@ -91,7 +93,8 @@ void ToneMappingEffect::init() { auto blitProgram = gpu::ShaderPointer(gpu::Shader::createProgram(blitVS, blitPS)); gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("toneMappingParamsBuffer"), 3)); + slotBindings.insert(gpu::Shader::Binding(std::string("toneMappingParamsBuffer"), ToneMappingEffect_ParamsSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("colorMap"), ToneMappingEffect_LightingMapSlot)); gpu::Shader::makeProgram(*blitProgram, slotBindings); auto blitState = std::make_shared(); blitState->setColorWriteMask(true, true, true, true); @@ -138,8 +141,8 @@ void ToneMappingEffect::render(RenderArgs* args) { batch.setModelTransform(model); } - batch.setUniformBuffer(3, _parametersBuffer); - batch.setResourceTexture(0, lightingBuffer); + batch.setUniformBuffer(ToneMappingEffect_ParamsSlot, _parametersBuffer); + batch.setResourceTexture(ToneMappingEffect_LightingMapSlot, lightingBuffer); batch.draw(gpu::TRIANGLE_STRIP, 4); }); } \ No newline at end of file diff --git a/libraries/render-utils/src/debug_deferred_buffer.slf b/libraries/render-utils/src/debug_deferred_buffer.slf index 375972cdc3..37ae32b675 100644 --- a/libraries/render-utils/src/debug_deferred_buffer.slf +++ b/libraries/render-utils/src/debug_deferred_buffer.slf @@ -14,6 +14,8 @@ <@include DeferredBuffer.slh@> +uniform sampler2D pyramidMap; + in vec2 uv; out vec4 outFragColor; From cf14f9a249d41c82965832dcf7a20fc73a94a5ee Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 24 Dec 2015 11:47:04 -0800 Subject: [PATCH 03/32] Implementing the SAO effect in progress --- .../src/AmbientOcclusionEffect.cpp | 123 +++++++++++++++++- .../render-utils/src/AmbientOcclusionEffect.h | 1 + 2 files changed, 119 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index e2a732ddb7..a73d356f6b 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -57,6 +57,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getPyramidPipeline() { struct AmbientOcclusionParams { vec4 _clipInfo; mat4 _projection; + vec4 _radius_s0_s1_s2; }; uniform ambientOcclusionParamsBuffer { @@ -116,15 +117,37 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + const int NUM_SAMPLES = 11; + const int NUM_SPIRAL_TURNS= 7; + const int LOG_MAX_OFFSET = 3; + const int MAX_MIP_LEVEL = 5; + + + // the depth texture + uniform sampler2D pyramidMap; + + float getZeye(vec2 texcoord) { + return -texture(pyramidMap, texcoord, 0).x; + } + struct AmbientOcclusionParams { vec4 _clipInfo; mat4 _projection; + vec4 _radius_s0_s1_s2; }; uniform ambientOcclusionParamsBuffer { AmbientOcclusionParams params; }; + float getProjScale() { + return 500.0; // this should be viewportHeight * Proj[1][1] / 2.0 + } + + float getRadius() { + return params._radius_s0_s1_s2.x; + } + vec3 evalEyePositionFromZeye(float Zeye, vec2 texcoord, mat4 projection) { // compute the view space position using the depth // basically manually pick the proj matrix components to do the inverse @@ -133,17 +156,107 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { return vec3(Xe, Ye, Zeye); } - // the depth texture - uniform sampler2D pyramidMap; + vec3 evalEyePosition(vec2 texcoord, mat4 projection) { + float Zeye = getZeye(texcoord); + return evalEyePositionFromZeye(Zeye, texcoord, projection); + } + + vec3 evalEyeNormal(vec3 C) { + return normalize(cross(dFdy(C), dFdx(C))); + } + + vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ + // Radius relative to ssR + float alpha = float(sampleNumber + 0.5) * (1.0 / NUM_SAMPLES); + float angle = alpha * (NUM_SPIRAL_TURNS * 6.28) + spinAngle; + + ssR = alpha; + return vec2(cos(angle), sin(angle)); + } + + vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) { + // Derivation: + // mipLevel = floor(log(ssR / MAX_OFFSET)); + # ifdef GL_EXT_gpu_shader5 + int mipLevel = clamp(findMSB(int(ssR)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); + # else + int mipLevel = clamp(int(floor(log2(ssR))) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); + # endif + + ivec2 ssP = ivec2(ssR * unitOffset) + ssC; + + vec3 P; + + // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. + // Manually clamp to the texture size because texelFetch bypasses the texture unit + ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), textureSize(CS_Z_buffer, mipLevel) - ivec2(1)); + P.z = texelFetch(CS_Z_buffer, mipP, mipLevel).r; + + // Offset to pixel center + P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); + + return P; + } + + + float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle) { + // Offset on the unit disk, spun for this pixel + float ssR; + vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR); + ssR *= ssDiskRadius; + + // The occluding point in camera space + vec3 Q = getOffsetPosition(ssC, unitOffset, ssR); + + vec3 v = Q - C; + + float vv = dot(v, v); + float vn = dot(v, n_C); + + const float epsilon = 0.01; + + // A: From the HPG12 paper + // Note large epsilon to avoid overdarkening within cracks + // return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6; + + // B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended] + float f = max(radius2 - vv, 0.0); return f * f * f * max((vn - bias) / (epsilon + vv), 0.0); + + // C: Medium contrast (which looks better at high radii), no division. Note that the + // contribution still falls off with radius^2, but we've adjusted the rate in a way that is + // more computationally efficient and happens to be aesthetically pleasing. + // return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0); + + // D: Low contrast, no division operation + // return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0); + } + in vec2 varTexCoord0; out vec4 outFragColor; void main(void) { - float Zeye = textureLod(pyramidMap, varTexCoord0, 0).x; - vec3 P = evalEyePositionFromZeye(-Zeye, varTexCoord0, params._projection); + // Pixel being shaded + ivec2 ssC = ivec2(gl_FragCoord.xy); - outFragColor = vec4(1.0, 0.0, 0.0, P.x / 100.0); + vec3 Cp = evalEyePosition(varTexCoord0, params._projection); + + vec3 Cn = evalEyeNormal(Cp); + + // Choose the screen-space sample radius + // proportional to the projected area of the sphere + float ssDiskRadius = -getProjScale() * getRadius() / Cp.z; + + float sum = 0.0; + for (int i = 0; i < NUM_SAMPLES; ++i) { + sum += sampleAO(ssC, Cp, Cn, ssDiskRadius, i); + } + + float intensityDivR6 = 1.0; + float A = max(0.0, 1.0 - sum * intensityDivR6 * (5.0 / NUM_SAMPLES)); + + + outFragColor = vec4(1.0, 0.0, 0.0, A); } )SCRIBE"; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index cabd361136..302e73f022 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -33,6 +33,7 @@ private: public: glm::vec4 _clipInfo; glm::mat4 _projection; + glm::vec4 _radius_s0_s1_s2{ 0.5, 0.0, 0.0, 0.0 }; Parameters() {} }; From 50b3610bcec370b2c37ed9c30788eb1e7ab82444 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 24 Dec 2015 14:48:01 -0800 Subject: [PATCH 04/32] Working on the ao --- .../src/AmbientOcclusionEffect.cpp | 89 +++++++++++++++---- 1 file changed, 70 insertions(+), 19 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index a73d356f6b..a593c09798 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -148,23 +148,49 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { return params._radius_s0_s1_s2.x; } - vec3 evalEyePositionFromZeye(float Zeye, vec2 texcoord, mat4 projection) { + vec3 evalEyePositionFromZeye(float Zeye, vec2 texcoord) { // compute the view space position using the depth // basically manually pick the proj matrix components to do the inverse - float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * projection[2][0] - projection[3][0]) / projection[0][0]; - float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * projection[2][1] - projection[3][1]) / projection[1][1]; + float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * params._projection[2][0] - params._projection[3][0]) / params._projection[0][0]; + float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * params._projection[2][1] - params._projection[3][1]) / params._projection[1][1]; return vec3(Xe, Ye, Zeye); } - vec3 evalEyePosition(vec2 texcoord, mat4 projection) { + vec3 evalEyePosition(vec2 texcoord) { float Zeye = getZeye(texcoord); - return evalEyePositionFromZeye(Zeye, texcoord, projection); + return evalEyePositionFromZeye(Zeye, texcoord); } vec3 evalEyeNormal(vec3 C) { - return normalize(cross(dFdy(C), dFdx(C))); + return -normalize(cross(dFdy(C), dFdx(C))); } + + /** Used for packing Z into the GB channels */ + float CSZToKey(float z) { + return clamp(z * (1.0 / params._clipInfo.z), 0.0, 1.0); + } + + + /** Used for packing Z into the GB channels */ + void packKey(float key, out vec2 p) { + + // Round to the nearest 1/256.0 + float temp = floor(key * 256.0); + + + + + + + // Integer part + p.x = temp * (1.0 / 256.0); + + // Fractional part + p.y = key * 256.0 - temp; + } + + vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ // Radius relative to ssR float alpha = float(sampleNumber + 0.5) * (1.0 / NUM_SAMPLES); @@ -173,15 +199,12 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { ssR = alpha; return vec2(cos(angle), sin(angle)); } + in vec2 varTexCoord0; vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) { // Derivation: // mipLevel = floor(log(ssR / MAX_OFFSET)); - # ifdef GL_EXT_gpu_shader5 int mipLevel = clamp(findMSB(int(ssR)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); - # else - int mipLevel = clamp(int(floor(log2(ssR))) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); - # endif ivec2 ssP = ivec2(ssR * unitOffset) + ssC; @@ -189,12 +212,14 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. // Manually clamp to the texture size because texelFetch bypasses the texture unit - ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), textureSize(CS_Z_buffer, mipLevel) - ivec2(1)); - P.z = texelFetch(CS_Z_buffer, mipP, mipLevel).r; + ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), textureSize(pyramidMap, mipLevel) - ivec2(1)); + P.z = -texelFetch(pyramidMap, mipP, mipLevel).r; // Offset to pixel center - P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); - + //P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); + + vec2 tapUV = (vec2(ssP) + vec2(0.5)) / textureSize(pyramidMap, 0); + P = evalEyePositionFromZeye(P.z, tapUV); return P; } @@ -213,7 +238,9 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { float vv = dot(v, v); float vn = dot(v, n_C); + const float bias = 0.01; const float epsilon = 0.01; + const float radius2 = 0.5 * 0.5; // A: From the HPG12 paper // Note large epsilon to avoid overdarkening within cracks @@ -232,14 +259,27 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { } - in vec2 varTexCoord0; out vec4 outFragColor; + vec3 debugValue(float f, float scale) { + if (f < 0.0) { + return vec3((scale + f) / scale, 0.0, 0.0); + } else { + return vec3(0.0, (scale - f) / scale, 0.0); + } + } + void main(void) { // Pixel being shaded ivec2 ssC = ivec2(gl_FragCoord.xy); - vec3 Cp = evalEyePosition(varTexCoord0, params._projection); + vec3 Cp = evalEyePosition(varTexCoord0); + + // packKey(CSZToKey(Cp.z), bilateralKey); + + // Hash function used in the HPG12 AlchemyAO paper + float randomPatternRotationAngle = (3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10; + vec3 Cn = evalEyeNormal(Cp); @@ -249,14 +289,24 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { float sum = 0.0; for (int i = 0; i < NUM_SAMPLES; ++i) { - sum += sampleAO(ssC, Cp, Cn, ssDiskRadius, i); + sum += sampleAO(ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); } float intensityDivR6 = 1.0; float A = max(0.0, 1.0 - sum * intensityDivR6 * (5.0 / NUM_SAMPLES)); + // Bilateral box-filter over a quad for free, respecting depth edges + // (the difference that this makes is subtle) + if (abs(dFdx(Cp.z)) < 0.02) { + A -= dFdx(A) * ((ssC.x & 1) - 0.5); + } + if (abs(dFdy(Cp.z)) < 0.02) { + A -= dFdy(A) * ((ssC.y & 1) - 0.5); + } - outFragColor = vec4(1.0, 0.0, 0.0, A); + + //outFragColor = vec4(debugValue(Cn.y, 10), A); + outFragColor = vec4(debugValue(Cn.y, 1), A); } )SCRIBE"; @@ -277,7 +327,8 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { // Stencil test all the ao passes for objects pixels only, not the background state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); - state->setColorWriteMask(false, false, false, true); + // state->setColorWriteMask(false, false, false, true); + state->setColorWriteMask(true, true, true, true); // Good to go add the brand new pipeline _occlusionPipeline = gpu::Pipeline::create(program, state); From 52f3c7e2cbadd3ed896cae915ebdad32a1c09784 Mon Sep 17 00:00:00 2001 From: samcake Date: Sat, 2 Jan 2016 11:27:50 -0400 Subject: [PATCH 05/32] Introducing the sl files and the blurring stages --- examples/utilities/tools/renderEngineDebug.js | 8 +- .../src/AmbientOcclusionEffect.cpp | 460 ++++++------------ .../render-utils/src/AmbientOcclusionEffect.h | 9 +- .../render-utils/src/DebugDeferredBuffer.cpp | 35 +- .../render-utils/src/DebugDeferredBuffer.h | 6 +- .../render-utils/src/FramebufferCache.cpp | 44 ++ libraries/render-utils/src/FramebufferCache.h | 13 + .../render-utils/src/RenderDeferredTask.cpp | 6 +- .../src/RenderScriptingInterface.cpp | 2 +- .../src/RenderScriptingInterface.h | 14 +- .../render-utils/src/ambient_occlusion.slf | 279 ----------- .../render-utils/src/ambient_occlusion.slv | 26 - .../src/debug_deferred_buffer.slf | 2 + libraries/render-utils/src/gaussian_blur.slf | 43 -- .../src/gaussian_blur_horizontal.slv | 43 -- .../src/gaussian_blur_vertical.slv | 43 -- .../render-utils/src/occlusion_blend.slf | 27 - libraries/render-utils/src/ssao.slh | 58 +++ .../src/ssao_makeHorizontalBlur.slf | 23 + .../render-utils/src/ssao_makeOcclusion.slf | 162 ++++++ .../render-utils/src/ssao_makePyramid.slf | 25 + .../src/ssao_makeVerticalBlur.slf | 23 + libraries/render/src/render/Engine.cpp | 4 +- libraries/render/src/render/Engine.h | 11 +- 24 files changed, 579 insertions(+), 787 deletions(-) delete mode 100644 libraries/render-utils/src/ambient_occlusion.slf delete mode 100644 libraries/render-utils/src/ambient_occlusion.slv delete mode 100644 libraries/render-utils/src/gaussian_blur.slf delete mode 100644 libraries/render-utils/src/gaussian_blur_horizontal.slv delete mode 100644 libraries/render-utils/src/gaussian_blur_vertical.slv delete mode 100644 libraries/render-utils/src/occlusion_blend.slf create mode 100644 libraries/render-utils/src/ssao.slh create mode 100644 libraries/render-utils/src/ssao_makeHorizontalBlur.slf create mode 100644 libraries/render-utils/src/ssao_makeOcclusion.slf create mode 100644 libraries/render-utils/src/ssao_makePyramid.slf create mode 100644 libraries/render-utils/src/ssao_makeVerticalBlur.slf diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index e95f7dce3f..61aea270c3 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -12,7 +12,7 @@ Script.include("cookies.js"); var MENU = "Developer>Render>Debug Deferred Buffer"; -var ACTIONS = ["Off", "Diffuse", "Alpha", "Specular", "Roughness", "Normal", "Depth", "Lighting", "AmbientOcclusion", "Custom"]; +var ACTIONS = ["Off", "Diffuse", "AmbientOcclusion", "Specular", "Roughness", "Normal", "Depth", "Lighting", "PyramidDepth", "OcclusionRaw", "OcclusionBlurred", "Custom"]; var SETTINGS_KEY = "EngineDebugScript.DebugMode"; Number.prototype.clamp = function(min, max) { @@ -52,6 +52,7 @@ var overlaysCounter = new CounterWidget(panel, "Overlays", Render.overlay3D); var resizing = false; var previousMode = Settings.getValue(SETTINGS_KEY, -1); +previousMode = 1; Menu.addActionGroup(MENU, ACTIONS, ACTIONS[previousMode + 1]); Render.deferredDebugMode = previousMode; Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 }; // Reset to default size @@ -98,6 +99,11 @@ panel.newSlider("Tone Mapping Exposure", -10, 10, function() { return Render.tone.exposure; }, function (value) { return (value); }); +panel.newSlider("Ambient Occlusion Radius", 0.0, 2.0, + function (value) { Render.ambientOcclusion.radius = value; }, + function() { return Render.ambientOcclusion.radius; }, + function (value) { return (value); }); + var tickTackPeriod = 500; function updateCounters() { diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index a593c09798..a62173d908 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -12,6 +12,9 @@ #include +#include //min max and more + + #include #include #include @@ -24,19 +27,16 @@ #include "ViewFrustum.h" #include "GeometryCache.h" -#include "ambient_occlusion_vert.h" -#include "ambient_occlusion_frag.h" -#include "gaussian_blur_vertical_vert.h" -#include "gaussian_blur_horizontal_vert.h" -#include "gaussian_blur_frag.h" -#include "occlusion_blend_frag.h" - - +#include "ssao_makePyramid_frag.h" +#include "ssao_makeOcclusion_frag.h" +#include "ssao_makeHorizontalBlur_frag.h" +#include "ssao_makeVerticalBlur_frag.h" const int AmbientOcclusionEffect_ParamsSlot = 0; const int AmbientOcclusionEffect_DeferredTransformSlot = 1; const int AmbientOcclusionEffect_DepthMapSlot = 0; const int AmbientOcclusionEffect_PyramidMapSlot = 0; +const int AmbientOcclusionEffect_OcclusionMapSlot = 0; AmbientOcclusionEffect::AmbientOcclusionEffect() { Parameters parameters; @@ -45,44 +45,8 @@ AmbientOcclusionEffect::AmbientOcclusionEffect() { const gpu::PipelinePointer& AmbientOcclusionEffect::getPyramidPipeline() { if (!_pyramidPipeline) { - const char AO_frag[] = R"SCRIBE(#version 410 core - // - // Created by Sam Gateau on 12/23/2015 - // 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 - // - - struct AmbientOcclusionParams { - vec4 _clipInfo; - mat4 _projection; - vec4 _radius_s0_s1_s2; - }; - - uniform ambientOcclusionParamsBuffer { - AmbientOcclusionParams params; - }; - - float evalZeyeFromZdb(float depth) { - return params._clipInfo.x / (depth * params._clipInfo.y + params._clipInfo.z); - } - - // the depth texture - uniform sampler2D depthMap; - - in vec2 varTexCoord0; - out vec4 outFragColor; - - void main(void) { - float Zdb = texture(depthMap, varTexCoord0).x; - float Zeye = -evalZeyeFromZdb(Zdb); - outFragColor = vec4(Zeye, 0.0, 0.0, 1.0); - } - - )SCRIBE"; auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(AO_frag)); + auto ps = gpu::Shader::createPixel(std::string(ssao_makePyramid_frag)); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -108,210 +72,8 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getPyramidPipeline() { const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { if (!_occlusionPipeline) { - const char AO_frag[] = R"SCRIBE(#version 410 core - // - // Created by Sam Gateau on 12/23/2015 - // 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 - // - - const int NUM_SAMPLES = 11; - const int NUM_SPIRAL_TURNS= 7; - const int LOG_MAX_OFFSET = 3; - const int MAX_MIP_LEVEL = 5; - - - // the depth texture - uniform sampler2D pyramidMap; - - float getZeye(vec2 texcoord) { - return -texture(pyramidMap, texcoord, 0).x; - } - - struct AmbientOcclusionParams { - vec4 _clipInfo; - mat4 _projection; - vec4 _radius_s0_s1_s2; - }; - - uniform ambientOcclusionParamsBuffer { - AmbientOcclusionParams params; - }; - - float getProjScale() { - return 500.0; // this should be viewportHeight * Proj[1][1] / 2.0 - } - - float getRadius() { - return params._radius_s0_s1_s2.x; - } - - vec3 evalEyePositionFromZeye(float Zeye, vec2 texcoord) { - // compute the view space position using the depth - // basically manually pick the proj matrix components to do the inverse - float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * params._projection[2][0] - params._projection[3][0]) / params._projection[0][0]; - float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * params._projection[2][1] - params._projection[3][1]) / params._projection[1][1]; - return vec3(Xe, Ye, Zeye); - } - - vec3 evalEyePosition(vec2 texcoord) { - float Zeye = getZeye(texcoord); - return evalEyePositionFromZeye(Zeye, texcoord); - } - - vec3 evalEyeNormal(vec3 C) { - return -normalize(cross(dFdy(C), dFdx(C))); - } - - - /** Used for packing Z into the GB channels */ - float CSZToKey(float z) { - return clamp(z * (1.0 / params._clipInfo.z), 0.0, 1.0); - } - - - /** Used for packing Z into the GB channels */ - void packKey(float key, out vec2 p) { - - // Round to the nearest 1/256.0 - float temp = floor(key * 256.0); - - - - - - - // Integer part - p.x = temp * (1.0 / 256.0); - - // Fractional part - p.y = key * 256.0 - temp; - } - - - vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ - // Radius relative to ssR - float alpha = float(sampleNumber + 0.5) * (1.0 / NUM_SAMPLES); - float angle = alpha * (NUM_SPIRAL_TURNS * 6.28) + spinAngle; - - ssR = alpha; - return vec2(cos(angle), sin(angle)); - } - in vec2 varTexCoord0; - - vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) { - // Derivation: - // mipLevel = floor(log(ssR / MAX_OFFSET)); - int mipLevel = clamp(findMSB(int(ssR)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); - - ivec2 ssP = ivec2(ssR * unitOffset) + ssC; - - vec3 P; - - // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. - // Manually clamp to the texture size because texelFetch bypasses the texture unit - ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), textureSize(pyramidMap, mipLevel) - ivec2(1)); - P.z = -texelFetch(pyramidMap, mipP, mipLevel).r; - - // Offset to pixel center - //P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); - - vec2 tapUV = (vec2(ssP) + vec2(0.5)) / textureSize(pyramidMap, 0); - P = evalEyePositionFromZeye(P.z, tapUV); - return P; - } - - - float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle) { - // Offset on the unit disk, spun for this pixel - float ssR; - vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR); - ssR *= ssDiskRadius; - - // The occluding point in camera space - vec3 Q = getOffsetPosition(ssC, unitOffset, ssR); - - vec3 v = Q - C; - - float vv = dot(v, v); - float vn = dot(v, n_C); - - const float bias = 0.01; - const float epsilon = 0.01; - const float radius2 = 0.5 * 0.5; - - // A: From the HPG12 paper - // Note large epsilon to avoid overdarkening within cracks - // return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6; - - // B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended] - float f = max(radius2 - vv, 0.0); return f * f * f * max((vn - bias) / (epsilon + vv), 0.0); - - // C: Medium contrast (which looks better at high radii), no division. Note that the - // contribution still falls off with radius^2, but we've adjusted the rate in a way that is - // more computationally efficient and happens to be aesthetically pleasing. - // return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0); - - // D: Low contrast, no division operation - // return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0); - } - - - out vec4 outFragColor; - - vec3 debugValue(float f, float scale) { - if (f < 0.0) { - return vec3((scale + f) / scale, 0.0, 0.0); - } else { - return vec3(0.0, (scale - f) / scale, 0.0); - } - } - - void main(void) { - // Pixel being shaded - ivec2 ssC = ivec2(gl_FragCoord.xy); - - vec3 Cp = evalEyePosition(varTexCoord0); - - // packKey(CSZToKey(Cp.z), bilateralKey); - - // Hash function used in the HPG12 AlchemyAO paper - float randomPatternRotationAngle = (3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10; - - - vec3 Cn = evalEyeNormal(Cp); - - // Choose the screen-space sample radius - // proportional to the projected area of the sphere - float ssDiskRadius = -getProjScale() * getRadius() / Cp.z; - - float sum = 0.0; - for (int i = 0; i < NUM_SAMPLES; ++i) { - sum += sampleAO(ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); - } - - float intensityDivR6 = 1.0; - float A = max(0.0, 1.0 - sum * intensityDivR6 * (5.0 / NUM_SAMPLES)); - - // Bilateral box-filter over a quad for free, respecting depth edges - // (the difference that this makes is subtle) - if (abs(dFdx(Cp.z)) < 0.02) { - A -= dFdx(A) * ((ssC.x & 1) - 0.5); - } - if (abs(dFdy(Cp.z)) < 0.02) { - A -= dFdy(A) * ((ssC.y & 1) - 0.5); - } - - - //outFragColor = vec4(debugValue(Cn.y, 10), A); - outFragColor = vec4(debugValue(Cn.y, 1), A); - } - - )SCRIBE"; auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(AO_frag)); + auto ps = gpu::Shader::createPixel(std::string(ssao_makeOcclusion_frag)); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -327,8 +89,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { // Stencil test all the ao passes for objects pixels only, not the background state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); - // state->setColorWriteMask(false, false, false, true); - state->setColorWriteMask(true, true, true, true); + state->setColorWriteMask(true, true, true, false); // Good to go add the brand new pipeline _occlusionPipeline = gpu::Pipeline::create(program, state); @@ -336,77 +97,148 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { return _occlusionPipeline; } -const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { - if (!_vBlurPipeline) { - auto vs = gpu::Shader::createVertex(std::string(gaussian_blur_vertical_vert)); - auto ps = gpu::Shader::createPixel(std::string(gaussian_blur_frag)); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - - 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, - gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); - - // 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())); - auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); - auto width = _vBlurBuffer->getWidth(); - auto height = _vBlurBuffer->getHeight(); - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); - _vBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); - */ - // Good to go add the brand new pipeline - _vBlurPipeline = gpu::Pipeline::create(program, state); - } - return _vBlurPipeline; -} const gpu::PipelinePointer& AmbientOcclusionEffect::getHBlurPipeline() { if (!_hBlurPipeline) { - auto vs = gpu::Shader::createVertex(std::string(gaussian_blur_horizontal_vert)); - auto ps = gpu::Shader::createPixel(std::string(gaussian_blur_frag)); + auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); + auto ps = gpu::Shader::createPixel(std::string(ssao_makeHorizontalBlur_frag)); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), AmbientOcclusionEffect_DeferredTransformSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), AmbientOcclusionEffect_OcclusionMapSlot)); + 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, - gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); - - /* // 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())); - auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); - auto width = _hBlurBuffer->getWidth(); - auto height = _hBlurBuffer->getHeight(); - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); - _hBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); - */ + + // Stencil test all the ao passes for objects pixels only, not the background + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); + + state->setColorWriteMask(true, true, true, false); + // Good to go add the brand new pipeline _hBlurPipeline = gpu::Pipeline::create(program, state); } return _hBlurPipeline; } +const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { + if (!_vBlurPipeline) { + auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); + auto ps = gpu::Shader::createPixel(std::string(ssao_makeVerticalBlur_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), AmbientOcclusionEffect_DeferredTransformSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), AmbientOcclusionEffect_OcclusionMapSlot)); + + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + // Stencil test all the ao passes for objects pixels only, not the background + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); + + // Vertical blur write just the final result Occlusion value in the alpha channel + state->setColorWriteMask(false, false, false, true); + + // Good to go add the brand new pipeline + _vBlurPipeline = gpu::Pipeline::create(program, state); + + const char blur_frag[] = R"SCRIBE(#version 410 core + // + // Created by Sam Gateau on 12/31/2015 + // 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 + // + + struct AmbientOcclusionParams { + vec4 _clipInfo; + mat4 _projection; + vec4 _radius_s0_s1_s2; + }; + + uniform ambientOcclusionParamsBuffer { + AmbientOcclusionParams params; + }; + + float evalZeyeFromZdb(float depth) { + return params._clipInfo.x / (depth * params._clipInfo.y + params._clipInfo.z); + } + + // the depth texture + uniform sampler2D depthMap; + + in vec2 varTexCoord0; + out vec4 outFragColor; + + ivec2 ssC = ivec2(gl_FragCoord.xy); + + vec4 temp = texelFetch(source, ssC, 0); + + keyPassThrough = temp.KEY_COMPONENTS; + float key = unpackKey(keyPassThrough); + + VALUE_TYPE sum = temp.VALUE_COMPONENTS; + + if (key == 1.0) { + // Sky pixel (if you aren't using depth keying, disable this test) + result = sum; + return; + } + + // Base weight for depth falloff. Increase this for more blurriness, + // decrease it for better edge discrimination + float BASE = gaussian[0]; + float totalWeight = BASE; + sum *= totalWeight; + + + for (int r = -R; r <= R; ++r) { + // We already handled the zero case above. This loop should be unrolled and the static branch optimized out, + // so the IF statement has no runtime cost + if (r != 0) { + temp = texelFetch(source, ssC + axis * (r * SCALE), 0); + float tapKey = unpackKey(temp.KEY_COMPONENTS); + VALUE_TYPE value = temp.VALUE_COMPONENTS; + + // spatial domain: offset gaussian tap + float weight = 0.3 + gaussian[abs(r)]; + + // range domain (the "bilateral" weight). As depth difference increases, decrease weight. + weight *= max(0.0, 1.0 + - (EDGE_SHARPNESS * 2000.0) * abs(tapKey - key) + ); + + sum += value * weight; + totalWeight += weight; + } + } + + const float epsilon = 0.0001; + result = sum / (totalWeight + epsilon); + + )SCRIBE"; + } + return _vBlurPipeline; +} + + void AmbientOcclusionEffect::setClipInfo(float nearZ, float farZ) { _parametersBuffer.edit()._clipInfo = glm::vec4(nearZ*farZ, farZ -nearZ, -farZ, 0.0f); } +void AmbientOcclusionEffect::setRadius(float radius) { + radius = std::max(0.01f, radius); + _parametersBuffer.edit()._radius_radius2_InvRadius6_s2 = glm::vec4(radius, radius * radius, 1.0f / pow(radius, 6.0f), 0.0f); +} + void AmbientOcclusionEffect::updateDeferredTransformBuffer(const render::RenderContextPointer& renderContext) { // Allocate the parameters buffer used by all the deferred shaders if (!_deferredTransformBuffer[0]._buffer) { @@ -515,7 +347,9 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext auto framebufferCache = DependencyManager::get(); auto depthBuffer = framebufferCache->getPrimaryDepthTexture(); auto pyramidFBO = framebufferCache->getDepthPyramidFramebuffer(); - auto occlusionFBO = framebufferCache->getDeferredFramebufferDepthColor(); + auto occlusionFBO = framebufferCache->getOcclusionFramebuffer(); + auto occlusionBlurredFBO = framebufferCache->getOcclusionBlurredFramebuffer(); + auto occlusionFinalFBO = framebufferCache->getDeferredFramebufferDepthColor(); QSize framebufferSize = framebufferCache->getFrameBufferSize(); float sMin = args->_viewport.x / (float)framebufferSize.width(); @@ -536,7 +370,9 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext auto pyramidPipeline = getPyramidPipeline(); auto occlusionPipeline = getOcclusionPipeline(); - + auto firstHBlurPipeline = getHBlurPipeline(); + auto lastVBlurPipeline = getVBlurPipeline(); + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.enableStereo(false); @@ -557,11 +393,12 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext // Pyramid pass batch.setFramebuffer(pyramidFBO); + batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(args->_viewFrustum->getFarClip(), 0.0f, 0.0f, 0.0f)); batch.setPipeline(pyramidPipeline); batch.setResourceTexture(AmbientOcclusionEffect_DepthMapSlot, depthBuffer); batch.draw(gpu::TRIANGLE_STRIP, 4); - // + // Make pyramid mips batch.setFramebuffer(occlusionFBO); batch.generateTextureMips(pyramidFBO->getRenderBuffer(0)); @@ -570,5 +407,16 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot, pyramidFBO->getRenderBuffer(0)); batch.draw(gpu::TRIANGLE_STRIP, 4); + // Blur 1 pass + batch.setFramebuffer(occlusionBlurredFBO); + batch.setPipeline(firstHBlurPipeline); + batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, occlusionFBO->getRenderBuffer(0)); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + // Blur 2 pass + batch.setFramebuffer(occlusionFinalFBO); + batch.setPipeline(lastVBlurPipeline); + batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, occlusionBlurredFBO->getRenderBuffer(0)); + batch.draw(gpu::TRIANGLE_STRIP, 4); }); } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 302e73f022..e058e4e030 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -24,6 +24,9 @@ public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); typedef render::Job::Model JobModel; + void setRadius(float radius); + float getRadius() const { return _parametersBuffer.get()._radius_radius2_InvRadius6_s2.x; } + private: void setClipInfo(float nearZ, float farZ); @@ -33,7 +36,7 @@ private: public: glm::vec4 _clipInfo; glm::mat4 _projection; - glm::vec4 _radius_s0_s1_s2{ 0.5, 0.0, 0.0, 0.0 }; + glm::vec4 _radius_radius2_InvRadius6_s2{ 0.5, 0.5 * 0.5, 1.0 / (0.25 * 0.25 * 0.25), 0.0 }; Parameters() {} }; @@ -56,8 +59,8 @@ private: const gpu::PipelinePointer& getPyramidPipeline(); const gpu::PipelinePointer& getOcclusionPipeline(); - const gpu::PipelinePointer& getHBlurPipeline(); - const gpu::PipelinePointer& getVBlurPipeline(); + const gpu::PipelinePointer& getHBlurPipeline(); // first + const gpu::PipelinePointer& getVBlurPipeline(); // second gpu::PipelinePointer _pyramidPipeline; gpu::PipelinePointer _occlusionPipeline; diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index fe71102a35..6e86942875 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -32,7 +32,9 @@ enum Slots { Specular, Depth, Lighting, - Pyramid + Pyramid, + OcclusionRaw, + OcclusionBlurred }; static const std::string DEEFAULT_DIFFUSE_SHADER { @@ -40,7 +42,7 @@ static const std::string DEEFAULT_DIFFUSE_SHADER { " return vec4(pow(texture(diffuseMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);" " }" }; -static const std::string DEEFAULT_ALPHA_SHADER { +static const std::string DEFAULT_AMBIENT_OCCLUSION_SHADER { "vec4 getFragmentColor() {" " return vec4(vec3(texture(diffuseMap, uv).a), 1.0);" " }" @@ -70,12 +72,23 @@ static const std::string DEEFAULT_LIGHTING_SHADER { " return vec4(pow(texture(lightingMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);" " }" }; -static const std::string DEFAULT_AMBIENT_OCCLUSION_SHADER { +static const std::string DEFAULT_PYRAMID_DEPTH_SHADER { "vec4 getFragmentColor() {" " return vec4(vec3(1.0 - texture(pyramidMap, uv).x * 0.01), 1.0);" //" return vec4(vec3(1.0 - textureLod(pyramidMap, uv, 3).x * 0.01), 1.0);" " }" }; +static const std::string DEFAULT_OCCLUSION_RAW_SHADER { + "vec4 getFragmentColor() {" + " return vec4(vec3(texture(occlusionRawMap, uv).x), 1.0);" + " }" +}; +static const std::string DEFAULT_OCCLUSION_BLURRED_SHADER { + "vec4 getFragmentColor() {" + " return vec4(vec3(texture(occlusionBlurredMap, uv).x), 1.0);" + " }" +}; + static const std::string DEEFAULT_CUSTOM_SHADER { "vec4 getFragmentColor() {" " return vec4(1.0, 0.0, 0.0, 1.0);" @@ -106,8 +119,8 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode, std::string cus switch (mode) { case DiffuseMode: return DEEFAULT_DIFFUSE_SHADER; - case AlphaMode: - return DEEFAULT_ALPHA_SHADER; + case AmbientOcclusionMode: + return DEFAULT_AMBIENT_OCCLUSION_SHADER; case SpecularMode: return DEEFAULT_SPECULAR_SHADER; case RoughnessMode: @@ -118,8 +131,12 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode, std::string cus return DEEFAULT_DEPTH_SHADER; case LightingMode: return DEEFAULT_LIGHTING_SHADER; - case AmbientOcclusionMode: - return DEFAULT_AMBIENT_OCCLUSION_SHADER; + case PyramidDepthMode: + return DEFAULT_PYRAMID_DEPTH_SHADER; + case OcclusionRawMode: + return DEFAULT_OCCLUSION_RAW_SHADER; + case OcclusionBlurredMode: + return DEFAULT_OCCLUSION_BLURRED_SHADER; case CustomMode: return getFileContent(customFile, DEEFAULT_CUSTOM_SHADER); } @@ -168,6 +185,8 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode, std::st slotBindings.insert(gpu::Shader::Binding("depthMap", Depth)); slotBindings.insert(gpu::Shader::Binding("lightingMap", Lighting)); slotBindings.insert(gpu::Shader::Binding("pyramidMap", Pyramid)); + slotBindings.insert(gpu::Shader::Binding("occlusionRawMap", OcclusionRaw)); + slotBindings.insert(gpu::Shader::Binding("occlusionBlurredMap", OcclusionBlurred)); gpu::Shader::makeProgram(*program, slotBindings); auto pipeline = gpu::Pipeline::create(program, std::make_shared()); @@ -216,6 +235,8 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setResourceTexture(Depth, framebufferCache->getPrimaryDepthTexture()); batch.setResourceTexture(Lighting, framebufferCache->getLightingTexture()); batch.setResourceTexture(Pyramid, framebufferCache->getDepthPyramidTexture()); + batch.setResourceTexture(OcclusionRaw, framebufferCache->getOcclusionTexture()); + batch.setResourceTexture(OcclusionBlurred, framebufferCache->getOcclusionBlurredTexture()); const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); const glm::vec2 bottomLeft(renderContext->_deferredDebugSize.x, renderContext->_deferredDebugSize.y); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index abfdf682d9..4575c6ac05 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -27,13 +27,15 @@ public: private: enum Modes : uint8_t { DiffuseMode = 0, - AlphaMode, + AmbientOcclusionMode, SpecularMode, RoughnessMode, NormalMode, DepthMode, LightingMode, - AmbientOcclusionMode, + PyramidDepthMode, + OcclusionRawMode, + OcclusionBlurredMode, CustomMode // Needs to stay last }; diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 58ee3f1170..4ebf14827f 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -47,6 +47,10 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) { _lightingFramebuffer.reset(); _depthPyramidFramebuffer.reset(); _depthPyramidTexture.reset(); + _occlusionFramebuffer.reset(); + _occlusionTexture.reset(); + _occlusionBlurredFramebuffer.reset(); + _occlusionBlurredTexture.reset(); } } @@ -105,6 +109,18 @@ void FramebufferCache::createPrimaryFramebuffer() { _depthPyramidFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _depthPyramidFramebuffer->setRenderBuffer(0, _depthPyramidTexture); _depthPyramidFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); + + + _occlusionTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGB), width, height, defaultSampler)); + _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); + _occlusionFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); + + + _occlusionBlurredTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGB), width, height, defaultSampler)); + _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture); + _occlusionBlurredFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); } @@ -220,4 +236,32 @@ gpu::TexturePointer FramebufferCache::getDepthPyramidTexture() { createPrimaryFramebuffer(); } return _depthPyramidTexture; +} + +gpu::FramebufferPointer FramebufferCache::getOcclusionFramebuffer() { + if (!_occlusionFramebuffer) { + createPrimaryFramebuffer(); + } + return _occlusionFramebuffer; +} + +gpu::TexturePointer FramebufferCache::getOcclusionTexture() { + if (!_occlusionTexture) { + createPrimaryFramebuffer(); + } + return _occlusionTexture; +} + +gpu::FramebufferPointer FramebufferCache::getOcclusionBlurredFramebuffer() { + if (!_occlusionBlurredFramebuffer) { + createPrimaryFramebuffer(); + } + return _occlusionBlurredFramebuffer; +} + +gpu::TexturePointer FramebufferCache::getOcclusionBlurredTexture() { + if (!_occlusionBlurredTexture) { + createPrimaryFramebuffer(); + } + return _occlusionBlurredTexture; } \ No newline at end of file diff --git a/libraries/render-utils/src/FramebufferCache.h b/libraries/render-utils/src/FramebufferCache.h index 4916882d9b..afc84c40c2 100644 --- a/libraries/render-utils/src/FramebufferCache.h +++ b/libraries/render-utils/src/FramebufferCache.h @@ -43,6 +43,12 @@ public: gpu::FramebufferPointer getDepthPyramidFramebuffer(); gpu::TexturePointer getDepthPyramidTexture(); + + gpu::FramebufferPointer getOcclusionFramebuffer(); + gpu::TexturePointer getOcclusionTexture(); + gpu::FramebufferPointer getOcclusionBlurredFramebuffer(); + gpu::TexturePointer getOcclusionBlurredTexture(); + gpu::TexturePointer getLightingTexture(); gpu::FramebufferPointer getLightingFramebuffer(); @@ -87,6 +93,13 @@ private: gpu::FramebufferPointer _depthPyramidFramebuffer; gpu::TexturePointer _depthPyramidTexture; + + + gpu::FramebufferPointer _occlusionFramebuffer; + gpu::TexturePointer _occlusionTexture; + + gpu::FramebufferPointer _occlusionBlurredFramebuffer; + gpu::TexturePointer _occlusionBlurredTexture; QSize _frameBufferSize{ 100, 100 }; }; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 019bcf7b7b..9614229122 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -158,12 +158,16 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend // TODO: turn on/off AO through menu item setOcclusionStatus(renderContext->getOcclusionStatus()); - + if (_occlusionJobIndex >= 0) { + _jobs[_occlusionJobIndex].edit().setRadius(renderContext->getAmbientOcclusion().radius); + } + setAntialiasingStatus(renderContext->getFxaaStatus()); setToneMappingExposure(renderContext->getTone().exposure); setToneMappingToneCurve(renderContext->getTone().toneCurve); + renderContext->getArgs()->_context->syncCache(); for (auto job : _jobs) { diff --git a/libraries/render-utils/src/RenderScriptingInterface.cpp b/libraries/render-utils/src/RenderScriptingInterface.cpp index a99dc814d5..6c7bbab6a9 100644 --- a/libraries/render-utils/src/RenderScriptingInterface.cpp +++ b/libraries/render-utils/src/RenderScriptingInterface.cpp @@ -42,7 +42,7 @@ QString RenderScripting::Tone::getCurve() const { render::RenderContext RenderScriptingInterface::getRenderContext() { render::RenderContext::ItemsConfig items{ *_opaque, *_transparent, *_overlay3D }; - return render::RenderContext{ items, *_tone, _drawStatus, _drawHitEffect, _deferredDebugSize, _deferredDebugMode }; + return render::RenderContext{ items, *_tone, *_ambientOcclusion, _drawStatus, _drawHitEffect, _deferredDebugSize, _deferredDebugMode }; } void RenderScriptingInterface::setItemCounts(const render::RenderContext::ItemsConfig& items) { diff --git a/libraries/render-utils/src/RenderScriptingInterface.h b/libraries/render-utils/src/RenderScriptingInterface.h index 08226ef6df..b330c23fc9 100644 --- a/libraries/render-utils/src/RenderScriptingInterface.h +++ b/libraries/render-utils/src/RenderScriptingInterface.h @@ -65,6 +65,14 @@ namespace RenderScripting { void setCurve(const QString& curve); }; using TonePointer = std::unique_ptr; + + class AmbientOcclusion : public QObject, public render::RenderContext::AmbientOcclusion { + Q_OBJECT + + public: + Q_PROPERTY(float radius MEMBER radius) + }; + using AmbientOcclusionPointer = std::unique_ptr; }; class RenderScriptingInterface : public QObject, public Dependency { @@ -77,7 +85,8 @@ class RenderScriptingInterface : public QObject, public Dependency { Q_PROPERTY(RenderScripting::ItemCounter* overlay3D READ getOverlay3D) Q_PROPERTY(RenderScripting::Tone* tone READ getTone) - + Q_PROPERTY(RenderScripting::AmbientOcclusion* ambientOcclusion READ getAmbientOcclusion) + Q_PROPERTY(int displayItemStatus MEMBER _drawStatus) Q_PROPERTY(bool displayHitEffect MEMBER _drawHitEffect) @@ -96,12 +105,15 @@ protected: RenderScripting::ItemCounter* getOverlay3D() const { return _overlay3D.get(); } RenderScripting::Tone* getTone() const { return _tone.get(); } + RenderScripting::AmbientOcclusion* getAmbientOcclusion() const { return _ambientOcclusion.get(); } RenderScripting::ItemStatePointer _opaque = RenderScripting::ItemStatePointer{new RenderScripting::ItemState{}}; RenderScripting::ItemStatePointer _transparent = RenderScripting::ItemStatePointer{new RenderScripting::ItemState{}}; RenderScripting::ItemCounterPointer _overlay3D = RenderScripting::ItemCounterPointer{new RenderScripting::ItemCounter{}}; RenderScripting::TonePointer _tone = RenderScripting::TonePointer{ new RenderScripting::Tone{} }; + + RenderScripting::AmbientOcclusionPointer _ambientOcclusion = RenderScripting::AmbientOcclusionPointer{ new RenderScripting::AmbientOcclusion{} }; // Options int _drawStatus = 0; diff --git a/libraries/render-utils/src/ambient_occlusion.slf b/libraries/render-utils/src/ambient_occlusion.slf deleted file mode 100644 index 8ab78891b0..0000000000 --- a/libraries/render-utils/src/ambient_occlusion.slf +++ /dev/null @@ -1,279 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// ambient_occlusion.frag -// fragment shader -// -// Created by Niraj Venkat on 7/15/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@> - -<@include gpu/Transform.slh@> - -<$declareStandardTransform()$> - -// Based on NVidia HBAO implementation in D3D11 -// http://www.nvidia.co.uk/object/siggraph-2008-HBAO.html - -in vec2 varTexcoord; - -uniform sampler2D depthTexture; -uniform sampler2D normalTexture; - -uniform float g_scale; -uniform float g_bias; -uniform float g_sample_rad; -uniform float g_intensity; - -// the distance to the near clip plane -uniform float near; - -// scale factor for depth: (far - near) / far -uniform float depthScale; - -// offset for depth texture coordinates -uniform vec2 depthTexCoordOffset; - -// scale for depth texture coordinates -uniform vec2 depthTexCoordScale; - -// the resolution of the occlusion buffer -// and its inverse -uniform vec2 renderTargetRes; -uniform vec2 renderTargetResInv; - - - -const float PI = 3.14159265; - -const float AOStrength = 1.9; - - -// TODO: R (radius) should be exposed as a uniform parameter -const float R = 0.01; -const float R2 = 0.01*0.01; -const float NegInvR2 = - 1.0 / (0.01*0.01); - - - -// can't use tan to initialize a const value -const float TanBias = 0.57735027; // tan(30.0 * PI / 180.0); -const float MaxRadiusPixels = 50.0; - -const int NumDirections = 6; -const int NumSamples = 4; - -out vec4 outFragColor; - -/** - * Gets the normal in view space from a normal texture. - * uv: the uv texture coordinates to look up in the texture at. - */ -vec3 GetViewNormalFromTexture(vec2 uv) { - // convert [0,1] -> [-1,1], note: since we're normalizing - // we don't need to do v*2 - 1.0, we can just do a v-0.5 - return normalize(texture(normalTexture, uv).xyz - 0.5); -} - -/** - * Gets the linearized depth in view space. - * d: the depth value [0-1], usually from a depth texture to convert. - */ -float ViewSpaceZFromDepth(float d){ - return near / (d * depthScale - 1.0); -} - -/** - * Converts a uv coordinate and depth value into a 3D view space coordinate. - * uv: the uv coordinates to convert - * z: the view space depth of the uv coordinate. - */ -vec3 UVToViewSpace(vec2 uv, float z){ - return vec3((depthTexCoordOffset + varTexcoord * depthTexCoordScale) * z, z); -} - -/** - * Converts a uv coordinate into a 3D view space coordinate. - * The depth of the uv coord is determined from the depth texture. - * uv: the uv coordinates to convert - */ -vec3 GetViewPos(vec2 uv) { - float z = ViewSpaceZFromDepth(texture(depthTexture, uv).r); - return UVToViewSpace(uv, z); -} - - -float TanToSin(float x) { - return x * inversesqrt(x*x + 1.0); -} - -float InvLength(vec2 V) { - return inversesqrt(dot(V, V)); -} - -float Tangent(vec3 V) { - return V.z * InvLength(V.xy); -} - -float BiasedTangent(vec3 V) { - return V.z * InvLength(V.xy) + TanBias; -} - -float Tangent(vec3 P, vec3 S) { - return -(P.z - S.z) * InvLength(S.xy - P.xy); -} - -float Length2(vec3 V) { - return dot(V, V); -} - -vec3 MinDiff(vec3 P, vec3 Pr, vec3 Pl) { - vec3 V1 = Pr - P; - vec3 V2 = P - Pl; - return (Length2(V1) < Length2(V2)) ? V1 : V2; -} - -vec2 SnapUVOffset(vec2 uv) { - return round(uv * renderTargetRes) * renderTargetResInv; -} - -float Falloff(float d2) { - return d2 * NegInvR2 + 1.0f; -} - -float HorizonOcclusion(vec2 deltaUV, vec3 P, vec3 dPdu, vec3 dPdv, float randstep, float numSamples) { - float ao = 0; - - // Offset the first coord with some noise - vec2 uv = varTexcoord + SnapUVOffset(randstep*deltaUV); - deltaUV = SnapUVOffset(deltaUV); - - // Calculate the tangent vector - vec3 T = deltaUV.x * dPdu + deltaUV.y * dPdv; - - // Get the angle of the tangent vector from the viewspace axis - float tanH = BiasedTangent(T); - float sinH = TanToSin(tanH); - - float tanS; - float d2; - vec3 S; - - // Sample to find the maximum angle - for (float s = 1; s <= numSamples; ++s) { - uv += deltaUV; - S = GetViewPos(uv); - tanS = Tangent(P, S); - d2 = Length2(S - P); - - // Is the sample within the radius and the angle greater? - if (d2 < R2 && tanS > tanH) { - float sinS = TanToSin(tanS); - // Apply falloff based on the distance - ao += Falloff(d2) * (sinS - sinH); - - tanH = tanS; - sinH = sinS; - } - } - return ao; -} - -vec2 RotateDirections(vec2 Dir, vec2 CosSin) { - return vec2(Dir.x*CosSin.x - Dir.y*CosSin.y, - Dir.x*CosSin.y + Dir.y*CosSin.x); -} - -void ComputeSteps(inout vec2 stepSizeUv, inout float numSteps, float rayRadiusPix, float rand) { - // Avoid oversampling if numSteps is greater than the kernel radius in pixels - numSteps = min(NumSamples, rayRadiusPix); - - // Divide by Ns+1 so that the farthest samples are not fully attenuated - float stepSizePix = rayRadiusPix / (numSteps + 1); - - // Clamp numSteps if it is greater than the max kernel footprint - float maxNumSteps = MaxRadiusPixels / stepSizePix; - if (maxNumSteps < numSteps) { - // Use dithering to avoid AO discontinuities - numSteps = floor(maxNumSteps + rand); - numSteps = max(numSteps, 1); - stepSizePix = MaxRadiusPixels / numSteps; - } - - // Step size in uv space - stepSizeUv = stepSizePix * renderTargetResInv; -} - -float getRandom(vec2 uv) { - return fract(sin(dot(uv.xy ,vec2(12.9898,78.233))) * 43758.5453); -} - -void main(void) { - mat4 projMatrix = getTransformCamera()._projection; - - float numDirections = NumDirections; - - vec3 P, Pr, Pl, Pt, Pb; - P = GetViewPos(varTexcoord); - - // Sample neighboring pixels - Pr = GetViewPos(varTexcoord + vec2( renderTargetResInv.x, 0)); - Pl = GetViewPos(varTexcoord + vec2(-renderTargetResInv.x, 0)); - Pt = GetViewPos(varTexcoord + vec2( 0, renderTargetResInv.y)); - Pb = GetViewPos(varTexcoord + vec2( 0,-renderTargetResInv.y)); - - // Calculate tangent basis vectors using the minimum difference - vec3 dPdu = MinDiff(P, Pr, Pl); - vec3 dPdv = MinDiff(P, Pt, Pb) * (renderTargetRes.y * renderTargetResInv.x); - - // Get the random samples from the noise function - vec3 random = vec3(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx), getRandom(varTexcoord.xx)); - - // Calculate the projected size of the hemisphere - float w = P.z * projMatrix[2][3] + projMatrix[3][3]; - vec2 rayRadiusUV = (0.5 * R * vec2(projMatrix[0][0], projMatrix[1][1]) / w); // [-1,1] -> [0,1] uv - float rayRadiusPix = rayRadiusUV.x * renderTargetRes.x; - - float ao = 1.0; - - // Make sure the radius of the evaluated hemisphere is more than a pixel - if(rayRadiusPix > 1.0) { - ao = 0.0; - float numSteps; - vec2 stepSizeUV; - - // Compute the number of steps - ComputeSteps(stepSizeUV, numSteps, rayRadiusPix, random.z); - - float alpha = 2.0 * PI / numDirections; - - // Calculate the horizon occlusion of each direction - for(float d = 0; d < numDirections; ++d) { - float theta = alpha * d; - - // Apply noise to the direction - vec2 dir = RotateDirections(vec2(cos(theta), sin(theta)), random.xy); - vec2 deltaUV = dir * stepSizeUV; - - // Sample the pixels along the direction - ao += HorizonOcclusion( deltaUV, - P, - dPdu, - dPdv, - random.z, - numSteps); - } - - // Average the results and produce the final AO - ao = 1.0 - ao / numDirections * AOStrength; - } - - - outFragColor = vec4(vec3(ao), 1.0); -} diff --git a/libraries/render-utils/src/ambient_occlusion.slv b/libraries/render-utils/src/ambient_occlusion.slv deleted file mode 100644 index 46da3f5fd5..0000000000 --- a/libraries/render-utils/src/ambient_occlusion.slv +++ /dev/null @@ -1,26 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// ambient_occlusion.vert -// vertex shader -// -// Created by Niraj Venkat on 7/15/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 gpu/Inputs.slh@> - -<@include gpu/Transform.slh@> - -<$declareStandardTransform()$> - -out vec2 varTexcoord; - -void main(void) { - varTexcoord = inTexCoord0.xy; - gl_Position = inPosition; -} diff --git a/libraries/render-utils/src/debug_deferred_buffer.slf b/libraries/render-utils/src/debug_deferred_buffer.slf index 37ae32b675..3a96486d41 100644 --- a/libraries/render-utils/src/debug_deferred_buffer.slf +++ b/libraries/render-utils/src/debug_deferred_buffer.slf @@ -15,6 +15,8 @@ <@include DeferredBuffer.slh@> uniform sampler2D pyramidMap; +uniform sampler2D occlusionRawMap; +uniform sampler2D occlusionBlurredMap; in vec2 uv; out vec4 outFragColor; diff --git a/libraries/render-utils/src/gaussian_blur.slf b/libraries/render-utils/src/gaussian_blur.slf deleted file mode 100644 index 01c1bc8807..0000000000 --- a/libraries/render-utils/src/gaussian_blur.slf +++ /dev/null @@ -1,43 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// gaussian_blur.frag -// fragment shader -// -// Created by Niraj Venkat on 7/17/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@> - -// the interpolated normal -//in vec4 interpolatedNormal; - -in vec2 varTexcoord; -in vec2 varBlurTexcoords[14]; - -uniform sampler2D occlusionTexture; - -out vec4 outFragColor; -void main(void) { - outFragColor = vec4(0.0); - outFragColor += texture(occlusionTexture, varBlurTexcoords[0])*0.0044299121055113265; - outFragColor += texture(occlusionTexture, varBlurTexcoords[1])*0.00895781211794; - outFragColor += texture(occlusionTexture, varBlurTexcoords[2])*0.0215963866053; - outFragColor += texture(occlusionTexture, varBlurTexcoords[3])*0.0443683338718; - outFragColor += texture(occlusionTexture, varBlurTexcoords[4])*0.0776744219933; - outFragColor += texture(occlusionTexture, varBlurTexcoords[5])*0.115876621105; - outFragColor += texture(occlusionTexture, varBlurTexcoords[6])*0.147308056121; - outFragColor += texture(occlusionTexture, varTexcoord)*0.159576912161; - outFragColor += texture(occlusionTexture, varBlurTexcoords[7])*0.147308056121; - outFragColor += texture(occlusionTexture, varBlurTexcoords[8])*0.115876621105; - outFragColor += texture(occlusionTexture, varBlurTexcoords[9])*0.0776744219933; - outFragColor += texture(occlusionTexture, varBlurTexcoords[10])*0.0443683338718; - outFragColor += texture(occlusionTexture, varBlurTexcoords[11])*0.0215963866053; - outFragColor += texture(occlusionTexture, varBlurTexcoords[12])*0.00895781211794; - outFragColor += texture(occlusionTexture, varBlurTexcoords[13])*0.0044299121055113265; -} diff --git a/libraries/render-utils/src/gaussian_blur_horizontal.slv b/libraries/render-utils/src/gaussian_blur_horizontal.slv deleted file mode 100644 index 7f8fb1c87f..0000000000 --- a/libraries/render-utils/src/gaussian_blur_horizontal.slv +++ /dev/null @@ -1,43 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// guassian_blur_horizontal.vert -// vertex shader -// -// Created by Niraj Venkat on 7/17/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 gpu/Inputs.slh@> - -<@include gpu/Transform.slh@> - -<$declareStandardTransform()$> - -out vec2 varTexcoord; -out vec2 varBlurTexcoords[14]; - -void main(void) { - varTexcoord = inTexCoord0.xy; - gl_Position = inPosition; - - varBlurTexcoords[0] = varTexcoord + vec2(-0.028, 0.0); - varBlurTexcoords[1] = varTexcoord + vec2(-0.024, 0.0); - varBlurTexcoords[2] = varTexcoord + vec2(-0.020, 0.0); - varBlurTexcoords[3] = varTexcoord + vec2(-0.016, 0.0); - varBlurTexcoords[4] = varTexcoord + vec2(-0.012, 0.0); - varBlurTexcoords[5] = varTexcoord + vec2(-0.008, 0.0); - varBlurTexcoords[6] = varTexcoord + vec2(-0.004, 0.0); - varBlurTexcoords[7] = varTexcoord + vec2(0.004, 0.0); - varBlurTexcoords[8] = varTexcoord + vec2(0.008, 0.0); - varBlurTexcoords[9] = varTexcoord + vec2(0.012, 0.0); - varBlurTexcoords[10] = varTexcoord + vec2(0.016, 0.0); - varBlurTexcoords[11] = varTexcoord + vec2(0.020, 0.0); - varBlurTexcoords[12] = varTexcoord + vec2(0.024, 0.0); - varBlurTexcoords[13] = varTexcoord + vec2(0.028, 0.0); -} - \ No newline at end of file diff --git a/libraries/render-utils/src/gaussian_blur_vertical.slv b/libraries/render-utils/src/gaussian_blur_vertical.slv deleted file mode 100644 index 4a4d65dcf9..0000000000 --- a/libraries/render-utils/src/gaussian_blur_vertical.slv +++ /dev/null @@ -1,43 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// guassian_blur_vertical.vert -// vertex shader -// -// Created by Niraj Venkat on 7/17/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 gpu/Inputs.slh@> - -<@include gpu/Transform.slh@> - -<$declareStandardTransform()$> - -out vec2 varTexcoord; -out vec2 varBlurTexcoords[14]; - -void main(void) { - varTexcoord = inTexCoord0.xy; - gl_Position = inPosition; - - varBlurTexcoords[0] = varTexcoord + vec2(0.0, -0.028); - varBlurTexcoords[1] = varTexcoord + vec2(0.0, -0.024); - varBlurTexcoords[2] = varTexcoord + vec2(0.0, -0.020); - varBlurTexcoords[3] = varTexcoord + vec2(0.0, -0.016); - varBlurTexcoords[4] = varTexcoord + vec2(0.0, -0.012); - varBlurTexcoords[5] = varTexcoord + vec2(0.0, -0.008); - varBlurTexcoords[6] = varTexcoord + vec2(0.0, -0.004); - varBlurTexcoords[7] = varTexcoord + vec2(0.0, 0.004); - varBlurTexcoords[8] = varTexcoord + vec2(0.0, 0.008); - varBlurTexcoords[9] = varTexcoord + vec2(0.0, 0.012); - varBlurTexcoords[10] = varTexcoord + vec2(0.0, 0.016); - varBlurTexcoords[11] = varTexcoord + vec2(0.0, 0.020); - varBlurTexcoords[12] = varTexcoord + vec2(0.0, 0.024); - varBlurTexcoords[13] = varTexcoord + vec2(0.0, 0.028); -} - \ No newline at end of file diff --git a/libraries/render-utils/src/occlusion_blend.slf b/libraries/render-utils/src/occlusion_blend.slf deleted file mode 100644 index 58873d9884..0000000000 --- a/libraries/render-utils/src/occlusion_blend.slf +++ /dev/null @@ -1,27 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// occlusion_blend.frag -// fragment shader -// -// Created by Niraj Venkat on 7/20/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@> - -in vec2 varTexcoord; -out vec4 outFragColor; - -uniform sampler2D blurredOcclusionTexture; - -void main(void) { - vec4 occlusionColor = texture(blurredOcclusionTexture, varTexcoord); - - outFragColor = vec4(vec3(0.0), occlusionColor.r); - -} diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh new file mode 100644 index 0000000000..9692127005 --- /dev/null +++ b/libraries/render-utils/src/ssao.slh @@ -0,0 +1,58 @@ + +<@if not SSAO_SLH@> +<@def SSAO_SLH@> + +<@func declareAmbientOcclusion()@> + +struct AmbientOcclusionParams { + vec4 _clipInfo; + mat4 _projection; + vec4 _radius_radius2_InvRadius6_s2; +}; + +uniform ambientOcclusionParamsBuffer { + AmbientOcclusionParams params; +}; + +float getProjScale() { + return 500.0; // this should be viewportHeight * Proj[1][1] / 2.0 +} + +float getRadius() { + return params._radius_radius2_InvRadius6_s2.x; +} +float getRadius2() { + return params._radius_radius2_InvRadius6_s2.y; +} +float getInvRadius6() { + return params._radius_radius2_InvRadius6_s2.z; +} + +float evalZeyeFromZdb(float depth) { + return params._clipInfo.x / (depth * params._clipInfo.y + params._clipInfo.z); +} + +vec3 evalEyePositionFromZeye(float Zeye, vec2 texcoord) { + // compute the view space position using the depth + // basically manually pick the proj matrix components to do the inverse + float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * params._projection[2][0] - params._projection[3][0]) / params._projection[0][0]; + float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * params._projection[2][1] - params._projection[3][1]) / params._projection[1][1]; + return vec3(Xe, Ye, Zeye); +} + +vec3 evalEyeNormal(vec3 C) { + return normalize(cross(dFdy(C), dFdx(C))); +} +<@endfunc@> + + +<@endif@> \ No newline at end of file diff --git a/libraries/render-utils/src/ssao_makeHorizontalBlur.slf b/libraries/render-utils/src/ssao_makeHorizontalBlur.slf new file mode 100644 index 0000000000..dcef20c480 --- /dev/null +++ b/libraries/render-utils/src/ssao_makeHorizontalBlur.slf @@ -0,0 +1,23 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gateau on 1/1/16. +// Copyright 2016 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 ssao.slh@> +<$declareAmbientOcclusion()$> + +// the depth texture +uniform sampler2D occlusionMap; + +in vec2 varTexCoord0; +out vec4 outFragColor; + +void main(void) { + outFragColor = texture(occlusionMap, varTexCoord0); +} diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf new file mode 100644 index 0000000000..6793be6978 --- /dev/null +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -0,0 +1,162 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gateau on 1/1/16. +// Copyright 2016 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 ssao.slh@> +<$declareAmbientOcclusion()$> + +const int NUM_SAMPLES = 11; +const float INV_NUM_SAMPLES = 1.0 / float(NUM_SAMPLES); +const int NUM_SPIRAL_TURNS= 7; +const int LOG_MAX_OFFSET = 3; +const int MAX_MIP_LEVEL = 5; + +// the depth pyramid texture +uniform sampler2D pyramidMap; + +float getZeye(vec2 texcoord) { + return -texture(pyramidMap, texcoord, 0).x; +} + +vec3 evalEyePosition(vec2 texcoord) { + float Zeye = getZeye(texcoord); + return evalEyePositionFromZeye(Zeye, texcoord); +} + +in vec2 varTexCoord0; +out vec4 outFragColor; + +/** Used for packing Z into the GB channels */ +float CSZToKey(float z) { + return clamp(z * (1.0 / params._clipInfo.z), 0.0, 1.0); +} + +/** Used for packing Z into the GB channels */ +void packKey(float key, out vec2 p) { + // Round to the nearest 1/256.0 + float temp = floor(key * 256.0); + + // Integer part + p.x = temp * (1.0 / 256.0); + + // Fractional part + p.y = key * 256.0 - temp; +} + +vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ + // Radius relative to ssR + float alpha = float(sampleNumber + 0.5) * INV_NUM_SAMPLES; + float angle = alpha * (NUM_SPIRAL_TURNS * 6.28) + spinAngle; + + ssR = alpha; + return vec2(cos(angle), sin(angle)); +} + +vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) { + // Derivation: + // mipLevel = floor(log(ssR / MAX_OFFSET)); + int mipLevel = clamp(findMSB(int(ssR)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); + + ivec2 ssP = ivec2(ssR * unitOffset) + ssC; + + vec3 P; + + // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. + // Manually clamp to the texture size because texelFetch bypasses the texture unit + ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), textureSize(pyramidMap, mipLevel) - ivec2(1)); + P.z = -texelFetch(pyramidMap, mipP, mipLevel).r; + + // Offset to pixel center + //P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); + + vec2 tapUV = (vec2(ssP) + vec2(0.5)) / textureSize(pyramidMap, 0); + P = evalEyePositionFromZeye(P.z, tapUV); + return P; +} + +float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle) { + // Offset on the unit disk, spun for this pixel + float ssR; + vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR); + ssR *= ssDiskRadius; + + // The occluding point in camera space + vec3 Q = getOffsetPosition(ssC, unitOffset, ssR); + + vec3 v = Q - C; + float vv = dot(v, v); + float vn = dot(v, n_C); + + const float bias = 0.01; + const float epsilon = 0.01; + float radius2 = getRadius2(); + + // A: From the HPG12 paper + // Note large epsilon to avoid overdarkening within cracks + // return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6; + + // B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended] + float f = max(radius2 - vv, 0.0); return f * f * f * max((vn - bias) / (epsilon + vv), 0.0); + + // C: Medium contrast (which looks better at high radii), no division. Note that the + // contribution still falls off with radius^2, but we've adjusted the rate in a way that is + // more computationally efficient and happens to be aesthetically pleasing. + // return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0); + + // D: Low contrast, no division operation + // return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0); +} + +vec3 debugValue(float f, float scale) { + if (f < 0.0) { + return vec3((scale + f) / scale, 0.0, 0.0); + } else { + return vec3(0.0, (scale - f) / scale, 0.0); + } +} + +void main(void) { + // Pixel being shaded + ivec2 ssC = ivec2(gl_FragCoord.xy); + + vec3 Cp = evalEyePosition(varTexCoord0); + + // packKey(CSZToKey(Cp.z), bilateralKey); + + // Hash function used in the HPG12 AlchemyAO paper + float randomPatternRotationAngle = (3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10; + //float randomPatternRotationAngle = 0; + + + vec3 Cn = evalEyeNormal(Cp); + + // Choose the screen-space sample radius + // proportional to the projected area of the sphere + float ssDiskRadius = -getProjScale() * getRadius() / Cp.z; + + float sum = 0.0; + for (int i = 0; i < NUM_SAMPLES; ++i) { + sum += sampleAO(ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); + } + + float A = max(0.0, 1.0 - sum * getInvRadius6() * 5.0 * INV_NUM_SAMPLES); + + // Bilateral box-filter over a quad for free, respecting depth edges + // (the difference that this makes is subtle) + if (abs(dFdx(Cp.z)) < 0.02) { + A -= dFdx(A) * ((ssC.x & 1) - 0.5); + } + if (abs(dFdy(Cp.z)) < 0.02) { + A -= dFdy(A) * ((ssC.y & 1) - 0.5); + } + + + outFragColor = vec4(A, debugValue(Cn.y, 10)); +} diff --git a/libraries/render-utils/src/ssao_makePyramid.slf b/libraries/render-utils/src/ssao_makePyramid.slf new file mode 100644 index 0000000000..577c0fd232 --- /dev/null +++ b/libraries/render-utils/src/ssao_makePyramid.slf @@ -0,0 +1,25 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gateau on 1/1/16. +// Copyright 2016 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 ssao.slh@> +<$declareAmbientOcclusion()$> + +// the depth texture +uniform sampler2D depthMap; + +in vec2 varTexCoord0; +out vec4 outFragColor; + +void main(void) { + float Zdb = texture(depthMap, varTexCoord0).x; + float Zeye = -evalZeyeFromZdb(Zdb); + outFragColor = vec4(Zeye, 0.0, 0.0, 1.0); +} diff --git a/libraries/render-utils/src/ssao_makeVerticalBlur.slf b/libraries/render-utils/src/ssao_makeVerticalBlur.slf new file mode 100644 index 0000000000..e1ed114817 --- /dev/null +++ b/libraries/render-utils/src/ssao_makeVerticalBlur.slf @@ -0,0 +1,23 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gateau on 1/1/16. +// Copyright 2016 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 ssao.slh@> +<$declareAmbientOcclusion()$> + +// the depth texture +uniform sampler2D occlusionMap; + +in vec2 varTexCoord0; +out vec4 outFragColor; + +void main(void) { + outFragColor = vec4(0.0, 0.0, 0.0, texture(occlusionMap, varTexCoord0).x); +} diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index 907c836347..6d065a3c58 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -13,11 +13,11 @@ #include "DrawTask.h" using namespace render; -RenderContext::RenderContext(ItemsConfig items, Tone tone, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode) +RenderContext::RenderContext(ItemsConfig items, Tone tone, AmbientOcclusion ao, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode) : _deferredDebugMode{ deferredDebugMode }, _deferredDebugSize{ deferredDebugSize }, _args{ nullptr }, _drawStatus{ drawStatus }, _drawHitEffect{ drawHitEffect }, - _items{ items }, _tone{ tone } {} +_items{ items }, _tone{ tone }, _ambientOcclusion{ ao } {} void RenderContext::setOptions(bool occlusion, bool fxaa, bool showOwned) { _occlusionStatus = occlusion; diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 4192dd3ed9..277d66ce35 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -76,14 +76,20 @@ public: int toneCurve = 1; // Means just Gamma 2.2 correction float exposure = 0.0; }; + + class AmbientOcclusion { + public: + float radius = 0.5; // radius in meters of the AO effect + }; - RenderContext(ItemsConfig items, Tone tone, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode); - RenderContext() : RenderContext({}, {}, {}, {}, {}, {}) {}; + RenderContext(ItemsConfig items, Tone tone, AmbientOcclusion ao, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode); + RenderContext() : RenderContext({}, {}, {}, {}, {}, {}, {}) {}; void setArgs(RenderArgs* args) { _args = args; } inline RenderArgs* getArgs() { return _args; } inline ItemsConfig& getItemsConfig() { return _items; } inline Tone& getTone() { return _tone; } + inline AmbientOcclusion& getAmbientOcclusion() { return _ambientOcclusion; } inline int getDrawStatus() { return _drawStatus; } inline bool getDrawHitEffect() { return _drawHitEffect; } inline bool getOcclusionStatus() { return _occlusionStatus; } @@ -105,6 +111,7 @@ protected: ItemsConfig _items; Tone _tone; + AmbientOcclusion _ambientOcclusion; }; typedef std::shared_ptr RenderContextPointer; From 2486d94b032f866e528cf69c19ea7a364e2bdf82 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 4 Jan 2016 14:36:46 -0400 Subject: [PATCH 06/32] A working prototype of ao... --- examples/utilities/tools/renderEngineDebug.js | 2 +- .../src/AmbientOcclusionEffect.cpp | 92 +++--------------- .../render-utils/src/AmbientOcclusionEffect.h | 1 + libraries/render-utils/src/DeferredBuffer.slh | 14 ++- .../render-utils/src/FramebufferCache.cpp | 2 +- .../src/directional_ambient_light.slf | 4 +- .../render-utils/src/directional_light.slf | 4 +- .../src/directional_skybox_light.slf | 4 +- libraries/render-utils/src/ssao.slh | 95 ++++++++++++++++++- .../src/ssao_makeHorizontalBlur.slf | 8 +- .../render-utils/src/ssao_makeOcclusion.slf | 41 ++------ .../src/ssao_makeVerticalBlur.slf | 9 +- 12 files changed, 142 insertions(+), 134 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index 61aea270c3..a6a6d1252f 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -52,7 +52,7 @@ var overlaysCounter = new CounterWidget(panel, "Overlays", Render.overlay3D); var resizing = false; var previousMode = Settings.getValue(SETTINGS_KEY, -1); -previousMode = 1; +previousMode = 4; // FIXME: just for debug purpose Menu.addActionGroup(MENU, ACTIONS, ACTIONS[previousMode + 1]); Render.deferredDebugMode = previousMode; Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 }; // Reset to default size diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index a62173d908..eb51fa68ea 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -80,7 +80,8 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), AmbientOcclusionEffect_DeferredTransformSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("pyramidMap"), AmbientOcclusionEffect_PyramidMapSlot)); - + + slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), AmbientOcclusionEffect_PyramidMapSlot + 1)); gpu::Shader::makeProgram(*program, slotBindings); @@ -90,7 +91,8 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); state->setColorWriteMask(true, true, true, false); - + //state->setColorWriteMask(true, true, true, true); + // Good to go add the brand new pipeline _occlusionPipeline = gpu::Pipeline::create(program, state); } @@ -147,83 +149,6 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { // Good to go add the brand new pipeline _vBlurPipeline = gpu::Pipeline::create(program, state); - - const char blur_frag[] = R"SCRIBE(#version 410 core - // - // Created by Sam Gateau on 12/31/2015 - // 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 - // - - struct AmbientOcclusionParams { - vec4 _clipInfo; - mat4 _projection; - vec4 _radius_s0_s1_s2; - }; - - uniform ambientOcclusionParamsBuffer { - AmbientOcclusionParams params; - }; - - float evalZeyeFromZdb(float depth) { - return params._clipInfo.x / (depth * params._clipInfo.y + params._clipInfo.z); - } - - // the depth texture - uniform sampler2D depthMap; - - in vec2 varTexCoord0; - out vec4 outFragColor; - - ivec2 ssC = ivec2(gl_FragCoord.xy); - - vec4 temp = texelFetch(source, ssC, 0); - - keyPassThrough = temp.KEY_COMPONENTS; - float key = unpackKey(keyPassThrough); - - VALUE_TYPE sum = temp.VALUE_COMPONENTS; - - if (key == 1.0) { - // Sky pixel (if you aren't using depth keying, disable this test) - result = sum; - return; - } - - // Base weight for depth falloff. Increase this for more blurriness, - // decrease it for better edge discrimination - float BASE = gaussian[0]; - float totalWeight = BASE; - sum *= totalWeight; - - - for (int r = -R; r <= R; ++r) { - // We already handled the zero case above. This loop should be unrolled and the static branch optimized out, - // so the IF statement has no runtime cost - if (r != 0) { - temp = texelFetch(source, ssC + axis * (r * SCALE), 0); - float tapKey = unpackKey(temp.KEY_COMPONENTS); - VALUE_TYPE value = temp.VALUE_COMPONENTS; - - // spatial domain: offset gaussian tap - float weight = 0.3 + gaussian[abs(r)]; - - // range domain (the "bilateral" weight). As depth difference increases, decrease weight. - weight *= max(0.0, 1.0 - - (EDGE_SHARPNESS * 2000.0) * abs(tapKey - key) - ); - - sum += value * weight; - totalWeight += weight; - } - } - - const float epsilon = 0.0001; - result = sum / (totalWeight + epsilon); - - )SCRIBE"; } return _vBlurPipeline; } @@ -346,6 +271,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext RenderArgs* args = renderContext->getArgs(); auto framebufferCache = DependencyManager::get(); auto depthBuffer = framebufferCache->getPrimaryDepthTexture(); + auto normalBuffer = framebufferCache->getDeferredNormalTexture(); auto pyramidFBO = framebufferCache->getDepthPyramidFramebuffer(); auto occlusionFBO = framebufferCache->getOcclusionFramebuffer(); auto occlusionBlurredFBO = framebufferCache->getOcclusionBlurredFramebuffer(); @@ -366,7 +292,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext setClipInfo(args->_viewFrustum->getNearClip(), args->_viewFrustum->getFarClip()); _parametersBuffer.edit()._projection = monoProjMat; - + _parametersBuffer.edit()._pixelInfo = args->_viewport; auto pyramidPipeline = getPyramidPipeline(); auto occlusionPipeline = getOcclusionPipeline(); @@ -404,9 +330,13 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext // Occlusion pass batch.setPipeline(occlusionPipeline); + + // batch.setFramebuffer(occlusionFinalFBO); batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot, pyramidFBO->getRenderBuffer(0)); + batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot + 1, normalBuffer); batch.draw(gpu::TRIANGLE_STRIP, 4); - + batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot + 1, gpu::TexturePointer()); + // Blur 1 pass batch.setFramebuffer(occlusionBlurredFBO); batch.setPipeline(firstHBlurPipeline); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index e058e4e030..4eecfc3fc7 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -34,6 +34,7 @@ private: // Class describing the uniform buffer with all the parameters common to the AO shaders class Parameters { public: + glm::vec4 _pixelInfo; glm::vec4 _clipInfo; glm::mat4 _projection; glm::vec4 _radius_radius2_InvRadius6_s2{ 0.5, 0.5 * 0.5, 1.0 / (0.25 * 0.25 * 0.25), 0.0 }; diff --git a/libraries/render-utils/src/DeferredBuffer.slh b/libraries/render-utils/src/DeferredBuffer.slh index 0157fc1fda..7555f25886 100755 --- a/libraries/render-utils/src/DeferredBuffer.slh +++ b/libraries/render-utils/src/DeferredBuffer.slh @@ -68,11 +68,14 @@ struct DeferredFragment { vec4 position; vec3 normal; vec3 diffuse; - float opacity; + float obscurance; vec3 specular; float gloss; + int mode; }; +const int LIGHT_MAPPED = 1; + DeferredFragment unpackDeferredFragment(DeferredTransform deferredTransform, vec2 texcoord) { DeferredFragment frag; frag.depthVal = texture(depthMap, texcoord).r; @@ -88,11 +91,16 @@ DeferredFragment unpackDeferredFragment(DeferredTransform deferredTransform, vec } frag.position = evalEyePositionFromZ(deferredTransform, frag.depthVal, texcoord); - // Unpack the normal from the map + // Unpack the normal from the map frag.normal = normalize(frag.normalVal.xyz * 2.0 - vec3(1.0)); + + frag.mode = 0; + if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { + frag.mode = LIGHT_MAPPED; + } frag.diffuse = frag.diffuseVal.xyz; - frag.opacity = frag.normalVal.w; + frag.obscurance = frag.diffuseVal.w; frag.specular = frag.specularVal.xyz; frag.gloss = frag.specularVal.w; diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 4ebf14827f..af20469c02 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -105,7 +105,7 @@ void FramebufferCache::createPrimaryFramebuffer() { // For AO: - _depthPyramidTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::HALF, gpu::RGB), width, height, smoothSampler)); + _depthPyramidTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), width, height, smoothSampler)); _depthPyramidFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _depthPyramidFramebuffer->setRenderBuffer(0, _depthPyramidTexture); _depthPyramidFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); diff --git a/libraries/render-utils/src/directional_ambient_light.slf b/libraries/render-utils/src/directional_ambient_light.slf index ae3b05862e..0d687f7204 100755 --- a/libraries/render-utils/src/directional_ambient_light.slf +++ b/libraries/render-utils/src/directional_ambient_light.slf @@ -27,7 +27,7 @@ void main(void) { DeferredTransform deferredTransform = getDeferredTransform(); DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); - if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { + if (frag.mode == LIGHT_MAPPED) { vec3 color = evalLightmappedColor( deferredTransform.viewInverse, 1.0, @@ -38,7 +38,7 @@ void main(void) { } else { vec3 color = evalAmbienSphereGlobalColor( deferredTransform.viewInverse, - 1.0, + frag.obscurance, frag.position.xyz, frag.normal, frag.diffuse, diff --git a/libraries/render-utils/src/directional_light.slf b/libraries/render-utils/src/directional_light.slf index 22b0157762..b8731054da 100644 --- a/libraries/render-utils/src/directional_light.slf +++ b/libraries/render-utils/src/directional_light.slf @@ -28,7 +28,7 @@ void main(void) { DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); // Light mapped or not ? - if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { + if (frag.mode == LIGHT_MAPPED) { vec3 color = evalLightmappedColor( deferredTransform.viewInverse, 1.0, @@ -39,7 +39,7 @@ void main(void) { } else { vec3 color = evalAmbienGlobalColor( deferredTransform.viewInverse, - 1.0, + frag.obscurance, frag.position.xyz, frag.normal, frag.diffuse, diff --git a/libraries/render-utils/src/directional_skybox_light.slf b/libraries/render-utils/src/directional_skybox_light.slf index ca3efef047..742518eed4 100755 --- a/libraries/render-utils/src/directional_skybox_light.slf +++ b/libraries/render-utils/src/directional_skybox_light.slf @@ -28,7 +28,7 @@ void main(void) { DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); // Light mapped or not ? - if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { + if (frag.mode == LIGHT_MAPPED) { vec3 color = evalLightmappedColor( deferredTransform.viewInverse, 1.0, @@ -39,7 +39,7 @@ void main(void) { } else { vec3 color = evalSkyboxGlobalColor( deferredTransform.viewInverse, - 1.0, + frag.obscurance, frag.position.xyz, frag.normal, frag.diffuse, diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 9692127005..ad696b50be 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -11,9 +11,28 @@ <@if not SSAO_SLH@> <@def SSAO_SLH@> +<@func declarePackOcclusionDepth()@> + +const float FAR_PLANE_Z = -300.0; + +float CSZToDephtKey(float z) { + return clamp(z * (1.0 / FAR_PLANE_Z), 0.0, 1.0); +} +vec3 packOcclusionDepth(float occlusion, float depth) { + // Round to the nearest 1/256.0 + float temp = floor(depth * 256.0); + return vec3(occlusion, temp * (1.0 / 256.0), depth * 256.0 - temp); +} +vec2 unpackOcclusionDepth(vec3 packed) { + float z = packed.y * (256.0 / 257.0) + packed.z * (1.0 / 257.0); + return vec2(packed.x, z); +} +<@endfunc@> + <@func declareAmbientOcclusion()@> struct AmbientOcclusionParams { + vec4 _pixelInfo; vec4 _clipInfo; mat4 _projection; vec4 _radius_radius2_InvRadius6_s2; @@ -23,8 +42,11 @@ uniform ambientOcclusionParamsBuffer { AmbientOcclusionParams params; }; +vec2 getWidthHeight() { + return params._pixelInfo.zw; +} float getProjScale() { - return 500.0; // this should be viewportHeight * Proj[1][1] / 2.0 + return getWidthHeight().y * params._projection[1][1] * 0.5; } float getRadius() { @@ -50,8 +72,77 @@ vec3 evalEyePositionFromZeye(float Zeye, vec2 texcoord) { } vec3 evalEyeNormal(vec3 C) { - return normalize(cross(dFdy(C), dFdx(C))); + //return normalize(cross(dFdy(C), dFdx(C))); + return normalize(cross(dFdx(C), dFdy(C))); } + +<@endfunc@> + +<@func declareBlurPass(axis)@> + +<$declarePackOcclusionDepth()$> + +// the source occlusion texture +uniform sampler2D occlusionMap; + +vec2 fetchOcclusionDepthRaw(ivec2 coords, out vec3 raw) { + raw = texelFetch(occlusionMap, coords, 0).xyz; + return unpackOcclusionDepth(raw); +} + +vec2 fetchOcclusionDepth(ivec2 coords) { + return unpackOcclusionDepth(texelFetch(occlusionMap, coords, 0).xyz); +} + + +const int BLUR_RADIUS = 4; +const int RADIUS_SCALE = 2; +const float EDGE_SHARPNESS = 1.0; + +const float gaussian[BLUR_RADIUS + 1] = +// float[](0.356642, 0.239400, 0.072410, 0.009869); // R = 2 +// float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // R = 3 +float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // R = 4 +// float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // R = 5.0 + +vec3 getBlurredOcclusion(vec2 coord) { + ivec2 ssC = ivec2(coord); + + vec3 rawSample; + vec2 occlusionDepth = fetchOcclusionDepthRaw(ssC, rawSample); + float key = occlusionDepth.y; + float sum = occlusionDepth.x; + + // Base weight for depth falloff. Increase this for more blurriness, + // decrease it for better edge discrimination + float BASE = gaussian[0]; + float totalWeight = BASE; + sum *= totalWeight; + + for (int r = -BLUR_RADIUS; r <= BLUR_RADIUS; ++r) { + // We already handled the zero case above. This loop should be unrolled and the static branch optimized out, + // so the IF statement has no runtime cost + if (r != 0) { + vec2 tapOZ = fetchOcclusionDepth(ssC + <$axis$> * (r * RADIUS_SCALE)); + + // spatial domain: offset gaussian tap + float weight = 0.3 + gaussian[abs(r)]; + + // range domain (the "bilateral" weight). As depth difference increases, decrease weight. + weight *= max(0.0, 1.0 - (EDGE_SHARPNESS * 2000.0) * abs(tapOZ.y - key)); + + sum += tapOZ.x * weight; + totalWeight += weight; + } + } + + const float epsilon = 0.0001; + float result = sum / (totalWeight + epsilon); + + rawSample.x = result; + return rawSample; +} + <@endfunc@> diff --git a/libraries/render-utils/src/ssao_makeHorizontalBlur.slf b/libraries/render-utils/src/ssao_makeHorizontalBlur.slf index dcef20c480..7be4f527ce 100644 --- a/libraries/render-utils/src/ssao_makeHorizontalBlur.slf +++ b/libraries/render-utils/src/ssao_makeHorizontalBlur.slf @@ -10,14 +10,14 @@ // <@include ssao.slh@> -<$declareAmbientOcclusion()$> -// the depth texture -uniform sampler2D occlusionMap; +const ivec2 horizontal = ivec2(1,0); +<$declareBlurPass(horizontal)$> + in vec2 varTexCoord0; out vec4 outFragColor; void main(void) { - outFragColor = texture(occlusionMap, varTexCoord0); + outFragColor = vec4(getBlurredOcclusion(gl_FragCoord.xy), 1.0); } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 6793be6978..3193bd05d4 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -11,6 +11,7 @@ <@include ssao.slh@> <$declareAmbientOcclusion()$> +<$declarePackOcclusionDepth()$> const int NUM_SAMPLES = 11; const float INV_NUM_SAMPLES = 1.0 / float(NUM_SAMPLES); @@ -21,34 +22,15 @@ const int MAX_MIP_LEVEL = 5; // the depth pyramid texture uniform sampler2D pyramidMap; -float getZeye(vec2 texcoord) { - return -texture(pyramidMap, texcoord, 0).x; -} - vec3 evalEyePosition(vec2 texcoord) { - float Zeye = getZeye(texcoord); + float Zeye = -texture(pyramidMap, texcoord, 0).x; return evalEyePositionFromZeye(Zeye, texcoord); } in vec2 varTexCoord0; out vec4 outFragColor; -/** Used for packing Z into the GB channels */ -float CSZToKey(float z) { - return clamp(z * (1.0 / params._clipInfo.z), 0.0, 1.0); -} - -/** Used for packing Z into the GB channels */ -void packKey(float key, out vec2 p) { - // Round to the nearest 1/256.0 - float temp = floor(key * 256.0); - - // Integer part - p.x = temp * (1.0 / 256.0); - - // Fractional part - p.y = key * 256.0 - temp; -} +uniform sampler2D normalMap; vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ // Radius relative to ssR @@ -76,7 +58,7 @@ vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) { // Offset to pixel center //P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); - vec2 tapUV = (vec2(ssP) + vec2(0.5)) / textureSize(pyramidMap, 0); + vec2 tapUV = (vec2(ssP) + vec2(0.5)) / getWidthHeight(); P = evalEyePositionFromZeye(P.z, tapUV); return P; } @@ -128,14 +110,11 @@ void main(void) { vec3 Cp = evalEyePosition(varTexCoord0); - // packKey(CSZToKey(Cp.z), bilateralKey); - // Hash function used in the HPG12 AlchemyAO paper float randomPatternRotationAngle = (3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10; - //float randomPatternRotationAngle = 0; - vec3 Cn = evalEyeNormal(Cp); + // vec3 Cn = normalize((texelFetch(normalMap, ssC, 0).xyz * 2.0) - vec3(1.0)); // Choose the screen-space sample radius // proportional to the projected area of the sphere @@ -143,20 +122,20 @@ void main(void) { float sum = 0.0; for (int i = 0; i < NUM_SAMPLES; ++i) { - sum += sampleAO(ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); + sum += sampleAO(ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); } float A = max(0.0, 1.0 - sum * getInvRadius6() * 5.0 * INV_NUM_SAMPLES); // Bilateral box-filter over a quad for free, respecting depth edges // (the difference that this makes is subtle) - if (abs(dFdx(Cp.z)) < 0.02) { + /*if (abs(dFdx(Cp.z)) < 0.02) { A -= dFdx(A) * ((ssC.x & 1) - 0.5); } if (abs(dFdy(Cp.z)) < 0.02) { A -= dFdy(A) * ((ssC.y & 1) - 0.5); - } + }*/ - - outFragColor = vec4(A, debugValue(Cn.y, 10)); + outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); + //outFragColor = vec4(0.5 * (Cn + vec3(1.0)), A); } diff --git a/libraries/render-utils/src/ssao_makeVerticalBlur.slf b/libraries/render-utils/src/ssao_makeVerticalBlur.slf index e1ed114817..40ad63b94e 100644 --- a/libraries/render-utils/src/ssao_makeVerticalBlur.slf +++ b/libraries/render-utils/src/ssao_makeVerticalBlur.slf @@ -8,16 +8,15 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - <@include ssao.slh@> -<$declareAmbientOcclusion()$> -// the depth texture -uniform sampler2D occlusionMap; +const ivec2 vertical = ivec2(0,1); +<$declareBlurPass(vertical)$> in vec2 varTexCoord0; out vec4 outFragColor; void main(void) { - outFragColor = vec4(0.0, 0.0, 0.0, texture(occlusionMap, varTexCoord0).x); + float occlusion = getBlurredOcclusion(gl_FragCoord.xy).x; + outFragColor = vec4(0.0, 0.0, 0.0, occlusion); } From 387706ea641bad9f6ead243067a01b0cc644deaf Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 4 Jan 2016 19:45:43 -0400 Subject: [PATCH 07/32] Fix shader-test compilation --- tests/shaders/src/main.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp index 0c63ee77c1..69b5ce5428 100644 --- a/tests/shaders/src/main.cpp +++ b/tests/shaders/src/main.cpp @@ -71,12 +71,6 @@ #include "textured_particle_frag.h" #include "textured_particle_vert.h" -#include "ambient_occlusion_vert.h" -#include "ambient_occlusion_frag.h" -#include "gaussian_blur_vertical_vert.h" -#include "gaussian_blur_horizontal_vert.h" -#include "gaussian_blur_frag.h" -#include "occlusion_blend_frag.h" #include "hit_effect_vert.h" #include "hit_effect_frag.h" @@ -210,12 +204,12 @@ void QTestWindow::draw() { testShaderBuild(model_shadow_vert, model_shadow_frag); testShaderBuild(untextured_particle_vert, untextured_particle_frag); testShaderBuild(textured_particle_vert, textured_particle_frag); - +/* FIXME: Bring back the ssao shader tests testShaderBuild(gaussian_blur_vertical_vert, gaussian_blur_frag); testShaderBuild(gaussian_blur_horizontal_vert, gaussian_blur_frag); testShaderBuild(ambient_occlusion_vert, ambient_occlusion_frag); testShaderBuild(ambient_occlusion_vert, occlusion_blend_frag); - +*/ testShaderBuild(hit_effect_vert, hit_effect_frag); testShaderBuild(overlay3D_vert, overlay3D_frag); From f92235b032c1401380f0dc5cb78d33c8157973de Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 4 Jan 2016 21:20:42 -0400 Subject: [PATCH 08/32] maybe fixes the compilation bug on windows/nvidia ? --- libraries/render-utils/src/ssao.slh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index ad696b50be..93b702b506 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -23,9 +23,9 @@ vec3 packOcclusionDepth(float occlusion, float depth) { float temp = floor(depth * 256.0); return vec3(occlusion, temp * (1.0 / 256.0), depth * 256.0 - temp); } -vec2 unpackOcclusionDepth(vec3 packed) { - float z = packed.y * (256.0 / 257.0) + packed.z * (1.0 / 257.0); - return vec2(packed.x, z); +vec2 unpackOcclusionDepth(vec3 raw) { + float z = raw.y * (256.0 / 257.0) + raw.z * (1.0 / 257.0); + return vec2(raw.x, z); } <@endfunc@> From c31b943b88db1b9b933aa0b2474116f662a89832 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 4 Jan 2016 23:02:30 -0400 Subject: [PATCH 09/32] APplying the AO to both direct lighting and ambient --- libraries/render-utils/src/DeferredGlobalLight.slh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 11e157a50c..cf7c6ede93 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -79,7 +79,7 @@ vec3 evalAmbienGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 positi vec4 fragEyeVector = invViewMat * vec4(-position, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); - vec3 color = diffuse.rgb * getLightColor(light) * getLightAmbientIntensity(light); + vec3 color = diffuse.rgb * getLightColor(light) * shadowAttenuation * getLightAmbientIntensity(light); vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); @@ -102,7 +102,7 @@ vec3 evalAmbienSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 vec3 fragEyeDir = normalize(fragEyeVector.xyz); vec3 ambientNormal = fragNormal.xyz; - vec3 color = diffuse.rgb * evalSphericalLight(ambientSphere, ambientNormal).xyz * getLightAmbientIntensity(light); + vec3 color = diffuse.rgb * evalSphericalLight(ambientSphere, ambientNormal).xyz * shadowAttenuation * getLightAmbientIntensity(light); vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); @@ -125,7 +125,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 positi vec4 fragEyeVector = invViewMat * vec4(-position, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); - vec3 color = diffuse.rgb * evalSphericalLight(ambientSphere, fragNormal).xyz * getLightAmbientIntensity(light); + vec3 color = diffuse.rgb * evalSphericalLight(ambientSphere, fragNormal).xyz * shadowAttenuation * getLightAmbientIntensity(light); vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); From 7e2cf741c00a23323b5677655a800fff18b348b0 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 6 Jan 2016 13:16:16 -0400 Subject: [PATCH 10/32] Clen up, exposingthe level of obscurance --- examples/utilities/tools/renderEngineDebug.js | 7 +++- .../src/AmbientOcclusionEffect.cpp | 23 +++++++++--- .../render-utils/src/AmbientOcclusionEffect.h | 20 +++++++--- .../render-utils/src/RenderDeferredTask.cpp | 1 + .../src/RenderScriptingInterface.h | 1 + libraries/render-utils/src/ssao.slh | 37 +++++++++++-------- .../render-utils/src/ssao_makeOcclusion.slf | 17 +++------ libraries/render/src/render/Engine.h | 3 +- 8 files changed, 68 insertions(+), 41 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index a6a6d1252f..fe5ce1e668 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -52,7 +52,7 @@ var overlaysCounter = new CounterWidget(panel, "Overlays", Render.overlay3D); var resizing = false; var previousMode = Settings.getValue(SETTINGS_KEY, -1); -previousMode = 4; // FIXME: just for debug purpose +previousMode = 1; // FIXME: just for debug purpose Menu.addActionGroup(MENU, ACTIONS, ACTIONS[previousMode + 1]); Render.deferredDebugMode = previousMode; Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 }; // Reset to default size @@ -104,6 +104,11 @@ panel.newSlider("Ambient Occlusion Radius", 0.0, 2.0, function() { return Render.ambientOcclusion.radius; }, function (value) { return (value); }); +panel.newSlider("Ambient Occlusion Level", 0.0, 1.0, + function (value) { Render.ambientOcclusion.level = value; }, + function() { return Render.ambientOcclusion.level; }, + function (value) { return (value); }); + var tickTackPeriod = 500; function updateCounters() { diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index eb51fa68ea..732ec71228 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -154,14 +154,27 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { } -void AmbientOcclusionEffect::setClipInfo(float nearZ, float farZ) { - _parametersBuffer.edit()._clipInfo = glm::vec4(nearZ*farZ, farZ -nearZ, -farZ, 0.0f); +void AmbientOcclusionEffect::setDepthInfo(float nearZ, float farZ) { + _parametersBuffer.edit()._depthInfo = glm::vec4(nearZ*farZ, farZ -nearZ, -farZ, 0.0f); } void AmbientOcclusionEffect::setRadius(float radius) { radius = std::max(0.01f, radius); - _parametersBuffer.edit()._radius_radius2_InvRadius6_s2 = glm::vec4(radius, radius * radius, 1.0f / pow(radius, 6.0f), 0.0f); + if (radius != getRadius()) { + auto& current = _parametersBuffer.edit()._radiusInfo; + current.x = radius; + current.y = radius * radius; + current.z = 1.0f / pow(radius, 6.0f); + } +} + +void AmbientOcclusionEffect::setLevel(float level) { + level = std::max(0.01f, level); + if (level != getLevel()) { + auto& current = _parametersBuffer.edit()._radiusInfo; + current.w = level; + } } void AmbientOcclusionEffect::updateDeferredTransformBuffer(const render::RenderContextPointer& renderContext) { @@ -290,8 +303,8 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext mat4 monoProjMat; args->_viewFrustum->evalProjectionMatrix(monoProjMat); - setClipInfo(args->_viewFrustum->getNearClip(), args->_viewFrustum->getFarClip()); - _parametersBuffer.edit()._projection = monoProjMat; + setDepthInfo(args->_viewFrustum->getNearClip(), args->_viewFrustum->getFarClip()); + _parametersBuffer.edit()._projection[0] = monoProjMat; _parametersBuffer.edit()._pixelInfo = args->_viewport; auto pyramidPipeline = getPyramidPipeline(); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 4eecfc3fc7..5e03f74e8b 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -25,20 +25,28 @@ public: typedef render::Job::Model JobModel; void setRadius(float radius); - float getRadius() const { return _parametersBuffer.get()._radius_radius2_InvRadius6_s2.x; } + float getRadius() const { return _parametersBuffer.get()._radiusInfo.x; } + + // Obscurance level which intensify or dim down the obscurance effect + void setLevel(float level); + float getLevel() const { return _parametersBuffer.get()._radiusInfo.w; } private: - void setClipInfo(float nearZ, float farZ); + void setDepthInfo(float nearZ, float farZ); // Class describing the uniform buffer with all the parameters common to the AO shaders class Parameters { public: + // radius info is { R, R^2, 1 / R^6, ObscuranceScale} + glm::vec4 _radiusInfo{ 0.5, 0.5 * 0.5, 1.0 / (0.25 * 0.25 * 0.25), 1.0 }; + // Pixel info is { viemport width height and stereo on off} glm::vec4 _pixelInfo; - glm::vec4 _clipInfo; - glm::mat4 _projection; - glm::vec4 _radius_radius2_InvRadius6_s2{ 0.5, 0.5 * 0.5, 1.0 / (0.25 * 0.25 * 0.25), 0.0 }; - + // Depth info is { n.f, f - n, -f} + glm::vec4 _depthInfo; + // Mono proj matrix or Left and Right proj matrix going from Mono Eye space to side clip space + glm::mat4 _projection[2]; + Parameters() {} }; typedef gpu::BufferView UniformBufferView; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 9614229122..2574f22a8c 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -160,6 +160,7 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend setOcclusionStatus(renderContext->getOcclusionStatus()); if (_occlusionJobIndex >= 0) { _jobs[_occlusionJobIndex].edit().setRadius(renderContext->getAmbientOcclusion().radius); + _jobs[_occlusionJobIndex].edit().setLevel(renderContext->getAmbientOcclusion().level); } setAntialiasingStatus(renderContext->getFxaaStatus()); diff --git a/libraries/render-utils/src/RenderScriptingInterface.h b/libraries/render-utils/src/RenderScriptingInterface.h index b330c23fc9..19d50ce1db 100644 --- a/libraries/render-utils/src/RenderScriptingInterface.h +++ b/libraries/render-utils/src/RenderScriptingInterface.h @@ -71,6 +71,7 @@ namespace RenderScripting { public: Q_PROPERTY(float radius MEMBER radius) + Q_PROPERTY(float level MEMBER level) }; using AmbientOcclusionPointer = std::unique_ptr; }; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 93b702b506..5bac9c6335 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -32,10 +32,10 @@ vec2 unpackOcclusionDepth(vec3 raw) { <@func declareAmbientOcclusion()@> struct AmbientOcclusionParams { + vec4 _radiusInfo; vec4 _pixelInfo; - vec4 _clipInfo; - mat4 _projection; - vec4 _radius_radius2_InvRadius6_s2; + vec4 _depthInfo; + mat4 _projection[2]; }; uniform ambientOcclusionParamsBuffer { @@ -46,28 +46,34 @@ vec2 getWidthHeight() { return params._pixelInfo.zw; } float getProjScale() { - return getWidthHeight().y * params._projection[1][1] * 0.5; + return getWidthHeight().y * params._projection[0][1][1] * 0.5; +} +mat4 getProjection(int side) { + return params._projection[side]; } float getRadius() { - return params._radius_radius2_InvRadius6_s2.x; + return params._radiusInfo.x; } float getRadius2() { - return params._radius_radius2_InvRadius6_s2.y; + return params._radiusInfo.y; } float getInvRadius6() { - return params._radius_radius2_InvRadius6_s2.z; + return params._radiusInfo.z; +} +float getObscuranceScaling() { + return params._radiusInfo.z * params._radiusInfo.w; } float evalZeyeFromZdb(float depth) { - return params._clipInfo.x / (depth * params._clipInfo.y + params._clipInfo.z); + return params._depthInfo.x / (depth * params._depthInfo.y + params._depthInfo.z); } vec3 evalEyePositionFromZeye(float Zeye, vec2 texcoord) { // compute the view space position using the depth // basically manually pick the proj matrix components to do the inverse - float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * params._projection[2][0] - params._projection[3][0]) / params._projection[0][0]; - float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * params._projection[2][1] - params._projection[3][1]) / params._projection[1][1]; + float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * params._projection[0][2][0] - params._projection[0][3][0]) / params._projection[0][0][0]; + float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * params._projection[0][2][1] - params._projection[0][3][1]) / params._projection[0][1][1]; return vec3(Xe, Ye, Zeye); } @@ -96,15 +102,14 @@ vec2 fetchOcclusionDepth(ivec2 coords) { const int BLUR_RADIUS = 4; -const int RADIUS_SCALE = 2; +const int RADIUS_SCALE = 3; const float EDGE_SHARPNESS = 1.0; const float gaussian[BLUR_RADIUS + 1] = -// float[](0.356642, 0.239400, 0.072410, 0.009869); // R = 2 -// float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // R = 3 -float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // R = 4 -// float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // R = 5.0 - +// float[](0.356642, 0.239400, 0.072410, 0.009869); +// float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0 +float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0 +// float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0 vec3 getBlurredOcclusion(vec2 coord) { ivec2 ssC = ivec2(coord); diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 3193bd05d4..6b5b768a28 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -85,15 +85,8 @@ float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in i // return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6; // B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended] - float f = max(radius2 - vv, 0.0); return f * f * f * max((vn - bias) / (epsilon + vv), 0.0); - - // C: Medium contrast (which looks better at high radii), no division. Note that the - // contribution still falls off with radius^2, but we've adjusted the rate in a way that is - // more computationally efficient and happens to be aesthetically pleasing. - // return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0); - - // D: Low contrast, no division operation - // return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0); + float f = max(radius2 - vv, 0.0); + return f * f * f * max((vn - bias) / (epsilon + vv), 0.0); } vec3 debugValue(float f, float scale) { @@ -125,16 +118,16 @@ void main(void) { sum += sampleAO(ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); } - float A = max(0.0, 1.0 - sum * getInvRadius6() * 5.0 * INV_NUM_SAMPLES); + float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * INV_NUM_SAMPLES); // Bilateral box-filter over a quad for free, respecting depth edges // (the difference that this makes is subtle) - /*if (abs(dFdx(Cp.z)) < 0.02) { + if (abs(dFdx(Cp.z)) < 0.02) { A -= dFdx(A) * ((ssC.x & 1) - 0.5); } if (abs(dFdy(Cp.z)) < 0.02) { A -= dFdy(A) * ((ssC.y & 1) - 0.5); - }*/ + } outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); //outFragColor = vec4(0.5 * (Cn + vec3(1.0)), A); diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 277d66ce35..bf77081502 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -79,7 +79,8 @@ public: class AmbientOcclusion { public: - float radius = 0.5; // radius in meters of the AO effect + float radius = 0.5f; // radius in meters of the AO effect + float level = 0.5f; // Level of the obscrance value }; RenderContext(ItemsConfig items, Tone tone, AmbientOcclusion ao, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode); From f5854641f9ae594665a07e3e3abf590a459cf20a Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 11 Jan 2016 18:33:39 -0800 Subject: [PATCH 11/32] Trying to improve the ao --- libraries/render-utils/src/point_light.slf | 2 +- libraries/render-utils/src/spot_light.slf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/point_light.slf b/libraries/render-utils/src/point_light.slf index 716a39aee9..fcfb0b336e 100644 --- a/libraries/render-utils/src/point_light.slf +++ b/libraries/render-utils/src/point_light.slf @@ -67,7 +67,7 @@ void main(void) { // Final Lighting color vec3 fragColor = (shading.w * frag.diffuse + shading.xyz); - _fragColor = vec4(fragColor * radialAttenuation * getLightColor(light) * getLightIntensity(light), 0.0); + _fragColor = vec4(fragColor * radialAttenuation * getLightColor(light) * getLightIntensity(light) * frag.obscurance, 0.0); if (getLightShowContour(light) > 0.0) { // Show edge diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index d7a20fc5e5..8170929636 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -74,7 +74,7 @@ void main(void) { // Final Lighting color vec3 fragColor = (shading.w * frag.diffuse + shading.xyz); - _fragColor = vec4(fragColor * angularAttenuation * radialAttenuation * getLightColor(light) * getLightIntensity(light), 0.0); + _fragColor = vec4(fragColor * angularAttenuation * radialAttenuation * getLightColor(light) * getLightIntensity(light) * frag.obscurance, 0.0); if (getLightShowContour(light) > 0.0) { // Show edges From 89d2d102f63e6e22729212ce18c131a91a3e3e13 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 12 Jan 2016 18:51:30 -0800 Subject: [PATCH 12/32] exposing the ditheringEnable field --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 8 ++++++++ libraries/render-utils/src/AmbientOcclusionEffect.h | 6 ++++++ libraries/render-utils/src/RenderDeferredTask.cpp | 1 + libraries/render-utils/src/RenderScriptingInterface.h | 1 + libraries/render-utils/src/ssao.slh | 7 ++++++- libraries/render-utils/src/ssao_makeOcclusion.slf | 6 +++--- libraries/render/src/render/Context.h | 1 + 7 files changed, 26 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 732ec71228..dcc1447935 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -177,6 +177,14 @@ void AmbientOcclusionEffect::setLevel(float level) { } } + +void AmbientOcclusionEffect::setDithering(bool enabled) { + if (enabled != isDitheringEnabled()) { + auto& current = _parametersBuffer.edit()._performanceCaps; + current.x = (float)enabled; + } +} + void AmbientOcclusionEffect::updateDeferredTransformBuffer(const render::RenderContextPointer& renderContext) { // Allocate the parameters buffer used by all the deferred shaders if (!_deferredTransformBuffer[0]._buffer) { diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index accc8cdb6c..4c7093bebb 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -30,6 +30,10 @@ public: void setLevel(float level); float getLevel() const { return _parametersBuffer.get()._radiusInfo.w; } + void setDithering(bool enabled); + bool isDitheringEnabled() const { return _parametersBuffer.get()._performanceCaps.x; } + + using JobModel = render::Task::Job::Model; private: @@ -41,6 +45,8 @@ private: public: // radius info is { R, R^2, 1 / R^6, ObscuranceScale} glm::vec4 _radiusInfo{ 0.5, 0.5 * 0.5, 1.0 / (0.25 * 0.25 * 0.25), 1.0 }; + // Performance parameters to adjust the effect + glm::vec4 _performanceCaps{ 1.0, 1.0, 1.0, 1.0 }; // Pixel info is { viemport width height and stereo on off} glm::vec4 _pixelInfo; // Depth info is { n.f, f - n, -f} diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 9993b64d78..c7af44a8bb 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -183,6 +183,7 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend if (_occlusionJobIndex >= 0) { _jobs[_occlusionJobIndex].edit().setRadius(renderContext->getAmbientOcclusion().radius); _jobs[_occlusionJobIndex].edit().setLevel(renderContext->getAmbientOcclusion().level); + _jobs[_occlusionJobIndex].edit().setDithering(renderContext->getAmbientOcclusion().ditheringEnabled); } setAntialiasingStatus(renderContext->getFxaaStatus()); diff --git a/libraries/render-utils/src/RenderScriptingInterface.h b/libraries/render-utils/src/RenderScriptingInterface.h index 19d50ce1db..af6d67801b 100644 --- a/libraries/render-utils/src/RenderScriptingInterface.h +++ b/libraries/render-utils/src/RenderScriptingInterface.h @@ -72,6 +72,7 @@ namespace RenderScripting { public: Q_PROPERTY(float radius MEMBER radius) Q_PROPERTY(float level MEMBER level) + Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled) }; using AmbientOcclusionPointer = std::unique_ptr; }; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 5bac9c6335..fa08f7c4bc 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -33,6 +33,7 @@ vec2 unpackOcclusionDepth(vec3 raw) { struct AmbientOcclusionParams { vec4 _radiusInfo; + vec4 _performanceCaps; vec4 _pixelInfo; vec4 _depthInfo; mat4 _projection[2]; @@ -65,6 +66,10 @@ float getObscuranceScaling() { return params._radiusInfo.z * params._radiusInfo.w; } +float isDitheringEnabled() { + return params._performanceCaps.x; +} + float evalZeyeFromZdb(float depth) { return params._depthInfo.x / (depth * params._depthInfo.y + params._depthInfo.z); } @@ -102,7 +107,7 @@ vec2 fetchOcclusionDepth(ivec2 coords) { const int BLUR_RADIUS = 4; -const int RADIUS_SCALE = 3; +const int RADIUS_SCALE = 2; const float EDGE_SHARPNESS = 1.0; const float gaussian[BLUR_RADIUS + 1] = diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 6b5b768a28..03d5f04633 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -53,7 +53,8 @@ vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) { // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. // Manually clamp to the texture size because texelFetch bypasses the texture unit ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), textureSize(pyramidMap, mipLevel) - ivec2(1)); - P.z = -texelFetch(pyramidMap, mipP, mipLevel).r; +// P.z = -texelFetch(pyramidMap, mipP, mipLevel).r; + P.z = -texelFetch(pyramidMap, ssP, 0).r; // Offset to pixel center //P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); @@ -104,10 +105,9 @@ void main(void) { vec3 Cp = evalEyePosition(varTexCoord0); // Hash function used in the HPG12 AlchemyAO paper - float randomPatternRotationAngle = (3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10; + float randomPatternRotationAngle = isDitheringEnabled() * (3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10; vec3 Cn = evalEyeNormal(Cp); - // vec3 Cn = normalize((texelFetch(normalMap, ssC, 0).xyz * 2.0) - vec3(1.0)); // Choose the screen-space sample radius // proportional to the projected area of the sphere diff --git a/libraries/render/src/render/Context.h b/libraries/render/src/render/Context.h index 934cb0f07e..bfcf9eb858 100644 --- a/libraries/render/src/render/Context.h +++ b/libraries/render/src/render/Context.h @@ -76,6 +76,7 @@ public: public: float radius = 0.5f; // radius in meters of the AO effect float level = 0.5f; // Level of the obscrance value + bool ditheringEnabled = true; }; RenderContext(ItemsConfig items, Tone tone, AmbientOcclusion ao, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode); From 0285d48de3eb731dd29179285232b6aa73706b0e Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 13 Jan 2016 18:57:47 -0800 Subject: [PATCH 13/32] Exposing many more controls of the AO in order to adjust the effect --- examples/utilities/tools/renderEngineDebug.js | 15 +++++++++ .../src/AmbientOcclusionEffect.cpp | 32 +++++++++++++++++-- .../render-utils/src/AmbientOcclusionEffect.h | 21 ++++++++++-- .../render-utils/src/RenderDeferredTask.cpp | 3 ++ .../src/RenderScriptingInterface.h | 3 ++ libraries/render-utils/src/ssao.slh | 28 +++++++++++++--- .../render-utils/src/ssao_makeOcclusion.slf | 24 +++++++------- libraries/render/src/render/Context.h | 3 ++ 8 files changed, 108 insertions(+), 21 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index fe5ce1e668..ce697481d9 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -109,6 +109,21 @@ panel.newSlider("Ambient Occlusion Level", 0.0, 1.0, function() { return Render.ambientOcclusion.level; }, function (value) { return (value); }); +panel.newSlider("Ambient Occlusion Num Samples", 1, 32, + function (value) { Render.ambientOcclusion.numSamples = value; }, + function() { return Render.ambientOcclusion.numSamples; }, + function (value) { return (value); }); + +panel.newSlider("Ambient Occlusion Num Spiral Turns", 0.0, 30.0, + function (value) { Render.ambientOcclusion.numSpiralTurns = value; }, + function() { return Render.ambientOcclusion.numSpiralTurns; }, + function (value) { return (value); }); + +panel.newCheckbox("Ambient Occlusion Dithering", + function (value) { Render.ambientOcclusion.ditheringEnabled = value; }, + function() { return Render.ambientOcclusion.ditheringEnabled; }, + function (value) { return (value); }); + var tickTackPeriod = 500; function updateCounters() { diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index dcc1447935..44dfde13dc 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -177,11 +177,35 @@ void AmbientOcclusionEffect::setLevel(float level) { } } - void AmbientOcclusionEffect::setDithering(bool enabled) { if (enabled != isDitheringEnabled()) { - auto& current = _parametersBuffer.edit()._performanceCaps; - current.x = (float)enabled; + auto& current = _parametersBuffer.edit()._sampleInfo; + current.w = (float)enabled; + } +} + +void AmbientOcclusionEffect::setNumSamples(int numSamples) { + numSamples = std::max(1.f, (float) numSamples); + if (numSamples != getNumSamples()) { + auto& current = _parametersBuffer.edit()._sampleInfo; + current.x = numSamples; + current.y = 1.0 / numSamples; + } +} + +void AmbientOcclusionEffect::setNumSpiralTurns(float numTurns) { + numTurns = std::max(0.f, (float)numTurns); + if (numTurns != getNumSpiralTurns()) { + auto& current = _parametersBuffer.edit()._sampleInfo; + current.z = numTurns; + } +} + +void AmbientOcclusionEffect::setEdgeSharpness(float sharpness) { + sharpness = std::max(0.f, (float)sharpness); + if (sharpness != getEdgeSharpness()) { + auto& current = _parametersBuffer.edit()._blurInfo; + current.x = sharpness; } } @@ -314,6 +338,8 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext setDepthInfo(args->_viewFrustum->getNearClip(), args->_viewFrustum->getFarClip()); _parametersBuffer.edit()._projection[0] = monoProjMat; _parametersBuffer.edit()._pixelInfo = args->_viewport; + _parametersBuffer.edit()._ditheringInfo.y += 0.25f; + auto pyramidPipeline = getPyramidPipeline(); auto occlusionPipeline = getOcclusionPipeline(); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 4c7093bebb..ce8a0abfe2 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -31,8 +31,19 @@ public: float getLevel() const { return _parametersBuffer.get()._radiusInfo.w; } void setDithering(bool enabled); - bool isDitheringEnabled() const { return _parametersBuffer.get()._performanceCaps.x; } + bool isDitheringEnabled() const { return _parametersBuffer.get()._ditheringInfo.w; } + // Number of samples per pixel to evaluate the Obscurance + void setNumSamples(int numSamples); + int getNumSamples() const { return (int)_parametersBuffer.get()._sampleInfo.x; } + + // Number of spiral turns defining an angle span to distribute the samples ray directions + void setNumSpiralTurns(float numTurns); + float getNumSpiralTurns() const { return _parametersBuffer.get()._sampleInfo.z; } + + // Edge blurring setting + void setEdgeSharpness(float sharpness); + int getEdgeSharpness() const { return (int)_parametersBuffer.get()._blurInfo.x; } using JobModel = render::Task::Job::Model; @@ -45,8 +56,12 @@ private: public: // radius info is { R, R^2, 1 / R^6, ObscuranceScale} glm::vec4 _radiusInfo{ 0.5, 0.5 * 0.5, 1.0 / (0.25 * 0.25 * 0.25), 1.0 }; - // Performance parameters to adjust the effect - glm::vec4 _performanceCaps{ 1.0, 1.0, 1.0, 1.0 }; + // Dithering info + glm::vec4 _ditheringInfo{ 1.0, 0.0, 0.0, 0.0 }; + // Sampling info + glm::vec4 _sampleInfo{ 11.0, 1.0/11.0, 7.0, 1.0 }; + // Blurring info + glm::vec4 _blurInfo{ 1.0, 0.0, 0.0, 0.0 }; // Pixel info is { viemport width height and stereo on off} glm::vec4 _pixelInfo; // Depth info is { n.f, f - n, -f} diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index c7af44a8bb..a7bdd42b7e 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -183,7 +183,10 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend if (_occlusionJobIndex >= 0) { _jobs[_occlusionJobIndex].edit().setRadius(renderContext->getAmbientOcclusion().radius); _jobs[_occlusionJobIndex].edit().setLevel(renderContext->getAmbientOcclusion().level); + _jobs[_occlusionJobIndex].edit().setNumSamples(renderContext->getAmbientOcclusion().numSamples); + _jobs[_occlusionJobIndex].edit().setNumSpiralTurns(renderContext->getAmbientOcclusion().numSpiralTurns); _jobs[_occlusionJobIndex].edit().setDithering(renderContext->getAmbientOcclusion().ditheringEnabled); + _jobs[_occlusionJobIndex].edit().setEdgeSharpness(renderContext->getAmbientOcclusion().edgeSharpness); } setAntialiasingStatus(renderContext->getFxaaStatus()); diff --git a/libraries/render-utils/src/RenderScriptingInterface.h b/libraries/render-utils/src/RenderScriptingInterface.h index af6d67801b..30ff17c47b 100644 --- a/libraries/render-utils/src/RenderScriptingInterface.h +++ b/libraries/render-utils/src/RenderScriptingInterface.h @@ -72,7 +72,10 @@ namespace RenderScripting { public: Q_PROPERTY(float radius MEMBER radius) Q_PROPERTY(float level MEMBER level) + Q_PROPERTY(int numSamples MEMBER numSamples) + Q_PROPERTY(float numSpiralTurns MEMBER numSpiralTurns) Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled) + Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness) }; using AmbientOcclusionPointer = std::unique_ptr; }; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index fa08f7c4bc..61bc6cbe89 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -33,7 +33,9 @@ vec2 unpackOcclusionDepth(vec3 raw) { struct AmbientOcclusionParams { vec4 _radiusInfo; - vec4 _performanceCaps; + vec4 _ditheringInfo; + vec4 _sampleInfo; + vec4 _blurInfo; vec4 _pixelInfo; vec4 _depthInfo; mat4 _projection[2]; @@ -67,7 +69,25 @@ float getObscuranceScaling() { } float isDitheringEnabled() { - return params._performanceCaps.x; + return params._ditheringInfo.x; +} +float getFrameDithering() { + return params._ditheringInfo.y; +} + + +float getNumSamples() { + return params._sampleInfo.x; +} +float getInvNumSamples() { + return params._sampleInfo.y; +} +float getNumSpiralTurns() { + return params._sampleInfo.z; +} + +float getBlurEdgeSharpness() { + return params._blurInfo.x; } float evalZeyeFromZdb(float depth) { @@ -92,6 +112,7 @@ vec3 evalEyeNormal(vec3 C) { <@func declareBlurPass(axis)@> <$declarePackOcclusionDepth()$> +<$declareAmbientOcclusion()$> // the source occlusion texture uniform sampler2D occlusionMap; @@ -108,7 +129,6 @@ vec2 fetchOcclusionDepth(ivec2 coords) { const int BLUR_RADIUS = 4; const int RADIUS_SCALE = 2; -const float EDGE_SHARPNESS = 1.0; const float gaussian[BLUR_RADIUS + 1] = // float[](0.356642, 0.239400, 0.072410, 0.009869); @@ -139,7 +159,7 @@ vec3 getBlurredOcclusion(vec2 coord) { float weight = 0.3 + gaussian[abs(r)]; // range domain (the "bilateral" weight). As depth difference increases, decrease weight. - weight *= max(0.0, 1.0 - (EDGE_SHARPNESS * 2000.0) * abs(tapOZ.y - key)); + weight *= max(0.0, 1.0 - (getBlurEdgeSharpness() * 2000.0) * abs(tapOZ.y - key)); sum += tapOZ.x * weight; totalWeight += weight; diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 03d5f04633..1da18b8ef8 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -13,9 +13,7 @@ <$declareAmbientOcclusion()$> <$declarePackOcclusionDepth()$> -const int NUM_SAMPLES = 11; -const float INV_NUM_SAMPLES = 1.0 / float(NUM_SAMPLES); -const int NUM_SPIRAL_TURNS= 7; + const int LOG_MAX_OFFSET = 3; const int MAX_MIP_LEVEL = 5; @@ -32,10 +30,15 @@ out vec4 outFragColor; uniform sampler2D normalMap; +float getAngleDithering(in ivec2 pixelPos) { + // Hash function used in the AlchemyAO paper + return isDitheringEnabled() * (3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10 + getFrameDithering(); +} + vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ // Radius relative to ssR - float alpha = float(sampleNumber + 0.5) * INV_NUM_SAMPLES; - float angle = alpha * (NUM_SPIRAL_TURNS * 6.28) + spinAngle; + float alpha = float(sampleNumber + 0.5) * getInvNumSamples(); + float angle = alpha * (getNumSpiralTurns() * 6.28) + spinAngle; ssR = alpha; return vec2(cos(angle), sin(angle)); @@ -53,8 +56,8 @@ vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) { // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. // Manually clamp to the texture size because texelFetch bypasses the texture unit ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), textureSize(pyramidMap, mipLevel) - ivec2(1)); -// P.z = -texelFetch(pyramidMap, mipP, mipLevel).r; - P.z = -texelFetch(pyramidMap, ssP, 0).r; + P.z = -texelFetch(pyramidMap, mipP, mipLevel).r; +// P.z = -texelFetch(pyramidMap, ssP, 0).r; // Offset to pixel center //P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); @@ -104,8 +107,7 @@ void main(void) { vec3 Cp = evalEyePosition(varTexCoord0); - // Hash function used in the HPG12 AlchemyAO paper - float randomPatternRotationAngle = isDitheringEnabled() * (3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10; + float randomPatternRotationAngle = getAngleDithering(ssC); vec3 Cn = evalEyeNormal(Cp); @@ -114,11 +116,11 @@ void main(void) { float ssDiskRadius = -getProjScale() * getRadius() / Cp.z; float sum = 0.0; - for (int i = 0; i < NUM_SAMPLES; ++i) { + for (int i = 0; i < getNumSamples(); ++i) { sum += sampleAO(ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); } - float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * INV_NUM_SAMPLES); + float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples()); // Bilateral box-filter over a quad for free, respecting depth edges // (the difference that this makes is subtle) diff --git a/libraries/render/src/render/Context.h b/libraries/render/src/render/Context.h index bfcf9eb858..fd6c25dfde 100644 --- a/libraries/render/src/render/Context.h +++ b/libraries/render/src/render/Context.h @@ -76,7 +76,10 @@ public: public: float radius = 0.5f; // radius in meters of the AO effect float level = 0.5f; // Level of the obscrance value + int numSamples = 11; // Num Samples per pixel + float numSpiralTurns = 7.0f; bool ditheringEnabled = true; + float edgeSharpness = 1.0f; }; RenderContext(ItemsConfig items, Tone tone, AmbientOcclusion ao, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode); From ae18bb8ef739058d1f1058087eb981ec1202a144 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 14 Jan 2016 19:23:29 -0800 Subject: [PATCH 14/32] FIxed the stereo rendering --- examples/utilities/tools/renderEngineDebug.js | 4 +- .../src/AmbientOcclusionEffect.cpp | 49 +++++++++++++---- .../render-utils/src/AmbientOcclusionEffect.h | 6 ++- libraries/render-utils/src/ssao.slh | 21 +++++--- .../render-utils/src/ssao_makeOcclusion.slf | 54 ++++++++++++------- .../render-utils/src/ssao_makePyramid.slf | 4 +- 6 files changed, 95 insertions(+), 43 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index ce697481d9..e6d15653a3 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -52,11 +52,13 @@ var overlaysCounter = new CounterWidget(panel, "Overlays", Render.overlay3D); var resizing = false; var previousMode = Settings.getValue(SETTINGS_KEY, -1); -previousMode = 1; // FIXME: just for debug purpose +previousMode = 8; // FIXME: just for debug purpose Menu.addActionGroup(MENU, ACTIONS, ACTIONS[previousMode + 1]); Render.deferredDebugMode = previousMode; Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 }; // Reset to default size +Render.deferredDebugSize = { x: -0.5, y: -1.0, z: 1.0, w: 1.0 }; // Reset to default size + function setEngineDeferredDebugSize(eventX) { var scaledX = (2.0 * (eventX / Window.innerWidth) - 1.0).clamp(-1.0, 1.0); Render.deferredDebugSize = { x: scaledX, y: -1.0, z: 1.0, w: 1.0 }; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 87b7a0643d..f7269d8206 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -178,8 +178,8 @@ void AmbientOcclusionEffect::setLevel(float level) { void AmbientOcclusionEffect::setDithering(bool enabled) { if (enabled != isDitheringEnabled()) { - auto& current = _parametersBuffer.edit()._sampleInfo; - current.w = (float)enabled; + auto& current = _parametersBuffer.edit()._ditheringInfo; + current.x = (float)enabled; } } @@ -331,16 +331,47 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext updateDeferredTransformBuffer(renderContext); - // Eval the mono projection - mat4 monoProjMat; - args->_viewFrustum->evalProjectionMatrix(monoProjMat); - + // Update the depth info with near and far (same for stereo) setDepthInfo(args->_viewFrustum->getNearClip(), args->_viewFrustum->getFarClip()); - _parametersBuffer.edit()._projection[0] = monoProjMat; - _parametersBuffer.edit()._pixelInfo = args->_viewport; - _parametersBuffer.edit()._ditheringInfo.y += 0.25f; + _parametersBuffer.edit()._pixelInfo = args->_viewport; + //_parametersBuffer.edit()._ditheringInfo.y += 0.25f; + + // Running in stero ? + bool isStereo = args->_context->isStereo(); + if (!isStereo) { + // Eval the mono projection + mat4 monoProjMat; + args->_viewFrustum->evalProjectionMatrix(monoProjMat); + _parametersBuffer.edit()._projection[0] = monoProjMat; + _parametersBuffer.edit()._stereoInfo = glm::vec4(0.0f, args->_viewport.z, 0.0f, 0.0f); + + } else { + + mat4 projMats[2]; + Transform viewTransforms[2]; + + DeferredTransform deferredTransforms[2]; + + + mat4 eyeViews[2]; + args->_context->getStereoProjections(projMats); + args->_context->getStereoViews(eyeViews); + + float halfWidth = 0.5f * sWidth; + + for (int i = 0; i < 2; i++) { + // Compose the mono Eye space to Stereo clip space Projection Matrix + auto sideViewMat = projMats[i] * eyeViews[i]; + + _parametersBuffer.edit()._projection[i] = sideViewMat; + } + + _parametersBuffer.edit()._stereoInfo = glm::vec4(1.0f, (float)(args->_viewport.z >> 1), 0.0f, 1.0f); + + } + auto pyramidPipeline = getPyramidPipeline(); auto occlusionPipeline = getOcclusionPipeline(); auto firstHBlurPipeline = getHBlurPipeline(); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index ce8a0abfe2..fd368682bd 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -31,7 +31,7 @@ public: float getLevel() const { return _parametersBuffer.get()._radiusInfo.w; } void setDithering(bool enabled); - bool isDitheringEnabled() const { return _parametersBuffer.get()._ditheringInfo.w; } + bool isDitheringEnabled() const { return _parametersBuffer.get()._ditheringInfo.x; } // Number of samples per pixel to evaluate the Obscurance void setNumSamples(int numSamples); @@ -57,7 +57,7 @@ private: // radius info is { R, R^2, 1 / R^6, ObscuranceScale} glm::vec4 _radiusInfo{ 0.5, 0.5 * 0.5, 1.0 / (0.25 * 0.25 * 0.25), 1.0 }; // Dithering info - glm::vec4 _ditheringInfo{ 1.0, 0.0, 0.0, 0.0 }; + glm::vec4 _ditheringInfo{ 0.0, 0.0, 0.0, 0.0 }; // Sampling info glm::vec4 _sampleInfo{ 11.0, 1.0/11.0, 7.0, 1.0 }; // Blurring info @@ -66,6 +66,8 @@ private: glm::vec4 _pixelInfo; // Depth info is { n.f, f - n, -f} glm::vec4 _depthInfo; + // Stereo info + glm::vec4 _stereoInfo{ 0.0 }; // Mono proj matrix or Left and Right proj matrix going from Mono Eye space to side clip space glm::mat4 _projection[2]; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 61bc6cbe89..43106e1d14 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -38,6 +38,7 @@ struct AmbientOcclusionParams { vec4 _blurInfo; vec4 _pixelInfo; vec4 _depthInfo; + vec4 _stereoInfo; mat4 _projection[2]; }; @@ -90,16 +91,20 @@ float getBlurEdgeSharpness() { return params._blurInfo.x; } -float evalZeyeFromZdb(float depth) { - return params._depthInfo.x / (depth * params._depthInfo.y + params._depthInfo.z); +bool isStereo() { + return params._stereoInfo.x > 0.0f; } -vec3 evalEyePositionFromZeye(float Zeye, vec2 texcoord) { - // compute the view space position using the depth - // basically manually pick the proj matrix components to do the inverse - float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * params._projection[0][2][0] - params._projection[0][3][0]) / params._projection[0][0][0]; - float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * params._projection[0][2][1] - params._projection[0][3][1]) / params._projection[0][1][1]; - return vec3(Xe, Ye, Zeye); +ivec2 getStereoSideInfo(int xPos) { + return (xPos < params._stereoInfo.y ? ivec2(0, 0) : ivec2(1, int(params._stereoInfo.y)) ); +} + +float getStereoSideWidth() { + return (params._stereoInfo.y); +} + +float evalZeyeFromZdb(float depth) { + return params._depthInfo.x / (depth * params._depthInfo.y + params._depthInfo.z); } vec3 evalEyeNormal(vec3 C) { diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 1da18b8ef8..8d72510f36 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -20,9 +20,16 @@ const int MAX_MIP_LEVEL = 5; // the depth pyramid texture uniform sampler2D pyramidMap; -vec3 evalEyePosition(vec2 texcoord) { - float Zeye = -texture(pyramidMap, texcoord, 0).x; - return evalEyePositionFromZeye(Zeye, texcoord); +float getZEye(ivec2 pixel) { + return -texelFetch(pyramidMap, pixel, 0).x; +} + +vec3 evalEyePositionFromZeye(ivec2 side, float Zeye, vec2 texcoord) { + // compute the view space position using the depth + // basically manually pick the proj matrix components to do the inverse + float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * params._projection[side.x][2][0] - params._projection[side.x][3][0]) / params._projection[side.x][0][0]; + float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * params._projection[side.x][2][1] - params._projection[side.x][3][1]) / params._projection[side.x][1][1]; + return vec3(Xe, Ye, Zeye); } in vec2 varTexCoord0; @@ -44,37 +51,36 @@ vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ return vec2(cos(angle), sin(angle)); } -vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) { +vec3 getOffsetPosition(ivec2 side, ivec2 ssC, vec2 unitOffset, float ssR) { // Derivation: // mipLevel = floor(log(ssR / MAX_OFFSET)); int mipLevel = clamp(findMSB(int(ssR)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); ivec2 ssP = ivec2(ssR * unitOffset) + ssC; + ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y); vec3 P; // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. // Manually clamp to the texture size because texelFetch bypasses the texture unit - ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), textureSize(pyramidMap, mipLevel) - ivec2(1)); + ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), textureSize(pyramidMap, mipLevel) - ivec2(1)); P.z = -texelFetch(pyramidMap, mipP, mipLevel).r; -// P.z = -texelFetch(pyramidMap, ssP, 0).r; +// P.z = -texelFetch(pyramidMap, ssPFull, 0).r; // Offset to pixel center - //P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); - - vec2 tapUV = (vec2(ssP) + vec2(0.5)) / getWidthHeight(); - P = evalEyePositionFromZeye(P.z, tapUV); + vec2 tapUV = (vec2(ssP) + vec2(0.5)) / getStereoSideWidth(); + P = evalEyePositionFromZeye(side, P.z, tapUV); return P; } -float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle) { +float sampleAO(in ivec2 side, in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle) { // Offset on the unit disk, spun for this pixel float ssR; vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR); ssR *= ssDiskRadius; // The occluding point in camera space - vec3 Q = getOffsetPosition(ssC, unitOffset, ssR); + vec3 Q = getOffsetPosition(side, ssC, unitOffset, ssR); vec3 v = Q - C; float vv = dot(v, v); @@ -84,11 +90,7 @@ float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in i const float epsilon = 0.01; float radius2 = getRadius2(); - // A: From the HPG12 paper - // Note large epsilon to avoid overdarkening within cracks - // return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6; - - // B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended] + // Fall off function as recommended in SAO paper float f = max(radius2 - vv, 0.0); return f * f * f * max((vn - bias) / (epsilon + vv), 0.0); } @@ -105,19 +107,31 @@ void main(void) { // Pixel being shaded ivec2 ssC = ivec2(gl_FragCoord.xy); - vec3 Cp = evalEyePosition(varTexCoord0); + // Fetch the z under the pixel (stereo or not) + float Zeye = getZEye(ssC); - float randomPatternRotationAngle = getAngleDithering(ssC); + // Stereo side info + ivec2 side = getStereoSideInfo(ssC.x); + // From now on, ssC is the pixel pos in the side + ssC.x -= side.y; + vec2 fragPos = (vec2(ssC) + 0.5) / getStereoSideWidth(); + + // The position and normal of the pixel fragment in Eye space + vec3 Cp = evalEyePositionFromZeye(side, Zeye, fragPos); vec3 Cn = evalEyeNormal(Cp); // Choose the screen-space sample radius // proportional to the projected area of the sphere float ssDiskRadius = -getProjScale() * getRadius() / Cp.z; + // Let's make noise + float randomPatternRotationAngle = getAngleDithering(ssC); + + // Accumulate the Obscurance for each samples float sum = 0.0; for (int i = 0; i < getNumSamples(); ++i) { - sum += sampleAO(ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); + sum += sampleAO(side, ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); } float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples()); diff --git a/libraries/render-utils/src/ssao_makePyramid.slf b/libraries/render-utils/src/ssao_makePyramid.slf index 577c0fd232..70d46fb432 100644 --- a/libraries/render-utils/src/ssao_makePyramid.slf +++ b/libraries/render-utils/src/ssao_makePyramid.slf @@ -12,14 +12,12 @@ <@include ssao.slh@> <$declareAmbientOcclusion()$> -// the depth texture uniform sampler2D depthMap; -in vec2 varTexCoord0; out vec4 outFragColor; void main(void) { - float Zdb = texture(depthMap, varTexCoord0).x; + float Zdb = texelFetch(depthMap, ivec2(gl_FragCoord.xy), 0).x; float Zeye = -evalZeyeFromZdb(Zdb); outFragColor = vec4(Zeye, 0.0, 0.0, 1.0); } From 2494623bc78d76e3bb55abf621e0e8d8858a19e0 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 15 Jan 2016 10:55:43 -0800 Subject: [PATCH 15/32] Cleaning the code for review --- interface/src/Menu.h | 2 +- .../src/AmbientOcclusionEffect.cpp | 129 +----------------- .../render-utils/src/AmbientOcclusionEffect.h | 14 -- 3 files changed, 3 insertions(+), 142 deletions(-) diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6bf66f1200..15e28a010a 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -187,7 +187,7 @@ namespace MenuOption { const QString CopyPath = "Copy Path to Clipboard"; const QString CoupleEyelids = "Couple Eyelids"; const QString CrashInterface = "Crash Interface"; - const QString DebugAmbientOcclusion = "Debug Ambient Occlusion"; + const QString DebugAmbientOcclusion = "Ambient Occlusion"; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DeleteBookmark = "Delete Bookmark..."; const QString DisableActivityLogger = "Disable Activity Logger"; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index f7269d8206..ccccd10104 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -32,7 +32,6 @@ #include "ssao_makeVerticalBlur_frag.h" const int AmbientOcclusionEffect_ParamsSlot = 0; -const int AmbientOcclusionEffect_DeferredTransformSlot = 1; const int AmbientOcclusionEffect_DepthMapSlot = 0; const int AmbientOcclusionEffect_PyramidMapSlot = 0; const int AmbientOcclusionEffect_OcclusionMapSlot = 0; @@ -50,9 +49,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getPyramidPipeline() { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); - slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), AmbientOcclusionEffect_DeferredTransformSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), AmbientOcclusionEffect_DepthMapSlot)); - gpu::Shader::makeProgram(*program, slotBindings); @@ -77,13 +74,9 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); - slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), AmbientOcclusionEffect_DeferredTransformSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("pyramidMap"), AmbientOcclusionEffect_PyramidMapSlot)); - - slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), AmbientOcclusionEffect_PyramidMapSlot + 1)); gpu::Shader::makeProgram(*program, slotBindings); - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); // Stencil test all the ao passes for objects pixels only, not the background @@ -107,9 +100,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getHBlurPipeline() { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); - slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), AmbientOcclusionEffect_DeferredTransformSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), AmbientOcclusionEffect_OcclusionMapSlot)); - gpu::Shader::makeProgram(*program, slotBindings); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); @@ -133,7 +124,6 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); - slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), AmbientOcclusionEffect_DeferredTransformSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), AmbientOcclusionEffect_OcclusionMapSlot)); gpu::Shader::makeProgram(*program, slotBindings); @@ -208,106 +198,6 @@ void AmbientOcclusionEffect::setEdgeSharpness(float sharpness) { } } -void AmbientOcclusionEffect::updateDeferredTransformBuffer(const render::RenderContextPointer& renderContext) { - // Allocate the parameters buffer used by all the deferred shaders - if (!_deferredTransformBuffer[0]._buffer) { - DeferredTransform parameters; - _deferredTransformBuffer[0] = gpu::BufferView(std::make_shared(sizeof(DeferredTransform), (const gpu::Byte*) ¶meters)); - _deferredTransformBuffer[1] = gpu::BufferView(std::make_shared(sizeof(DeferredTransform), (const gpu::Byte*) ¶meters)); - } - - RenderArgs* args = renderContext->getArgs(); - - // THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport) - auto framebufferCache = DependencyManager::get(); - QSize framebufferSize = framebufferCache->getFrameBufferSize(); - auto monoViewport = args->_viewport; - float sMin = args->_viewport.x / (float)framebufferSize.width(); - float sWidth = args->_viewport.z / (float)framebufferSize.width(); - float tMin = args->_viewport.y / (float)framebufferSize.height(); - float tHeight = args->_viewport.w / (float)framebufferSize.height(); - - // The view frustum is the mono frustum base - auto viewFrustum = args->_viewFrustum; - - // Eval the mono projection - mat4 monoProjMat; - viewFrustum->evalProjectionMatrix(monoProjMat); - - // The mono view transform - Transform monoViewTransform; - viewFrustum->evalViewTransform(monoViewTransform); - - // THe mono view matrix coming from the mono view transform - glm::mat4 monoViewMat; - monoViewTransform.getMatrix(monoViewMat); - - // Running in stero ? - bool isStereo = args->_context->isStereo(); - int numPasses = 1; - - mat4 projMats[2]; - Transform viewTransforms[2]; - ivec4 viewports[2]; - vec4 clipQuad[2]; - vec2 screenBottomLeftCorners[2]; - vec2 screenTopRightCorners[2]; - vec4 fetchTexcoordRects[2]; - - DeferredTransform deferredTransforms[2]; - - if (isStereo) { - numPasses = 2; - - mat4 eyeViews[2]; - args->_context->getStereoProjections(projMats); - args->_context->getStereoViews(eyeViews); - - float halfWidth = 0.5f * sWidth; - - for (int i = 0; i < numPasses; i++) { - // In stereo, the 2 sides are layout side by side in the mono viewport and their width is half - int sideWidth = monoViewport.z >> 1; - viewports[i] = ivec4(monoViewport.x + (i * sideWidth), monoViewport.y, sideWidth, monoViewport.w); - - deferredTransforms[i].projection = projMats[i]; - - auto sideViewMat = monoViewMat * glm::inverse(eyeViews[i]); - viewTransforms[i].evalFromRawMatrix(sideViewMat); - deferredTransforms[i].viewInverse = sideViewMat; - - deferredTransforms[i].stereoSide = (i == 0 ? -1.0f : 1.0f); - - clipQuad[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight); - screenBottomLeftCorners[i] = glm::vec2(-1.0f + i * 1.0f, -1.0f); - screenTopRightCorners[i] = glm::vec2(i * 1.0f, 1.0f); - - fetchTexcoordRects[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight); - } - } else { - - viewports[0] = monoViewport; - projMats[0] = monoProjMat; - - deferredTransforms[0].projection = monoProjMat; - - deferredTransforms[0].viewInverse = monoViewMat; - viewTransforms[0] = monoViewTransform; - - deferredTransforms[0].stereoSide = 0.0f; - - clipQuad[0] = glm::vec4(sMin, tMin, sWidth, tHeight); - screenBottomLeftCorners[0] = glm::vec2(-1.0f, -1.0f); - screenTopRightCorners[0] = glm::vec2(1.0f, 1.0f); - - fetchTexcoordRects[0] = glm::vec4(sMin, tMin, sWidth, tHeight); - } - - _deferredTransformBuffer[0]._buffer->setSubData(0, sizeof(DeferredTransform), (const gpu::Byte*) &deferredTransforms[0]); - _deferredTransformBuffer[1]._buffer->setSubData(0, sizeof(DeferredTransform), (const gpu::Byte*) &deferredTransforms[1]); - -} - void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { assert(renderContext->getArgs()); assert(renderContext->getArgs()->_viewFrustum); @@ -328,13 +218,9 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext float tMin = args->_viewport.y / (float)framebufferSize.height(); float tHeight = args->_viewport.w / (float)framebufferSize.height(); - - updateDeferredTransformBuffer(renderContext); - // Update the depth info with near and far (same for stereo) setDepthInfo(args->_viewFrustum->getNearClip(), args->_viewFrustum->getFarClip()); - _parametersBuffer.edit()._pixelInfo = args->_viewport; //_parametersBuffer.edit()._ditheringInfo.y += 0.25f; @@ -350,11 +236,6 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext } else { mat4 projMats[2]; - Transform viewTransforms[2]; - - DeferredTransform deferredTransforms[2]; - - mat4 eyeViews[2]; args->_context->getStereoProjections(projMats); args->_context->getStereoViews(eyeViews); @@ -364,7 +245,6 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext for (int i = 0; i < 2; i++) { // Compose the mono Eye space to Stereo clip space Projection Matrix auto sideViewMat = projMats[i] * eyeViews[i]; - _parametersBuffer.edit()._projection[i] = sideViewMat; } @@ -380,9 +260,6 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.enableStereo(false); - batch.setUniformBuffer(AmbientOcclusionEffect_DeferredTransformSlot, _deferredTransformBuffer[0]); - - batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(glm::mat4()); batch.setViewTransform(Transform()); @@ -403,15 +280,13 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext batch.draw(gpu::TRIANGLE_STRIP, 4); // Make pyramid mips - batch.setFramebuffer(occlusionFBO); batch.generateTextureMips(pyramidFBO->getRenderBuffer(0)); // Occlusion pass + batch.setFramebuffer(occlusionFBO); + batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(1.0f)); batch.setPipeline(occlusionPipeline); - - // batch.setFramebuffer(occlusionFinalFBO); batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot, pyramidFBO->getRenderBuffer(0)); - batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot + 1, normalBuffer); batch.draw(gpu::TRIANGLE_STRIP, 4); batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot + 1, gpu::TexturePointer()); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index fd368682bd..1964073a8a 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -76,20 +76,6 @@ private: typedef gpu::BufferView UniformBufferView; gpu::BufferView _parametersBuffer; - // Class describing the uniform buffer with all the parameters common to the deferred shaders - class DeferredTransform { - public: - glm::mat4 projection; - glm::mat4 viewInverse; - float stereoSide{ 0.f }; - float spareA, spareB, spareC; - - DeferredTransform() {} - }; - UniformBufferView _deferredTransformBuffer[2]; - void updateDeferredTransformBuffer(const render::RenderContextPointer& renderContext); - - const gpu::PipelinePointer& getPyramidPipeline(); const gpu::PipelinePointer& getOcclusionPipeline(); const gpu::PipelinePointer& getHBlurPipeline(); // first From 483c28dc2dd9e3febb04e501893dccb0e14d4ec8 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 15 Jan 2016 19:00:18 -0800 Subject: [PATCH 16/32] Adding gpu timer feature to actually the GPU cost of rendering --- libraries/gpu/src/gpu/GLBackendQuery.cpp | 1 + libraries/gpu/src/gpu/Query.cpp | 49 +++++++++++++++++-- libraries/gpu/src/gpu/Query.h | 38 ++++++++++++-- .../src/AmbientOcclusionEffect.cpp | 7 ++- .../render-utils/src/AmbientOcclusionEffect.h | 3 ++ .../render-utils/src/RenderDeferredTask.cpp | 1 - .../render-utils/src/RenderDeferredTask.h | 4 -- .../render-utils/src/ssao_makeOcclusion.slf | 1 - 8 files changed, 88 insertions(+), 16 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackendQuery.cpp b/libraries/gpu/src/gpu/GLBackendQuery.cpp index 0a76d38963..ca7b96a7e5 100644 --- a/libraries/gpu/src/gpu/GLBackendQuery.cpp +++ b/libraries/gpu/src/gpu/GLBackendQuery.cpp @@ -100,6 +100,7 @@ void GLBackend::do_getQuery(Batch& batch, size_t paramOffset) { #else glGetQueryObjectui64v(glquery->_qo, GL_QUERY_RESULT, &glquery->_result); #endif + query->triggerReturnHandler(glquery->_result); (void)CHECK_GL_ERROR(); } } diff --git a/libraries/gpu/src/gpu/Query.cpp b/libraries/gpu/src/gpu/Query.cpp index b8ed729c99..626cb192d7 100644 --- a/libraries/gpu/src/gpu/Query.cpp +++ b/libraries/gpu/src/gpu/Query.cpp @@ -10,11 +10,13 @@ // #include "Query.h" -#include +#include "GPULogging.h" +#include "Batch.h" using namespace gpu; -Query::Query() +Query::Query(const Handler& returnHandler) : + _returnHandler(returnHandler) { } @@ -22,6 +24,45 @@ Query::~Query() { } -double Query::getElapsedTime() { - return 0.0; +double Query::getElapsedTime() const { + return ((double) _queryResult) * 0.000001; } + +void Query::triggerReturnHandler(uint64_t queryResult) { + _queryResult = queryResult; + if (_returnHandler) { + _returnHandler(*this); + } +} + + +Timer::Timer() { + _timerQueries.resize(6, std::make_shared([&] (const Query& query) { + auto elapsedTime = query.getElapsedTime(); + _movingAverage.addSample(elapsedTime); + + static int frameNum = 0; + frameNum++; + frameNum %= 10; + if (frameNum == 0) { + auto value = _movingAverage.average; + qCDebug(gpulogging) << "AO on gpu = " << value; + } + })); + +} + +void Timer::begin(gpu::Batch& batch) { + batch.beginQuery(_timerQueries[_currentTimerQueryIndex]); +} +void Timer::end(gpu::Batch& batch) { + batch.endQuery(_timerQueries[_currentTimerQueryIndex]); + _currentTimerQueryIndex = (_currentTimerQueryIndex + 1) % _timerQueries.size(); + + auto returnQuery = _timerQueries[_currentTimerQueryIndex]; + batch.getQuery(returnQuery); +} + +void Timer::onQueryReturned(const Query& query) { + +} \ No newline at end of file diff --git a/libraries/gpu/src/gpu/Query.h b/libraries/gpu/src/gpu/Query.h index 25897c5c91..b468ba95ed 100644 --- a/libraries/gpu/src/gpu/Query.h +++ b/libraries/gpu/src/gpu/Query.h @@ -13,26 +13,56 @@ #include #include +#include #include +#include #include "Format.h" namespace gpu { + class Batch; + class Query { public: - Query(); + using Handler = std::function; + + Query(const Handler& returnHandler); ~Query(); - uint32 queryResult; - - double getElapsedTime(); + double getElapsedTime() const; const GPUObjectPointer gpuObject {}; + void triggerReturnHandler(uint64_t queryResult); + protected: + Handler _returnHandler; + + uint64_t _queryResult = 0; }; typedef std::shared_ptr QueryPointer; typedef std::vector< QueryPointer > Queries; + + + // gpu timer is just returning an estimate of the time taken by a chunck of work delimited by the + // begin and end calls repeated for several times. + // The result is always a late average of the time spent for that same task a few cycles ago. + class Timer { + public: + Timer(); + void begin(gpu::Batch& batch); + void end(gpu::Batch& batch); + + double getAverage() const; + + protected: + + void onQueryReturned(const Query& query); + + gpu::Queries _timerQueries; + int _currentTimerQueryIndex = 0; + MovingAverage _movingAverage; + }; }; #endif diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index ccccd10104..084c74e756 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -19,6 +19,7 @@ #include #include #include +#include "RenderUtilsLogging.h" #include "AmbientOcclusionEffect.h" #include "TextureCache.h" @@ -240,8 +241,6 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext args->_context->getStereoProjections(projMats); args->_context->getStereoViews(eyeViews); - float halfWidth = 0.5f * sWidth; - for (int i = 0; i < 2; i++) { // Compose the mono Eye space to Stereo clip space Projection Matrix auto sideViewMat = projMats[i] * eyeViews[i]; @@ -260,6 +259,8 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.enableStereo(false); + _gpuTimer.begin(batch); + batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(glm::mat4()); batch.setViewTransform(Transform()); @@ -302,5 +303,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, occlusionBlurredFBO->getRenderBuffer(0)); batch.draw(gpu::TRIANGLE_STRIP, 4); + _gpuTimer.end(batch); + }); } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 1964073a8a..873a934a12 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -16,6 +16,7 @@ #include "render/DrawTask.h" + class AmbientOcclusionEffect { public: @@ -85,6 +86,8 @@ private: gpu::PipelinePointer _occlusionPipeline; gpu::PipelinePointer _hBlurPipeline; gpu::PipelinePointer _vBlurPipeline; + + gpu::Timer _gpuTimer; }; #endif // hifi_AmbientOcclusionEffect_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 14da2b3102..4cc5486640 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -68,7 +68,6 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo } void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - PerformanceTimer perfTimer("ToneMappingDeferred"); _toneMappingEffect.render(renderContext->getArgs()); } diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 85e3e7f211..16fe6f9f3a 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -156,10 +156,6 @@ public: int getToneMappingToneCurve() const; virtual void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - - - gpu::Queries _timerQueries; - int _currentTimerQueryIndex = 0; }; diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 8d72510f36..8e17307280 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -32,7 +32,6 @@ vec3 evalEyePositionFromZeye(ivec2 side, float Zeye, vec2 texcoord) { return vec3(Xe, Ye, Zeye); } -in vec2 varTexCoord0; out vec4 outFragColor; uniform sampler2D normalMap; From 39f1649cdfadf30de60a682e76d8a3a39f24e5ff Mon Sep 17 00:00:00 2001 From: samcake Date: Sat, 16 Jan 2016 22:16:07 -0800 Subject: [PATCH 17/32] refining the settings for the blur pass and splitting the uniforms in 2 buffers, one per frame with transform info and one for the parameters which are rarely changing --- examples/utilities/tools/renderEngineDebug.js | 17 ++- .../src/AmbientOcclusionEffect.cpp | 100 +++++++++++- .../render-utils/src/AmbientOcclusionEffect.h | 44 ++++-- .../render-utils/src/RenderDeferredTask.cpp | 2 + .../src/RenderScriptingInterface.h | 2 + libraries/render-utils/src/ssao.slh | 142 +++++++++++------- .../render-utils/src/ssao_makeOcclusion.slf | 13 +- libraries/render/src/render/Context.h | 2 + 8 files changed, 238 insertions(+), 84 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index e6d15653a3..42786aa5f4 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -52,7 +52,7 @@ var overlaysCounter = new CounterWidget(panel, "Overlays", Render.overlay3D); var resizing = false; var previousMode = Settings.getValue(SETTINGS_KEY, -1); -previousMode = 8; // FIXME: just for debug purpose +previousMode = 1; // FIXME: just for debug purpose Menu.addActionGroup(MENU, ACTIONS, ACTIONS[previousMode + 1]); Render.deferredDebugMode = previousMode; Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 }; // Reset to default size @@ -126,6 +126,21 @@ panel.newCheckbox("Ambient Occlusion Dithering", function() { return Render.ambientOcclusion.ditheringEnabled; }, function (value) { return (value); }); +panel.newSlider("Ambient Occlusion Edge Sharpness", 0.0, 1.0, + function (value) { Render.ambientOcclusion.edgeSharpness = value; }, + function() { return Render.ambientOcclusion.edgeSharpness; }, + function (value) { return (value); }); + +panel.newSlider("Ambient Occlusion Blur Radius", 0.0, 6.0, + function (value) { Render.ambientOcclusion.blurRadius = value; }, + function() { return Render.ambientOcclusion.blurRadius; }, + function (value) { return (value); }); + +panel.newSlider("Ambient Occlusion Blur Deviation", 0.0, 3.0, + function (value) { Render.ambientOcclusion.blurDeviation = value; }, + function() { return Render.ambientOcclusion.blurDeviation; }, + function (value) { return (value); }); + var tickTackPeriod = 500; function updateCounters() { diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 084c74e756..8eea44bec3 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -32,12 +32,70 @@ #include "ssao_makeHorizontalBlur_frag.h" #include "ssao_makeVerticalBlur_frag.h" -const int AmbientOcclusionEffect_ParamsSlot = 0; +class GaussianDistribution { +public: + + static double integral(float x, float deviation) { + return 0.5 * erf(x / (deviation * sqrt(2.0))); + } + + static double rangeIntegral(float x0, float x1, float deviation) { + return integral(x1, deviation) - integral(x0, deviation); + } + + static std::vector evalSampling(int samplingRadius, float deviation) { + std::vector coefs(samplingRadius + 1, 0.0f); + + // corner case when radius is 0 or under + if (samplingRadius <= 0) { + coefs[0] = 1.0; + return coefs; + } + + // Evaluate all the samples range integral of width 1 from center until the penultimate one + float halfWidth = 0.5f; + double sum = 0.0; + for (int i = 0; i < samplingRadius; i++) { + float x = (float) i; + double sample = rangeIntegral(x - halfWidth, x + halfWidth, deviation); + coefs[i] = sample; + sum += sample; + } + + // last sample goes to infinity + float lastSampleX0 = (float) samplingRadius - halfWidth; + float largeEnough = lastSampleX0 + 1000.0f * deviation; + double sample = rangeIntegral(lastSampleX0, largeEnough, deviation); + coefs[samplingRadius] = sample; + sum += sample; + + return coefs; + } + + static void evalSampling(float* coefs, unsigned int coefsLength, int samplingRadius, float deviation) { + auto coefsVector = evalSampling(samplingRadius, deviation); + if (coefsLength> coefsVector.size() + 1) { + unsigned int coefsNum = 0; + for (auto s : coefsVector) { + coefs[coefsNum] = s; + coefsNum++; + } + for (;coefsNum < coefsLength; coefsNum++) { + coefs[coefsNum] = 0.0f; + } + } + } +}; + +const int AmbientOcclusionEffect_FrameTransformSlot = 0; +const int AmbientOcclusionEffect_ParamsSlot = 1; const int AmbientOcclusionEffect_DepthMapSlot = 0; const int AmbientOcclusionEffect_PyramidMapSlot = 0; const int AmbientOcclusionEffect_OcclusionMapSlot = 0; AmbientOcclusionEffect::AmbientOcclusionEffect() { + FrameTransform frameTransform; + _frameTransformBuffer = gpu::BufferView(std::make_shared(sizeof(FrameTransform), (const gpu::Byte*) &frameTransform)); Parameters parameters; _parametersBuffer = gpu::BufferView(std::make_shared(sizeof(Parameters), (const gpu::Byte*) ¶meters)); } @@ -49,6 +107,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getPyramidPipeline() { gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), AmbientOcclusionEffect_DepthMapSlot)); gpu::Shader::makeProgram(*program, slotBindings); @@ -74,6 +133,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("pyramidMap"), AmbientOcclusionEffect_PyramidMapSlot)); gpu::Shader::makeProgram(*program, slotBindings); @@ -100,6 +160,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getHBlurPipeline() { gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), AmbientOcclusionEffect_OcclusionMapSlot)); gpu::Shader::makeProgram(*program, slotBindings); @@ -124,6 +185,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), AmbientOcclusionEffect_OcclusionMapSlot)); @@ -145,8 +207,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { void AmbientOcclusionEffect::setDepthInfo(float nearZ, float farZ) { - _parametersBuffer.edit()._depthInfo = glm::vec4(nearZ*farZ, farZ -nearZ, -farZ, 0.0f); - + _frameTransformBuffer.edit()._depthInfo = glm::vec4(nearZ*farZ, farZ -nearZ, -farZ, 0.0f); } void AmbientOcclusionEffect::setRadius(float radius) { @@ -199,6 +260,28 @@ void AmbientOcclusionEffect::setEdgeSharpness(float sharpness) { } } +void AmbientOcclusionEffect::setBlurRadius(int radius) { + radius = std::max(0, std::min(6, radius)); + if (radius != getBlurRadius()) { + auto& current = _parametersBuffer.edit()._blurInfo; + current.y = (float)radius; + updateGaussianDistribution(); + } +} + +void AmbientOcclusionEffect::setBlurDeviation(float deviation) { + deviation = std::max(0.0f, deviation); + if (deviation != getBlurDeviation()) { + auto& current = _parametersBuffer.edit()._blurInfo; + current.z = deviation; + updateGaussianDistribution(); + } +} +void AmbientOcclusionEffect::updateGaussianDistribution() { + auto coefs = _parametersBuffer.edit()._gaussianCoefs; + GaussianDistribution::evalSampling(coefs, Parameters::GAUSSIAN_COEFS_LENGTH, getBlurRadius(), getBlurDeviation()); +} + void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { assert(renderContext->getArgs()); assert(renderContext->getArgs()->_viewFrustum); @@ -222,7 +305,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext // Update the depth info with near and far (same for stereo) setDepthInfo(args->_viewFrustum->getNearClip(), args->_viewFrustum->getFarClip()); - _parametersBuffer.edit()._pixelInfo = args->_viewport; + _frameTransformBuffer.edit()._pixelInfo = args->_viewport; //_parametersBuffer.edit()._ditheringInfo.y += 0.25f; // Running in stero ? @@ -231,8 +314,8 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext // Eval the mono projection mat4 monoProjMat; args->_viewFrustum->evalProjectionMatrix(monoProjMat); - _parametersBuffer.edit()._projection[0] = monoProjMat; - _parametersBuffer.edit()._stereoInfo = glm::vec4(0.0f, args->_viewport.z, 0.0f, 0.0f); + _frameTransformBuffer.edit()._projection[0] = monoProjMat; + _frameTransformBuffer.edit()._stereoInfo = glm::vec4(0.0f, args->_viewport.z, 0.0f, 0.0f); } else { @@ -244,10 +327,10 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext for (int i = 0; i < 2; i++) { // Compose the mono Eye space to Stereo clip space Projection Matrix auto sideViewMat = projMats[i] * eyeViews[i]; - _parametersBuffer.edit()._projection[i] = sideViewMat; + _frameTransformBuffer.edit()._projection[i] = sideViewMat; } - _parametersBuffer.edit()._stereoInfo = glm::vec4(1.0f, (float)(args->_viewport.z >> 1), 0.0f, 1.0f); + _frameTransformBuffer.edit()._stereoInfo = glm::vec4(1.0f, (float)(args->_viewport.z >> 1), 0.0f, 1.0f); } @@ -270,6 +353,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext model.setScale(glm::vec3(sWidth, tHeight, 1.0)); batch.setModelTransform(model); + batch.setUniformBuffer(AmbientOcclusionEffect_FrameTransformSlot, _frameTransformBuffer); batch.setUniformBuffer(AmbientOcclusionEffect_ParamsSlot, _parametersBuffer); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 873a934a12..1274995f48 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -46,12 +46,42 @@ public: void setEdgeSharpness(float sharpness); int getEdgeSharpness() const { return (int)_parametersBuffer.get()._blurInfo.x; } + // Blurring Radius + // 0 means no blurring + const int MAX_BLUR_RADIUS = 6; + void setBlurRadius(int radius); + int getBlurRadius() const { return (int)_parametersBuffer.get()._blurInfo.y; } + + void setBlurDeviation(float deviation); + float getBlurDeviation() const { return _parametersBuffer.get()._blurInfo.z; } + + using JobModel = render::Task::Job::Model; private: + void updateGaussianDistribution(); void setDepthInfo(float nearZ, float farZ); + + typedef gpu::BufferView UniformBufferView; + // Class describing the uniform buffer with the transform info common to the AO shaders + // It s changing every frame + class FrameTransform { + public: + // Pixel info is { viemport width height and stereo on off} + glm::vec4 _pixelInfo; + // Depth info is { n.f, f - n, -f} + glm::vec4 _depthInfo; + // Stereo info + glm::vec4 _stereoInfo{ 0.0 }; + // Mono proj matrix or Left and Right proj matrix going from Mono Eye space to side clip space + glm::mat4 _projection[2]; + + FrameTransform() {} + }; + gpu::BufferView _frameTransformBuffer; + // Class describing the uniform buffer with all the parameters common to the AO shaders class Parameters { public: @@ -62,19 +92,13 @@ private: // Sampling info glm::vec4 _sampleInfo{ 11.0, 1.0/11.0, 7.0, 1.0 }; // Blurring info - glm::vec4 _blurInfo{ 1.0, 0.0, 0.0, 0.0 }; - // Pixel info is { viemport width height and stereo on off} - glm::vec4 _pixelInfo; - // Depth info is { n.f, f - n, -f} - glm::vec4 _depthInfo; - // Stereo info - glm::vec4 _stereoInfo{ 0.0 }; - // Mono proj matrix or Left and Right proj matrix going from Mono Eye space to side clip space - glm::mat4 _projection[2]; + glm::vec4 _blurInfo{ 1.0, 3.0, 2.0, 0.0 }; + // gaussian distribution coefficients first is the sampling radius (max is 6) + const static int GAUSSIAN_COEFS_LENGTH = 8; + float _gaussianCoefs[GAUSSIAN_COEFS_LENGTH]; Parameters() {} }; - typedef gpu::BufferView UniformBufferView; gpu::BufferView _parametersBuffer; const gpu::PipelinePointer& getPyramidPipeline(); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 4cc5486640..af297d125c 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -186,6 +186,8 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend _jobs[_occlusionJobIndex].edit().setNumSpiralTurns(renderContext->getAmbientOcclusion().numSpiralTurns); _jobs[_occlusionJobIndex].edit().setDithering(renderContext->getAmbientOcclusion().ditheringEnabled); _jobs[_occlusionJobIndex].edit().setEdgeSharpness(renderContext->getAmbientOcclusion().edgeSharpness); + _jobs[_occlusionJobIndex].edit().setBlurRadius(renderContext->getAmbientOcclusion().blurRadius); + _jobs[_occlusionJobIndex].edit().setBlurDeviation(renderContext->getAmbientOcclusion().blurDeviation); } setAntialiasingStatus(renderContext->getFxaaStatus()); diff --git a/libraries/render-utils/src/RenderScriptingInterface.h b/libraries/render-utils/src/RenderScriptingInterface.h index 30ff17c47b..751026b1a2 100644 --- a/libraries/render-utils/src/RenderScriptingInterface.h +++ b/libraries/render-utils/src/RenderScriptingInterface.h @@ -76,6 +76,8 @@ namespace RenderScripting { Q_PROPERTY(float numSpiralTurns MEMBER numSpiralTurns) Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled) Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness) + Q_PROPERTY(int blurRadius MEMBER blurRadius) + Q_PROPERTY(float blurDeviation MEMBER blurDeviation) }; using AmbientOcclusionPointer = std::unique_ptr; }; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 43106e1d14..733c6b9074 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -31,31 +31,60 @@ vec2 unpackOcclusionDepth(vec3 raw) { <@func declareAmbientOcclusion()@> -struct AmbientOcclusionParams { - vec4 _radiusInfo; - vec4 _ditheringInfo; - vec4 _sampleInfo; - vec4 _blurInfo; +struct AmbientOcclusionFrameTransform { vec4 _pixelInfo; vec4 _depthInfo; vec4 _stereoInfo; mat4 _projection[2]; }; +struct AmbientOcclusionParams { + vec4 _radiusInfo; + vec4 _ditheringInfo; + vec4 _sampleInfo; + vec4 _blurInfo; + float _gaussianCoefs[8]; +}; + +uniform ambientOcclusionFrameTransformBuffer { + AmbientOcclusionFrameTransform frameTransform; +}; uniform ambientOcclusionParamsBuffer { AmbientOcclusionParams params; }; vec2 getWidthHeight() { - return params._pixelInfo.zw; + return frameTransform._pixelInfo.zw; } float getProjScale() { - return getWidthHeight().y * params._projection[0][1][1] * 0.5; + return getWidthHeight().y * frameTransform._projection[0][1][1] * 0.5; } mat4 getProjection(int side) { - return params._projection[side]; + return frameTransform._projection[side]; } +bool isStereo() { + return frameTransform._stereoInfo.x > 0.0f; +} + +ivec2 getStereoSideInfo(int xPos) { + return (xPos < frameTransform._stereoInfo.y ? ivec2(0, 0) : ivec2(1, int(frameTransform._stereoInfo.y)) ); +} + +float getStereoSideWidth() { + return (frameTransform._stereoInfo.y); +} + +float evalZeyeFromZdb(float depth) { + return frameTransform._depthInfo.x / (depth * frameTransform._depthInfo.y + frameTransform._depthInfo.z); +} + +vec3 evalEyeNormal(vec3 C) { + //return normalize(cross(dFdy(C), dFdx(C))); + return normalize(cross(dFdx(C), dFdy(C))); +} + + float getRadius() { return params._radiusInfo.x; } @@ -91,26 +120,33 @@ float getBlurEdgeSharpness() { return params._blurInfo.x; } -bool isStereo() { - return params._stereoInfo.x > 0.0f; +#ifdef CONSTANT_GAUSSIAN +const int BLUR_RADIUS = 4; +const float gaussian[BLUR_RADIUS + 1] = +// float[](0.356642, 0.239400, 0.072410, 0.009869); +// float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0 +float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0 +//float[](0.197413, 0.17467, 0.12098,0.065591,0.040059); +// float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0 + +int getBlurRadius() { + return BLUR_RADIUS; + return int(params._blurInfo.y); } -ivec2 getStereoSideInfo(int xPos) { - return (xPos < params._stereoInfo.y ? ivec2(0, 0) : ivec2(1, int(params._stereoInfo.y)) ); +float getBlurCoef(int c) { + return gaussian[c]; + return params._gaussianCoefs[c]; +} +#else +int getBlurRadius() { + return int(params._blurInfo.y); } -float getStereoSideWidth() { - return (params._stereoInfo.y); -} - -float evalZeyeFromZdb(float depth) { - return params._depthInfo.x / (depth * params._depthInfo.y + params._depthInfo.z); -} - -vec3 evalEyeNormal(vec3 C) { - //return normalize(cross(dFdy(C), dFdx(C))); - return normalize(cross(dFdx(C), dFdy(C))); +float getBlurCoef(int c) { + return params._gaussianCoefs[c]; } +#endif <@endfunc@> @@ -131,49 +167,47 @@ vec2 fetchOcclusionDepth(ivec2 coords) { return unpackOcclusionDepth(texelFetch(occlusionMap, coords, 0).xyz); } - -const int BLUR_RADIUS = 4; const int RADIUS_SCALE = 2; -const float gaussian[BLUR_RADIUS + 1] = -// float[](0.356642, 0.239400, 0.072410, 0.009869); -// float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0 -float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0 -// float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0 +vec2 evalTapWeightedValue(int r, ivec2 ssC, float key) { + ivec2 tapOffset = <$axis$> * (r * RADIUS_SCALE); + vec2 tapOZ = fetchOcclusionDepth(ssC + tapOffset); + + // spatial domain: offset gaussian tap + float weight = 0.3 + getBlurCoef(abs(r)); + + // range domain (the "bilateral" weight). As depth difference increases, decrease weight. + weight *= max(0.0, 1.0 - (getBlurEdgeSharpness() * 2000.0) * abs(tapOZ.y - key)); + + return vec2(tapOZ.x * weight, weight); +} + vec3 getBlurredOcclusion(vec2 coord) { ivec2 ssC = ivec2(coord); vec3 rawSample; vec2 occlusionDepth = fetchOcclusionDepthRaw(ssC, rawSample); float key = occlusionDepth.y; - float sum = occlusionDepth.x; + + // Central pixel contribution + float mainWeight = getBlurCoef(0); + vec2 weightedSums = vec2(occlusionDepth.x * mainWeight, mainWeight); - // Base weight for depth falloff. Increase this for more blurriness, - // decrease it for better edge discrimination - float BASE = gaussian[0]; - float totalWeight = BASE; - sum *= totalWeight; - - for (int r = -BLUR_RADIUS; r <= BLUR_RADIUS; ++r) { - // We already handled the zero case above. This loop should be unrolled and the static branch optimized out, - // so the IF statement has no runtime cost - if (r != 0) { - vec2 tapOZ = fetchOcclusionDepth(ssC + <$axis$> * (r * RADIUS_SCALE)); - - // spatial domain: offset gaussian tap - float weight = 0.3 + gaussian[abs(r)]; - - // range domain (the "bilateral" weight). As depth difference increases, decrease weight. - weight *= max(0.0, 1.0 - (getBlurEdgeSharpness() * 2000.0) * abs(tapOZ.y - key)); - - sum += tapOZ.x * weight; - totalWeight += weight; - } + // Accumulate weighted contributions along the bluring axis in the [-radius, radius] range + int blurRadius = getBlurRadius(); + // negative side first + for (int r = -blurRadius; r <= -1; ++r) { + weightedSums += evalTapWeightedValue(r, ssC, key); + } + // then possitive side + for (int r = 1; r <= blurRadius; ++r) { + weightedSums += evalTapWeightedValue(r, ssC, key); } + // Final normalization const float epsilon = 0.0001; - float result = sum / (totalWeight + epsilon); - + float result = weightedSums.x / (weightedSums.y + epsilon); + rawSample.x = result; return rawSample; } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 8e17307280..6e128945c5 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -27,8 +27,8 @@ float getZEye(ivec2 pixel) { vec3 evalEyePositionFromZeye(ivec2 side, float Zeye, vec2 texcoord) { // compute the view space position using the depth // basically manually pick the proj matrix components to do the inverse - float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * params._projection[side.x][2][0] - params._projection[side.x][3][0]) / params._projection[side.x][0][0]; - float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * params._projection[side.x][2][1] - params._projection[side.x][3][1]) / params._projection[side.x][1][1]; + float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * frameTransform._projection[side.x][2][0] - frameTransform._projection[side.x][3][0]) / frameTransform._projection[side.x][0][0]; + float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * frameTransform._projection[side.x][2][1] - frameTransform._projection[side.x][3][1]) / frameTransform._projection[side.x][1][1]; return vec3(Xe, Ye, Zeye); } @@ -94,14 +94,6 @@ float sampleAO(in ivec2 side, in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssD return f * f * f * max((vn - bias) / (epsilon + vv), 0.0); } -vec3 debugValue(float f, float scale) { - if (f < 0.0) { - return vec3((scale + f) / scale, 0.0, 0.0); - } else { - return vec3(0.0, (scale - f) / scale, 0.0); - } -} - void main(void) { // Pixel being shaded ivec2 ssC = ivec2(gl_FragCoord.xy); @@ -145,5 +137,4 @@ void main(void) { } outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); - //outFragColor = vec4(0.5 * (Cn + vec3(1.0)), A); } diff --git a/libraries/render/src/render/Context.h b/libraries/render/src/render/Context.h index fd6c25dfde..144b3bb434 100644 --- a/libraries/render/src/render/Context.h +++ b/libraries/render/src/render/Context.h @@ -80,6 +80,8 @@ public: float numSpiralTurns = 7.0f; bool ditheringEnabled = true; float edgeSharpness = 1.0f; + int blurRadius = 3; + float blurDeviation = 2.1f; }; RenderContext(ItemsConfig items, Tone tone, AmbientOcclusion ao, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode); From bc579f2605e8cdf4968f91ef87ca8f37db18eea2 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 18 Jan 2016 09:53:41 -0800 Subject: [PATCH 18/32] Clening up the gpu::Timer behavior, now need a way to show it --- libraries/gpu/src/gpu/GLBackendQuery.cpp | 7 ++- libraries/gpu/src/gpu/Query.cpp | 45 +++++++++---------- libraries/gpu/src/gpu/Query.h | 11 +++-- .../render-utils/src/AmbientOcclusionEffect.h | 2 + .../render-utils/src/DeferredLightingEffect.h | 2 +- 5 files changed, 37 insertions(+), 30 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackendQuery.cpp b/libraries/gpu/src/gpu/GLBackendQuery.cpp index ca7b96a7e5..f3a81d504c 100644 --- a/libraries/gpu/src/gpu/GLBackendQuery.cpp +++ b/libraries/gpu/src/gpu/GLBackendQuery.cpp @@ -98,9 +98,12 @@ void GLBackend::do_getQuery(Batch& batch, size_t paramOffset) { glGetQueryObjectui64vEXT(glquery->_qo, GL_QUERY_RESULT, &glquery->_result); #endif #else - glGetQueryObjectui64v(glquery->_qo, GL_QUERY_RESULT, &glquery->_result); + glGetQueryObjectui64v(glquery->_qo, GL_QUERY_RESULT_AVAILABLE, &glquery->_result); + if (glquery->_result == GL_TRUE) { + glGetQueryObjectui64v(glquery->_qo, GL_QUERY_RESULT, &glquery->_result); + query->triggerReturnHandler(glquery->_result); + } #endif - query->triggerReturnHandler(glquery->_result); (void)CHECK_GL_ERROR(); } } diff --git a/libraries/gpu/src/gpu/Query.cpp b/libraries/gpu/src/gpu/Query.cpp index 626cb192d7..24b8bcebd7 100644 --- a/libraries/gpu/src/gpu/Query.cpp +++ b/libraries/gpu/src/gpu/Query.cpp @@ -37,32 +37,31 @@ void Query::triggerReturnHandler(uint64_t queryResult) { Timer::Timer() { - _timerQueries.resize(6, std::make_shared([&] (const Query& query) { - auto elapsedTime = query.getElapsedTime(); - _movingAverage.addSample(elapsedTime); - - static int frameNum = 0; - frameNum++; - frameNum %= 10; - if (frameNum == 0) { - auto value = _movingAverage.average; - qCDebug(gpulogging) << "AO on gpu = " << value; - } - })); - + for (int i = 0; i < QUERY_QUEUE_SIZE; i++) { + _timerQueries.push_back(std::make_shared([&, i] (const Query& query) { + _tailIndex ++; + auto elapsedTime = query.getElapsedTime(); + _movingAverage.addSample(elapsedTime); + })); + } } void Timer::begin(gpu::Batch& batch) { - batch.beginQuery(_timerQueries[_currentTimerQueryIndex]); + _headIndex++; + batch.beginQuery(_timerQueries[rangeIndex(_headIndex)]); } void Timer::end(gpu::Batch& batch) { - batch.endQuery(_timerQueries[_currentTimerQueryIndex]); - _currentTimerQueryIndex = (_currentTimerQueryIndex + 1) % _timerQueries.size(); - - auto returnQuery = _timerQueries[_currentTimerQueryIndex]; - batch.getQuery(returnQuery); + if (_headIndex < 0) { + return; + } + batch.endQuery(_timerQueries[rangeIndex(_headIndex)]); + + if (_tailIndex < 0) { + _tailIndex = _headIndex; + } + + // Pull the previous tail query hopping to see it return + if (_tailIndex != _headIndex) { + batch.getQuery(_timerQueries[rangeIndex(_tailIndex)]); + } } - -void Timer::onQueryReturned(const Query& query) { - -} \ No newline at end of file diff --git a/libraries/gpu/src/gpu/Query.h b/libraries/gpu/src/gpu/Query.h index b468ba95ed..5bfb21cb38 100644 --- a/libraries/gpu/src/gpu/Query.h +++ b/libraries/gpu/src/gpu/Query.h @@ -56,12 +56,15 @@ namespace gpu { double getAverage() const; protected: - - void onQueryReturned(const Query& query); + + static const int QUERY_QUEUE_SIZE = 4; gpu::Queries _timerQueries; - int _currentTimerQueryIndex = 0; - MovingAverage _movingAverage; + int _headIndex = -1; + int _tailIndex = -1; + MovingAverage _movingAverage; + + int rangeIndex(int index) const { return (index % QUERY_QUEUE_SIZE); } }; }; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 1274995f48..657e72cf31 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -56,6 +56,8 @@ public: float getBlurDeviation() const { return _parametersBuffer.get()._blurInfo.z; } + double getTimerAverage() const { return _gpuTimer.getAverage(); } + using JobModel = render::Task::Job::Model; private: diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index cb746153a1..cea12f3f3b 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -50,7 +50,7 @@ public: void setGlobalAtmosphere(const model::AtmospherePointer& atmosphere) { _atmosphere = atmosphere; } void setGlobalSkybox(const model::SkyboxPointer& skybox); - + private: DeferredLightingEffect() = default; From 93c7c182b3682be6df38cfbbae276dca6bd71d84 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 18 Jan 2016 14:10:59 -0800 Subject: [PATCH 19/32] Exposing the gpu RangeTimer counter for the AO effect --- examples/utilities/tools/renderEngineDebug.js | 18 +++++++++++++----- interface/src/Application.cpp | 2 ++ libraries/gpu/src/gpu/Query.cpp | 10 +++++++--- libraries/gpu/src/gpu/Query.h | 6 +++--- .../render-utils/src/AmbientOcclusionEffect.h | 4 ++-- .../render-utils/src/RenderDeferredTask.cpp | 5 +++++ .../src/RenderScriptingInterface.cpp | 4 ++++ .../src/RenderScriptingInterface.h | 4 ++++ libraries/render/src/render/Context.h | 2 ++ 9 files changed, 42 insertions(+), 13 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index 42786aa5f4..2d615872f6 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -104,12 +104,12 @@ panel.newSlider("Tone Mapping Exposure", -10, 10, panel.newSlider("Ambient Occlusion Radius", 0.0, 2.0, function (value) { Render.ambientOcclusion.radius = value; }, function() { return Render.ambientOcclusion.radius; }, - function (value) { return (value); }); + function (value) { return (value.toFixed(2)); }); panel.newSlider("Ambient Occlusion Level", 0.0, 1.0, function (value) { Render.ambientOcclusion.level = value; }, function() { return Render.ambientOcclusion.level; }, - function (value) { return (value); }); + function (value) { return (value.toFixed(2)); }); panel.newSlider("Ambient Occlusion Num Samples", 1, 32, function (value) { Render.ambientOcclusion.numSamples = value; }, @@ -119,7 +119,7 @@ panel.newSlider("Ambient Occlusion Num Samples", 1, 32, panel.newSlider("Ambient Occlusion Num Spiral Turns", 0.0, 30.0, function (value) { Render.ambientOcclusion.numSpiralTurns = value; }, function() { return Render.ambientOcclusion.numSpiralTurns; }, - function (value) { return (value); }); + function (value) { return (value.toFixed(2)); }); panel.newCheckbox("Ambient Occlusion Dithering", function (value) { Render.ambientOcclusion.ditheringEnabled = value; }, @@ -129,7 +129,7 @@ panel.newCheckbox("Ambient Occlusion Dithering", panel.newSlider("Ambient Occlusion Edge Sharpness", 0.0, 1.0, function (value) { Render.ambientOcclusion.edgeSharpness = value; }, function() { return Render.ambientOcclusion.edgeSharpness; }, - function (value) { return (value); }); + function (value) { return (value.toFixed(2)); }); panel.newSlider("Ambient Occlusion Blur Radius", 0.0, 6.0, function (value) { Render.ambientOcclusion.blurRadius = value; }, @@ -139,7 +139,14 @@ panel.newSlider("Ambient Occlusion Blur Radius", 0.0, 6.0, panel.newSlider("Ambient Occlusion Blur Deviation", 0.0, 3.0, function (value) { Render.ambientOcclusion.blurDeviation = value; }, function() { return Render.ambientOcclusion.blurDeviation; }, - function (value) { return (value); }); + function (value) { return (value.toFixed(2)); }); + + +panel.newSlider("Ambient Occlusion GPU time", 0.0, 10.0, + function (value) {}, + function() { return Render.ambientOcclusion.gpuTime; }, + function (value) { return (value.toFixed(2) + " ms"); }); + var tickTackPeriod = 500; @@ -147,6 +154,7 @@ function updateCounters() { opaquesCounter.update(); transparentsCounter.update(); overlaysCounter.update(); + panel.update("Ambient Occlusion GPU time"); } Script.setInterval(updateCounters, tickTackPeriod); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ccde915ecc..78cddad9e7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3853,6 +3853,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se auto engineContext = _renderEngine->getRenderContext(); renderInterface->setItemCounts(engineContext->getItemsConfig()); + renderInterface->setJobGPUTimes(engineContext->getAmbientOcclusion().gpuTime); + } activeRenderingThread = nullptr; diff --git a/libraries/gpu/src/gpu/Query.cpp b/libraries/gpu/src/gpu/Query.cpp index 24b8bcebd7..2e28dcd061 100644 --- a/libraries/gpu/src/gpu/Query.cpp +++ b/libraries/gpu/src/gpu/Query.cpp @@ -36,7 +36,7 @@ void Query::triggerReturnHandler(uint64_t queryResult) { } -Timer::Timer() { +RangeTimer::RangeTimer() { for (int i = 0; i < QUERY_QUEUE_SIZE; i++) { _timerQueries.push_back(std::make_shared([&, i] (const Query& query) { _tailIndex ++; @@ -46,11 +46,11 @@ Timer::Timer() { } } -void Timer::begin(gpu::Batch& batch) { +void RangeTimer::begin(gpu::Batch& batch) { _headIndex++; batch.beginQuery(_timerQueries[rangeIndex(_headIndex)]); } -void Timer::end(gpu::Batch& batch) { +void RangeTimer::end(gpu::Batch& batch) { if (_headIndex < 0) { return; } @@ -65,3 +65,7 @@ void Timer::end(gpu::Batch& batch) { batch.getQuery(_timerQueries[rangeIndex(_tailIndex)]); } } + +double RangeTimer::getAverage() const { + return _movingAverage.average; +} \ No newline at end of file diff --git a/libraries/gpu/src/gpu/Query.h b/libraries/gpu/src/gpu/Query.h index 5bfb21cb38..67dfc29438 100644 --- a/libraries/gpu/src/gpu/Query.h +++ b/libraries/gpu/src/gpu/Query.h @@ -44,12 +44,12 @@ namespace gpu { typedef std::vector< QueryPointer > Queries; - // gpu timer is just returning an estimate of the time taken by a chunck of work delimited by the + // gpu RangeTimer is just returning an estimate of the time taken by a chunck of work delimited by the // begin and end calls repeated for several times. // The result is always a late average of the time spent for that same task a few cycles ago. - class Timer { + class RangeTimer { public: - Timer(); + RangeTimer(); void begin(gpu::Batch& batch); void end(gpu::Batch& batch); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 657e72cf31..8cda1c355c 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -56,7 +56,7 @@ public: float getBlurDeviation() const { return _parametersBuffer.get()._blurInfo.z; } - double getTimerAverage() const { return _gpuTimer.getAverage(); } + double getGPUTime() const { return _gpuTimer.getAverage(); } using JobModel = render::Task::Job::Model; @@ -113,7 +113,7 @@ private: gpu::PipelinePointer _hBlurPipeline; gpu::PipelinePointer _vBlurPipeline; - gpu::Timer _gpuTimer; + gpu::RangeTimer _gpuTimer; }; #endif // hifi_AmbientOcclusionEffect_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index af297d125c..17d957b432 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -202,6 +202,11 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend job.run(sceneContext, renderContext); } + if (_occlusionJobIndex >= 0 && renderContext->getOcclusionStatus()) { + renderContext->getAmbientOcclusion().gpuTime = _jobs[_occlusionJobIndex].edit().getGPUTime(); + } else { + renderContext->getAmbientOcclusion().gpuTime = 0.0; + } }; void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { diff --git a/libraries/render-utils/src/RenderScriptingInterface.cpp b/libraries/render-utils/src/RenderScriptingInterface.cpp index 6c7bbab6a9..6b3fedd97f 100644 --- a/libraries/render-utils/src/RenderScriptingInterface.cpp +++ b/libraries/render-utils/src/RenderScriptingInterface.cpp @@ -49,4 +49,8 @@ void RenderScriptingInterface::setItemCounts(const render::RenderContext::ItemsC _opaque->setCounts(items.opaque); _transparent->setCounts(items.transparent); _overlay3D->setCounts(items.overlay3D); +} + +void RenderScriptingInterface::setJobGPUTimes(double aoTime) { + _ambientOcclusion->gpuTime = aoTime; } \ No newline at end of file diff --git a/libraries/render-utils/src/RenderScriptingInterface.h b/libraries/render-utils/src/RenderScriptingInterface.h index 751026b1a2..95741ce641 100644 --- a/libraries/render-utils/src/RenderScriptingInterface.h +++ b/libraries/render-utils/src/RenderScriptingInterface.h @@ -78,6 +78,7 @@ namespace RenderScripting { Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness) Q_PROPERTY(int blurRadius MEMBER blurRadius) Q_PROPERTY(float blurDeviation MEMBER blurDeviation) + Q_PROPERTY(double gpuTime MEMBER gpuTime) }; using AmbientOcclusionPointer = std::unique_ptr; }; @@ -103,6 +104,9 @@ class RenderScriptingInterface : public QObject, public Dependency { render::RenderContext getRenderContext(); void setItemCounts(const render::RenderContext::ItemsConfig& items); + // FIXME: It is ugly, we need a cleaner solution + void setJobGPUTimes(double aoTime); + protected: RenderScriptingInterface(); ~RenderScriptingInterface() {}; diff --git a/libraries/render/src/render/Context.h b/libraries/render/src/render/Context.h index 144b3bb434..baca2640a0 100644 --- a/libraries/render/src/render/Context.h +++ b/libraries/render/src/render/Context.h @@ -82,6 +82,8 @@ public: float edgeSharpness = 1.0f; int blurRadius = 3; float blurDeviation = 2.1f; + + double gpuTime = 0.0; }; RenderContext(ItemsConfig items, Tone tone, AmbientOcclusion ao, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode); From 91dff3195e668dd789e593166ecf11120ba1a1d2 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 18 Jan 2016 14:28:26 -0800 Subject: [PATCH 20/32] Remove the setup values used for debuging --- examples/utilities/tools/renderEngineDebug.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index 2d615872f6..608ce6001e 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -52,13 +52,11 @@ var overlaysCounter = new CounterWidget(panel, "Overlays", Render.overlay3D); var resizing = false; var previousMode = Settings.getValue(SETTINGS_KEY, -1); -previousMode = 1; // FIXME: just for debug purpose +previousMode = -1; Menu.addActionGroup(MENU, ACTIONS, ACTIONS[previousMode + 1]); Render.deferredDebugMode = previousMode; Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 }; // Reset to default size -Render.deferredDebugSize = { x: -0.5, y: -1.0, z: 1.0, w: 1.0 }; // Reset to default size - function setEngineDeferredDebugSize(eventX) { var scaledX = (2.0 * (eventX / Window.innerWidth) - 1.0).clamp(-1.0, 1.0); Render.deferredDebugSize = { x: scaledX, y: -1.0, z: 1.0, w: 1.0 }; From 6f93fb311492d42390992d0cd53131cadba4c5b9 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 19 Jan 2016 12:12:51 -0800 Subject: [PATCH 21/32] Can now process the AO at lower resolution in orer to gsave performances --- examples/utilities/tools/renderEngineDebug.js | 7 ++- .../src/AmbientOcclusionEffect.cpp | 30 +++++++++--- .../render-utils/src/AmbientOcclusionEffect.h | 5 ++ .../render-utils/src/DebugDeferredBuffer.cpp | 31 +++++------- .../render-utils/src/DebugDeferredBuffer.h | 3 +- libraries/render-utils/src/DeferredBuffer.slh | 6 ++- .../src/DeferredLightingEffect.cpp | 49 ++++++++++++------- .../render-utils/src/FramebufferCache.cpp | 41 ++++++++++++---- libraries/render-utils/src/FramebufferCache.h | 8 ++- .../render-utils/src/RenderDeferredTask.cpp | 1 + .../src/RenderScriptingInterface.h | 1 + .../src/debug_deferred_buffer.slf | 2 +- libraries/render-utils/src/ssao.slh | 20 +++++--- .../render-utils/src/ssao_makeOcclusion.slf | 6 +-- .../src/ssao_makeVerticalBlur.slf | 2 +- libraries/render/src/render/Context.h | 1 + 16 files changed, 146 insertions(+), 67 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index 8cd1312609..f57f451e61 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -12,7 +12,7 @@ Script.include("cookies.js"); var MENU = "Developer>Render>Debug Deferred Buffer"; -var ACTIONS = ["Off", "Diffuse", "Metallic", "Roughness", "Normal", "Depth", "Lighting", "PyramidDepth", "AmbientOcclusion", "OcclusionRaw", "OcclusionBlurred", "Custom"]; +var ACTIONS = ["Off", "Diffuse", "Metallic", "Roughness", "Normal", "Depth", "Lighting", "Shadow", "PyramidDepth", "AmbientOcclusion", "OcclusionBlurred", "Custom"]; var SETTINGS_KEY = "EngineDebugScript.DebugMode"; Number.prototype.clamp = function(min, max) { @@ -99,6 +99,11 @@ panel.newSlider("Tone Mapping Exposure", -10, 10, function() { return Render.tone.exposure; }, function (value) { return (value); }); +panel.newSlider("Ambient Occlusion Resolution Level", 0.0, 4.0, + function (value) { Render.ambientOcclusion.resolutionLevel = value; }, + function() { return Render.ambientOcclusion.resolutionLevel; }, + function (value) { return (value); }); + panel.newSlider("Ambient Occlusion Radius", 0.0, 2.0, function (value) { Render.ambientOcclusion.radius = value; }, function() { return Render.ambientOcclusion.radius; }, diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 8eea44bec3..20393816dc 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -197,8 +197,8 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); // Vertical blur write just the final result Occlusion value in the alpha channel - state->setColorWriteMask(false, false, false, true); - + state->setColorWriteMask(true, true, true, false); + // Good to go add the brand new pipeline _vBlurPipeline = gpu::Pipeline::create(program, state); } @@ -210,6 +210,17 @@ void AmbientOcclusionEffect::setDepthInfo(float nearZ, float farZ) { _frameTransformBuffer.edit()._depthInfo = glm::vec4(nearZ*farZ, farZ -nearZ, -farZ, 0.0f); } +void AmbientOcclusionEffect::setResolutionLevel(int level) { + level = std::max(0, std::min(level, 4)); + if (level != getResolutionLevel()) { + auto& current = _parametersBuffer.edit()._resolutionInfo; + current.x = (float)level; + + // Communicate the change to the Framebuffer cache + DependencyManager::get()->setAmbientOcclusionResolutionLevel(level); + } +} + void AmbientOcclusionEffect::setRadius(float radius) { radius = std::max(0.01f, radius); if (radius != getRadius()) { @@ -294,7 +305,6 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext auto pyramidFBO = framebufferCache->getDepthPyramidFramebuffer(); auto occlusionFBO = framebufferCache->getOcclusionFramebuffer(); auto occlusionBlurredFBO = framebufferCache->getOcclusionBlurredFramebuffer(); - auto occlusionFinalFBO = framebufferCache->getDeferredFramebufferDepthColor(); QSize framebufferSize = framebufferCache->getFrameBufferSize(); float sMin = args->_viewport.x / (float)framebufferSize.width(); @@ -302,6 +312,8 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext float tMin = args->_viewport.y / (float)framebufferSize.height(); float tHeight = args->_viewport.w / (float)framebufferSize.height(); + auto resolutionLevel = getResolutionLevel(); + // Update the depth info with near and far (same for stereo) setDepthInfo(args->_viewFrustum->getNearClip(), args->_viewFrustum->getFarClip()); @@ -367,6 +379,12 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext // Make pyramid mips batch.generateTextureMips(pyramidFBO->getRenderBuffer(0)); + // Adjust Viewport for rendering resolution + if (resolutionLevel > 0) { + glm::ivec4 viewport(args->_viewport.x, args->_viewport.y, args->_viewport.z >> resolutionLevel, args->_viewport.w >> resolutionLevel); + batch.setViewportTransform(viewport); + } + // Occlusion pass batch.setFramebuffer(occlusionFBO); batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(1.0f)); @@ -375,14 +393,14 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext batch.draw(gpu::TRIANGLE_STRIP, 4); batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot + 1, gpu::TexturePointer()); - // Blur 1 pass + // Blur 1st pass batch.setFramebuffer(occlusionBlurredFBO); batch.setPipeline(firstHBlurPipeline); batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, occlusionFBO->getRenderBuffer(0)); batch.draw(gpu::TRIANGLE_STRIP, 4); - // Blur 2 pass - batch.setFramebuffer(occlusionFinalFBO); + // Blur 2nd pass + batch.setFramebuffer(occlusionFBO); batch.setPipeline(lastVBlurPipeline); batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, occlusionBlurredFBO->getRenderBuffer(0)); batch.draw(gpu::TRIANGLE_STRIP, 4); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 8cda1c355c..4919d89b04 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -24,6 +24,9 @@ public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + void setResolutionLevel(int level); + int getResolutionLevel() const { return _parametersBuffer.get()._resolutionInfo.x; } + void setRadius(float radius); float getRadius() const { return _parametersBuffer.get()._radiusInfo.x; } @@ -87,6 +90,8 @@ private: // Class describing the uniform buffer with all the parameters common to the AO shaders class Parameters { public: + // Resolution info + glm::vec4 _resolutionInfo{ 1.0, 1.0, 1.0, 1.0 }; // radius info is { R, R^2, 1 / R^6, ObscuranceScale} glm::vec4 _radiusInfo{ 0.5, 0.5 * 0.5, 1.0 / (0.25 * 0.25 * 0.25), 1.0 }; // Dithering info diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 3491e5a416..c504a58848 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -35,8 +35,8 @@ enum Slots { Lighting, Shadow, Pyramid, - OcclusionRaw, - OcclusionBlurred + AmbientOcclusion, + AmbientOcclusionBlurred }; static const std::string DEFAULT_DIFFUSE_SHADER { @@ -79,24 +79,19 @@ static const std::string DEFAULT_SHADOW_SHADER{ " }" }; -static const std::string DEFAULT_AMBIENT_OCCLUSION_SHADER{ - "vec4 getFragmentColor() {" - " return vec4(vec3(texture(diffuseMap, uv).a), 1.0);" - " }" -}; - static const std::string DEFAULT_PYRAMID_DEPTH_SHADER { "vec4 getFragmentColor() {" " return vec4(vec3(1.0 - texture(pyramidMap, uv).x * 0.01), 1.0);" //" return vec4(vec3(1.0 - textureLod(pyramidMap, uv, 3).x * 0.01), 1.0);" " }" }; -static const std::string DEFAULT_OCCLUSION_RAW_SHADER { + +static const std::string DEFAULT_AMBIENT_OCCLUSION_SHADER{ "vec4 getFragmentColor() {" - " return vec4(vec3(texture(occlusionRawMap, uv).x), 1.0);" + " return vec4(vec3(texture(occlusionMap, uv).x), 1.0);" " }" }; -static const std::string DEFAULT_OCCLUSION_BLURRED_SHADER { +static const std::string DEFAULT_AMBIENT_OCCLUSION_BLURRED_SHADER{ "vec4 getFragmentColor() {" " return vec4(vec3(texture(occlusionBlurredMap, uv).x), 1.0);" " }" @@ -148,10 +143,8 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode, std::string cus return DEFAULT_PYRAMID_DEPTH_SHADER; case AmbientOcclusionMode: return DEFAULT_AMBIENT_OCCLUSION_SHADER; - case OcclusionRawMode: - return DEFAULT_OCCLUSION_RAW_SHADER; - case OcclusionBlurredMode: - return DEFAULT_OCCLUSION_BLURRED_SHADER; + case AmbientOcclusionBlurredMode: + return DEFAULT_AMBIENT_OCCLUSION_BLURRED_SHADER; case CustomMode: return getFileContent(customFile, DEFAULT_CUSTOM_SHADER); } @@ -201,8 +194,8 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode, std::st slotBindings.insert(gpu::Shader::Binding("lightingMap", Lighting)); slotBindings.insert(gpu::Shader::Binding("shadowMapColor", Shadow)); slotBindings.insert(gpu::Shader::Binding("pyramidMap", Pyramid)); - slotBindings.insert(gpu::Shader::Binding("occlusionRawMap", OcclusionRaw)); - slotBindings.insert(gpu::Shader::Binding("occlusionBlurredMap", OcclusionBlurred)); + slotBindings.insert(gpu::Shader::Binding("occlusionMap", AmbientOcclusion)); + slotBindings.insert(gpu::Shader::Binding("occlusionBlurredMap", AmbientOcclusionBlurred)); gpu::Shader::makeProgram(*program, slotBindings); auto pipeline = gpu::Pipeline::create(program, std::make_shared()); @@ -260,8 +253,8 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setResourceTexture(Lighting, framebufferCache->getLightingTexture()); batch.setResourceTexture(Shadow, lightStage.lights[0]->shadow.framebuffer->getRenderBuffer(0)); batch.setResourceTexture(Pyramid, framebufferCache->getDepthPyramidTexture()); - batch.setResourceTexture(OcclusionRaw, framebufferCache->getOcclusionTexture()); - batch.setResourceTexture(OcclusionBlurred, framebufferCache->getOcclusionBlurredTexture()); + batch.setResourceTexture(AmbientOcclusion, framebufferCache->getOcclusionTexture()); + batch.setResourceTexture(AmbientOcclusionBlurred, framebufferCache->getOcclusionBlurredTexture()); const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); const glm::vec2 bottomLeft(renderContext->_deferredDebugSize.x, renderContext->_deferredDebugSize.y); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index 03187b589d..ef0fe512b2 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -35,8 +35,7 @@ private: ShadowMode, PyramidDepthMode, AmbientOcclusionMode, - OcclusionRawMode, - OcclusionBlurredMode, + AmbientOcclusionBlurredMode, CustomMode // Needs to stay last }; struct CustomPipeline { diff --git a/libraries/render-utils/src/DeferredBuffer.slh b/libraries/render-utils/src/DeferredBuffer.slh index 7555f25886..3f9aef6dd1 100755 --- a/libraries/render-utils/src/DeferredBuffer.slh +++ b/libraries/render-utils/src/DeferredBuffer.slh @@ -24,6 +24,9 @@ uniform sampler2D specularMap; // the depth texture uniform sampler2D depthMap; +// the obscurance texture +uniform sampler2D obscuranceMap; + // the lighting texture uniform sampler2D lightingMap; @@ -82,6 +85,7 @@ DeferredFragment unpackDeferredFragment(DeferredTransform deferredTransform, vec frag.normalVal = texture(normalMap, texcoord); frag.diffuseVal = texture(diffuseMap, texcoord); frag.specularVal = texture(specularMap, texcoord); + frag.obscurance = texture(obscuranceMap, texcoord).x; if (getStereoMode(deferredTransform)) { if (texcoord.x > 0.5) { @@ -100,10 +104,10 @@ DeferredFragment unpackDeferredFragment(DeferredTransform deferredTransform, vec } frag.diffuse = frag.diffuseVal.xyz; - frag.obscurance = frag.diffuseVal.w; frag.specular = frag.specularVal.xyz; frag.gloss = frag.specularVal.w; + return frag; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 5af89e7afc..e43e76c87a 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -49,6 +49,15 @@ struct LightLocations { int shadowTransformBuffer; }; +enum { + DEFERRED_BUFFER_COLOR_UNIT = 0, + DEFERRED_BUFFER_NORMAL_UNIT = 1, + DEFERRED_BUFFER_EMISSIVE_UNIT = 2, + DEFERRED_BUFFER_DEPTH_UNIT = 3, + DEFERRED_BUFFER_OBSCURANCE_UNIT = 4, + SHADOW_MAP_UNIT = 5, + SKYBOX_MAP_UNIT = 6, +}; static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations); void DeferredLightingEffect::init() { @@ -172,16 +181,17 @@ void DeferredLightingEffect::render(RenderArgs* args) { batch.setStateScissorRect(args->_viewport); // BInd the G-Buffer surfaces - batch.setResourceTexture(0, framebufferCache->getDeferredColorTexture()); - batch.setResourceTexture(1, framebufferCache->getDeferredNormalTexture()); - batch.setResourceTexture(2, framebufferCache->getDeferredSpecularTexture()); - batch.setResourceTexture(3, framebufferCache->getPrimaryDepthTexture()); + batch.setResourceTexture(DEFERRED_BUFFER_COLOR_UNIT, framebufferCache->getDeferredColorTexture()); + batch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, framebufferCache->getDeferredNormalTexture()); + batch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, framebufferCache->getDeferredSpecularTexture()); + batch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, framebufferCache->getPrimaryDepthTexture()); + batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, framebufferCache->getOcclusionTexture()); assert(_lightStage.lights.size() > 0); const auto& globalShadow = _lightStage.lights[0]->shadow; // Bind the shadow buffer - batch.setResourceTexture(4, globalShadow.map); + batch.setResourceTexture(SHADOW_MAP_UNIT, globalShadow.map); // THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport) auto monoViewport = args->_viewport; @@ -323,7 +333,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { } if (useSkyboxCubemap) { - batch.setResourceTexture(5, _skybox->getCubemap()); + batch.setResourceTexture(SKYBOX_MAP_UNIT, _skybox->getCubemap()); } if (locations->lightBufferUnit >= 0) { @@ -345,7 +355,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { } if (useSkyboxCubemap) { - batch.setResourceTexture(5, nullptr); + batch.setResourceTexture(SKYBOX_MAP_UNIT, nullptr); } } @@ -461,10 +471,14 @@ void DeferredLightingEffect::render(RenderArgs* args) { } // Probably not necessary in the long run because the gpu layer would unbound this texture if used as render target - batch.setResourceTexture(0, nullptr); - batch.setResourceTexture(1, nullptr); - batch.setResourceTexture(2, nullptr); - batch.setResourceTexture(3, nullptr); + batch.setResourceTexture(DEFERRED_BUFFER_COLOR_UNIT, nullptr); + batch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, nullptr); + batch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, nullptr); + batch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, nullptr); + batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, nullptr); + batch.setResourceTexture(SHADOW_MAP_UNIT, nullptr); + batch.setResourceTexture(SKYBOX_MAP_UNIT, nullptr); + batch.setUniformBuffer(_directionalLightLocations->deferredTransformBuffer, nullptr); }); @@ -489,12 +503,13 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS); gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1)); - slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2)); - slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), 3)); - slotBindings.insert(gpu::Shader::Binding(std::string("shadowMap"), 4)); - slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), 5)); + slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), DEFERRED_BUFFER_COLOR_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), DEFERRED_BUFFER_NORMAL_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), DEFERRED_BUFFER_EMISSIVE_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), DEFERRED_BUFFER_DEPTH_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("obscuranceMap"), DEFERRED_BUFFER_OBSCURANCE_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("shadowMap"), SHADOW_MAP_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), SKYBOX_MAP_UNIT)); static const int LIGHT_GPU_SLOT = 3; static const int ATMOSPHERE_GPU_SLOT = 4; diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 075d9ca69f..025c0285d4 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -111,17 +111,32 @@ void FramebufferCache::createPrimaryFramebuffer() { _depthPyramidFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); - _occlusionTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGB), width, height, defaultSampler)); + resizeAmbientOcclusionBuffers(); +} + + +void FramebufferCache::resizeAmbientOcclusionBuffers() { + _occlusionFramebuffer.reset(); + _occlusionTexture.reset(); + _occlusionBlurredFramebuffer.reset(); + _occlusionBlurredTexture.reset(); + + + auto width = _frameBufferSize.width() >> _AOResolutionLevel; + auto height = _frameBufferSize.height() >> _AOResolutionLevel; + auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGB); + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_POINT_MAG_LINEAR); + auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format + + _occlusionTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); _occlusionFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); - - - _occlusionBlurredTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGB), width, height, defaultSampler)); + + _occlusionBlurredTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture); _occlusionBlurredFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); - } gpu::FramebufferPointer FramebufferCache::getPrimaryFramebuffer() { @@ -230,30 +245,38 @@ gpu::TexturePointer FramebufferCache::getDepthPyramidTexture() { return _depthPyramidTexture; } +void FramebufferCache::setAmbientOcclusionResolutionLevel(int level) { + level = std::max(0, std::min(level, 4)); + if (level != _AOResolutionLevel) { + _AOResolutionLevel = level; + resizeAmbientOcclusionBuffers(); + } +} + gpu::FramebufferPointer FramebufferCache::getOcclusionFramebuffer() { if (!_occlusionFramebuffer) { - createPrimaryFramebuffer(); + resizeAmbientOcclusionBuffers(); } return _occlusionFramebuffer; } gpu::TexturePointer FramebufferCache::getOcclusionTexture() { if (!_occlusionTexture) { - createPrimaryFramebuffer(); + resizeAmbientOcclusionBuffers(); } return _occlusionTexture; } gpu::FramebufferPointer FramebufferCache::getOcclusionBlurredFramebuffer() { if (!_occlusionBlurredFramebuffer) { - createPrimaryFramebuffer(); + resizeAmbientOcclusionBuffers(); } return _occlusionBlurredFramebuffer; } gpu::TexturePointer FramebufferCache::getOcclusionBlurredTexture() { if (!_occlusionBlurredTexture) { - createPrimaryFramebuffer(); + resizeAmbientOcclusionBuffers(); } return _occlusionBlurredTexture; } \ No newline at end of file diff --git a/libraries/render-utils/src/FramebufferCache.h b/libraries/render-utils/src/FramebufferCache.h index f0600d85bb..cf126b20b1 100644 --- a/libraries/render-utils/src/FramebufferCache.h +++ b/libraries/render-utils/src/FramebufferCache.h @@ -46,7 +46,8 @@ public: gpu::FramebufferPointer getDepthPyramidFramebuffer(); gpu::TexturePointer getDepthPyramidTexture(); - + + void setAmbientOcclusionResolutionLevel(int level); gpu::FramebufferPointer getOcclusionFramebuffer(); gpu::TexturePointer getOcclusionTexture(); gpu::FramebufferPointer getOcclusionBlurredFramebuffer(); @@ -102,6 +103,11 @@ private: gpu::TexturePointer _occlusionBlurredTexture; QSize _frameBufferSize{ 100, 100 }; + int _AOResolutionLevel = 0; + + // Resize/reallocate the buffers used for AO + // the size of the AO buffers is scaled by the AOResolutionScale; + void resizeAmbientOcclusionBuffers(); }; #endif // hifi_FramebufferCache_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 935723d864..3396e44d58 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -172,6 +172,7 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend setOcclusionStatus(renderContext->getOcclusionStatus()); if (_occlusionJobIndex >= 0) { + _jobs[_occlusionJobIndex].edit().setResolutionLevel(renderContext->getAmbientOcclusion().resolutionLevel); _jobs[_occlusionJobIndex].edit().setRadius(renderContext->getAmbientOcclusion().radius); _jobs[_occlusionJobIndex].edit().setLevel(renderContext->getAmbientOcclusion().level); _jobs[_occlusionJobIndex].edit().setNumSamples(renderContext->getAmbientOcclusion().numSamples); diff --git a/libraries/render-utils/src/RenderScriptingInterface.h b/libraries/render-utils/src/RenderScriptingInterface.h index 95741ce641..41448f06c6 100644 --- a/libraries/render-utils/src/RenderScriptingInterface.h +++ b/libraries/render-utils/src/RenderScriptingInterface.h @@ -70,6 +70,7 @@ namespace RenderScripting { Q_OBJECT public: + Q_PROPERTY(int resolutionLevel MEMBER resolutionLevel) Q_PROPERTY(float radius MEMBER radius) Q_PROPERTY(float level MEMBER level) Q_PROPERTY(int numSamples MEMBER numSamples) diff --git a/libraries/render-utils/src/debug_deferred_buffer.slf b/libraries/render-utils/src/debug_deferred_buffer.slf index 3a96486d41..bbc50fa97a 100644 --- a/libraries/render-utils/src/debug_deferred_buffer.slf +++ b/libraries/render-utils/src/debug_deferred_buffer.slf @@ -15,7 +15,7 @@ <@include DeferredBuffer.slh@> uniform sampler2D pyramidMap; -uniform sampler2D occlusionRawMap; +uniform sampler2D occlusionMap; uniform sampler2D occlusionBlurredMap; in vec2 uv; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 733c6b9074..3cf24f2ebd 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -39,6 +39,7 @@ struct AmbientOcclusionFrameTransform { }; struct AmbientOcclusionParams { + vec4 _resolutionInfo; vec4 _radiusInfo; vec4 _ditheringInfo; vec4 _sampleInfo; @@ -53,8 +54,13 @@ uniform ambientOcclusionParamsBuffer { AmbientOcclusionParams params; }; + +int getResolutionLevel() { + return int(params._resolutionInfo.x); +} + vec2 getWidthHeight() { - return frameTransform._pixelInfo.zw; + return vec2(ivec2(frameTransform._pixelInfo.zw) >> getResolutionLevel()); } float getProjScale() { return getWidthHeight().y * frameTransform._projection[0][1][1] * 0.5; @@ -67,14 +73,16 @@ bool isStereo() { return frameTransform._stereoInfo.x > 0.0f; } -ivec2 getStereoSideInfo(int xPos) { - return (xPos < frameTransform._stereoInfo.y ? ivec2(0, 0) : ivec2(1, int(frameTransform._stereoInfo.y)) ); +float getStereoSideWidth() { + return float(int(frameTransform._stereoInfo.y) >> getResolutionLevel()); } -float getStereoSideWidth() { - return (frameTransform._stereoInfo.y); +ivec2 getStereoSideInfo(int xPos) { + int sideWidth = int(getStereoSideWidth()); + return (xPos < sideWidth ? ivec2(0, 0) : ivec2(1, sideWidth) ); } + float evalZeyeFromZdb(float depth) { return frameTransform._depthInfo.x / (depth * frameTransform._depthInfo.y + frameTransform._depthInfo.z); } @@ -199,7 +207,7 @@ vec3 getBlurredOcclusion(vec2 coord) { for (int r = -blurRadius; r <= -1; ++r) { weightedSums += evalTapWeightedValue(r, ssC, key); } - // then possitive side + // then positive side for (int r = 1; r <= blurRadius; ++r) { weightedSums += evalTapWeightedValue(r, ssC, key); } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 6e128945c5..1cfef02ba5 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -21,7 +21,7 @@ const int MAX_MIP_LEVEL = 5; uniform sampler2D pyramidMap; float getZEye(ivec2 pixel) { - return -texelFetch(pyramidMap, pixel, 0).x; + return -texelFetch(pyramidMap, pixel, getResolutionLevel()).x; } vec3 evalEyePositionFromZeye(ivec2 side, float Zeye, vec2 texcoord) { @@ -62,8 +62,8 @@ vec3 getOffsetPosition(ivec2 side, ivec2 ssC, vec2 unitOffset, float ssR) { // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. // Manually clamp to the texture size because texelFetch bypasses the texture unit - ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), textureSize(pyramidMap, mipLevel) - ivec2(1)); - P.z = -texelFetch(pyramidMap, mipP, mipLevel).r; + ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), textureSize(pyramidMap, getResolutionLevel() + mipLevel) - ivec2(1)); + P.z = -texelFetch(pyramidMap, mipP, getResolutionLevel() + mipLevel).r; // P.z = -texelFetch(pyramidMap, ssPFull, 0).r; // Offset to pixel center diff --git a/libraries/render-utils/src/ssao_makeVerticalBlur.slf b/libraries/render-utils/src/ssao_makeVerticalBlur.slf index 40ad63b94e..f0a6139906 100644 --- a/libraries/render-utils/src/ssao_makeVerticalBlur.slf +++ b/libraries/render-utils/src/ssao_makeVerticalBlur.slf @@ -18,5 +18,5 @@ out vec4 outFragColor; void main(void) { float occlusion = getBlurredOcclusion(gl_FragCoord.xy).x; - outFragColor = vec4(0.0, 0.0, 0.0, occlusion); + outFragColor = vec4(occlusion, 0.0, 0.0, occlusion); } diff --git a/libraries/render/src/render/Context.h b/libraries/render/src/render/Context.h index baca2640a0..b32f3ad66b 100644 --- a/libraries/render/src/render/Context.h +++ b/libraries/render/src/render/Context.h @@ -74,6 +74,7 @@ public: class AmbientOcclusion { public: + int resolutionLevel = 0; float radius = 0.5f; // radius in meters of the AO effect float level = 0.5f; // Level of the obscrance value int numSamples = 11; // Num Samples per pixel From 584d50b59447f28f31fe9987f2c9838287314ebe Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 19 Jan 2016 17:56:07 -0800 Subject: [PATCH 22/32] Experimenting with AO on the lightmaped surface --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 4 ++-- libraries/render-utils/src/DeferredGlobalLight.slh | 4 ++-- libraries/render-utils/src/directional_ambient_light.slf | 1 + .../render-utils/src/directional_ambient_light_shadow.slf | 1 + libraries/render-utils/src/directional_light.slf | 1 + libraries/render-utils/src/directional_light_shadow.slf | 1 + libraries/render-utils/src/directional_skybox_light.slf | 1 + .../render-utils/src/directional_skybox_light_shadow.slf | 1 + 8 files changed, 10 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 20393816dc..1558c99585 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -36,7 +36,7 @@ class GaussianDistribution { public: static double integral(float x, float deviation) { - return 0.5 * erf(x / (deviation * sqrt(2.0))); + return 0.5 * erf((double)x / ((double)deviation * sqrt(2.0))); } static double rangeIntegral(float x0, float x1, float deviation) { @@ -227,7 +227,7 @@ void AmbientOcclusionEffect::setRadius(float radius) { auto& current = _parametersBuffer.edit()._radiusInfo; current.x = radius; current.y = radius * radius; - current.z = 1.0f / pow(radius, 6.0f); + current.z = 1.0f / pow(radius, 6.0); } } diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index a995bdbac4..75fe187e46 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -136,7 +136,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu <@endfunc@> <@func declareEvalLightmappedColor()@> -vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, vec3 normal, vec3 diffuse, vec3 lightmap) { +vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 normal, vec3 diffuse, vec3 lightmap) { Light light = getLight(); @@ -156,7 +156,7 @@ vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, vec3 normal, // ambient is a tiny percentage of the lightmap and only when in the shadow vec3 ambientLight = (1 - lightAttenuation) * lightmap * getLightAmbientIntensity(light); - return diffuse * (ambientLight + diffuseLight); + return obscurance * diffuse * (ambientLight + diffuseLight); } <@endfunc@> diff --git a/libraries/render-utils/src/directional_ambient_light.slf b/libraries/render-utils/src/directional_ambient_light.slf index bfc0709406..3d1b9db46c 100755 --- a/libraries/render-utils/src/directional_ambient_light.slf +++ b/libraries/render-utils/src/directional_ambient_light.slf @@ -31,6 +31,7 @@ void main(void) { vec3 color = evalLightmappedColor( deferredTransform.viewInverse, shadowAttenuation, + frag.obscurance, frag.normal, frag.diffuse, frag.specularVal.xyz); diff --git a/libraries/render-utils/src/directional_ambient_light_shadow.slf b/libraries/render-utils/src/directional_ambient_light_shadow.slf index 3368400f6c..ffe0e21851 100644 --- a/libraries/render-utils/src/directional_ambient_light_shadow.slf +++ b/libraries/render-utils/src/directional_ambient_light_shadow.slf @@ -33,6 +33,7 @@ void main(void) { vec3 color = evalLightmappedColor( deferredTransform.viewInverse, shadowAttenuation, + frag.obscurance, frag.normal, frag.diffuse, frag.specularVal.xyz); diff --git a/libraries/render-utils/src/directional_light.slf b/libraries/render-utils/src/directional_light.slf index 0e706a0a14..e07c57a905 100644 --- a/libraries/render-utils/src/directional_light.slf +++ b/libraries/render-utils/src/directional_light.slf @@ -32,6 +32,7 @@ void main(void) { vec3 color = evalLightmappedColor( deferredTransform.viewInverse, shadowAttenuation, + frag.obscurance, frag.normal, frag.diffuse, frag.specularVal.xyz); diff --git a/libraries/render-utils/src/directional_light_shadow.slf b/libraries/render-utils/src/directional_light_shadow.slf index 7ae462ea71..4aa041b847 100644 --- a/libraries/render-utils/src/directional_light_shadow.slf +++ b/libraries/render-utils/src/directional_light_shadow.slf @@ -34,6 +34,7 @@ void main(void) { vec3 color = evalLightmappedColor( deferredTransform.viewInverse, shadowAttenuation, + frag.obscurance, frag.normal, frag.diffuse, frag.specularVal.xyz); diff --git a/libraries/render-utils/src/directional_skybox_light.slf b/libraries/render-utils/src/directional_skybox_light.slf index 07349f8b90..78fdc4e234 100755 --- a/libraries/render-utils/src/directional_skybox_light.slf +++ b/libraries/render-utils/src/directional_skybox_light.slf @@ -32,6 +32,7 @@ void main(void) { vec3 color = evalLightmappedColor( deferredTransform.viewInverse, shadowAttenuation, + frag.obscurance, frag.normal, frag.diffuse, frag.specularVal.xyz); diff --git a/libraries/render-utils/src/directional_skybox_light_shadow.slf b/libraries/render-utils/src/directional_skybox_light_shadow.slf index 4c7cdfddf5..bbce15be68 100644 --- a/libraries/render-utils/src/directional_skybox_light_shadow.slf +++ b/libraries/render-utils/src/directional_skybox_light_shadow.slf @@ -34,6 +34,7 @@ void main(void) { vec3 color = evalLightmappedColor( deferredTransform.viewInverse, shadowAttenuation, + frag.obscurance, frag.normal, frag.diffuse, frag.specularVal.xyz); From dc40337dc1d16ad0b90d34009b94da8fb247c1a5 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 19 Jan 2016 18:02:47 -0800 Subject: [PATCH 23/32] Adjusting default settings --- libraries/render/src/render/Context.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render/src/render/Context.h b/libraries/render/src/render/Context.h index b32f3ad66b..91311e9eff 100644 --- a/libraries/render/src/render/Context.h +++ b/libraries/render/src/render/Context.h @@ -74,15 +74,15 @@ public: class AmbientOcclusion { public: - int resolutionLevel = 0; + int resolutionLevel = 1; float radius = 0.5f; // radius in meters of the AO effect float level = 0.5f; // Level of the obscrance value int numSamples = 11; // Num Samples per pixel float numSpiralTurns = 7.0f; bool ditheringEnabled = true; float edgeSharpness = 1.0f; - int blurRadius = 3; - float blurDeviation = 2.1f; + int blurRadius = 4; + float blurDeviation = 2.5f; double gpuTime = 0.0; }; From c5c51f2af2430ec87380f2a7fe794af9c58adf20 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 19 Jan 2016 18:57:03 -0800 Subject: [PATCH 24/32] Make sure the resolution level for ao is correct --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 2 +- libraries/render-utils/src/AmbientOcclusionEffect.h | 2 +- libraries/render-utils/src/FramebufferCache.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 1558c99585..bbe0485760 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -227,7 +227,7 @@ void AmbientOcclusionEffect::setRadius(float radius) { auto& current = _parametersBuffer.edit()._radiusInfo; current.x = radius; current.y = radius * radius; - current.z = 1.0f / pow(radius, 6.0); + current.z = 1.0f / pow((double)radius, 6.0); } } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 4919d89b04..e80c5b0136 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -91,7 +91,7 @@ private: class Parameters { public: // Resolution info - glm::vec4 _resolutionInfo{ 1.0, 1.0, 1.0, 1.0 }; + glm::vec4 _resolutionInfo{ -1.0, 0.0, 0.0, 0.0 }; // radius info is { R, R^2, 1 / R^6, ObscuranceScale} glm::vec4 _radiusInfo{ 0.5, 0.5 * 0.5, 1.0 / (0.25 * 0.25 * 0.25), 1.0 }; // Dithering info diff --git a/libraries/render-utils/src/FramebufferCache.h b/libraries/render-utils/src/FramebufferCache.h index cf126b20b1..7c7c309572 100644 --- a/libraries/render-utils/src/FramebufferCache.h +++ b/libraries/render-utils/src/FramebufferCache.h @@ -103,7 +103,7 @@ private: gpu::TexturePointer _occlusionBlurredTexture; QSize _frameBufferSize{ 100, 100 }; - int _AOResolutionLevel = 0; + int _AOResolutionLevel = 1; // AO perform at half res // Resize/reallocate the buffers used for AO // the size of the AO buffers is scaled by the AOResolutionScale; From 379c8828348b444899594f10fff9a1cc0d292b45 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 20 Jan 2016 02:03:09 -0800 Subject: [PATCH 25/32] Debugging the darkness and pointing out bugs --- examples/utilities/tools/renderEngineDebug.js | 2 +- .../src/AmbientOcclusionEffect.cpp | 26 ++++++++++--------- .../render-utils/src/DebugDeferredBuffer.cpp | 6 +++-- .../src/DeferredLightingEffect.cpp | 2 ++ .../render-utils/src/FramebufferCache.cpp | 3 ++- .../render-utils/src/ssao_makeOcclusion.slf | 14 ++++++++-- 6 files changed, 35 insertions(+), 18 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index f57f451e61..645982ff2c 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -52,7 +52,7 @@ var overlaysCounter = new CounterWidget(panel, "Overlays", Render.overlay3D); var resizing = false; var previousMode = Settings.getValue(SETTINGS_KEY, -1); -previousMode = -1; +previousMode = 8; Menu.addActionGroup(MENU, ACTIONS, ACTIONS[previousMode + 1]); Render.deferredDebugMode = previousMode; Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 }; // Reset to default size diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index bbe0485760..2fa8571575 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -391,20 +391,22 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext batch.setPipeline(occlusionPipeline); batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot, pyramidFBO->getRenderBuffer(0)); batch.draw(gpu::TRIANGLE_STRIP, 4); - batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot + 1, gpu::TexturePointer()); + - // Blur 1st pass - batch.setFramebuffer(occlusionBlurredFBO); - batch.setPipeline(firstHBlurPipeline); - batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, occlusionFBO->getRenderBuffer(0)); - batch.draw(gpu::TRIANGLE_STRIP, 4); - - // Blur 2nd pass - batch.setFramebuffer(occlusionFBO); - batch.setPipeline(lastVBlurPipeline); - batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, occlusionBlurredFBO->getRenderBuffer(0)); - batch.draw(gpu::TRIANGLE_STRIP, 4); + if (getBlurRadius() > 0) { + // Blur 1st pass + batch.setFramebuffer(occlusionBlurredFBO); + batch.setPipeline(firstHBlurPipeline); + batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, occlusionFBO->getRenderBuffer(0)); + batch.draw(gpu::TRIANGLE_STRIP, 4); + // Blur 2nd pass + batch.setFramebuffer(occlusionFBO); + batch.setPipeline(lastVBlurPipeline); + batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, occlusionBlurredFBO->getRenderBuffer(0)); + batch.draw(gpu::TRIANGLE_STRIP, 4); + } + _gpuTimer.end(batch); }); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index c504a58848..75664c1849 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -57,7 +57,7 @@ static const std::string DEFAULT_ROUGHNESS_SHADER { }; static const std::string DEFAULT_NORMAL_SHADER { "vec4 getFragmentColor() {" - " return vec4(normalize(texture(normalMap, uv).xyz), 1.0);" + " return vec4(normalize(texture(normalMap, uv).xyz * 2.0 - vec3(1.0)), 1.0);" " }" }; static const std::string DEFAULT_DEPTH_SHADER { @@ -88,7 +88,9 @@ static const std::string DEFAULT_PYRAMID_DEPTH_SHADER { static const std::string DEFAULT_AMBIENT_OCCLUSION_SHADER{ "vec4 getFragmentColor() {" - " return vec4(vec3(texture(occlusionMap, uv).x), 1.0);" + //" return vec4(vec3(texture(occlusionMap, uv).x), 1.0);" + " return vec4(vec3(texture(occlusionMap, uv).xyz), 1.0);" + // when drawing normal " return vec4(normalize(texture(occlusionMap, uv).xyz * 2.0 - vec3(1.0)), 1.0);" " }" }; static const std::string DEFAULT_AMBIENT_OCCLUSION_BLURRED_SHADER{ diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index e43e76c87a..eea8f9e27e 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -185,6 +185,8 @@ void DeferredLightingEffect::render(RenderArgs* args) { batch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, framebufferCache->getDeferredNormalTexture()); batch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, framebufferCache->getDeferredSpecularTexture()); batch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, framebufferCache->getPrimaryDepthTexture()); + + // need to assign the white texture if ao is off batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, framebufferCache->getOcclusionTexture()); assert(_lightStage.lights.size() > 0); diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 025c0285d4..cc2a057379 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -105,7 +105,8 @@ void FramebufferCache::createPrimaryFramebuffer() { // For AO: - _depthPyramidTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), width, height, smoothSampler)); + auto pointMipSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT); + _depthPyramidTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), width, height, pointMipSampler)); _depthPyramidFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _depthPyramidFramebuffer->setRenderBuffer(0, _depthPyramidTexture); _depthPyramidFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 1cfef02ba5..9ca1e4ad07 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -64,7 +64,6 @@ vec3 getOffsetPosition(ivec2 side, ivec2 ssC, vec2 unitOffset, float ssR) { // Manually clamp to the texture size because texelFetch bypasses the texture unit ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), textureSize(pyramidMap, getResolutionLevel() + mipLevel) - ivec2(1)); P.z = -texelFetch(pyramidMap, mipP, getResolutionLevel() + mipLevel).r; -// P.z = -texelFetch(pyramidMap, ssPFull, 0).r; // Offset to pixel center vec2 tapUV = (vec2(ssP) + vec2(0.5)) / getStereoSideWidth(); @@ -136,5 +135,16 @@ void main(void) { A -= dFdy(A) * ((ssC.y & 1) - 0.5); } - outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); + // Debug Normal: outFragColor = vec4((Cn + vec3(1.0))* 0.5, 1.0); + // Debug Radius outFragColor = vec4(vec3(ssDiskRadius / 100.0), 1.0); + // Debug MaxMiplevel outFragColor = vec4(1.0 - vec3(float(clamp(findMSB(int(ssDiskRadius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL))/ float(MAX_MIP_LEVEL)), 1.0); + // Debug OffsetPosition + float ssR; + vec2 unitOffset = tapLocation(int(getNumSamples() - 1), 0, ssR); + vec3 Q = getOffsetPosition(side, ssC, unitOffset, ssR * ssDiskRadius); + //outFragColor = vec4(vec3(Q.x / 10.0, Q.y / 2.0, -Q.z/ 3.0), 1.0); + vec3 v = normalize(Q - Cp); + outFragColor = vec4((v + vec3(1.0))* 0.5, 1.0); + + //outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); } From 35ea04ae7cf6994b65d62815e43ee62d472d17a8 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 20 Jan 2016 11:13:50 -0800 Subject: [PATCH 26/32] fixing the bug that kept AO when ao is off... --- libraries/render-utils/src/DeferredLightingEffect.cpp | 10 ++++++++-- libraries/render-utils/src/DeferredLightingEffect.h | 4 +++- libraries/render-utils/src/RenderDeferredTask.cpp | 2 +- libraries/render-utils/src/RenderShadowTask.cpp | 3 ++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index e43e76c87a..a69343fb34 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -155,7 +155,8 @@ void DeferredLightingEffect::prepare(RenderArgs* args) { }); } -void DeferredLightingEffect::render(RenderArgs* args) { +void DeferredLightingEffect::render(const render::RenderContextPointer& renderContext) { + auto args = renderContext->getArgs(); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { // Allocate the parameters buffer used by all the deferred shaders @@ -170,6 +171,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { // perform deferred lighting, rendering to free fbo auto framebufferCache = DependencyManager::get(); + auto textureCache = DependencyManager::get(); QSize framebufferSize = framebufferCache->getFrameBufferSize(); @@ -185,7 +187,11 @@ void DeferredLightingEffect::render(RenderArgs* args) { batch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, framebufferCache->getDeferredNormalTexture()); batch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, framebufferCache->getDeferredSpecularTexture()); batch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, framebufferCache->getPrimaryDepthTexture()); - batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, framebufferCache->getOcclusionTexture()); + if (renderContext->getOcclusionStatus()) { + batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, framebufferCache->getOcclusionTexture()); + } else { + batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, textureCache->getWhiteTexture()); + } assert(_lightStage.lights.size() > 0); const auto& globalShadow = _lightStage.lights[0]->shadow; diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index d11dee7d49..314cf47202 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -21,6 +21,8 @@ #include "model/Stage.h" #include "model/Geometry.h" +#include "render/Context.h" + #include "LightStage.h" class RenderArgs; @@ -42,7 +44,7 @@ public: float intensity = 0.5f, const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI); void prepare(RenderArgs* args); - void render(RenderArgs* args); + void render(const render::RenderContextPointer& renderContext); void setupTransparent(RenderArgs* args, int lightBufferUnit); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 3396e44d58..3419adafe8 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -64,7 +64,7 @@ void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderC } void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - DependencyManager::get()->render(renderContext->getArgs()); + DependencyManager::get()->render(renderContext); } void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index b6b9f15f60..bc1c17e0d0 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -13,6 +13,7 @@ #include +#include "render/Context.h" #include "DeferredLightingEffect.h" #include "FramebufferCache.h" @@ -116,7 +117,7 @@ RenderShadowTask::RenderShadowTask() : Task() { addJob("RenderShadowMap", shadowShapes, shapePlumber); } -void RenderShadowTask::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { +void RenderShadowTask::run(const SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { assert(sceneContext); RenderArgs* args = renderContext->getArgs(); From 8d1ab01018e38a3e6a96f3681254b64950b2955e Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 20 Jan 2016 18:32:44 -0800 Subject: [PATCH 27/32] exposing one more parameter --- examples/utilities/tools/renderEngineDebug.js | 5 +++++ libraries/render-utils/src/AmbientOcclusionEffect.cpp | 9 +++++++++ libraries/render-utils/src/AmbientOcclusionEffect.h | 8 ++++++-- libraries/render-utils/src/RenderDeferredTask.cpp | 1 + libraries/render-utils/src/RenderScriptingInterface.h | 1 + libraries/render-utils/src/ssao.slh | 3 +++ libraries/render-utils/src/ssao_makeOcclusion.slf | 9 +++------ libraries/render/src/render/Context.h | 1 + 8 files changed, 29 insertions(+), 8 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index 645982ff2c..5d38561eda 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -129,6 +129,11 @@ panel.newCheckbox("Ambient Occlusion Dithering", function() { return Render.ambientOcclusion.ditheringEnabled; }, function (value) { return (value); }); +panel.newSlider("Ambient Occlusion Falloff Bias", 0.0, 0.2, + function (value) { Render.ambientOcclusion.falloffBias = value; }, + function() { return Render.ambientOcclusion.falloffBias; }, + function (value) { return (value.toFixed(2)); }); + panel.newSlider("Ambient Occlusion Edge Sharpness", 0.0, 1.0, function (value) { Render.ambientOcclusion.edgeSharpness = value; }, function() { return Render.ambientOcclusion.edgeSharpness; }, diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index d2ef8fc222..2020add89b 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -246,6 +246,15 @@ void AmbientOcclusionEffect::setDithering(bool enabled) { } } +void AmbientOcclusionEffect::setFalloffBias(float bias) { + bias = std::max(0.0f, std::min(bias, 0.2f)); + if (bias != getFalloffBias()) { + auto& current = _parametersBuffer.edit()._ditheringInfo; + current.z = (float)bias; + } +} + + void AmbientOcclusionEffect::setNumSamples(int numSamples) { numSamples = std::max(1.f, (float) numSamples); if (numSamples != getNumSamples()) { diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index e80c5b0136..89401eaa42 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -37,6 +37,10 @@ public: void setDithering(bool enabled); bool isDitheringEnabled() const { return _parametersBuffer.get()._ditheringInfo.x; } + // Faloff Bias + void setFalloffBias(float bias); + int getFalloffBias() const { return (int)_parametersBuffer.get()._ditheringInfo.z; } + // Number of samples per pixel to evaluate the Obscurance void setNumSamples(int numSamples); int getNumSamples() const { return (int)_parametersBuffer.get()._sampleInfo.x; } @@ -94,8 +98,8 @@ private: glm::vec4 _resolutionInfo{ -1.0, 0.0, 0.0, 0.0 }; // radius info is { R, R^2, 1 / R^6, ObscuranceScale} glm::vec4 _radiusInfo{ 0.5, 0.5 * 0.5, 1.0 / (0.25 * 0.25 * 0.25), 1.0 }; - // Dithering info - glm::vec4 _ditheringInfo{ 0.0, 0.0, 0.0, 0.0 }; + // Dithering info + glm::vec4 _ditheringInfo{ 0.0, 0.0, 0.01, 0.0 }; // Sampling info glm::vec4 _sampleInfo{ 11.0, 1.0/11.0, 7.0, 1.0 }; // Blurring info diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index fa15abe086..1adf350f96 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -180,6 +180,7 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend _jobs[_occlusionJobIndex].edit().setNumSamples(renderContext->getAmbientOcclusion().numSamples); _jobs[_occlusionJobIndex].edit().setNumSpiralTurns(renderContext->getAmbientOcclusion().numSpiralTurns); _jobs[_occlusionJobIndex].edit().setDithering(renderContext->getAmbientOcclusion().ditheringEnabled); + _jobs[_occlusionJobIndex].edit().setFalloffBias(renderContext->getAmbientOcclusion().falloffBias); _jobs[_occlusionJobIndex].edit().setEdgeSharpness(renderContext->getAmbientOcclusion().edgeSharpness); _jobs[_occlusionJobIndex].edit().setBlurRadius(renderContext->getAmbientOcclusion().blurRadius); _jobs[_occlusionJobIndex].edit().setBlurDeviation(renderContext->getAmbientOcclusion().blurDeviation); diff --git a/libraries/render-utils/src/RenderScriptingInterface.h b/libraries/render-utils/src/RenderScriptingInterface.h index 41448f06c6..947240fea6 100644 --- a/libraries/render-utils/src/RenderScriptingInterface.h +++ b/libraries/render-utils/src/RenderScriptingInterface.h @@ -76,6 +76,7 @@ namespace RenderScripting { Q_PROPERTY(int numSamples MEMBER numSamples) Q_PROPERTY(float numSpiralTurns MEMBER numSpiralTurns) Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled) + Q_PROPERTY(float falloffBias MEMBER falloffBias) Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness) Q_PROPERTY(int blurRadius MEMBER blurRadius) Q_PROPERTY(float blurDeviation MEMBER blurDeviation) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 3cf24f2ebd..811898a803 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -113,6 +113,9 @@ float getFrameDithering() { return params._ditheringInfo.y; } +float getFalloffBias() { + return params._ditheringInfo.z; +} float getNumSamples() { return params._sampleInfo.x; diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index a765372e09..f9abde9791 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -84,13 +84,10 @@ float sampleAO(in ivec2 side, in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssD float vv = dot(v, v); float vn = dot(v, n_C); - const float bias = 0.01; - const float epsilon = 0.01; - float radius2 = getRadius2(); - // Fall off function as recommended in SAO paper - float f = max(radius2 - vv, 0.0); - return f * f * f * max((vn - bias) / (epsilon + vv), 0.0); + const float epsilon = 0.01; + float f = max(getRadius2() - vv, 0.0); + return f * f * f * max((vn - getFalloffBias()) / (epsilon + vv), 0.0); } void main(void) { diff --git a/libraries/render/src/render/Context.h b/libraries/render/src/render/Context.h index 91311e9eff..c438a91049 100644 --- a/libraries/render/src/render/Context.h +++ b/libraries/render/src/render/Context.h @@ -80,6 +80,7 @@ public: int numSamples = 11; // Num Samples per pixel float numSpiralTurns = 7.0f; bool ditheringEnabled = true; + float falloffBias = 0.01f; float edgeSharpness = 1.0f; int blurRadius = 4; float blurDeviation = 2.5f; From 16573357d81ba4b506e9c1db1b983c49c33d42fb Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 21 Jan 2016 15:50:38 -0800 Subject: [PATCH 28/32] FIxing the AO results at the border of the frame by guarding the fetch out of the frame --- libraries/gpu/src/gpu/Query.h | 2 +- .../src/AmbientOcclusionEffect.cpp | 68 +++++++++++-------- .../render-utils/src/AmbientOcclusionEffect.h | 43 ++++++------ .../render-utils/src/FramebufferCache.cpp | 2 +- libraries/render-utils/src/ssao.slh | 21 ++++-- .../render-utils/src/ssao_makeOcclusion.slf | 32 +++++---- 6 files changed, 100 insertions(+), 68 deletions(-) diff --git a/libraries/gpu/src/gpu/Query.h b/libraries/gpu/src/gpu/Query.h index 67dfc29438..8e4026fe0f 100644 --- a/libraries/gpu/src/gpu/Query.h +++ b/libraries/gpu/src/gpu/Query.h @@ -57,7 +57,7 @@ namespace gpu { protected: - static const int QUERY_QUEUE_SIZE = 4; + static const int QUERY_QUEUE_SIZE { 4 }; gpu::Queries _timerQueries; int _headIndex = -1; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 2020add89b..2b696dd444 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -48,7 +48,7 @@ public: // corner case when radius is 0 or under if (samplingRadius <= 0) { - coefs[0] = 1.0; + coefs[0] = 1.0f; return coefs; } @@ -140,12 +140,11 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - // Stencil test all the ao passes for objects pixels only, not the background + // Stencil test the ao passes for objects pixels only, not the background state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); state->setColorWriteMask(true, true, true, false); - //state->setColorWriteMask(true, true, true, true); - + // Good to go add the brand new pipeline _occlusionPipeline = gpu::Pipeline::create(program, state); } @@ -168,7 +167,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getHBlurPipeline() { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); // Stencil test all the ao passes for objects pixels only, not the background - state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); + //state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); state->setColorWriteMask(true, true, true, false); @@ -194,7 +193,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); // Stencil test all the ao passes for objects pixels only, not the background - state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); + //state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); // Vertical blur write just the final result Occlusion value in the alpha channel state->setColorWriteMask(true, true, true, false); @@ -207,13 +206,13 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { void AmbientOcclusionEffect::setDepthInfo(float nearZ, float farZ) { - _frameTransformBuffer.edit()._depthInfo = glm::vec4(nearZ*farZ, farZ -nearZ, -farZ, 0.0f); + _frameTransformBuffer.edit().depthInfo = glm::vec4(nearZ*farZ, farZ -nearZ, -farZ, 0.0f); } void AmbientOcclusionEffect::setResolutionLevel(int level) { level = std::max(0, std::min(level, 4)); if (level != getResolutionLevel()) { - auto& current = _parametersBuffer.edit()._resolutionInfo; + auto& current = _parametersBuffer.edit().resolutionInfo; current.x = (float)level; // Communicate the change to the Framebuffer cache @@ -222,68 +221,77 @@ void AmbientOcclusionEffect::setResolutionLevel(int level) { } void AmbientOcclusionEffect::setRadius(float radius) { + const double RADIUS_POWER = 6.0; radius = std::max(0.01f, radius); if (radius != getRadius()) { - auto& current = _parametersBuffer.edit()._radiusInfo; + auto& current = _parametersBuffer.edit().radiusInfo; current.x = radius; current.y = radius * radius; - current.z = (float)(1.0 / pow((double)radius, 6.0)); + current.z = (float)(1.0 / pow((double)radius, RADIUS_POWER)); } } void AmbientOcclusionEffect::setLevel(float level) { level = std::max(0.01f, level); if (level != getLevel()) { - auto& current = _parametersBuffer.edit()._radiusInfo; + auto& current = _parametersBuffer.edit().radiusInfo; current.w = level; } } void AmbientOcclusionEffect::setDithering(bool enabled) { if (enabled != isDitheringEnabled()) { - auto& current = _parametersBuffer.edit()._ditheringInfo; + auto& current = _parametersBuffer.edit().ditheringInfo; current.x = (float)enabled; } } +void AmbientOcclusionEffect::setBordering(bool enabled) { + if (enabled != isBorderingEnabled()) { + auto& current = _parametersBuffer.edit().ditheringInfo; + current.w = (float)enabled; + } +} + void AmbientOcclusionEffect::setFalloffBias(float bias) { bias = std::max(0.0f, std::min(bias, 0.2f)); if (bias != getFalloffBias()) { - auto& current = _parametersBuffer.edit()._ditheringInfo; + auto& current = _parametersBuffer.edit().ditheringInfo; current.z = (float)bias; } } void AmbientOcclusionEffect::setNumSamples(int numSamples) { - numSamples = std::max(1.f, (float) numSamples); + numSamples = std::max(1.0f, (float) numSamples); if (numSamples != getNumSamples()) { - auto& current = _parametersBuffer.edit()._sampleInfo; + auto& current = _parametersBuffer.edit().sampleInfo; current.x = numSamples; - current.y = 1.0 / numSamples; + current.y = 1.0f / numSamples; } } void AmbientOcclusionEffect::setNumSpiralTurns(float numTurns) { - numTurns = std::max(0.f, (float)numTurns); + numTurns = std::max(0.0f, (float)numTurns); if (numTurns != getNumSpiralTurns()) { - auto& current = _parametersBuffer.edit()._sampleInfo; + auto& current = _parametersBuffer.edit().sampleInfo; current.z = numTurns; } } void AmbientOcclusionEffect::setEdgeSharpness(float sharpness) { - sharpness = std::max(0.f, (float)sharpness); + sharpness = std::max(0.0f, (float)sharpness); if (sharpness != getEdgeSharpness()) { - auto& current = _parametersBuffer.edit()._blurInfo; + auto& current = _parametersBuffer.edit().blurInfo; current.x = sharpness; } } void AmbientOcclusionEffect::setBlurRadius(int radius) { - radius = std::max(0, std::min(6, radius)); + const int MAX_BLUR_RADIUS = 6; + radius = std::max(0, std::min(MAX_BLUR_RADIUS, radius)); if (radius != getBlurRadius()) { - auto& current = _parametersBuffer.edit()._blurInfo; + auto& current = _parametersBuffer.edit().blurInfo; current.y = (float)radius; updateGaussianDistribution(); } @@ -292,7 +300,7 @@ void AmbientOcclusionEffect::setBlurRadius(int radius) { void AmbientOcclusionEffect::setBlurDeviation(float deviation) { deviation = std::max(0.0f, deviation); if (deviation != getBlurDeviation()) { - auto& current = _parametersBuffer.edit()._blurInfo; + auto& current = _parametersBuffer.edit().blurInfo; current.z = deviation; updateGaussianDistribution(); } @@ -326,7 +334,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext // Update the depth info with near and far (same for stereo) setDepthInfo(args->_viewFrustum->getNearClip(), args->_viewFrustum->getFarClip()); - _frameTransformBuffer.edit()._pixelInfo = args->_viewport; + _frameTransformBuffer.edit().pixelInfo = args->_viewport; //_parametersBuffer.edit()._ditheringInfo.y += 0.25f; // Running in stero ? @@ -335,8 +343,8 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext // Eval the mono projection mat4 monoProjMat; args->_viewFrustum->evalProjectionMatrix(monoProjMat); - _frameTransformBuffer.edit()._projection[0] = monoProjMat; - _frameTransformBuffer.edit()._stereoInfo = glm::vec4(0.0f, args->_viewport.z, 0.0f, 0.0f); + _frameTransformBuffer.edit().projection[0] = monoProjMat; + _frameTransformBuffer.edit().stereoInfo = glm::vec4(0.0f, (float)args->_viewport.z, 0.0f, 0.0f); } else { @@ -348,10 +356,10 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext for (int i = 0; i < 2; i++) { // Compose the mono Eye space to Stereo clip space Projection Matrix auto sideViewMat = projMats[i] * eyeViews[i]; - _frameTransformBuffer.edit()._projection[i] = sideViewMat; + _frameTransformBuffer.edit().projection[i] = sideViewMat; } - _frameTransformBuffer.edit()._stereoInfo = glm::vec4(1.0f, (float)(args->_viewport.z >> 1), 0.0f, 1.0f); + _frameTransformBuffer.edit().stereoInfo = glm::vec4(1.0f, (float)(args->_viewport.z >> 1), 0.0f, 1.0f); } @@ -370,8 +378,8 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext batch.setViewTransform(Transform()); Transform model; - model.setTranslation(glm::vec3(sMin, tMin, 0.0)); - model.setScale(glm::vec3(sWidth, tHeight, 1.0)); + model.setTranslation(glm::vec3(sMin, tMin, 0.0f)); + model.setScale(glm::vec3(sWidth, tHeight, 1.0f)); batch.setModelTransform(model); batch.setUniformBuffer(AmbientOcclusionEffect_FrameTransformSlot, _frameTransformBuffer); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 89401eaa42..7c1333ad6e 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -25,42 +25,47 @@ public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); void setResolutionLevel(int level); - int getResolutionLevel() const { return _parametersBuffer.get()._resolutionInfo.x; } + int getResolutionLevel() const { return _parametersBuffer.get().resolutionInfo.x; } void setRadius(float radius); - float getRadius() const { return _parametersBuffer.get()._radiusInfo.x; } + float getRadius() const { return _parametersBuffer.get().radiusInfo.x; } // Obscurance level which intensify or dim down the obscurance effect void setLevel(float level); - float getLevel() const { return _parametersBuffer.get()._radiusInfo.w; } + float getLevel() const { return _parametersBuffer.get().radiusInfo.w; } + // On to randomize the distribution of rays per pixel, should always be true void setDithering(bool enabled); - bool isDitheringEnabled() const { return _parametersBuffer.get()._ditheringInfo.x; } + bool isDitheringEnabled() const { return _parametersBuffer.get().ditheringInfo.x; } + + // On to avoid evaluating information from non existing pixels Out of the frame, should always be true + void setBordering(bool enabled); + bool isBorderingEnabled() const { return _parametersBuffer.get().ditheringInfo.w; } // Faloff Bias void setFalloffBias(float bias); - int getFalloffBias() const { return (int)_parametersBuffer.get()._ditheringInfo.z; } + int getFalloffBias() const { return (int)_parametersBuffer.get().ditheringInfo.z; } // Number of samples per pixel to evaluate the Obscurance void setNumSamples(int numSamples); - int getNumSamples() const { return (int)_parametersBuffer.get()._sampleInfo.x; } + int getNumSamples() const { return (int)_parametersBuffer.get().sampleInfo.x; } // Number of spiral turns defining an angle span to distribute the samples ray directions void setNumSpiralTurns(float numTurns); - float getNumSpiralTurns() const { return _parametersBuffer.get()._sampleInfo.z; } + float getNumSpiralTurns() const { return _parametersBuffer.get().sampleInfo.z; } // Edge blurring setting void setEdgeSharpness(float sharpness); - int getEdgeSharpness() const { return (int)_parametersBuffer.get()._blurInfo.x; } + int getEdgeSharpness() const { return (int)_parametersBuffer.get().blurInfo.x; } // Blurring Radius // 0 means no blurring const int MAX_BLUR_RADIUS = 6; void setBlurRadius(int radius); - int getBlurRadius() const { return (int)_parametersBuffer.get()._blurInfo.y; } + int getBlurRadius() const { return (int)_parametersBuffer.get().blurInfo.y; } void setBlurDeviation(float deviation); - float getBlurDeviation() const { return _parametersBuffer.get()._blurInfo.z; } + float getBlurDeviation() const { return _parametersBuffer.get().blurInfo.z; } double getGPUTime() const { return _gpuTimer.getAverage(); } @@ -79,13 +84,13 @@ private: class FrameTransform { public: // Pixel info is { viemport width height and stereo on off} - glm::vec4 _pixelInfo; + glm::vec4 pixelInfo; // Depth info is { n.f, f - n, -f} - glm::vec4 _depthInfo; + glm::vec4 depthInfo; // Stereo info - glm::vec4 _stereoInfo{ 0.0 }; + glm::vec4 stereoInfo { 0.0 }; // Mono proj matrix or Left and Right proj matrix going from Mono Eye space to side clip space - glm::mat4 _projection[2]; + glm::mat4 projection[2]; FrameTransform() {} }; @@ -95,15 +100,15 @@ private: class Parameters { public: // Resolution info - glm::vec4 _resolutionInfo{ -1.0, 0.0, 0.0, 0.0 }; + glm::vec4 resolutionInfo { -1.0f, 0.0f, 0.0f, 0.0f }; // radius info is { R, R^2, 1 / R^6, ObscuranceScale} - glm::vec4 _radiusInfo{ 0.5, 0.5 * 0.5, 1.0 / (0.25 * 0.25 * 0.25), 1.0 }; + glm::vec4 radiusInfo{ 0.5f, 0.5f * 0.5f, 1.0f / (0.25f * 0.25f * 0.25f), 1.0f }; // Dithering info - glm::vec4 _ditheringInfo{ 0.0, 0.0, 0.01, 0.0 }; + glm::vec4 ditheringInfo { 0.0f, 0.0f, 0.01f, 0.0f }; // Sampling info - glm::vec4 _sampleInfo{ 11.0, 1.0/11.0, 7.0, 1.0 }; + glm::vec4 sampleInfo { 11.0f, 1.0/11.0f, 7.0f, 1.0f }; // Blurring info - glm::vec4 _blurInfo{ 1.0, 3.0, 2.0, 0.0 }; + glm::vec4 blurInfo { 1.0f, 3.0f, 2.0f, 0.0f }; // gaussian distribution coefficients first is the sampling radius (max is 6) const static int GAUSSIAN_COEFS_LENGTH = 8; float _gaussianCoefs[GAUSSIAN_COEFS_LENGTH]; diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index cc2a057379..fe7e9f9993 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -126,7 +126,7 @@ void FramebufferCache::resizeAmbientOcclusionBuffers() { auto width = _frameBufferSize.width() >> _AOResolutionLevel; auto height = _frameBufferSize.height() >> _AOResolutionLevel; auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGB); - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_POINT_MAG_LINEAR); + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR); auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format _occlusionTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 811898a803..decc535cf2 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -77,9 +77,9 @@ float getStereoSideWidth() { return float(int(frameTransform._stereoInfo.y) >> getResolutionLevel()); } -ivec2 getStereoSideInfo(int xPos) { +ivec3 getStereoSideInfo(int xPos) { int sideWidth = int(getStereoSideWidth()); - return (xPos < sideWidth ? ivec2(0, 0) : ivec2(1, sideWidth) ); + return ivec3(xPos < sideWidth ? ivec2(0, 0) : ivec2(1, sideWidth), sideWidth); } @@ -112,6 +112,9 @@ float isDitheringEnabled() { float getFrameDithering() { return params._ditheringInfo.y; } +float isBorderingEnabled() { + return params._ditheringInfo.w; +} float getFalloffBias() { return params._ditheringInfo.z; @@ -180,8 +183,13 @@ vec2 fetchOcclusionDepth(ivec2 coords) { const int RADIUS_SCALE = 2; -vec2 evalTapWeightedValue(int r, ivec2 ssC, float key) { +vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 ssC, float key) { ivec2 tapOffset = <$axis$> * (r * RADIUS_SCALE); + ivec2 ssP = (ssC + tapOffset); + + if ((ssP.x < side.y || ssP.x >= side.z + side.y) || (ssP.y < 0 || ssP.y >= int(getWidthHeight().y))) { + return vec2(0.0); + } vec2 tapOZ = fetchOcclusionDepth(ssC + tapOffset); // spatial domain: offset gaussian tap @@ -196,6 +204,9 @@ vec2 evalTapWeightedValue(int r, ivec2 ssC, float key) { vec3 getBlurredOcclusion(vec2 coord) { ivec2 ssC = ivec2(coord); + // Stereo side info + ivec3 side = getStereoSideInfo(ssC.x); + vec3 rawSample; vec2 occlusionDepth = fetchOcclusionDepthRaw(ssC, rawSample); float key = occlusionDepth.y; @@ -208,11 +219,11 @@ vec3 getBlurredOcclusion(vec2 coord) { int blurRadius = getBlurRadius(); // negative side first for (int r = -blurRadius; r <= -1; ++r) { - weightedSums += evalTapWeightedValue(r, ssC, key); + weightedSums += evalTapWeightedValue(side, r, ssC, key); } // then positive side for (int r = 1; r <= blurRadius; ++r) { - weightedSums += evalTapWeightedValue(r, ssC, key); + weightedSums += evalTapWeightedValue(side, r, ssC, key); } // Final normalization diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index f9abde9791..5c9a2865cc 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -24,11 +24,11 @@ float getZEye(ivec2 pixel) { return -texelFetch(pyramidMap, pixel, getResolutionLevel()).x; } -vec3 evalEyePositionFromZeye(ivec2 side, float Zeye, vec2 texcoord) { +vec3 evalEyePositionFromZeye(int side, float Zeye, vec2 texcoord) { // compute the view space position using the depth // basically manually pick the proj matrix components to do the inverse - float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * frameTransform._projection[side.x][2][0] - frameTransform._projection[side.x][3][0]) / frameTransform._projection[side.x][0][0]; - float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * frameTransform._projection[side.x][2][1] - frameTransform._projection[side.x][3][1]) / frameTransform._projection[side.x][1][1]; + float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * frameTransform._projection[side][2][0] - frameTransform._projection[side][3][0]) / frameTransform._projection[side][0][0]; + float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * frameTransform._projection[side][2][1] - frameTransform._projection[side][3][1]) / frameTransform._projection[side][1][1]; return vec3(Xe, Ye, Zeye); } @@ -50,12 +50,18 @@ vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ return vec2(cos(angle), sin(angle)); } -vec3 getOffsetPosition(ivec2 side, ivec2 ssC, vec2 unitOffset, float ssR) { +vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec2 unitOffset, float ssR) { // Derivation: // mipLevel = floor(log(ssR / MAX_OFFSET)); int mipLevel = clamp(findMSB(int(ssR)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); - ivec2 ssP = ivec2(ssR * unitOffset) + ssC; + ivec2 ssOffset = ivec2(ssR * unitOffset); + ivec2 ssP = ssOffset + ssC; + if (bool(isBorderingEnabled())) { + ssP.x = ((ssP.x < 0 || ssP.x >= side.z) ? ssC.x - ssOffset.x : ssP.x); + ssP.y = ((ssP.y < 0 || ssP.y >= int(getWidthHeight().y)) ? ssC.y - ssOffset.y : ssP.y); + } + ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y); vec3 P; @@ -66,17 +72,19 @@ vec3 getOffsetPosition(ivec2 side, ivec2 ssC, vec2 unitOffset, float ssR) { P.z = -texelFetch(pyramidMap, mipP, getResolutionLevel() + mipLevel).r; // Offset to pixel center - vec2 tapUV = (vec2(ssP) + vec2(0.5)) / getStereoSideWidth(); - P = evalEyePositionFromZeye(side, P.z, tapUV); + vec2 tapUV = (vec2(ssP) + vec2(0.5)) / float(side.z); + P = evalEyePositionFromZeye(side.x, P.z, tapUV); return P; } -float sampleAO(in ivec2 side, in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle) { +float sampleAO(in ivec3 side, in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle) { // Offset on the unit disk, spun for this pixel float ssR; vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR); ssR *= ssDiskRadius; + + // The occluding point in camera space vec3 Q = getOffsetPosition(side, ssC, unitOffset, ssR); @@ -98,14 +106,14 @@ void main(void) { float Zeye = getZEye(ssC); // Stereo side info - ivec2 side = getStereoSideInfo(ssC.x); + ivec3 side = getStereoSideInfo(ssC.x); // From now on, ssC is the pixel pos in the side ssC.x -= side.y; vec2 fragPos = (vec2(ssC) + 0.5) / getStereoSideWidth(); // The position and normal of the pixel fragment in Eye space - vec3 Cp = evalEyePositionFromZeye(side, Zeye, fragPos); + vec3 Cp = evalEyePositionFromZeye(side.x, Zeye, fragPos); vec3 Cn = evalEyeNormal(Cp); // Choose the screen-space sample radius @@ -125,12 +133,12 @@ void main(void) { // Bilateral box-filter over a quad for free, respecting depth edges // (the difference that this makes is subtle) - if (abs(dFdx(Cp.z)) < 0.02) { + /* if (abs(dFdx(Cp.z)) < 0.02) { A -= dFdx(A) * ((ssC.x & 1) - 0.5); } if (abs(dFdy(Cp.z)) < 0.02) { A -= dFdy(A) * ((ssC.y & 1) - 0.5); - } + }*/ outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); From 9c344c6498ce1e06eecd09961df85b34a4d9535b Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 21 Jan 2016 16:38:21 -0800 Subject: [PATCH 29/32] FIxing the bordering enble default value --- libraries/render-utils/src/AmbientOcclusionEffect.h | 2 +- libraries/render-utils/src/ssao.slh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 7c1333ad6e..dfbc5b996e 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -104,7 +104,7 @@ private: // radius info is { R, R^2, 1 / R^6, ObscuranceScale} glm::vec4 radiusInfo{ 0.5f, 0.5f * 0.5f, 1.0f / (0.25f * 0.25f * 0.25f), 1.0f }; // Dithering info - glm::vec4 ditheringInfo { 0.0f, 0.0f, 0.01f, 0.0f }; + glm::vec4 ditheringInfo { 0.0f, 0.0f, 0.01f, 1.0f }; // Sampling info glm::vec4 sampleInfo { 11.0f, 1.0/11.0f, 7.0f, 1.0f }; // Blurring info diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index decc535cf2..83fc8c4513 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -134,6 +134,7 @@ float getBlurEdgeSharpness() { return params._blurInfo.x; } +// KEEP this dead code for eventual performance improvment #ifdef CONSTANT_GAUSSIAN const int BLUR_RADIUS = 4; const float gaussian[BLUR_RADIUS + 1] = From 402809fe2f3a31f4049d0f836ba2b7c72b075fa9 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 21 Jan 2016 16:44:35 -0800 Subject: [PATCH 30/32] FIxing coding standards --- .../src/AmbientOcclusionEffect.cpp | 3 ++- libraries/render/src/render/Context.h | 22 +++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 2b696dd444..596848cedd 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -210,7 +210,8 @@ void AmbientOcclusionEffect::setDepthInfo(float nearZ, float farZ) { } void AmbientOcclusionEffect::setResolutionLevel(int level) { - level = std::max(0, std::min(level, 4)); + const int MAX_RESOLUTION_LEVEL = 4; + level = std::max(0, std::min(level, MAX_RESOLUTION_LEVEL)); if (level != getResolutionLevel()) { auto& current = _parametersBuffer.edit().resolutionInfo; current.x = (float)level; diff --git a/libraries/render/src/render/Context.h b/libraries/render/src/render/Context.h index c438a91049..fcbdc5c6fe 100644 --- a/libraries/render/src/render/Context.h +++ b/libraries/render/src/render/Context.h @@ -74,18 +74,18 @@ public: class AmbientOcclusion { public: - int resolutionLevel = 1; - float radius = 0.5f; // radius in meters of the AO effect - float level = 0.5f; // Level of the obscrance value - int numSamples = 11; // Num Samples per pixel - float numSpiralTurns = 7.0f; - bool ditheringEnabled = true; - float falloffBias = 0.01f; - float edgeSharpness = 1.0f; - int blurRadius = 4; - float blurDeviation = 2.5f; + int resolutionLevel { 1 }; + float radius { 0.5f }; // radius in meters of the AO effect + float level { 0.5f }; // Level of the obscrance value + int numSamples { 11 }; // Num Samples per pixel + float numSpiralTurns { 7.0f }; + bool ditheringEnabled { true }; + float falloffBias { 0.01f }; + float edgeSharpness { 1.0f }; + int blurRadius { 4 }; + float blurDeviation { 2.5f}; - double gpuTime = 0.0; + double gpuTime { 0.0 }; }; RenderContext(ItemsConfig items, Tone tone, AmbientOcclusion ao, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode); From 8eddd527316ff86919da3171946f935d5c652d93 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 21 Jan 2016 16:54:37 -0800 Subject: [PATCH 31/32] Fixing coding guidelines --- libraries/render-utils/src/ssao.slh | 8 +++++--- libraries/render-utils/src/ssao_makeOcclusion.slf | 8 +++++--- libraries/render/src/render/Context.h | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 83fc8c4513..f3c52bc1a6 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -134,10 +134,10 @@ float getBlurEdgeSharpness() { return params._blurInfo.x; } -// KEEP this dead code for eventual performance improvment #ifdef CONSTANT_GAUSSIAN const int BLUR_RADIUS = 4; const float gaussian[BLUR_RADIUS + 1] = +// KEEP this dead code for eventual performance improvment // float[](0.356642, 0.239400, 0.072410, 0.009869); // float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0 float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0 @@ -183,6 +183,8 @@ vec2 fetchOcclusionDepth(ivec2 coords) { } const int RADIUS_SCALE = 2; +const float BLUR_WEIGHT_OFFSET = 0.3; +const float BLUR_EDGE_SCALE = 2000.0; vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 ssC, float key) { ivec2 tapOffset = <$axis$> * (r * RADIUS_SCALE); @@ -194,10 +196,10 @@ vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 ssC, float key) { vec2 tapOZ = fetchOcclusionDepth(ssC + tapOffset); // spatial domain: offset gaussian tap - float weight = 0.3 + getBlurCoef(abs(r)); + float weight = BLUR_WEIGHT_OFFSET + getBlurCoef(abs(r)); // range domain (the "bilateral" weight). As depth difference increases, decrease weight. - weight *= max(0.0, 1.0 - (getBlurEdgeSharpness() * 2000.0) * abs(tapOZ.y - key)); + weight *= max(0.0, 1.0 - (getBlurEdgeSharpness() * BLUR_EDGE_SCALE) * abs(tapOZ.y - key)); return vec2(tapOZ.x * weight, weight); } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 5c9a2865cc..4c08da19bd 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -41,10 +41,12 @@ float getAngleDithering(in ivec2 pixelPos) { return isDitheringEnabled() * (3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10 + getFrameDithering(); } +const float TWO_PI = 6.28; + vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ // Radius relative to ssR float alpha = float(sampleNumber + 0.5) * getInvNumSamples(); - float angle = alpha * (getNumSpiralTurns() * 6.28) + spinAngle; + float angle = alpha * (getNumSpiralTurns() * TWO_PI) + spinAngle; ssR = alpha; return vec2(cos(angle), sin(angle)); @@ -133,12 +135,12 @@ void main(void) { // Bilateral box-filter over a quad for free, respecting depth edges // (the difference that this makes is subtle) - /* if (abs(dFdx(Cp.z)) < 0.02) { + if (abs(dFdx(Cp.z)) < 0.02) { A -= dFdx(A) * ((ssC.x & 1) - 0.5); } if (abs(dFdy(Cp.z)) < 0.02) { A -= dFdy(A) * ((ssC.y & 1) - 0.5); - }*/ + } outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); diff --git a/libraries/render/src/render/Context.h b/libraries/render/src/render/Context.h index fcbdc5c6fe..c3087d82d0 100644 --- a/libraries/render/src/render/Context.h +++ b/libraries/render/src/render/Context.h @@ -113,7 +113,7 @@ protected: int _drawStatus; // bitflag bool _drawHitEffect; bool _occlusionStatus { false }; - bool _fxaaStatus = { false }; + bool _fxaaStatus { false }; ItemsConfig _items; Tone _tone; From b5aa5fcb467940e72e882652f0ca9869bfbb7ad3 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 21 Jan 2016 17:36:53 -0800 Subject: [PATCH 32/32] more clean up --- .../render-utils/src/AmbientOcclusionEffect.cpp | 13 ++----------- libraries/render-utils/src/FramebufferCache.cpp | 3 ++- libraries/render-utils/src/ssao_makeOcclusion.slf | 2 ++ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 596848cedd..30360fdbce 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -115,7 +115,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getPyramidPipeline() { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - // Stencil test all the ao passes for objects pixels only, not the background + // Stencil test the pyramid passe for objects pixels only, not the background state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); state->setColorWriteMask(true, false, false, false); @@ -140,9 +140,6 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - // Stencil test the ao passes for objects pixels only, not the background - state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); - state->setColorWriteMask(true, true, true, false); // Good to go add the brand new pipeline @@ -165,10 +162,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getHBlurPipeline() { gpu::Shader::makeProgram(*program, slotBindings); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - - // Stencil test all the ao passes for objects pixels only, not the background - //state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); - + state->setColorWriteMask(true, true, true, false); // Good to go add the brand new pipeline @@ -192,9 +186,6 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - // Stencil test all the ao passes for objects pixels only, not the background - //state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); - // Vertical blur write just the final result Occlusion value in the alpha channel state->setColorWriteMask(true, true, true, false); diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index fe7e9f9993..7948dfcefe 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -247,7 +247,8 @@ gpu::TexturePointer FramebufferCache::getDepthPyramidTexture() { } void FramebufferCache::setAmbientOcclusionResolutionLevel(int level) { - level = std::max(0, std::min(level, 4)); + const int MAX_AO_RESOLUTION_LEVEL = 4; + level = std::max(0, std::min(level, MAX_AO_RESOLUTION_LEVEL)); if (level != _AOResolutionLevel) { _AOResolutionLevel = level; resizeAmbientOcclusionBuffers(); diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 4c08da19bd..72424cad1e 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -133,6 +133,7 @@ void main(void) { float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples()); + outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0);