HAO (Horrendous Ambient Occlusion)

This commit is contained in:
Niraj Venkat 2015-07-23 18:53:43 -07:00
parent 9ccf316513
commit 216c499d14
5 changed files with 211 additions and 60 deletions

View file

@ -2,7 +2,7 @@
// AmbientOcclusionEffect.cpp
// interface/src/renderer
//
// Created by Andrzej Kapolka on 7/14/13.
// Created by Niraj Venkat on 7/14/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
@ -19,10 +19,11 @@
#include <PathUtils.h>
#include <SharedUtil.h>
#include "AbstractViewStateInterface.h"
#include "gpu/StandardShaderLib.h"
#include "AmbientOcclusionEffect.h"
#include "RenderUtil.h"
#include "TextureCache.h"
#include "FramebufferCache.h"
#include "DependencyManager.h"
#include "ViewFrustum.h"
#include "GeometryCache.h"
@ -34,9 +35,8 @@
#include "gaussian_blur_frag.h"
#include "occlusion_blend_vert.h"
#include "occlusion_blend_frag.h"
const int ROTATION_WIDTH = 4;
const int ROTATION_HEIGHT = 4;
//#include "occlusion_result_vert.h"
#include "occlusion_result_frag.h"
/*
void AmbientOcclusionEffect::init(AbstractViewStateInterface* viewState) {
@ -197,6 +197,8 @@ const gpu::PipelinePointer& AmbientOcclusion::getOcclusionPipeline() {
_gBiasLoc = program->getUniforms().findLocation("g_bias");
_gSampleRadiusLoc = program->getUniforms().findLocation("g_sample_rad");
_gIntensityLoc = program->getUniforms().findLocation("g_intensity");
_bufferWidthLoc = program->getUniforms().findLocation("bufferWidth");
_bufferHeightLoc = program->getUniforms().findLocation("bufferHeight");
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
@ -209,7 +211,7 @@ const gpu::PipelinePointer& AmbientOcclusion::getOcclusionPipeline() {
// Link the occlusion FBO to texture
_occlusionBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32,
DependencyManager::get<TextureCache>()->getFrameBufferSize().width(), DependencyManager::get<TextureCache>()->getFrameBufferSize().height()));
DependencyManager::get<FramebufferCache>()->getFrameBufferSize().width(), DependencyManager::get<FramebufferCache>()->getFrameBufferSize().height()));
auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
auto width = _occlusionBuffer->getWidth();
auto height = _occlusionBuffer->getHeight();
@ -242,7 +244,7 @@ const gpu::PipelinePointer& AmbientOcclusion::getVBlurPipeline() {
// Link the horizontal blur FBO to texture
_vBlurBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32,
DependencyManager::get<TextureCache>()->getFrameBufferSize().width(), DependencyManager::get<TextureCache>()->getFrameBufferSize().height()));
DependencyManager::get<FramebufferCache>()->getFrameBufferSize().width(), DependencyManager::get<FramebufferCache>()->getFrameBufferSize().height()));
auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
auto width = _vBlurBuffer->getWidth();
auto height = _vBlurBuffer->getHeight();
@ -275,7 +277,7 @@ const gpu::PipelinePointer& AmbientOcclusion::getHBlurPipeline() {
// Link the horizontal blur FBO to texture
_hBlurBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32,
DependencyManager::get<TextureCache>()->getFrameBufferSize().width(), DependencyManager::get<TextureCache>()->getFrameBufferSize().height()));
DependencyManager::get<FramebufferCache>()->getFrameBufferSize().width(), DependencyManager::get<FramebufferCache>()->getFrameBufferSize().height()));
auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
auto width = _hBlurBuffer->getWidth();
auto height = _hBlurBuffer->getHeight();
@ -295,6 +297,9 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() {
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("blurredOcclusionTexture"), 0));
slotBindings.insert(gpu::Shader::Binding(std::string("colorTexture"), 1));
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
@ -303,17 +308,16 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() {
// Blend on transparent
state->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO);
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
// Link the horizontal blur FBO to texture
_hBlurBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32,
DependencyManager::get<TextureCache>()->getFrameBufferSize().width(), DependencyManager::get<TextureCache>()->getFrameBufferSize().height()));
// Link the blend FBO to texture
_blendBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32,
DependencyManager::get<FramebufferCache>()->getFrameBufferSize().width(), DependencyManager::get<FramebufferCache>()->getFrameBufferSize().height()));
auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
auto width = _hBlurBuffer->getWidth();
auto height = _hBlurBuffer->getHeight();
auto width = _blendBuffer->getWidth();
auto height = _blendBuffer->getHeight();
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
_hBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler));
_blendTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler));
// Good to go add the brand new pipeline
_blendPipeline.reset(gpu::Pipeline::create(program, state));
@ -321,38 +325,67 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() {
return _blendPipeline;
}
const gpu::PipelinePointer& AmbientOcclusion::getAOResultPipeline() {
if (!_AOResultPipeline) {
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(ambient_occlusion_vert)));
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(occlusion_result_frag)));
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
//gpu::ShaderPointer program = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawTransformUnitQuadVS(), gpu::StandardShaderLib::getDrawTexturePS());
gpu::Shader::BindingSet slotBindings;
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(false, false, gpu::LESS_EQUAL);
// Blend on transparent
state->setBlendFunction(false,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
// Good to go add the brand new pipeline
_AOResultPipeline.reset(gpu::Pipeline::create(program, state));
}
return _AOResultPipeline;
}
void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) {
// create a simple pipeline that does:
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
RenderArgs* args = renderContext->args;
auto& scene = sceneContext->_scene;
// Allright, something to render let's do it
gpu::Batch batch;
glm::mat4 projMat;
Transform viewMat;
args->_viewFrustum->evalProjectionMatrix(projMat);
args->_viewFrustum->evalViewTransform(viewMat);
if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
}
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat);
batch.setModelTransform(Transform());
// Occlusion step
getOcclusionPipeline();
batch.setResourceTexture(0, DependencyManager::get<TextureCache>()->getPrimaryDepthTexture());
batch.setResourceTexture(1, DependencyManager::get<TextureCache>()->getPrimaryNormalTexture());
batch.setResourceTexture(0, DependencyManager::get<FramebufferCache>()->getPrimaryDepthTexture());
batch.setResourceTexture(1, DependencyManager::get<FramebufferCache>()->getPrimaryNormalTexture());
_occlusionBuffer->setRenderBuffer(0, _occlusionTexture);
batch.setFramebuffer(_occlusionBuffer);
// bind the first gpu::Pipeline we need - for calculating occlusion buffer
// Occlusion uniforms
g_scale = 1.0f;
g_bias = 1.0f;
g_sample_rad = 1.0f;
g_intensity = 1.0f;
// Bind the first gpu::Pipeline we need - for calculating occlusion buffer
batch.setPipeline(getOcclusionPipeline());
batch._glUniform1f(_gScaleLoc, g_scale);
batch._glUniform1f(_gBiasLoc, g_bias);
batch._glUniform1f(_gSampleRadiusLoc, g_sample_rad);
batch._glUniform1f(_gIntensityLoc, g_intensity);
batch._glUniform1f(_bufferWidthLoc, DependencyManager::get<FramebufferCache>()->getFrameBufferSize().width());
batch._glUniform1f(_bufferHeightLoc, DependencyManager::get<FramebufferCache>()->getFrameBufferSize().height());
glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f);
glm::vec2 bottomLeft(-1.0f, -1.0f);
@ -367,7 +400,7 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons
_vBlurBuffer->setRenderBuffer(0, _vBlurTexture);
batch.setFramebuffer(_vBlurBuffer);
// bind the second gpu::Pipeline we need - for calculating blur buffer
// Bind the second gpu::Pipeline we need - for calculating blur buffer
batch.setPipeline(getVBlurPipeline());
DependencyManager::get<GeometryCache>()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color);
@ -378,29 +411,38 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons
_hBlurBuffer->setRenderBuffer(0, _hBlurTexture);
batch.setFramebuffer(_hBlurBuffer);
// bind the third gpu::Pipeline we need - for calculating blur buffer
// Bind the third gpu::Pipeline we need - for calculating blur buffer
batch.setPipeline(getHBlurPipeline());
DependencyManager::get<GeometryCache>()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color);
// "Blend" step
batch.setResourceTexture(0, _occlusionTexture);
batch.setFramebuffer(DependencyManager::get<TextureCache>()->getPrimaryFramebuffer());
// Blend step
getBlendPipeline();
batch.setResourceTexture(0, _hBlurTexture);
batch.setResourceTexture(1, DependencyManager::get<FramebufferCache>()->getPrimaryColorTexture());
batch.setFramebuffer(_blendBuffer);
// bind the fourth gpu::Pipeline we need - for blending the primary framefuffer with blurred occlusion texture
// Bind the fourth gpu::Pipeline we need - for blending the primary color buffer with blurred occlusion texture
batch.setPipeline(getBlendPipeline());
DependencyManager::get<GeometryCache>()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color);
// Final AO result step
getAOResultPipeline();
batch.setResourceTexture(0, _hBlurTexture);
batch.setFramebuffer(DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer());
// Bind the fifth gpu::Pipeline we need - for displaying the blended texture
batch.setPipeline(getAOResultPipeline());
glm::vec2 bottomLeftSmall(0.5f, -1.0f);
glm::vec2 topRightSmall(1.0f, -0.5f);
DependencyManager::get<GeometryCache>()->renderQuad(batch, bottomLeftSmall, topRightSmall, texCoordTopLeft, texCoordBottomRight, color);
DependencyManager::get<GeometryCache>()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color);
// Ready to render
args->_context->syncCache();
renderContext->args->_context->syncCache();
args->_context->render((batch));
// need to fetch forom the z buffer and render something in a new render target a result that combine the z and produce a fake AO result
}

View file

@ -28,21 +28,38 @@ public:
const gpu::PipelinePointer& getHBlurPipeline();
const gpu::PipelinePointer& getVBlurPipeline();
const gpu::PipelinePointer& getBlendPipeline();
const gpu::PipelinePointer& getAOResultPipeline();
private:
// Uniforms for AO
gpu::int32 _gScaleLoc;
gpu::int32 _gBiasLoc;
gpu::int32 _gSampleRadiusLoc;
gpu::int32 _gIntensityLoc;
gpu::int32 _bufferWidthLoc;
gpu::int32 _bufferHeightLoc;
float g_scale;
float g_bias;
float g_sample_rad;
float g_intensity;
gpu::PipelinePointer _occlusionPipeline;
gpu::PipelinePointer _hBlurPipeline;
gpu::PipelinePointer _vBlurPipeline;
gpu::PipelinePointer _blendPipeline;
gpu::PipelinePointer _AOResultPipeline;
gpu::FramebufferPointer _occlusionBuffer;
gpu::FramebufferPointer _hBlurBuffer;
gpu::FramebufferPointer _vBlurBuffer;
gpu::FramebufferPointer _blendBuffer;
gpu::TexturePointer _occlusionTexture;
gpu::TexturePointer _hBlurTexture;
gpu::TexturePointer _vBlurTexture;
gpu::TexturePointer _blendTexture;
};
#endif // hifi_AmbientOcclusionEffect_h

View file

@ -14,36 +14,96 @@
<@include DeferredBufferWrite.slh@>
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
varying vec2 varTexcoord;
uniform sampler2D depthTexture;
uniform sampler2D normalTexture;
float getRandom(vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
uniform float g_scale;
uniform float g_bias;
uniform float g_sample_rad;
uniform float g_intensity;
uniform float bufferWidth;
uniform float bufferHeight;
#define SAMPLE_COUNT 4
float getRandom(vec2 uv) {
return fract(sin(dot(uv.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
/*
float doAmbientOcclusion(vec2 tcoord, vec2 uv, vec3 p, vec3 cnorm) {
vec3 diff = getPosition(tcoord + uv) - p;
vec3 v = normalize(diff);
float d = length(diff) * g_scale;
return max(0.0, dot(cnorm, v) - g_bias) * (1.0/(1.0 + d)) * g_intensity;
}
*/
void main(void) {
vec3 sampleKernel[4] = { vec3(0.2, 0.0, 0.0),
vec3(0.0, 0.2, 0.0),
vec3(0.0, 0.0, 0.2),
vec3(0.2, 0.2, 0.2) };
vec4 depthColor = texture2D(depthTexture, varTexcoord.xy);
vec4 normalColor = texture2D(normalTexture, varTexcoord.xy);
float z = depthColor.r; // fetch the z-value from our depth texture
float n = 1.0; // the near plane
float f = 30.0; // the far plane
float c = (2.0 * n) / (f + n - z * (f - n)); // convert to linear values
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
vec4 linearizedDepthColor = vec4(c, c, c, 1.0);
gl_FragColor = mix(linearizedDepthColor, normalColor, 0.5);
//gl_FragColor = linearizedDepthColor;
vec3 eyeDir = vec3(0.0);
vec3 cameraPositionWorldSpace;
<$transformEyeToWorldDir(cam, eyeDir, cameraPositionWorldSpace)$>
//vec3 p = getPosition(i.uv);
//vec3 n = getNormal(i.uv);
//vec2 rand = vec2(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx));
vec4 depthColor = texture2D(depthTexture, varTexcoord);
// z in non linear range [0,1]
float depthVal = depthColor.r;
// conversion into NDC [-1,1]
float zNDC = depthVal * 2.0 - 1.0;
float n = 1.0; // the near plane
float f = 30.0; // the far plane
float l = -1.0; // left
float r = 1.0; // right
float b = -1.0; // bottom
float t = 1.0; // top
// conversion into eye space
float zEye = 2*f*n / (zNDC*(f-n)-(f+n));
// Converting from pixel coordinates to NDC
float xNDC = gl_FragCoord.x/bufferWidth * 2.0 - 1.0;
float yNDC = gl_FragCoord.y/bufferHeight * 2.0 - 1.0;
// Unprojecting X and Y from NDC to eye space
float xEye = -zEye*(xNDC*(r-l)+(r+l))/(2.0*n);
float yEye = -zEye*(yNDC*(t-b)+(t+b))/(2.0*n);
vec3 currentFragEyeSpace = vec3(xEye, yEye, zEye);
vec3 currentFragWorldSpace;
<$transformEyeToWorldDir(cam, currentFragEyeSpace, currentFragWorldSpace)$>
vec3 cameraToPositionRay = normalize(currentFragWorldSpace - cameraPositionWorldSpace);
vec3 origin = cameraToPositionRay * depthVal + cameraPositionWorldSpace;
vec3 normal = normalize(texture2D(normalTexture, varTexcoord).xyz);
//normal = normalize(normal * normalMatrix);
vec3 rvec = vec3(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx), getRandom(varTexcoord.xx)) * 2.0 - 1.0;
vec3 tangent = normalize(rvec - normal * dot(rvec, normal));
vec3 bitangent = cross(normal, tangent);
mat3 tbn = mat3(tangent, bitangent, normal);
float occlusion = 0.0;
for (int i = 0; i < SAMPLE_COUNT; ++i) {
vec3 samplePos = origin + (tbn * sampleKernel[i]) * g_sample_rad;
vec4 offset = cam._projectionViewUntranslated * vec4(samplePos, 1.0);
offset.xy = (offset.xy / offset.w) * 0.5 + 0.5;
float depth = length(samplePos - cameraPositionWorldSpace);
float sampleDepthVal = texture2D(depthTexture, offset.xy).r;
float rangeDelta = abs(depthVal - sampleDepthVal);
float rangeCheck = smoothstep(0.0, 1.0, g_sample_rad / rangeDelta);
occlusion += rangeCheck * step(sampleDepthVal, depth);
}
occlusion = 1.0 - occlusion / float(SAMPLE_COUNT);
occlusion = clamp(pow(occlusion, g_intensity), 0.0, 1.0);
gl_FragColor = vec4(occlusion, occlusion, occlusion, 1.0);
}

View file

@ -17,8 +17,17 @@
varying vec2 varTexcoord;
uniform sampler2D blurredOcclusionTexture;
uniform sampler2D colorTexture;
void main(void) {
vec4 depthColor = texture2D(blurredOcclusionTexture, varTexcoord.xy);
gl_FragColor = depthColor;
vec4 occlusionColor = texture2D(blurredOcclusionTexture, varTexcoord);
vec4 currentColor = texture2D(colorTexture, varTexcoord);
if(occlusionColor.r == 1.0) {
gl_FragColor = currentColor;
}
else {
gl_FragColor = mix(occlusionColor, currentColor, 0.5);
}
gl_FragColor = occlusionColor;
}

View file

@ -0,0 +1,23 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// occlusion_result.frag
// fragment shader
//
// Created by Niraj Venkat on 7/23/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferWrite.slh@>
varying vec2 varTexcoord;
uniform sampler2D resultTexture;
void main(void) {
gl_FragColor = texture2D(resultTexture, varTexcoord);
}