Working on AO

This commit is contained in:
samcake 2015-12-23 17:27:20 -08:00
parent ee6d720f2b
commit dbc4506cee
11 changed files with 409 additions and 359 deletions

View file

@ -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) {

View file

@ -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

View file

@ -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<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();
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<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();
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<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 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<FramebufferCache>();
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<GeometryCache>()->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<GeometryCache>()->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<GeometryCache>()->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<GeometryCache>()->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<gpu::Buffer>(sizeof(Parameters), (const gpu::Byte*) &parameters));
}
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<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();
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<Parameters>()._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<gpu::Buffer>(sizeof(DeferredTransform), (const gpu::Byte*) &parameters));
_deferredTransformBuffer[1] = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(DeferredTransform), (const gpu::Byte*) &parameters));
}
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<FramebufferCache>();
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<FramebufferCache>();
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<Parameters>()._projection = monoProjMat;
auto pyramidPipeline = getPyramidPipeline();
auto occlusionPipeline = getOcclusionPipeline();
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
auto framebufferCache = DependencyManager::get<FramebufferCache>();
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);
});
}

View file

@ -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<AmbientOcclusion> 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<AmbientOcclusionEffect> 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;

View file

@ -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<gpu::State>());
@ -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);

View file

@ -33,6 +33,7 @@ private:
NormalMode,
DepthMode,
LightingMode,
AmbientOcclusionMode,
CustomMode // Needs to stay last
};

View file

@ -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;

View file

@ -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;
}

View file

@ -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 };
};

View file

@ -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<gpu::State>();
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);
});
}

View file

@ -14,6 +14,8 @@
<@include DeferredBuffer.slh@>
uniform sampler2D pyramidMap;
in vec2 uv;
out vec4 outFragColor;