From ff2a58b3eb622e3b6d84c4e1513b87e1e696dade Mon Sep 17 00:00:00 2001 From: Raffi Bedikian Date: Sun, 30 Aug 2015 20:49:03 -0700 Subject: [PATCH] Add FXAA effect class, modeled after AO effect --- .../render-utils/src/AntialiasingEffect.cpp | 151 ++++++++++++++++++ .../render-utils/src/AntialiasingEffect.h | 44 +++++ .../render-utils/src/RenderDeferredTask.cpp | 8 + .../render-utils/src/RenderDeferredTask.h | 5 + 4 files changed, 208 insertions(+) create mode 100644 libraries/render-utils/src/AntialiasingEffect.cpp create mode 100644 libraries/render-utils/src/AntialiasingEffect.h diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp new file mode 100644 index 0000000000..4e1b6f451c --- /dev/null +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -0,0 +1,151 @@ +// +// AntialiasingEffect.cpp +// libraries/render-utils/src/ +// +// Created by Raffi Bedikian on 8/30/15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +#include + +#include +#include +#include + +#include "gpu/StandardShaderLib.h" +#include "AntialiasingEffect.h" +#include "TextureCache.h" +#include "FramebufferCache.h" +#include "DependencyManager.h" +#include "ViewFrustum.h" +#include "GeometryCache.h" + +#include "fxaa_vert.h" +#include "fxaa_frag.h" +#include "fxaa_blend_frag.h" + + +Antialiasing::Antialiasing() { +} + +const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { + if (!_antialiasingPipeline) { + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(fxaa_vert))); + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fxaa_frag))); + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("colorTexture"), 0)); + + gpu::Shader::makeProgram(*program, slotBindings); + + _texcoordOffsetLoc = program->getUniforms().findLocation("texcoordOffset"); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + state->setDepthTest(false, false, gpu::LESS_EQUAL); + + // Link the antialiasing FBO to texture + _antialiasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, + DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); + auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + auto width = _antialiasingBuffer->getWidth(); + auto height = _antialiasingBuffer->getHeight(); + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + _antialiasingTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); + + // Good to go add the brand new pipeline + _antialiasingPipeline.reset(gpu::Pipeline::create(program, state)); + } + return _antialiasingPipeline; +} + +const gpu::PipelinePointer& Antialiasing::getBlendPipeline() { + if (!_blendPipeline) { + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(fxaa_vert))); + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fxaa_blend_frag))); + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("colorTexture"), 0)); + + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + state->setDepthTest(false, false, gpu::LESS_EQUAL); + + // Good to go add the brand new pipeline + _blendPipeline.reset(gpu::Pipeline::create(program, state)); + } + return _blendPipeline; +} + +void Antialiasing::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { + assert(renderContext->args); + assert(renderContext->args->_viewFrustum); + + gpu::Batch batch; + RenderArgs* args = renderContext->args; + + auto framebufferCache = DependencyManager::get(); + QSize framebufferSize = framebufferCache->getFrameBufferSize(); + float fbWidth = framebufferSize.width(); + float fbHeight = framebufferSize.height(); + float sMin = args->_viewport.x / fbWidth; + float sWidth = args->_viewport.z / fbWidth; + float tMin = args->_viewport.y / fbHeight; + float tHeight = args->_viewport.w / fbHeight; + + glm::mat4 projMat; + Transform viewMat; + args->_viewFrustum->evalProjectionMatrix(projMat); + args->_viewFrustum->evalViewTransform(viewMat); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + batch.setModelTransform(Transform()); + + // FXAA step + getAntialiasingPipeline(); + batch.setResourceTexture(0, framebufferCache->getPrimaryColorTexture()); + _antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture); + batch.setFramebuffer(_antialiasingBuffer); + batch.setPipeline(getAntialiasingPipeline()); + + // 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; + + batch._glUniform2f(_texcoordOffsetLoc, 1.0 / fbWidth, 1.0 / fbHeight); + + glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f); + glm::vec2 bottomLeft(-1.0f, -1.0f); + glm::vec2 topRight(1.0f, 1.0f); + glm::vec2 texCoordTopLeft(0.0f, 0.0f); + glm::vec2 texCoordBottomRight(1.0f, 1.0f); + DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); + + // Blend step + getBlendPipeline(); + batch.setResourceTexture(0, _antialiasingTexture); + batch.setFramebuffer(framebufferCache->getPrimaryFramebuffer()); + batch.setPipeline(getBlendPipeline()); + + DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); + + // Ready to render + args->_context->render((batch)); +} diff --git a/libraries/render-utils/src/AntialiasingEffect.h b/libraries/render-utils/src/AntialiasingEffect.h new file mode 100644 index 0000000000..96cf3aaf3e --- /dev/null +++ b/libraries/render-utils/src/AntialiasingEffect.h @@ -0,0 +1,44 @@ +// +// AntialiasingEffect.h +// libraries/render-utils/src/ +// +// Created by Raffi Bedikian on 8/30/15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AntialiasingEffect_h +#define hifi_AntialiasingEffect_h + +#include + +#include "render/DrawTask.h" + +class Antialiasing { +public: + + Antialiasing(); + + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + typedef render::Job::Model JobModel; + + const gpu::PipelinePointer& getAntialiasingPipeline(); + const gpu::PipelinePointer& getBlendPipeline(); + +private: + + // Uniforms for AA + gpu::int32 _texcoordOffsetLoc; + + gpu::FramebufferPointer _antialiasingBuffer; + + gpu::TexturePointer _antialiasingTexture; + + gpu::PipelinePointer _antialiasingPipeline; + gpu::PipelinePointer _blendPipeline; + +}; + +#endif // hifi_AntialiasingEffect_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index ca3f87f53f..137294c5b6 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -23,6 +23,7 @@ #include "render/DrawStatus.h" #include "AmbientOcclusionEffect.h" +#include "AntialiasingEffect.h" #include "overlay3D_vert.h" #include "overlay3D_frag.h" @@ -88,6 +89,11 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.back().setEnabled(false); _occlusionJobIndex = _jobs.size() - 1; + _jobs.push_back(Job(new Antialiasing::JobModel("Antialiasing"))); + + _jobs.back().setEnabled(false); + _antialiasingJobIndex = _jobs.size() - 1; + _jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent", FetchItems( ItemFilter::Builder::transparentShape().withoutLayered(), @@ -146,6 +152,8 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend // TODO: turn on/off AO through menu item setOcclusionStatus(renderContext->_occlusionStatus); + setAntialiasingStatus(renderContext->_fxaaStatus); + renderContext->args->_context->syncCache(); for (auto job : _jobs) { diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 0041f5d9aa..8366a2665d 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -91,6 +91,11 @@ public: void setOcclusionStatus(bool draw) { if (_occlusionJobIndex >= 0) { _jobs[_occlusionJobIndex].setEnabled(draw); } } bool doOcclusionStatus() const { if (_occlusionJobIndex >= 0) { return _jobs[_occlusionJobIndex].isEnabled(); } else { return false; } } + int _antialiasingJobIndex = -1; + + void setAntialiasingStatus(bool draw) { if (_antialiasingJobIndex >= 0) { _jobs[_antialiasingJobIndex].setEnabled(draw); } } + bool doAntialiasingStatus() const { if (_antialiasingJobIndex >= 0) { return _jobs[_antialiasingJobIndex].isEnabled(); } else { return false; } } + virtual void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);