mirror of
https://github.com/overte-org/overte.git
synced 2025-04-14 14:47:19 +02:00
Merge pull request #8433 from samcake/hdr
Fix Screen Space ambient occlusion which was broken since a while
This commit is contained in:
commit
9801ff075a
18 changed files with 973 additions and 471 deletions
|
@ -180,10 +180,10 @@ public:
|
|||
using Index = int;
|
||||
|
||||
BufferPointer _buffer;
|
||||
Size _offset;
|
||||
Size _size;
|
||||
Element _element;
|
||||
uint16 _stride;
|
||||
Size _offset { 0 };
|
||||
Size _size { 0 };
|
||||
Element _element { DEFAULT_ELEMENT };
|
||||
uint16 _stride { 0 };
|
||||
|
||||
BufferView(const BufferView& view) = default;
|
||||
BufferView& operator=(const BufferView& view) = default;
|
||||
|
|
|
@ -30,9 +30,88 @@
|
|||
|
||||
#include "ssao_makePyramid_frag.h"
|
||||
#include "ssao_makeOcclusion_frag.h"
|
||||
#include "ssao_debugOcclusion_frag.h"
|
||||
#include "ssao_makeHorizontalBlur_frag.h"
|
||||
#include "ssao_makeVerticalBlur_frag.h"
|
||||
|
||||
|
||||
AmbientOcclusionFramebuffer::AmbientOcclusionFramebuffer() {
|
||||
}
|
||||
|
||||
void AmbientOcclusionFramebuffer::updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer) {
|
||||
//If the depth buffer or size changed, we need to delete our FBOs
|
||||
bool reset = false;
|
||||
if ((_linearDepthTexture != linearDepthBuffer)) {
|
||||
_linearDepthTexture = linearDepthBuffer;
|
||||
reset = true;
|
||||
}
|
||||
if (_linearDepthTexture) {
|
||||
auto newFrameSize = glm::ivec2(_linearDepthTexture->getDimensions());
|
||||
if (_frameSize != newFrameSize) {
|
||||
_frameSize = newFrameSize;
|
||||
reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (reset) {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
void AmbientOcclusionFramebuffer::clear() {
|
||||
_occlusionFramebuffer.reset();
|
||||
_occlusionTexture.reset();
|
||||
_occlusionBlurredFramebuffer.reset();
|
||||
_occlusionBlurredTexture.reset();
|
||||
}
|
||||
|
||||
gpu::TexturePointer AmbientOcclusionFramebuffer::getLinearDepthTexture() {
|
||||
return _linearDepthTexture;
|
||||
}
|
||||
|
||||
void AmbientOcclusionFramebuffer::allocate() {
|
||||
|
||||
auto width = _frameSize.x;
|
||||
auto height = _frameSize.y;
|
||||
|
||||
_occlusionTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
_occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
_occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture);
|
||||
|
||||
_occlusionBlurredTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
_occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
_occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture);
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer AmbientOcclusionFramebuffer::getOcclusionFramebuffer() {
|
||||
if (!_occlusionFramebuffer) {
|
||||
allocate();
|
||||
}
|
||||
return _occlusionFramebuffer;
|
||||
}
|
||||
|
||||
gpu::TexturePointer AmbientOcclusionFramebuffer::getOcclusionTexture() {
|
||||
if (!_occlusionTexture) {
|
||||
allocate();
|
||||
}
|
||||
return _occlusionTexture;
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer AmbientOcclusionFramebuffer::getOcclusionBlurredFramebuffer() {
|
||||
if (!_occlusionBlurredFramebuffer) {
|
||||
allocate();
|
||||
}
|
||||
return _occlusionBlurredFramebuffer;
|
||||
}
|
||||
|
||||
gpu::TexturePointer AmbientOcclusionFramebuffer::getOcclusionBlurredTexture() {
|
||||
if (!_occlusionBlurredTexture) {
|
||||
allocate();
|
||||
}
|
||||
return _occlusionBlurredTexture;
|
||||
}
|
||||
|
||||
|
||||
class GaussianDistribution {
|
||||
public:
|
||||
|
||||
|
@ -90,15 +169,11 @@ public:
|
|||
|
||||
const int AmbientOcclusionEffect_FrameTransformSlot = 0;
|
||||
const int AmbientOcclusionEffect_ParamsSlot = 1;
|
||||
const int AmbientOcclusionEffect_DepthMapSlot = 0;
|
||||
const int AmbientOcclusionEffect_PyramidMapSlot = 0;
|
||||
const int AmbientOcclusionEffect_CameraCorrectionSlot = 2;
|
||||
const int AmbientOcclusionEffect_LinearDepthMapSlot = 0;
|
||||
const int AmbientOcclusionEffect_OcclusionMapSlot = 0;
|
||||
|
||||
AmbientOcclusionEffect::AmbientOcclusionEffect() {
|
||||
FrameTransform frameTransform;
|
||||
_frameTransformBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(FrameTransform), (const gpu::Byte*) &frameTransform));
|
||||
Parameters parameters;
|
||||
_parametersBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Parameters), (const gpu::Byte*) ¶meters));
|
||||
}
|
||||
|
||||
void AmbientOcclusionEffect::configure(const Config& config) {
|
||||
|
@ -108,67 +183,75 @@ void AmbientOcclusionEffect::configure(const Config& config) {
|
|||
|
||||
const double RADIUS_POWER = 6.0;
|
||||
const auto& radius = config.radius;
|
||||
if (radius != getRadius()) {
|
||||
auto& current = _parametersBuffer.edit<Parameters>().radiusInfo;
|
||||
if (radius != _parametersBuffer->getRadius()) {
|
||||
auto& current = _parametersBuffer->radiusInfo;
|
||||
current.x = radius;
|
||||
current.y = radius * radius;
|
||||
current.z = (float)(1.0 / pow((double)radius, RADIUS_POWER));
|
||||
}
|
||||
|
||||
if (config.obscuranceLevel != getObscuranceLevel()) {
|
||||
auto& current = _parametersBuffer.edit<Parameters>().radiusInfo;
|
||||
if (config.obscuranceLevel != _parametersBuffer->getObscuranceLevel()) {
|
||||
auto& current = _parametersBuffer->radiusInfo;
|
||||
current.w = config.obscuranceLevel;
|
||||
}
|
||||
|
||||
if (config.falloffBias != getFalloffBias()) {
|
||||
auto& current = _parametersBuffer.edit<Parameters>().ditheringInfo;
|
||||
if (config.falloffBias != _parametersBuffer->getFalloffBias()) {
|
||||
auto& current = _parametersBuffer->ditheringInfo;
|
||||
current.z = config.falloffBias;
|
||||
}
|
||||
|
||||
if (config.edgeSharpness != getEdgeSharpness()) {
|
||||
auto& current = _parametersBuffer.edit<Parameters>().blurInfo;
|
||||
if (config.edgeSharpness != _parametersBuffer->getEdgeSharpness()) {
|
||||
auto& current = _parametersBuffer->blurInfo;
|
||||
current.x = config.edgeSharpness;
|
||||
}
|
||||
|
||||
if (config.blurDeviation != getBlurDeviation()) {
|
||||
auto& current = _parametersBuffer.edit<Parameters>().blurInfo;
|
||||
if (config.blurDeviation != _parametersBuffer->getBlurDeviation()) {
|
||||
auto& current = _parametersBuffer->blurInfo;
|
||||
current.z = config.blurDeviation;
|
||||
shouldUpdateGaussian = true;
|
||||
}
|
||||
|
||||
if (config.numSpiralTurns != getNumSpiralTurns()) {
|
||||
auto& current = _parametersBuffer.edit<Parameters>().sampleInfo;
|
||||
if (config.numSpiralTurns != _parametersBuffer->getNumSpiralTurns()) {
|
||||
auto& current = _parametersBuffer->sampleInfo;
|
||||
current.z = config.numSpiralTurns;
|
||||
}
|
||||
|
||||
if (config.numSamples != getNumSamples()) {
|
||||
auto& current = _parametersBuffer.edit<Parameters>().sampleInfo;
|
||||
if (config.numSamples != _parametersBuffer->getNumSamples()) {
|
||||
auto& current = _parametersBuffer->sampleInfo;
|
||||
current.x = config.numSamples;
|
||||
current.y = 1.0f / config.numSamples;
|
||||
}
|
||||
|
||||
const auto& resolutionLevel = config.resolutionLevel;
|
||||
if (resolutionLevel != getResolutionLevel()) {
|
||||
auto& current = _parametersBuffer.edit<Parameters>().resolutionInfo;
|
||||
current.x = (float)resolutionLevel;
|
||||
|
||||
// Communicate the change to the Framebuffer cache
|
||||
DependencyManager::get<FramebufferCache>()->setAmbientOcclusionResolutionLevel(resolutionLevel);
|
||||
if (config.fetchMipsEnabled != _parametersBuffer->isFetchMipsEnabled()) {
|
||||
auto& current = _parametersBuffer->sampleInfo;
|
||||
current.w = (float)config.fetchMipsEnabled;
|
||||
}
|
||||
|
||||
if (config.blurRadius != getBlurRadius()) {
|
||||
auto& current = _parametersBuffer.edit<Parameters>().blurInfo;
|
||||
if (!_framebuffer) {
|
||||
_framebuffer = std::make_shared<AmbientOcclusionFramebuffer>();
|
||||
}
|
||||
|
||||
if (config.perspectiveScale != _parametersBuffer->getPerspectiveScale()) {
|
||||
_parametersBuffer->resolutionInfo.z = config.perspectiveScale;
|
||||
}
|
||||
if (config.resolutionLevel != _parametersBuffer->getResolutionLevel()) {
|
||||
auto& current = _parametersBuffer->resolutionInfo;
|
||||
current.x = (float) config.resolutionLevel;
|
||||
}
|
||||
|
||||
if (config.blurRadius != _parametersBuffer->getBlurRadius()) {
|
||||
auto& current = _parametersBuffer->blurInfo;
|
||||
current.y = (float)config.blurRadius;
|
||||
shouldUpdateGaussian = true;
|
||||
}
|
||||
|
||||
if (config.ditheringEnabled != isDitheringEnabled()) {
|
||||
auto& current = _parametersBuffer.edit<Parameters>().ditheringInfo;
|
||||
if (config.ditheringEnabled != _parametersBuffer->isDitheringEnabled()) {
|
||||
auto& current = _parametersBuffer->ditheringInfo;
|
||||
current.x = (float)config.ditheringEnabled;
|
||||
}
|
||||
|
||||
if (config.borderingEnabled != isBorderingEnabled()) {
|
||||
auto& current = _parametersBuffer.edit<Parameters>().ditheringInfo;
|
||||
if (config.borderingEnabled != _parametersBuffer->isBorderingEnabled()) {
|
||||
auto& current = _parametersBuffer->ditheringInfo;
|
||||
current.w = (float)config.borderingEnabled;
|
||||
}
|
||||
|
||||
|
@ -177,32 +260,6 @@ void AmbientOcclusionEffect::configure(const Config& config) {
|
|||
}
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& AmbientOcclusionEffect::getPyramidPipeline() {
|
||||
if (!_pyramidPipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(ssao_makePyramid_frag));
|
||||
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);
|
||||
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
// 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);
|
||||
|
||||
// Good to go add the brand new pipeline
|
||||
_pyramidPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _pyramidPipeline;
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() {
|
||||
if (!_occlusionPipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
||||
|
@ -210,9 +267,11 @@ 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("deferredFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("pyramidMap"), AmbientOcclusionEffect_PyramidMapSlot));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("cameraCorrectionBuffer"), AmbientOcclusionEffect_CameraCorrectionSlot));
|
||||
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("pyramidMap"), AmbientOcclusionEffect_LinearDepthMapSlot));
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
@ -234,6 +293,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getHBlurPipeline() {
|
|||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("cameraCorrectionBuffer"), AmbientOcclusionEffect_CameraCorrectionSlot));
|
||||
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);
|
||||
|
@ -256,6 +316,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() {
|
|||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("cameraCorrectionBuffer"), AmbientOcclusionEffect_CameraCorrectionSlot));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), AmbientOcclusionEffect_OcclusionMapSlot));
|
||||
|
||||
|
@ -272,76 +333,50 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() {
|
|||
return _vBlurPipeline;
|
||||
}
|
||||
|
||||
|
||||
void AmbientOcclusionEffect::setDepthInfo(float nearZ, float farZ) {
|
||||
_frameTransformBuffer.edit<FrameTransform>().depthInfo = glm::vec4(nearZ*farZ, farZ -nearZ, -farZ, 0.0f);
|
||||
}
|
||||
|
||||
void AmbientOcclusionEffect::updateGaussianDistribution() {
|
||||
auto coefs = _parametersBuffer.edit<Parameters>()._gaussianCoefs;
|
||||
GaussianDistribution::evalSampling(coefs, Parameters::GAUSSIAN_COEFS_LENGTH, getBlurRadius(), getBlurDeviation());
|
||||
auto coefs = _parametersBuffer->_gaussianCoefs;
|
||||
GaussianDistribution::evalSampling(coefs, Parameters::GAUSSIAN_COEFS_LENGTH, _parametersBuffer->getBlurRadius(), _parametersBuffer->getBlurDeviation());
|
||||
}
|
||||
|
||||
void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) {
|
||||
#ifdef FIX_THE_FRAMEBUFFER_CACHE
|
||||
void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->hasViewFrustum());
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
|
||||
// FIXME: Different render modes should have different tasks
|
||||
if (args->_renderMode != RenderArgs::DEFAULT_RENDER_MODE) {
|
||||
return;
|
||||
const auto& frameTransform = inputs.get0();
|
||||
const auto& linearDepthFramebuffer = inputs.get2();
|
||||
|
||||
auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture();
|
||||
auto sourceViewport = args->_viewport;
|
||||
auto occlusionViewport = sourceViewport;
|
||||
|
||||
if (!_framebuffer) {
|
||||
_framebuffer = std::make_shared<AmbientOcclusionFramebuffer>();
|
||||
}
|
||||
|
||||
if (_parametersBuffer->getResolutionLevel() > 0) {
|
||||
linearDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture();
|
||||
occlusionViewport = occlusionViewport >> _parametersBuffer->getResolutionLevel();
|
||||
}
|
||||
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
auto depthBuffer = framebufferCache->getPrimaryDepthTexture();
|
||||
auto normalBuffer = framebufferCache->getDeferredNormalTexture();
|
||||
auto pyramidFBO = framebufferCache->getDepthPyramidFramebuffer();
|
||||
auto occlusionFBO = framebufferCache->getOcclusionFramebuffer();
|
||||
auto occlusionBlurredFBO = framebufferCache->getOcclusionBlurredFramebuffer();
|
||||
_framebuffer->updateLinearDepth(linearDepthTexture);
|
||||
|
||||
|
||||
auto occlusionFBO = _framebuffer->getOcclusionFramebuffer();
|
||||
auto occlusionBlurredFBO = _framebuffer->getOcclusionBlurredFramebuffer();
|
||||
|
||||
outputs.edit0() = _framebuffer;
|
||||
outputs.edit1() = _parametersBuffer;
|
||||
|
||||
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();
|
||||
auto framebufferSize = _framebuffer->getSourceFrameSize();
|
||||
|
||||
float sMin = occlusionViewport.x / (float)framebufferSize.x;
|
||||
float sWidth = occlusionViewport.z / (float)framebufferSize.x;
|
||||
float tMin = occlusionViewport.y / (float)framebufferSize.y;
|
||||
float tHeight = occlusionViewport.w / (float)framebufferSize.y;
|
||||
|
||||
auto resolutionLevel = getResolutionLevel();
|
||||
|
||||
// Update the depth info with near and far (same for stereo)
|
||||
setDepthInfo(args->getViewFrustum().getNearClip(), args->getViewFrustum().getFarClip());
|
||||
|
||||
_frameTransformBuffer.edit<FrameTransform>().pixelInfo = args->_viewport;
|
||||
//_parametersBuffer.edit<Parameters>()._ditheringInfo.y += 0.25f;
|
||||
|
||||
// Running in stero ?
|
||||
bool isStereo = args->_context->isStereo();
|
||||
if (!isStereo) {
|
||||
// Eval the mono projection
|
||||
mat4 monoProjMat;
|
||||
args->getViewFrustum().evalProjectionMatrix(monoProjMat);
|
||||
_frameTransformBuffer.edit<FrameTransform>().projection[0] = monoProjMat;
|
||||
_frameTransformBuffer.edit<FrameTransform>().stereoInfo = glm::vec4(0.0f, (float)args->_viewport.z, 0.0f, 0.0f);
|
||||
|
||||
} else {
|
||||
|
||||
mat4 projMats[2];
|
||||
mat4 eyeViews[2];
|
||||
args->_context->getStereoProjections(projMats);
|
||||
args->_context->getStereoViews(eyeViews);
|
||||
|
||||
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<FrameTransform>().projection[i] = sideViewMat;
|
||||
}
|
||||
|
||||
_frameTransformBuffer.edit<FrameTransform>().stereoInfo = glm::vec4(1.0f, (float)(args->_viewport.z >> 1), 0.0f, 1.0f);
|
||||
|
||||
}
|
||||
|
||||
auto pyramidPipeline = getPyramidPipeline();
|
||||
auto occlusionPipeline = getOcclusionPipeline();
|
||||
auto firstHBlurPipeline = getHBlurPipeline();
|
||||
auto lastVBlurPipeline = getVBlurPipeline();
|
||||
|
@ -351,7 +386,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext
|
|||
|
||||
_gpuTimer.begin(batch);
|
||||
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setViewportTransform(occlusionViewport);
|
||||
batch.setProjectionTransform(glm::mat4());
|
||||
batch.resetViewTransform();
|
||||
|
||||
|
@ -360,35 +395,22 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext
|
|||
model.setScale(glm::vec3(sWidth, tHeight, 1.0f));
|
||||
batch.setModelTransform(model);
|
||||
|
||||
batch.setUniformBuffer(AmbientOcclusionEffect_FrameTransformSlot, _frameTransformBuffer);
|
||||
batch.setUniformBuffer(AmbientOcclusionEffect_FrameTransformSlot, frameTransform->getFrameTransformBuffer());
|
||||
batch.setUniformBuffer(AmbientOcclusionEffect_ParamsSlot, _parametersBuffer);
|
||||
|
||||
|
||||
// Pyramid pass
|
||||
batch.setFramebuffer(pyramidFBO);
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(args->getViewFrustum().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.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);
|
||||
}
|
||||
|
||||
|
||||
// We need this with the mips levels
|
||||
batch.generateTextureMips(_framebuffer->getLinearDepthTexture());
|
||||
|
||||
// Occlusion pass
|
||||
batch.setFramebuffer(occlusionFBO);
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(1.0f));
|
||||
batch.setPipeline(occlusionPipeline);
|
||||
batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot, pyramidFBO->getRenderBuffer(0));
|
||||
batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, _framebuffer->getLinearDepthTexture());
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
|
||||
if (getBlurRadius() > 0) {
|
||||
if (_parametersBuffer->getBlurRadius() > 0) {
|
||||
// Blur 1st pass
|
||||
batch.setFramebuffer(occlusionBlurredFBO);
|
||||
batch.setPipeline(firstHBlurPipeline);
|
||||
|
@ -402,10 +424,118 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext
|
|||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
|
||||
|
||||
batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, nullptr);
|
||||
batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, nullptr);
|
||||
|
||||
_gpuTimer.end(batch);
|
||||
});
|
||||
|
||||
// Update the timer
|
||||
std::static_pointer_cast<Config>(renderContext->jobConfig)->gpuTime = _gpuTimer.getAverage();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
DebugAmbientOcclusion::DebugAmbientOcclusion() {
|
||||
}
|
||||
|
||||
void DebugAmbientOcclusion::configure(const Config& config) {
|
||||
|
||||
_showCursorPixel = config.showCursorPixel;
|
||||
|
||||
auto cursorPos = glm::vec2(_parametersBuffer->pixelInfo);
|
||||
if (cursorPos != config.debugCursorTexcoord) {
|
||||
_parametersBuffer->pixelInfo = glm::vec4(config.debugCursorTexcoord, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& DebugAmbientOcclusion::getDebugPipeline() {
|
||||
if (!_debugPipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(ssao_debugOcclusion_frag));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("debugAmbientOcclusionBuffer"), 2));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("pyramidMap"), AmbientOcclusionEffect_LinearDepthMapSlot));
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
state->setColorWriteMask(true, true, true, false);
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
// Good to go add the brand new pipeline
|
||||
_debugPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _debugPipeline;
|
||||
}
|
||||
|
||||
void DebugAmbientOcclusion::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->hasViewFrustum());
|
||||
|
||||
if (!_showCursorPixel) {
|
||||
return;
|
||||
}
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
|
||||
const auto& frameTransform = inputs.get0();
|
||||
const auto& linearDepthFramebuffer = inputs.get2();
|
||||
const auto& ambientOcclusionUniforms = inputs.get3();
|
||||
|
||||
// Skip if AO is not started yet
|
||||
if (!ambientOcclusionUniforms._buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture();
|
||||
auto sourceViewport = args->_viewport;
|
||||
auto occlusionViewport = sourceViewport;
|
||||
|
||||
auto resolutionLevel = ambientOcclusionUniforms->getResolutionLevel();
|
||||
|
||||
if (resolutionLevel > 0) {
|
||||
linearDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture();
|
||||
occlusionViewport = occlusionViewport >> ambientOcclusionUniforms->getResolutionLevel();
|
||||
}
|
||||
|
||||
|
||||
auto framebufferSize = glm::ivec2(linearDepthTexture->getDimensions());
|
||||
|
||||
float sMin = occlusionViewport.x / (float)framebufferSize.x;
|
||||
float sWidth = occlusionViewport.z / (float)framebufferSize.x;
|
||||
float tMin = occlusionViewport.y / (float)framebufferSize.y;
|
||||
float tHeight = occlusionViewport.w / (float)framebufferSize.y;
|
||||
|
||||
auto debugPipeline = getDebugPipeline();
|
||||
|
||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
||||
batch.setViewportTransform(sourceViewport);
|
||||
batch.setProjectionTransform(glm::mat4());
|
||||
batch.setViewTransform(Transform());
|
||||
|
||||
Transform model;
|
||||
model.setTranslation(glm::vec3(sMin, tMin, 0.0f));
|
||||
model.setScale(glm::vec3(sWidth, tHeight, 1.0f));
|
||||
batch.setModelTransform(model);
|
||||
|
||||
batch.setUniformBuffer(AmbientOcclusionEffect_FrameTransformSlot, frameTransform->getFrameTransformBuffer());
|
||||
batch.setUniformBuffer(AmbientOcclusionEffect_ParamsSlot, ambientOcclusionUniforms);
|
||||
batch.setUniformBuffer(2, _parametersBuffer);
|
||||
|
||||
batch.setPipeline(debugPipeline);
|
||||
batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, linearDepthTexture);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
|
||||
batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, nullptr);
|
||||
});
|
||||
|
||||
}
|
||||
|
|
@ -16,11 +16,49 @@
|
|||
|
||||
#include "render/DrawTask.h"
|
||||
|
||||
#include "DeferredFrameTransform.h"
|
||||
#include "DeferredFramebuffer.h"
|
||||
#include "SurfaceGeometryPass.h"
|
||||
|
||||
class AmbientOcclusionFramebuffer {
|
||||
public:
|
||||
AmbientOcclusionFramebuffer();
|
||||
|
||||
gpu::FramebufferPointer getOcclusionFramebuffer();
|
||||
gpu::TexturePointer getOcclusionTexture();
|
||||
|
||||
gpu::FramebufferPointer getOcclusionBlurredFramebuffer();
|
||||
gpu::TexturePointer getOcclusionBlurredTexture();
|
||||
|
||||
// Update the source framebuffer size which will drive the allocation of all the other resources.
|
||||
void updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer);
|
||||
gpu::TexturePointer getLinearDepthTexture();
|
||||
const glm::ivec2& getSourceFrameSize() const { return _frameSize; }
|
||||
|
||||
protected:
|
||||
void clear();
|
||||
void allocate();
|
||||
|
||||
gpu::TexturePointer _linearDepthTexture;
|
||||
|
||||
gpu::FramebufferPointer _occlusionFramebuffer;
|
||||
gpu::TexturePointer _occlusionTexture;
|
||||
|
||||
gpu::FramebufferPointer _occlusionBlurredFramebuffer;
|
||||
gpu::TexturePointer _occlusionBlurredTexture;
|
||||
|
||||
|
||||
glm::ivec2 _frameSize;
|
||||
};
|
||||
|
||||
using AmbientOcclusionFramebufferPointer = std::shared_ptr<AmbientOcclusionFramebuffer>;
|
||||
|
||||
class AmbientOcclusionEffectConfig : public render::Job::Config::Persistent {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty)
|
||||
Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled NOTIFY dirty)
|
||||
Q_PROPERTY(bool borderingEnabled MEMBER borderingEnabled NOTIFY dirty)
|
||||
Q_PROPERTY(bool fetchMipsEnabled MEMBER fetchMipsEnabled NOTIFY dirty)
|
||||
Q_PROPERTY(float radius MEMBER radius WRITE setRadius)
|
||||
Q_PROPERTY(float obscuranceLevel MEMBER obscuranceLevel WRITE setObscuranceLevel)
|
||||
Q_PROPERTY(float falloffBias MEMBER falloffBias WRITE setFalloffBias)
|
||||
|
@ -49,72 +87,62 @@ public:
|
|||
double getGpuTime() { return gpuTime; }
|
||||
|
||||
float radius{ 0.5f };
|
||||
float perspectiveScale{ 1.0f };
|
||||
float obscuranceLevel{ 0.5f }; // intensify or dim down the obscurance effect
|
||||
float falloffBias{ 0.01f };
|
||||
float edgeSharpness{ 1.0f };
|
||||
float blurDeviation{ 2.5f };
|
||||
float numSpiralTurns{ 7.0f }; // defining an angle span to distribute the samples ray directions
|
||||
int numSamples{ 11 };
|
||||
int numSamples{ 16 };
|
||||
int resolutionLevel{ 1 };
|
||||
int blurRadius{ 4 }; // 0 means no blurring
|
||||
bool ditheringEnabled{ true }; // randomize the distribution of rays per pixel, should always be true
|
||||
bool ditheringEnabled{ true }; // randomize the distribution of taps per pixel, should always be true
|
||||
bool borderingEnabled{ true }; // avoid evaluating information from non existing pixels out of the frame, should always be true
|
||||
bool fetchMipsEnabled{ true }; // fetch taps in sub mips to otpimize cache, should always be true
|
||||
double gpuTime{ 0.0 };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
|
||||
namespace gpu {
|
||||
template <class T> class UniformBuffer : public gpu::BufferView {
|
||||
public:
|
||||
|
||||
static BufferPointer makeBuffer() {
|
||||
T t;
|
||||
return std::make_shared<gpu::Buffer>(sizeof(T), (const gpu::Byte*) &t);
|
||||
}
|
||||
~UniformBuffer<T>() {};
|
||||
UniformBuffer<T>() : gpu::BufferView(makeBuffer()) {}
|
||||
|
||||
const T* operator ->() const { return &get<T>(); }
|
||||
T* operator ->() {
|
||||
return &edit<T>(0);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
class AmbientOcclusionEffect {
|
||||
public:
|
||||
using Inputs = render::VaryingSet3<DeferredFrameTransformPointer, DeferredFramebufferPointer, LinearDepthFramebufferPointer>;
|
||||
using Outputs = render::VaryingSet2<AmbientOcclusionFramebufferPointer, gpu::BufferView>;
|
||||
using Config = AmbientOcclusionEffectConfig;
|
||||
using JobModel = render::Job::Model<AmbientOcclusionEffect, Config>;
|
||||
using JobModel = render::Job::ModelIO<AmbientOcclusionEffect, Inputs, Outputs, Config>;
|
||||
|
||||
AmbientOcclusionEffect();
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs);
|
||||
|
||||
float getRadius() const { return _parametersBuffer.get<Parameters>().radiusInfo.x; }
|
||||
float getObscuranceLevel() const { return _parametersBuffer.get<Parameters>().radiusInfo.w; }
|
||||
float getFalloffBias() const { return (float)_parametersBuffer.get<Parameters>().ditheringInfo.z; }
|
||||
float getEdgeSharpness() const { return (float)_parametersBuffer.get<Parameters>().blurInfo.x; }
|
||||
float getBlurDeviation() const { return _parametersBuffer.get<Parameters>().blurInfo.z; }
|
||||
float getNumSpiralTurns() const { return _parametersBuffer.get<Parameters>().sampleInfo.z; }
|
||||
int getNumSamples() const { return (int)_parametersBuffer.get<Parameters>().sampleInfo.x; }
|
||||
int getResolutionLevel() const { return _parametersBuffer.get<Parameters>().resolutionInfo.x; }
|
||||
int getBlurRadius() const { return (int)_parametersBuffer.get<Parameters>().blurInfo.y; }
|
||||
bool isDitheringEnabled() const { return _parametersBuffer.get<Parameters>().ditheringInfo.x; }
|
||||
bool isBorderingEnabled() const { return _parametersBuffer.get<Parameters>().ditheringInfo.w; }
|
||||
|
||||
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:
|
||||
// Resolution info
|
||||
glm::vec4 resolutionInfo { -1.0f, 0.0f, 0.0f, 0.0f };
|
||||
glm::vec4 resolutionInfo { -1.0f, 0.0f, 1.0f, 0.0f };
|
||||
// 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
|
||||
|
@ -126,22 +154,92 @@ private:
|
|||
// gaussian distribution coefficients first is the sampling radius (max is 6)
|
||||
const static int GAUSSIAN_COEFS_LENGTH = 8;
|
||||
float _gaussianCoefs[GAUSSIAN_COEFS_LENGTH];
|
||||
|
||||
|
||||
Parameters() {}
|
||||
};
|
||||
gpu::BufferView _parametersBuffer;
|
||||
|
||||
const gpu::PipelinePointer& getPyramidPipeline();
|
||||
int getResolutionLevel() const { return resolutionInfo.x; }
|
||||
float getRadius() const { return radiusInfo.x; }
|
||||
float getPerspectiveScale() const { return resolutionInfo.z; }
|
||||
float getObscuranceLevel() const { return radiusInfo.w; }
|
||||
float getFalloffBias() const { return (float)ditheringInfo.z; }
|
||||
float getEdgeSharpness() const { return (float)blurInfo.x; }
|
||||
float getBlurDeviation() const { return blurInfo.z; }
|
||||
|
||||
float getNumSpiralTurns() const { return sampleInfo.z; }
|
||||
int getNumSamples() const { return (int)sampleInfo.x; }
|
||||
bool isFetchMipsEnabled() const { return sampleInfo.w; }
|
||||
|
||||
int getBlurRadius() const { return (int)blurInfo.y; }
|
||||
bool isDitheringEnabled() const { return ditheringInfo.x; }
|
||||
bool isBorderingEnabled() const { return ditheringInfo.w; }
|
||||
};
|
||||
using ParametersBuffer = gpu::UniformBuffer<Parameters>;
|
||||
|
||||
private:
|
||||
void updateGaussianDistribution();
|
||||
|
||||
ParametersBuffer _parametersBuffer;
|
||||
|
||||
const gpu::PipelinePointer& getOcclusionPipeline();
|
||||
const gpu::PipelinePointer& getHBlurPipeline(); // first
|
||||
const gpu::PipelinePointer& getVBlurPipeline(); // second
|
||||
|
||||
gpu::PipelinePointer _pyramidPipeline;
|
||||
gpu::PipelinePointer _occlusionPipeline;
|
||||
gpu::PipelinePointer _hBlurPipeline;
|
||||
gpu::PipelinePointer _vBlurPipeline;
|
||||
|
||||
AmbientOcclusionFramebufferPointer _framebuffer;
|
||||
|
||||
gpu::RangeTimer _gpuTimer;
|
||||
|
||||
friend class DebugAmbientOcclusion;
|
||||
};
|
||||
|
||||
|
||||
class DebugAmbientOcclusionConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool showCursorPixel MEMBER showCursorPixel NOTIFY dirty)
|
||||
Q_PROPERTY(glm::vec2 debugCursorTexcoord MEMBER debugCursorTexcoord NOTIFY dirty)
|
||||
public:
|
||||
DebugAmbientOcclusionConfig() : render::Job::Config(true) {}
|
||||
|
||||
bool showCursorPixel{ false };
|
||||
glm::vec2 debugCursorTexcoord{ 0.5f, 0.5f };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
|
||||
class DebugAmbientOcclusion {
|
||||
public:
|
||||
using Inputs = render::VaryingSet4<DeferredFrameTransformPointer, DeferredFramebufferPointer, LinearDepthFramebufferPointer, AmbientOcclusionEffect::ParametersBuffer>;
|
||||
using Config = DebugAmbientOcclusionConfig;
|
||||
using JobModel = render::Job::ModelI<DebugAmbientOcclusion, Inputs, Config>;
|
||||
|
||||
DebugAmbientOcclusion();
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs);
|
||||
|
||||
private:
|
||||
|
||||
// Class describing the uniform buffer with all the parameters common to the debug AO shaders
|
||||
class Parameters {
|
||||
public:
|
||||
// Pixel info
|
||||
glm::vec4 pixelInfo { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
|
||||
Parameters() {}
|
||||
};
|
||||
gpu::UniformBuffer<Parameters> _parametersBuffer;
|
||||
|
||||
const gpu::PipelinePointer& getDebugPipeline();
|
||||
|
||||
gpu::PipelinePointer _debugPipeline;
|
||||
|
||||
bool _showCursorPixel{ false };
|
||||
};
|
||||
|
||||
#endif // hifi_AmbientOcclusionEffect_h
|
||||
|
|
|
@ -202,14 +202,14 @@ static const std::string DEFAULT_DEBUG_SCATTERING_SHADER{
|
|||
|
||||
static const std::string DEFAULT_AMBIENT_OCCLUSION_SHADER{
|
||||
"vec4 getFragmentColor() {"
|
||||
" return vec4(vec3(texture(obscuranceMap, uv).x), 1.0);"
|
||||
" return vec4(vec3(texture(obscuranceMap, uv).xyz), 1.0);"
|
||||
// When drawing color " 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);"
|
||||
// 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{
|
||||
"vec4 getFragmentColor() {"
|
||||
" return vec4(vec3(texture(occlusionBlurredMap, uv).x), 1.0);"
|
||||
" return vec4(vec3(texture(occlusionBlurredMap, uv).xyz), 1.0);"
|
||||
" }"
|
||||
};
|
||||
|
||||
|
@ -379,6 +379,7 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren
|
|||
auto& deferredFramebuffer = inputs.get0();
|
||||
auto& linearDepthTarget = inputs.get1();
|
||||
auto& surfaceGeometryFramebuffer = inputs.get2();
|
||||
auto& ambientOcclusionFramebuffer = inputs.get3();
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
@ -402,29 +403,51 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren
|
|||
|
||||
batch.setPipeline(getPipeline(_mode, first));
|
||||
|
||||
batch.setResourceTexture(Albedo, deferredFramebuffer->getDeferredColorTexture());
|
||||
batch.setResourceTexture(Normal, deferredFramebuffer->getDeferredNormalTexture());
|
||||
batch.setResourceTexture(Specular, deferredFramebuffer->getDeferredSpecularTexture());
|
||||
batch.setResourceTexture(Depth, deferredFramebuffer->getPrimaryDepthTexture());
|
||||
batch.setResourceTexture(Lighting, deferredFramebuffer->getLightingTexture());
|
||||
batch.setResourceTexture(Shadow, lightStage.lights[0]->shadow.framebuffer->getDepthStencilBuffer());
|
||||
batch.setResourceTexture(LinearDepth, linearDepthTarget->getLinearDepthTexture());
|
||||
batch.setResourceTexture(HalfLinearDepth, linearDepthTarget->getHalfLinearDepthTexture());
|
||||
batch.setResourceTexture(HalfNormal, linearDepthTarget->getHalfNormalTexture());
|
||||
|
||||
batch.setResourceTexture(Curvature, surfaceGeometryFramebuffer->getCurvatureTexture());
|
||||
batch.setResourceTexture(DiffusedCurvature, surfaceGeometryFramebuffer->getLowCurvatureTexture());
|
||||
if (DependencyManager::get<DeferredLightingEffect>()->isAmbientOcclusionEnabled()) {
|
||||
batch.setResourceTexture(AmbientOcclusion, framebufferCache->getOcclusionTexture());
|
||||
} else {
|
||||
// need to assign the white texture if ao is off
|
||||
batch.setResourceTexture(AmbientOcclusion, textureCache->getWhiteTexture());
|
||||
}
|
||||
batch.setResourceTexture(AmbientOcclusionBlurred, framebufferCache->getOcclusionBlurredTexture());
|
||||
if (deferredFramebuffer) {
|
||||
batch.setResourceTexture(Albedo, deferredFramebuffer->getDeferredColorTexture());
|
||||
batch.setResourceTexture(Normal, deferredFramebuffer->getDeferredNormalTexture());
|
||||
batch.setResourceTexture(Specular, deferredFramebuffer->getDeferredSpecularTexture());
|
||||
batch.setResourceTexture(Depth, deferredFramebuffer->getPrimaryDepthTexture());
|
||||
batch.setResourceTexture(Lighting, deferredFramebuffer->getLightingTexture());
|
||||
}
|
||||
if (!lightStage.lights.empty()) {
|
||||
batch.setResourceTexture(Shadow, lightStage.lights[0]->shadow.framebuffer->getDepthStencilBuffer());
|
||||
}
|
||||
|
||||
if (linearDepthTarget) {
|
||||
batch.setResourceTexture(LinearDepth, linearDepthTarget->getLinearDepthTexture());
|
||||
batch.setResourceTexture(HalfLinearDepth, linearDepthTarget->getHalfLinearDepthTexture());
|
||||
batch.setResourceTexture(HalfNormal, linearDepthTarget->getHalfNormalTexture());
|
||||
}
|
||||
if (surfaceGeometryFramebuffer) {
|
||||
batch.setResourceTexture(Curvature, surfaceGeometryFramebuffer->getCurvatureTexture());
|
||||
batch.setResourceTexture(DiffusedCurvature, surfaceGeometryFramebuffer->getLowCurvatureTexture());
|
||||
}
|
||||
if (ambientOcclusionFramebuffer) {
|
||||
batch.setResourceTexture(AmbientOcclusion, ambientOcclusionFramebuffer->getOcclusionTexture());
|
||||
batch.setResourceTexture(AmbientOcclusionBlurred, ambientOcclusionFramebuffer->getOcclusionBlurredTexture());
|
||||
}
|
||||
const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
const glm::vec2 bottomLeft(_size.x, _size.y);
|
||||
const glm::vec2 topRight(_size.z, _size.w);
|
||||
geometryBuffer->renderQuad(batch, bottomLeft, topRight, color);
|
||||
|
||||
|
||||
batch.setResourceTexture(Albedo, nullptr);
|
||||
batch.setResourceTexture(Normal, nullptr);
|
||||
batch.setResourceTexture(Specular, nullptr);
|
||||
batch.setResourceTexture(Depth, nullptr);
|
||||
batch.setResourceTexture(Lighting, nullptr);
|
||||
batch.setResourceTexture(Shadow, nullptr);
|
||||
batch.setResourceTexture(LinearDepth, nullptr);
|
||||
batch.setResourceTexture(HalfLinearDepth, nullptr);
|
||||
batch.setResourceTexture(HalfNormal, nullptr);
|
||||
|
||||
batch.setResourceTexture(Curvature, nullptr);
|
||||
batch.setResourceTexture(DiffusedCurvature, nullptr);
|
||||
|
||||
batch.setResourceTexture(AmbientOcclusion, nullptr);
|
||||
batch.setResourceTexture(AmbientOcclusionBlurred, nullptr);
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <render/DrawTask.h>
|
||||
#include "DeferredFramebuffer.h"
|
||||
#include "SurfaceGeometryPass.h"
|
||||
#include "AmbientOcclusionEffect.h"
|
||||
|
||||
class DebugDeferredBufferConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
|
@ -36,7 +37,7 @@ signals:
|
|||
|
||||
class DebugDeferredBuffer {
|
||||
public:
|
||||
using Inputs = render::VaryingSet4<DeferredFramebufferPointer, LinearDepthFramebufferPointer, SurfaceGeometryFramebufferPointer, gpu::FramebufferPointer>;
|
||||
using Inputs = render::VaryingSet4<DeferredFramebufferPointer, LinearDepthFramebufferPointer, SurfaceGeometryFramebufferPointer, AmbientOcclusionFramebufferPointer>;
|
||||
using Config = DebugDeferredBufferConfig;
|
||||
using JobModel = render::Job::ModelI<DebugDeferredBuffer, Inputs, Config>;
|
||||
|
||||
|
|
|
@ -403,7 +403,7 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c
|
|||
const DeferredFramebufferPointer& deferredFramebuffer,
|
||||
const LightingModelPointer& lightingModel,
|
||||
const SurfaceGeometryFramebufferPointer& surfaceGeometryFramebuffer,
|
||||
const gpu::FramebufferPointer& lowCurvatureNormalFramebuffer,
|
||||
const AmbientOcclusionFramebufferPointer& ambientOcclusionFramebuffer,
|
||||
const SubsurfaceScatteringResourcePointer& subsurfaceScatteringResource) {
|
||||
|
||||
auto args = renderContext->args;
|
||||
|
@ -434,7 +434,7 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c
|
|||
|
||||
// FIXME: Different render modes should have different tasks
|
||||
if (args->_renderMode == RenderArgs::DEFAULT_RENDER_MODE && deferredLightingEffect->isAmbientOcclusionEnabled()) {
|
||||
batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, framebufferCache->getOcclusionTexture());
|
||||
batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, ambientOcclusionFramebuffer->getOcclusionTexture());
|
||||
} else {
|
||||
// need to assign the white texture if ao is off
|
||||
batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, textureCache->getWhiteTexture());
|
||||
|
@ -449,9 +449,6 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c
|
|||
// Subsurface scattering specific
|
||||
if (surfaceGeometryFramebuffer) {
|
||||
batch.setResourceTexture(DEFERRED_BUFFER_CURVATURE_UNIT, surfaceGeometryFramebuffer->getCurvatureTexture());
|
||||
}
|
||||
if (lowCurvatureNormalFramebuffer) {
|
||||
// batch.setResourceTexture(DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT, lowCurvatureNormalFramebuffer->getRenderBuffer(0));
|
||||
batch.setResourceTexture(DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT, surfaceGeometryFramebuffer->getLowCurvatureTexture());
|
||||
}
|
||||
if (subsurfaceScatteringResource) {
|
||||
|
@ -698,7 +695,7 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo
|
|||
auto deferredFramebuffer = inputs.get1();
|
||||
auto lightingModel = inputs.get2();
|
||||
auto surfaceGeometryFramebuffer = inputs.get3();
|
||||
auto lowCurvatureNormalFramebuffer = inputs.get4();
|
||||
auto ssaoFramebuffer = inputs.get4();
|
||||
auto subsurfaceScatteringResource = inputs.get5();
|
||||
auto args = renderContext->args;
|
||||
|
||||
|
@ -706,7 +703,7 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo
|
|||
_gpuTimer.begin(batch);
|
||||
});
|
||||
|
||||
setupJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer, lowCurvatureNormalFramebuffer, subsurfaceScatteringResource);
|
||||
setupJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer, ssaoFramebuffer, subsurfaceScatteringResource);
|
||||
|
||||
lightsJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel);
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "LightStage.h"
|
||||
#include "SurfaceGeometryPass.h"
|
||||
#include "SubsurfaceScattering.h"
|
||||
#include "AmbientOcclusionEffect.h"
|
||||
|
||||
class RenderArgs;
|
||||
struct LightLocations;
|
||||
|
@ -138,7 +139,7 @@ public:
|
|||
const DeferredFramebufferPointer& deferredFramebuffer,
|
||||
const LightingModelPointer& lightingModel,
|
||||
const SurfaceGeometryFramebufferPointer& surfaceGeometryFramebuffer,
|
||||
const gpu::FramebufferPointer& lowCurvatureNormalFramebuffer,
|
||||
const AmbientOcclusionFramebufferPointer& ambientOcclusionFramebuffer,
|
||||
const SubsurfaceScatteringResourcePointer& subsurfaceScatteringResource);
|
||||
};
|
||||
|
||||
|
@ -178,7 +179,7 @@ signals:
|
|||
|
||||
class RenderDeferred {
|
||||
public:
|
||||
using Inputs = render::VaryingSet6 < DeferredFrameTransformPointer, DeferredFramebufferPointer, LightingModelPointer, SurfaceGeometryFramebufferPointer, gpu::FramebufferPointer, SubsurfaceScatteringResourcePointer>;
|
||||
using Inputs = render::VaryingSet6 < DeferredFrameTransformPointer, DeferredFramebufferPointer, LightingModelPointer, SurfaceGeometryFramebufferPointer, AmbientOcclusionFramebufferPointer, SubsurfaceScatteringResourcePointer>;
|
||||
using Config = RenderDeferredConfig;
|
||||
using JobModel = render::Job::ModelI<RenderDeferred, Inputs, Config>;
|
||||
|
||||
|
|
|
@ -93,6 +93,13 @@ bool isStereo() {
|
|||
float getStereoSideWidth(int resolutionLevel) {
|
||||
return float(int(frameTransform._stereoInfo.y) >> resolutionLevel);
|
||||
}
|
||||
float getStereoSideHeight(int resolutionLevel) {
|
||||
return float(int(frameTransform._pixelInfo.w) >> resolutionLevel);
|
||||
}
|
||||
|
||||
vec2 getSideImageSize(int resolutionLevel) {
|
||||
return vec2(float(int(frameTransform._stereoInfo.y) >> resolutionLevel), float(int(frameTransform._pixelInfo.w) >> resolutionLevel));
|
||||
}
|
||||
|
||||
ivec4 getStereoSideInfo(int xPos, int resolutionLevel) {
|
||||
int sideWidth = int(getStereoSideWidth(resolutionLevel));
|
||||
|
|
|
@ -22,10 +22,6 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) {
|
|||
if (_frameBufferSize != frameBufferSize) {
|
||||
_frameBufferSize = frameBufferSize;
|
||||
_selfieFramebuffer.reset();
|
||||
_occlusionFramebuffer.reset();
|
||||
_occlusionTexture.reset();
|
||||
_occlusionBlurredFramebuffer.reset();
|
||||
_occlusionBlurredTexture.reset();
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_cachedFramebuffers.clear();
|
||||
|
@ -45,33 +41,6 @@ void FramebufferCache::createPrimaryFramebuffer() {
|
|||
_selfieFramebuffer->setRenderBuffer(0, tex);
|
||||
|
||||
auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR);
|
||||
|
||||
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_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(colorFormat, width, height, defaultSampler));
|
||||
_occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
_occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture);
|
||||
// _occlusionBlurredFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
}
|
||||
|
||||
|
||||
|
@ -98,40 +67,3 @@ gpu::FramebufferPointer FramebufferCache::getSelfieFramebuffer() {
|
|||
}
|
||||
return _selfieFramebuffer;
|
||||
}
|
||||
|
||||
void FramebufferCache::setAmbientOcclusionResolutionLevel(int level) {
|
||||
const int MAX_AO_RESOLUTION_LEVEL = 4;
|
||||
level = std::max(0, std::min(level, MAX_AO_RESOLUTION_LEVEL));
|
||||
if (level != _AOResolutionLevel) {
|
||||
_AOResolutionLevel = level;
|
||||
resizeAmbientOcclusionBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer FramebufferCache::getOcclusionFramebuffer() {
|
||||
if (!_occlusionFramebuffer) {
|
||||
resizeAmbientOcclusionBuffers();
|
||||
}
|
||||
return _occlusionFramebuffer;
|
||||
}
|
||||
|
||||
gpu::TexturePointer FramebufferCache::getOcclusionTexture() {
|
||||
if (!_occlusionTexture) {
|
||||
resizeAmbientOcclusionBuffers();
|
||||
}
|
||||
return _occlusionTexture;
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer FramebufferCache::getOcclusionBlurredFramebuffer() {
|
||||
if (!_occlusionBlurredFramebuffer) {
|
||||
resizeAmbientOcclusionBuffers();
|
||||
}
|
||||
return _occlusionBlurredFramebuffer;
|
||||
}
|
||||
|
||||
gpu::TexturePointer FramebufferCache::getOcclusionBlurredTexture() {
|
||||
if (!_occlusionBlurredTexture) {
|
||||
resizeAmbientOcclusionBuffers();
|
||||
}
|
||||
return _occlusionBlurredTexture;
|
||||
}
|
|
@ -27,12 +27,6 @@ public:
|
|||
void setFrameBufferSize(QSize frameBufferSize);
|
||||
const QSize& getFrameBufferSize() const { return _frameBufferSize; }
|
||||
|
||||
void setAmbientOcclusionResolutionLevel(int level);
|
||||
gpu::FramebufferPointer getOcclusionFramebuffer();
|
||||
gpu::TexturePointer getOcclusionTexture();
|
||||
gpu::FramebufferPointer getOcclusionBlurredFramebuffer();
|
||||
gpu::TexturePointer getOcclusionBlurredTexture();
|
||||
|
||||
/// Returns the framebuffer object used to render selfie maps;
|
||||
gpu::FramebufferPointer getSelfieFramebuffer();
|
||||
|
||||
|
@ -50,21 +44,10 @@ private:
|
|||
|
||||
gpu::FramebufferPointer _selfieFramebuffer;
|
||||
|
||||
gpu::FramebufferPointer _occlusionFramebuffer;
|
||||
gpu::TexturePointer _occlusionTexture;
|
||||
|
||||
gpu::FramebufferPointer _occlusionBlurredFramebuffer;
|
||||
gpu::TexturePointer _occlusionBlurredTexture;
|
||||
|
||||
QSize _frameBufferSize{ 100, 100 };
|
||||
int _AOResolutionLevel = 1; // AO perform at half res
|
||||
|
||||
std::mutex _mutex;
|
||||
std::list<gpu::FramebufferPointer> _cachedFramebuffers;
|
||||
|
||||
// Resize/reallocate the buffers used for AO
|
||||
// the size of the AO buffers is scaled by the AOResolutionScale;
|
||||
void resizeAmbientOcclusionBuffers();
|
||||
};
|
||||
|
||||
#endif // hifi_FramebufferCache_h
|
||||
|
|
|
@ -124,10 +124,6 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
|
|||
const auto linearDepthPassInputs = LinearDepthPass::Inputs(deferredFrameTransform, deferredFramebuffer).hasVarying();
|
||||
const auto linearDepthPassOutputs = addJob<LinearDepthPass>("LinearDepth", linearDepthPassInputs);
|
||||
const auto linearDepthTarget = linearDepthPassOutputs.getN<LinearDepthPass::Outputs>(0);
|
||||
const auto linearDepthTexture = linearDepthPassOutputs.getN<LinearDepthPass::Outputs>(2);
|
||||
const auto halfLinearDepthTexture = linearDepthPassOutputs.getN<LinearDepthPass::Outputs>(3);
|
||||
const auto halfNormalTexture = linearDepthPassOutputs.getN<LinearDepthPass::Outputs>(4);
|
||||
|
||||
|
||||
// Curvature pass
|
||||
const auto surfaceGeometryPassInputs = SurfaceGeometryPass::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).hasVarying();
|
||||
|
@ -141,14 +137,17 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
|
|||
const auto scatteringResource = addJob<SubsurfaceScattering>("Scattering");
|
||||
|
||||
// AO job
|
||||
addJob<AmbientOcclusionEffect>("AmbientOcclusion");
|
||||
const auto ambientOcclusionInputs = AmbientOcclusionEffect::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).hasVarying();
|
||||
const auto ambientOcclusionOutputs = addJob<AmbientOcclusionEffect>("AmbientOcclusion", ambientOcclusionInputs);
|
||||
const auto ambientOcclusionFramebuffer = ambientOcclusionOutputs.getN<AmbientOcclusionEffect::Outputs>(0);
|
||||
const auto ambientOcclusionUniforms = ambientOcclusionOutputs.getN<AmbientOcclusionEffect::Outputs>(1);
|
||||
|
||||
// Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now.
|
||||
addJob<DrawLight>("DrawLight", lights);
|
||||
|
||||
const auto deferredLightingInputs = RenderDeferred::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel,
|
||||
surfaceGeometryFramebuffer, lowCurvatureNormalFramebuffer, scatteringResource).hasVarying();
|
||||
|
||||
surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).hasVarying();
|
||||
|
||||
// DeferredBuffer is complete, now let's shade it into the LightingBuffer
|
||||
addJob<RenderDeferred>("RenderDeferred", deferredLightingInputs);
|
||||
|
||||
|
@ -175,11 +174,15 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
|
|||
|
||||
// Debugging stages
|
||||
{
|
||||
// Debugging Deferred buffer job
|
||||
const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer));
|
||||
addJob<DebugDeferredBuffer>("DebugDeferredBuffer", debugFramebuffers);
|
||||
|
||||
addJob<DebugSubsurfaceScattering>("DebugScattering", deferredLightingInputs);
|
||||
|
||||
// Debugging Deferred buffer job
|
||||
const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, lowCurvatureNormalFramebuffer));
|
||||
addJob<DebugDeferredBuffer>("DebugDeferredBuffer", debugFramebuffers);
|
||||
const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).hasVarying();
|
||||
addJob<DebugAmbientOcclusion>("DebugAmbientOcclusion", debugAmbientOcclusionInputs);
|
||||
|
||||
|
||||
// Scene Octree Debuging job
|
||||
{
|
||||
|
|
|
@ -61,6 +61,9 @@ void LinearDepthFramebuffer::updatePrimaryDepth(const gpu::TexturePointer& depth
|
|||
void LinearDepthFramebuffer::clear() {
|
||||
_linearDepthFramebuffer.reset();
|
||||
_linearDepthTexture.reset();
|
||||
_downsampleFramebuffer.reset();
|
||||
_halfLinearDepthTexture.reset();
|
||||
_halfNormalTexture.reset();
|
||||
}
|
||||
|
||||
void LinearDepthFramebuffer::allocate() {
|
||||
|
@ -71,7 +74,6 @@ void LinearDepthFramebuffer::allocate() {
|
|||
// For Linear Depth:
|
||||
_linearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), width, height,
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
// _linearDepthTexture->autoGenerateMips(1);
|
||||
_linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
_linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture);
|
||||
_linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat());
|
||||
|
@ -79,6 +81,7 @@ void LinearDepthFramebuffer::allocate() {
|
|||
// For Downsampling:
|
||||
_halfLinearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y,
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
_halfLinearDepthTexture->autoGenerateMips(5);
|
||||
|
||||
_halfNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y,
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
|
@ -193,7 +196,7 @@ void LinearDepthPass::run(const render::SceneContextPointer& sceneContext, const
|
|||
batch.setResourceTexture(DepthLinearPass_NormalMapSlot, normalTexture);
|
||||
batch.setPipeline(downsamplePipeline);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
|
||||
_gpuTimer.end(batch);
|
||||
});
|
||||
|
||||
|
|
|
@ -30,13 +30,8 @@ vec2 unpackOcclusionDepth(vec3 raw) {
|
|||
<@endfunc@>
|
||||
|
||||
<@func declareAmbientOcclusion()@>
|
||||
|
||||
struct AmbientOcclusionFrameTransform {
|
||||
vec4 _pixelInfo;
|
||||
vec4 _depthInfo;
|
||||
vec4 _stereoInfo;
|
||||
mat4 _projection[2];
|
||||
};
|
||||
<@include DeferredTransform.slh@>
|
||||
<$declareDeferredFrameTransform()$>
|
||||
|
||||
struct AmbientOcclusionParams {
|
||||
vec4 _resolutionInfo;
|
||||
|
@ -47,52 +42,20 @@ struct AmbientOcclusionParams {
|
|||
float _gaussianCoefs[8];
|
||||
};
|
||||
|
||||
uniform ambientOcclusionFrameTransformBuffer {
|
||||
AmbientOcclusionFrameTransform frameTransform;
|
||||
};
|
||||
uniform ambientOcclusionParamsBuffer {
|
||||
AmbientOcclusionParams params;
|
||||
};
|
||||
|
||||
|
||||
float getPerspectiveScale() {
|
||||
|
||||
return (params._resolutionInfo.z);
|
||||
}
|
||||
int getResolutionLevel() {
|
||||
|
||||
return int(params._resolutionInfo.x);
|
||||
}
|
||||
|
||||
vec2 getWidthHeight() {
|
||||
return vec2(ivec2(frameTransform._pixelInfo.zw) >> getResolutionLevel());
|
||||
}
|
||||
float getProjScale() {
|
||||
return getWidthHeight().y * frameTransform._projection[0][1][1] * 0.5;
|
||||
}
|
||||
mat4 getProjection(int side) {
|
||||
return frameTransform._projection[side];
|
||||
}
|
||||
|
||||
bool isStereo() {
|
||||
return frameTransform._stereoInfo.x > 0.0f;
|
||||
}
|
||||
|
||||
float getStereoSideWidth() {
|
||||
return float(int(frameTransform._stereoInfo.y) >> getResolutionLevel());
|
||||
}
|
||||
|
||||
ivec3 getStereoSideInfo(int xPos) {
|
||||
int sideWidth = int(getStereoSideWidth());
|
||||
return ivec3(xPos < sideWidth ? ivec2(0, 0) : ivec2(1, sideWidth), sideWidth);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -130,6 +93,10 @@ float getNumSpiralTurns() {
|
|||
return params._sampleInfo.z;
|
||||
}
|
||||
|
||||
int doFetchMips() {
|
||||
return int(params._sampleInfo.w);
|
||||
}
|
||||
|
||||
float getBlurEdgeSharpness() {
|
||||
return params._blurInfo.x;
|
||||
}
|
||||
|
@ -163,6 +130,181 @@ float getBlurCoef(int c) {
|
|||
|
||||
<@endfunc@>
|
||||
|
||||
<@func declareSamplingDisk()@>
|
||||
|
||||
float getAngleDitheringWorldPos(in vec3 pixelWorldPos) {
|
||||
vec3 worldPosFract = fract(pixelWorldPos * 1.0);
|
||||
|
||||
ivec3 pixelPos = ivec3(worldPosFract * 256);
|
||||
|
||||
return isDitheringEnabled() * ((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) + (3 * pixelPos.y ^ pixelPos.z + pixelPos.x * pixelPos.z)) * 10 + getFrameDithering();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
float evalDiskRadius(float Zeye, vec2 imageSize) {
|
||||
// Choose the screen-space sample radius
|
||||
// proportional to the projected area of the sphere
|
||||
float ssDiskRadius = -( getProjScale(getResolutionLevel()) * getRadius() / Zeye ) * getPerspectiveScale();
|
||||
|
||||
// clamp the disk to fit in the image otherwise too many unknown
|
||||
ssDiskRadius = min(ssDiskRadius, imageSize.y * 0.5);
|
||||
|
||||
return ssDiskRadius;
|
||||
}
|
||||
|
||||
const float TWO_PI = 6.28;
|
||||
|
||||
vec3 getUnitTapLocation(int sampleNumber, float spinAngle){
|
||||
// Radius relative to ssR
|
||||
float alpha = float(sampleNumber + 0.5) * getInvNumSamples();
|
||||
float angle = alpha * (getNumSpiralTurns() * TWO_PI) + spinAngle;
|
||||
return vec3(cos(angle), sin(angle), alpha);
|
||||
}
|
||||
|
||||
vec3 getTapLocation(int sampleNumber, float spinAngle, float outerRadius) {
|
||||
vec3 tap = getUnitTapLocation(sampleNumber, spinAngle);
|
||||
tap.xy *= tap.z;
|
||||
tap *= outerRadius;
|
||||
return tap;
|
||||
}
|
||||
|
||||
vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius, vec2 pixelPos, vec2 imageSize) {
|
||||
vec3 tap = getTapLocation(sampleNumber, spinAngle, outerRadius);
|
||||
vec2 tapPos = pixelPos + tap.xy;
|
||||
|
||||
if (!(isBorderingEnabled() > 0.0)) {
|
||||
return tap;
|
||||
}
|
||||
bool redoTap = false;
|
||||
|
||||
if ((tapPos.x < 0.5)) {
|
||||
tapPos.x = -tapPos.x;
|
||||
redoTap = true;
|
||||
} else if ((tapPos.x > imageSize.x - 0.5)) {
|
||||
tapPos.x -= (imageSize.x - tapPos.x);
|
||||
redoTap = true;
|
||||
}
|
||||
|
||||
if ((tapPos.y < 0.5)) {
|
||||
tapPos.y = -tapPos.y;
|
||||
redoTap = true;
|
||||
} else if ((tapPos.y > imageSize.y - 0.5)) {
|
||||
tapPos.y -= (imageSize.y - tapPos.y);
|
||||
redoTap = true;
|
||||
}
|
||||
/*
|
||||
if ((tapPos.x < 0.5)) {
|
||||
tapPos.x = 0.5;
|
||||
redoTap = true;
|
||||
} else if ((tapPos.x > imageSize.x - 0.5)) {
|
||||
tapPos.x = imageSize.x - 0.5;
|
||||
redoTap = true;
|
||||
}
|
||||
|
||||
if ((tapPos.y < 0.5)) {
|
||||
tapPos.y = 0.5;
|
||||
redoTap = true;
|
||||
} else if ((tapPos.y > imageSize.y - 0.5)) {
|
||||
tapPos.y = imageSize.y - 0.5;
|
||||
redoTap = true;
|
||||
}
|
||||
*/
|
||||
|
||||
if (redoTap) {
|
||||
tap.xy = tapPos - pixelPos;
|
||||
tap.z = length(tap.xy);
|
||||
tap.z = 0;
|
||||
}
|
||||
|
||||
return tap;
|
||||
}
|
||||
|
||||
<@endfunc@>
|
||||
|
||||
|
||||
<@func declareFetchDepthPyramidMap()@>
|
||||
|
||||
|
||||
// the depth pyramid texture
|
||||
uniform sampler2D pyramidMap;
|
||||
|
||||
float getZEye(ivec2 pixel, int level) {
|
||||
return -texelFetch(pyramidMap, pixel, level).x;
|
||||
}
|
||||
|
||||
const int LOG_MAX_OFFSET = 3;
|
||||
const int MAX_MIP_LEVEL = 5;
|
||||
int evalMipFromRadius(float radius) {
|
||||
// mipLevel = floor(log(ssR / MAX_OFFSET));
|
||||
return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL);
|
||||
}
|
||||
|
||||
|
||||
vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) {
|
||||
ivec2 ssP = ivec2(tap.xy) + ssC;
|
||||
ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y);
|
||||
|
||||
|
||||
vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize;
|
||||
|
||||
vec2 fetchUV = vec2(tapUV.x + side.w * 0.5 * (side.x - tapUV.x), tapUV.y);
|
||||
|
||||
vec3 P;
|
||||
P.xy = tapUV;
|
||||
P.z = -texture(pyramidMap, fetchUV).x;
|
||||
|
||||
return P;
|
||||
}
|
||||
|
||||
vec3 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) {
|
||||
int mipLevel = evalMipFromRadius(tap.z * doFetchMips());
|
||||
|
||||
ivec2 ssP = ivec2(tap.xy) + ssC;
|
||||
ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y);
|
||||
|
||||
// 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 mipSize = textureSize(pyramidMap, mipLevel);
|
||||
ivec2 mipSize = max(ivec2(imageSize) >> mipLevel, ivec2(1));
|
||||
|
||||
ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), mipSize - ivec2(1));
|
||||
|
||||
vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize;
|
||||
vec2 fetchUV = vec2(tapUV.x + side.w * 0.5 * (side.x - tapUV.x), tapUV.y);
|
||||
// vec2 tapUV = (vec2(mipP) + vec2(0.5)) / vec2(mipSize);
|
||||
|
||||
vec3 P;
|
||||
P.xy = tapUV;
|
||||
// P.z = -texelFetch(pyramidMap, mipP, mipLevel).x;
|
||||
P.z = -textureLod(pyramidMap, fetchUV, float(mipLevel)).x;
|
||||
|
||||
return P;
|
||||
}
|
||||
|
||||
|
||||
|
||||
<@endfunc@>
|
||||
|
||||
|
||||
<@func declareEvalObscurance()@>
|
||||
|
||||
float evalAO(in vec3 C, in vec3 n_C, in vec3 Q) {
|
||||
vec3 v = Q - C;
|
||||
float vv = dot(v, v);
|
||||
float vn = dot(v, n_C);
|
||||
|
||||
// Fall off function as recommended in SAO paper
|
||||
const float epsilon = 0.01;
|
||||
float f = max(getRadius2() - vv, 0.0);
|
||||
return f * f * f * max((vn - getFalloffBias()) / (epsilon + vv), 0.0);
|
||||
}
|
||||
|
||||
<@endfunc@>
|
||||
|
||||
<@func declareBlurPass(axis)@>
|
||||
|
||||
<$declarePackOcclusionDepth()$>
|
||||
|
@ -188,7 +330,7 @@ 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))) {
|
||||
if ((ssP.x < side.y || ssP.x >= side.z + side.y) || (ssP.y < 0 || ssP.y >= int(getWidthHeight(getResolutionLevel()).y))) {
|
||||
return vec2(0.0);
|
||||
}
|
||||
vec2 tapOZ = fetchOcclusionDepth(ssC + tapOffset);
|
||||
|
@ -206,7 +348,7 @@ vec3 getBlurredOcclusion(vec2 coord) {
|
|||
ivec2 ssC = ivec2(coord);
|
||||
|
||||
// Stereo side info
|
||||
ivec3 side = getStereoSideInfo(ssC.x);
|
||||
ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel());
|
||||
|
||||
vec3 rawSample;
|
||||
vec2 occlusionDepth = fetchOcclusionDepthRaw(ssC, rawSample);
|
||||
|
@ -220,11 +362,11 @@ vec3 getBlurredOcclusion(vec2 coord) {
|
|||
int blurRadius = getBlurRadius();
|
||||
// negative side first
|
||||
for (int r = -blurRadius; r <= -1; ++r) {
|
||||
weightedSums += evalTapWeightedValue(side, r, ssC, key);
|
||||
weightedSums += evalTapWeightedValue(side.xyz, r, ssC, key);
|
||||
}
|
||||
// then positive side
|
||||
for (int r = 1; r <= blurRadius; ++r) {
|
||||
weightedSums += evalTapWeightedValue(side, r, ssC, key);
|
||||
weightedSums += evalTapWeightedValue(side.xyz, r, ssC, key);
|
||||
}
|
||||
|
||||
// Final normalization
|
||||
|
|
130
libraries/render-utils/src/ssao_debugOcclusion.slf
Normal file
130
libraries/render-utils/src/ssao_debugOcclusion.slf
Normal file
|
@ -0,0 +1,130 @@
|
|||
<@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()$>
|
||||
<$declareFetchDepthPyramidMap()$>
|
||||
<$declareSamplingDisk()$>
|
||||
<$declareEvalObscurance()$>
|
||||
|
||||
<$declarePackOcclusionDepth()$>
|
||||
|
||||
<@include gpu/Color.slh@>
|
||||
<$declareColorWheel()$>
|
||||
|
||||
struct DebugParams{
|
||||
vec4 pixelInfo;
|
||||
};
|
||||
|
||||
uniform debugAmbientOcclusionBuffer {
|
||||
DebugParams debugParams;
|
||||
};
|
||||
|
||||
vec2 getDebugCursorTexcoord(){
|
||||
return debugParams.pixelInfo.xy;
|
||||
}
|
||||
|
||||
out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
vec2 imageSize = getSideImageSize(getResolutionLevel());
|
||||
|
||||
// In debug adjust the correct frag pixel based on base resolution
|
||||
vec2 fragCoord = gl_FragCoord.xy;
|
||||
if (getResolutionLevel() > 0) {
|
||||
fragCoord /= float (1 << getResolutionLevel());
|
||||
}
|
||||
|
||||
// Pixel Debugged
|
||||
vec2 cursorUV = getDebugCursorTexcoord();
|
||||
vec2 cursorPixelPos = cursorUV * imageSize;
|
||||
|
||||
ivec2 ssC = ivec2(cursorPixelPos);
|
||||
|
||||
// Fetch the z under the pixel (stereo or not)
|
||||
float Zeye = getZEye(ssC, 0);
|
||||
|
||||
// Stereo side info
|
||||
ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel());
|
||||
|
||||
// From now on, ssC is the pixel pos in the side
|
||||
ssC.x -= side.y;
|
||||
vec2 fragPos = (vec2(ssC) + vec2(0.5)) / imageSize;
|
||||
|
||||
// The position and normal of the pixel fragment in Eye space
|
||||
vec3 Cp = evalEyePositionFromZeye(side.x, Zeye, fragPos);
|
||||
vec3 Cn = evalEyeNormal(Cp);
|
||||
|
||||
// Choose the screen-space sample radius
|
||||
float ssDiskRadius = evalDiskRadius(Cp.z, imageSize);
|
||||
|
||||
vec2 fragToCursor = cursorPixelPos - fragCoord.xy;
|
||||
if (dot(fragToCursor,fragToCursor) > ssDiskRadius * ssDiskRadius) {
|
||||
discard;
|
||||
}
|
||||
|
||||
// Let's make noise
|
||||
//float randomPatternRotationAngle = getAngleDithering(ssC);
|
||||
vec3 wCp = (getViewInverse() * vec4(Cp, 1.0)).xyz;
|
||||
float randomPatternRotationAngle = getAngleDitheringWorldPos(wCp);
|
||||
|
||||
|
||||
// Accumulate the Obscurance for each samples
|
||||
float sum = 0.0;
|
||||
float keepTapRadius = 1.0;
|
||||
int keepedMip = -1;
|
||||
bool keep = false;
|
||||
|
||||
for (int i = 0; i < getNumSamples(); ++i) {
|
||||
vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, cursorPixelPos, imageSize);
|
||||
|
||||
// The occluding point in camera space
|
||||
vec2 fragToTap = vec2(ssC) + tap.xy - fragCoord.xy;
|
||||
if (dot(fragToTap,fragToTap) < keepTapRadius) {
|
||||
keep = true;
|
||||
keepedMip = evalMipFromRadius(tap.z * doFetchMips());
|
||||
}
|
||||
|
||||
vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize);
|
||||
|
||||
vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy);
|
||||
|
||||
sum += float(tap.z > 0.0) * evalAO(Cp, Cn, Q);
|
||||
}
|
||||
|
||||
|
||||
float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples());
|
||||
|
||||
<! // KEEP IT for Debugging
|
||||
// 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(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0);
|
||||
|
||||
if ((dot(fragToCursor,fragToCursor) < (100.0 * keepTapRadius * keepTapRadius) )) {
|
||||
// outFragColor = vec4(vec3(A), 1.0);
|
||||
outFragColor = vec4(vec3(A), 1.0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!keep) {
|
||||
outFragColor = vec4(0.1);
|
||||
} else {
|
||||
outFragColor.rgb = colorWheel(float(keepedMip)/float(MAX_MIP_LEVEL));
|
||||
}
|
||||
}
|
|
@ -11,129 +11,58 @@
|
|||
|
||||
<@include ssao.slh@>
|
||||
<$declareAmbientOcclusion()$>
|
||||
<$declareFetchDepthPyramidMap()$>
|
||||
<$declareSamplingDisk()$>
|
||||
<$declareEvalObscurance()$>
|
||||
|
||||
<$declarePackOcclusionDepth()$>
|
||||
|
||||
|
||||
const int LOG_MAX_OFFSET = 3;
|
||||
const int MAX_MIP_LEVEL = 5;
|
||||
|
||||
// the depth pyramid texture
|
||||
uniform sampler2D pyramidMap;
|
||||
|
||||
float getZEye(ivec2 pixel) {
|
||||
return -texelFetch(pyramidMap, pixel, getResolutionLevel()).x;
|
||||
}
|
||||
|
||||
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][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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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() * TWO_PI) + spinAngle;
|
||||
|
||||
ssR = alpha;
|
||||
return vec2(cos(angle), sin(angle));
|
||||
}
|
||||
|
||||
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 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;
|
||||
|
||||
// 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, getResolutionLevel() + mipLevel) - ivec2(1));
|
||||
P.z = -texelFetch(pyramidMap, mipP, getResolutionLevel() + mipLevel).r;
|
||||
|
||||
// Offset to pixel center
|
||||
vec2 tapUV = (vec2(ssP) + vec2(0.5)) / float(side.z);
|
||||
P = evalEyePositionFromZeye(side.x, P.z, tapUV);
|
||||
return P;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
vec3 v = Q - C;
|
||||
float vv = dot(v, v);
|
||||
float vn = dot(v, n_C);
|
||||
|
||||
// Fall off function as recommended in SAO paper
|
||||
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) {
|
||||
vec2 imageSize = getSideImageSize(getResolutionLevel());
|
||||
|
||||
// Pixel being shaded
|
||||
ivec2 ssC = ivec2(gl_FragCoord.xy);
|
||||
vec2 fragCoord = gl_FragCoord.xy;
|
||||
ivec2 ssC = ivec2(fragCoord.xy);
|
||||
|
||||
// Fetch the z under the pixel (stereo or not)
|
||||
float Zeye = getZEye(ssC);
|
||||
float Zeye = getZEye(ssC, 0);
|
||||
|
||||
// Stereo side info
|
||||
ivec3 side = getStereoSideInfo(ssC.x);
|
||||
ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel());
|
||||
|
||||
// From now on, ssC is the pixel pos in the side
|
||||
ssC.x -= side.y;
|
||||
vec2 fragPos = (vec2(ssC) + 0.5) / getStereoSideWidth();
|
||||
vec2 fragPos = (vec2(ssC) + vec2(0.5)) / imageSize;
|
||||
|
||||
// The position and normal of the pixel fragment in Eye space
|
||||
vec3 Cp = evalEyePositionFromZeye(side.x, 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;
|
||||
float ssDiskRadius = evalDiskRadius(Cp.z, imageSize);
|
||||
|
||||
// Let's make noise
|
||||
float randomPatternRotationAngle = getAngleDithering(ssC);
|
||||
//vec3 wCp = (getViewInverse() * vec4(Cp, 1.0)).xyz;
|
||||
//float randomPatternRotationAngle = getAngleDitheringWorldPos(wCp);
|
||||
|
||||
// Accumulate the Obscurance for each samples
|
||||
float sum = 0.0;
|
||||
for (int i = 0; i < getNumSamples(); ++i) {
|
||||
sum += sampleAO(side, ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle);
|
||||
vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, ssC, imageSize);
|
||||
|
||||
vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize);
|
||||
|
||||
vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy);
|
||||
|
||||
sum += float(tap.z > 0.0) * evalAO(Cp, Cn, Q);
|
||||
}
|
||||
|
||||
float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples());
|
||||
|
||||
<! // KEEP IT for Debugging
|
||||
// KEEP IT for Debugging
|
||||
// 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) {
|
||||
|
@ -142,20 +71,16 @@ void main(void) {
|
|||
if (abs(dFdy(Cp.z)) < 0.02) {
|
||||
A -= dFdy(A) * ((ssC.y & 1) - 0.5);
|
||||
}
|
||||
!>
|
||||
|
||||
|
||||
outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0);
|
||||
|
||||
<! // KEEP IT for Debugging
|
||||
// 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);
|
||||
!>
|
||||
/* {
|
||||
vec3 tap = getTapLocationClamped(2, randomPatternRotationAngle, ssDiskRadius, ssC, imageSize);
|
||||
vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize);
|
||||
vec2 fetchUV = vec2(tapUVZ.x + side.w * 0.5 * (side.x - tapUVZ.x), tapUVZ.y);
|
||||
vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy);
|
||||
outFragColor = vec4(fetchUV, 0.0, 1.0);
|
||||
}*/
|
||||
|
||||
}
|
||||
|
|
88
scripts/developer/utilities/render/ambientOcclusionPass.qml
Normal file
88
scripts/developer/utilities/render/ambientOcclusionPass.qml
Normal file
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// surfaceGeometryPass.qml
|
||||
//
|
||||
// Created by Sam Gateau on 6/6/2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import "configSlider"
|
||||
import "../lib/plotperf"
|
||||
|
||||
Column {
|
||||
spacing: 8
|
||||
Column {
|
||||
id: surfaceGeometry
|
||||
spacing: 10
|
||||
|
||||
Column{
|
||||
Repeater {
|
||||
model: [
|
||||
"Radius:radius:2.0:false",
|
||||
"Level:obscuranceLevel:1.0:false",
|
||||
"Num Taps:numSamples:32:true",
|
||||
"Taps Spiral:numSpiralTurns:10.0:false",
|
||||
"Falloff Bias:falloffBias:0.2:false",
|
||||
"Edge Sharpness:edgeSharpness:1.0:false",
|
||||
"Blur Radius:blurRadius:10.0:false",
|
||||
]
|
||||
ConfigSlider {
|
||||
label: qsTr(modelData.split(":")[0])
|
||||
integral: (modelData.split(":")[3] == 'true')
|
||||
config: Render.getConfig("AmbientOcclusion")
|
||||
property: modelData.split(":")[1]
|
||||
max: modelData.split(":")[2]
|
||||
min: 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
Row{
|
||||
Column {
|
||||
Repeater {
|
||||
model: [
|
||||
"resolutionLevel:resolutionLevel",
|
||||
"ditheringEnabled:ditheringEnabled",
|
||||
"fetchMipsEnabled:fetchMipsEnabled",
|
||||
"borderingEnabled:borderingEnabled"
|
||||
]
|
||||
CheckBox {
|
||||
text: qsTr(modelData.split(":")[0])
|
||||
checked: Render.getConfig("AmbientOcclusion")[modelData.split(":")[1]]
|
||||
onCheckedChanged: { Render.getConfig("AmbientOcclusion")[modelData.split(":")[1]] = checked }
|
||||
}
|
||||
}
|
||||
}
|
||||
Column {
|
||||
Repeater {
|
||||
model: [
|
||||
"debugEnabled:showCursorPixel"
|
||||
]
|
||||
CheckBox {
|
||||
text: qsTr(modelData.split(":")[0])
|
||||
checked: Render.getConfig("DebugAmbientOcclusion")[modelData.split(":")[1]]
|
||||
onCheckedChanged: { Render.getConfig("DebugAmbientOcclusion")[modelData.split(":")[1]] = checked }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlotPerf {
|
||||
title: "Timing"
|
||||
height: 50
|
||||
object: Render.getConfig("AmbientOcclusion")
|
||||
valueUnit: "ms"
|
||||
valueScale: 1
|
||||
valueNumDigits: "4"
|
||||
plots: [
|
||||
{
|
||||
prop: "gpuTime",
|
||||
label: "gpu",
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// debugSurfaceGeometryPass.js
|
||||
//
|
||||
// Created by Sam Gateau on 6/6/2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// Set up the qml ui
|
||||
var qml = Script.resolvePath('ambientOcclusionPass.qml');
|
||||
var window = new OverlayWindow({
|
||||
title: 'Ambient Occlusion Pass',
|
||||
source: qml,
|
||||
width: 400, height: 250,
|
||||
});
|
||||
window.setPosition(Window.innerWidth - 420, 50 + 550 + 50);
|
||||
window.closed.connect(function() { Script.stop(); });
|
||||
|
||||
|
||||
var moveDebugCursor = false;
|
||||
Controller.mousePressEvent.connect(function (e) {
|
||||
if (e.isMiddleButton) {
|
||||
moveDebugCursor = true;
|
||||
setDebugCursor(e.x, e.y);
|
||||
}
|
||||
});
|
||||
Controller.mouseReleaseEvent.connect(function() { moveDebugCursor = false; });
|
||||
Controller.mouseMoveEvent.connect(function (e) { if (moveDebugCursor) setDebugCursor(e.x, e.y); });
|
||||
|
||||
|
||||
function setDebugCursor(x, y) {
|
||||
nx = (x / Window.innerWidth);
|
||||
ny = 1.0 - ((y) / (Window.innerHeight - 32));
|
||||
|
||||
Render.getConfig("DebugAmbientOcclusion").debugCursorTexcoord = { x: nx, y: ny };
|
||||
}
|
|
@ -24,6 +24,7 @@ Column {
|
|||
"Emissive:LightingModel:enableEmissive",
|
||||
"Lightmap:LightingModel:enableLightmap",
|
||||
"Background:LightingModel:enableBackground",
|
||||
"ssao:AmbientOcclusion:enabled",
|
||||
]
|
||||
CheckBox {
|
||||
text: modelData.split(":")[0]
|
||||
|
|
Loading…
Reference in a new issue