Commit fc9878ef authored by David C. Lonie's avatar David C. Lonie

Add an FXAA implementation.

FXAA is an antialiasing technique that is applied in a post-processing
pass. This implementation:

- Is a single-pass fragment shader.
- Detects edges.
- Searches for edge endpoints.
- Interpolates colors along the edge to give a smooth, antialiased
  color gradient.
- Detects and corrects sub-pixel antialiasing.
parent 94dfcdac
......@@ -117,6 +117,15 @@ vtkRenderer::vtkRenderer()
this->GL2PSSpecialPropCollection = NULL;
this->UseFXAA = false;
this->FXAARelativeContrastThreshold = 1.f / 8.f;
this->FXAAHardContrastThreshold = 1.f / 16.f;
this->FXAASubpixelBlendLimit = 3.f / 4.f;
this->FXAASubpixelContrastThreshold = 1.f / 4.f;
this->FXAAEndpointSearchIterations = 12;
this->FXAAUseHighQualityEndpoints = true;
this->FXAADebugOption = 0;
this->UseShadows = 0;
this->UseHiddenLineRemoval = 0;
......
......@@ -528,6 +528,31 @@ public:
// method to release graphics resources in any derived renderers.
virtual void ReleaseGraphicsResources(vtkWindow *);
// Description:
// Turn on/off FXAA anti-aliasing, if supported. Initial value is off.
vtkSetMacro(UseFXAA, bool)
vtkGetMacro(UseFXAA, bool)
vtkBooleanMacro(UseFXAA, bool)
// Description:
// Tuning parameters for FXAA. See vtkOpenGLFXAAFilter.h for documentation
// and suggested values.
vtkSetClampMacro(FXAARelativeContrastThreshold, float, 0.f, 1.f)
vtkGetMacro(FXAARelativeContrastThreshold, float)
vtkSetClampMacro(FXAAHardContrastThreshold, float, 0.f, 1.f)
vtkGetMacro(FXAAHardContrastThreshold, float)
vtkSetClampMacro(FXAASubpixelBlendLimit, float, 0.f, 1.f)
vtkGetMacro(FXAASubpixelBlendLimit, float)
vtkSetClampMacro(FXAASubpixelContrastThreshold, float, 0.f, 1.f)
vtkGetMacro(FXAASubpixelContrastThreshold, float)
vtkSetClampMacro(FXAAEndpointSearchIterations, int, 0, VTK_INT_MAX)
vtkGetMacro(FXAAEndpointSearchIterations, int)
vtkSetMacro(FXAAUseHighQualityEndpoints, bool)
vtkGetMacro(FXAAUseHighQualityEndpoints, bool)
vtkBooleanMacro(FXAAUseHighQualityEndpoints, bool)
vtkSetMacro(FXAADebugOption, int)
vtkGetMacro(FXAADebugOption, int)
// Description:
// Turn on/off rendering of shadows if supported
// Initial value is off.
......@@ -691,6 +716,22 @@ protected:
// This is only used internally.
vtkCamera *GetActiveCameraAndResetIfCreated();
// Description:
// If this flag is on and the rendering engine supports it, FXAA will be used
// to antialias the scene. Default is off.
bool UseFXAA;
// Description:
// Parameters for FXAA. See vtkOpenGLFXAAFilter.h for documentation and
// suggested values.
float FXAARelativeContrastThreshold;
float FXAAHardContrastThreshold;
float FXAASubpixelBlendLimit;
float FXAASubpixelContrastThreshold;
int FXAAEndpointSearchIterations;
bool FXAAUseHighQualityEndpoints;
int FXAADebugOption;
// Description:
// If this flag is on and the rendering engine supports it render shadows
// Initial value is off.
......
......@@ -33,6 +33,7 @@ set(Module_SRCS
vtkOpenGLActor.cxx
vtkOpenGLBufferObject.cxx
vtkOpenGLCamera.cxx
vtkOpenGLFXAAFilter.cxx
vtkOpenGLGL2PSHelper.cxx
vtkOpenGLGlyph3DHelper.cxx
vtkOpenGLGlyph3DMapper.cxx
......@@ -148,6 +149,7 @@ set(shader_files
glsl/vtkEDLBilateralFilterFS.glsl
glsl/vtkEDLComposeFS.glsl
glsl/vtkEDLShadeFS.glsl
glsl/vtkFXAAFilterFS.glsl
glsl/vtkGaussianBlurPassFS.glsl
glsl/vtkGaussianBlurPassVS.glsl
glsl/vtkGlyph3DVS.glsl
......
......@@ -6,6 +6,7 @@ vtk_add_test_cxx(${vtk-module}CxxTests tests
TestDepthOfFieldPass.cxx
TestDepthPeelingPass.cxx
TestEDLPass.cxx
TestFXAAFilter.cxx
TestGaussianBlurPass.cxx
TestLightingMapLuminancePass.cxx
TestLightingMapNormalsPass.cxx
......
/*=========================================================================
Program: Visualization Toolkit
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
//
// This test is unlikely to fail if FXAA isn't working, but can be used to
// quickly check the same scene with/without FXAA enabled.
//
#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkConeSource.h"
#include "vtkCylinderSource.h"
#include "vtkDiskSource.h"
#include "vtkLineSource.h"
#include "vtkNew.h"
#include "vtkOpenGLRenderer.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkRegressionTestImage.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkSphereSource.h"
#include "vtkTextActor.h"
#include "vtkTextProperty.h"
namespace {
void BuildRenderer(vtkRenderer *renderer, int widthBias)
{
const size_t NUM_LINES = 10;
vtkNew<vtkLineSource> lines[NUM_LINES];
vtkNew<vtkPolyDataMapper> mappers[NUM_LINES];
vtkNew<vtkActor> actors[NUM_LINES];
for (size_t i = 0; i < NUM_LINES; ++i)
{
double c = static_cast<double>(2 * i) /
static_cast<double>(NUM_LINES - 1) - 1.;
lines[i]->SetPoint1(-1, c, 0.);
lines[i]->SetPoint2( 1, -c, 0.);
mappers[i]->SetInputConnection(lines[i]->GetOutputPort());
actors[i]->SetMapper(mappers[i].Get());
actors[i]->GetProperty()->SetColor(0., 1., 0.);
actors[i]->GetProperty()->SetRepresentationToWireframe();
actors[i]->GetProperty()->SetLineWidth((i + widthBias) % 2 ? 1 : 3);
renderer->AddActor(actors[i].Get());
}
vtkNew<vtkSphereSource> sphere;
sphere->SetCenter(0., 0.6, 0.);
sphere->SetThetaResolution(80);
sphere->SetPhiResolution(80);
sphere->SetRadius(0.4);
vtkNew<vtkPolyDataMapper> sphereMapper;
sphereMapper->SetInputConnection(sphere->GetOutputPort());
vtkNew<vtkActor> sphereActor;
sphereActor->SetMapper(sphereMapper.Get());
sphereActor->GetProperty()->SetColor(0.9, 0.4, 0.2);
sphereActor->GetProperty()->SetAmbient(.6);
sphereActor->GetProperty()->SetDiffuse(.4);
renderer->AddActor(sphereActor.Get());
vtkNew<vtkConeSource> cone;
cone->SetCenter(0., 0.5, -0.5);
cone->SetResolution(160);
cone->SetRadius(.9);
cone->SetHeight(0.9);
cone->SetDirection(0., -1., 0.);
vtkNew<vtkPolyDataMapper> coneMapper;
coneMapper->SetInputConnection(cone->GetOutputPort());
vtkNew<vtkActor> coneActor;
coneActor->SetMapper(coneMapper.Get());
coneActor->GetProperty()->SetColor(0.9, .6, 0.8);
coneActor->GetProperty()->SetAmbient(.6);
coneActor->GetProperty()->SetDiffuse(.4);
renderer->AddActor(coneActor.Get());
vtkNew<vtkDiskSource> disk;
disk->SetCircumferentialResolution(80);
disk->SetInnerRadius(0);
disk->SetOuterRadius(0.5);
vtkNew<vtkPolyDataMapper> diskMapper;
diskMapper->SetInputConnection(disk->GetOutputPort());
vtkNew<vtkActor> diskActor;
diskActor->SetPosition(0., -0.5, -0.5);
diskActor->SetMapper(diskMapper.Get());
diskActor->GetProperty()->SetColor(.3, .1, .4);
diskActor->GetProperty()->SetAmbient(.6);
diskActor->GetProperty()->SetDiffuse(.4);
renderer->AddActor(diskActor.Get());
vtkNew<vtkCylinderSource> cyl;
cyl->SetCenter(0., -.5, 0.);
cyl->SetHeight(.6);
cyl->SetRadius(.2);
cyl->SetResolution(80);
vtkNew<vtkPolyDataMapper> cylMapper;
cylMapper->SetInputConnection(cyl->GetOutputPort());
vtkNew<vtkActor> cylActor;
cylActor->SetOrigin(cyl->GetCenter());
cylActor->RotateWXYZ(35, -0.2, 0., 1.);
cylActor->SetMapper(cylMapper.Get());
cylActor->GetProperty()->SetColor(0.3, .9, .4);
cylActor->GetProperty()->SetAmbient(.6);
cylActor->GetProperty()->SetDiffuse(.4);
renderer->AddActor(cylActor.Get());
renderer->SetBackground(0., 0., 0.);
renderer->GetActiveCamera()->ParallelProjectionOn();
renderer->ResetCamera();
renderer->ResetCameraClippingRange();
renderer->GetActiveCamera()->SetParallelScale(0.9);
}
} // end anon namespace
int TestFXAAFilter(int argc, char *argv[])
{
vtkNew<vtkRenderWindowInteractor> iren;
vtkNew<vtkRenderWindow> renWin;
renWin->SetMultiSamples(0);
iren->SetRenderWindow(renWin.Get());
vtkNew<vtkRenderer> renderer;
vtkNew<vtkRenderer> rendererFXAA;
rendererFXAA->UseFXAAOn();
vtkNew<vtkTextActor> label;
label->SetInput("No FXAA");
label->GetTextProperty()->SetFontSize(20);
label->GetTextProperty()->SetJustificationToCentered();
label->GetTextProperty()->SetVerticalJustificationToBottom();
label->SetPosition(85, 10);
renderer->AddActor2D(label.Get());
vtkNew<vtkTextActor> labelFXAA;
labelFXAA->SetInput("FXAA");
labelFXAA->GetTextProperty()->SetFontSize(20);
labelFXAA->GetTextProperty()->SetJustificationToCentered();
labelFXAA->GetTextProperty()->SetVerticalJustificationToBottom();
labelFXAA->SetPosition(85, 10);
rendererFXAA->AddActor2D(labelFXAA.Get());
renderer->SetViewport(0., 0., .5, 1.);
BuildRenderer(renderer.Get(), 0);
renWin->AddRenderer(renderer.Get());
rendererFXAA->SetViewport(.5, 0., 1., 1.);
BuildRenderer(rendererFXAA.Get(), 1);
renWin->AddRenderer(rendererFXAA.Get());
renWin->SetSize(1000, 500);
renWin->Render();
int retVal = vtkRegressionTestImage(renWin.Get());
if (retVal == vtkRegressionTester::DO_INTERACTOR)
{
iren->Start();
}
return !retVal;
}
This diff is collapsed.
......@@ -11,6 +11,7 @@ vtk_module(vtkRenderingOpenGL2
TEST_DEPENDS
vtkIOLegacy
vtkRenderingImage
vtkRenderingFreeType
vtkTestingCore
vtkTestingRendering
vtkImagingGeneral
......
This diff is collapsed.
/*=========================================================================
Program: Visualization Toolkit
Module: vtkOpenGLFXAAFilter.h
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
// .NAME vtkOpenGLFXAAFilter - Perform FXAA antialiasing on the current
// framebuffer.
//
// .SECTION Description
// Call Execute() to run a FXAA antialiasing pass on the current OpenGL
// framebuffer. See method documentation for tunable parameters.
//
// Based on the following implementation and description:
//
// Whitepaper:
// http://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf
//
// Sample implementation:
// https://github.com/NVIDIAGameWorks/GraphicsSamples/blob/master/samples/es3-kepler/FXAA/FXAA3_11.h
//
// TODO there are currently some "banding" artifacts on some edges, particularly
// single pixel lines. These seem to be caused by using a linear RGB input,
// rather than a gamma-correct sRGB input. Future work should combine this pass
// with a gamma correction pass to correct this. Bonus points for precomputing
// luminosity into the sRGB's alpha channel to save cycles in the FXAA shader!
#ifndef vtkOpenGLFXAAFilter_h
#define vtkOpenGLFXAAFilter_h
#include "vtkRenderingOpenGL2Module.h" // For export macro
#include "vtkObject.h"
class vtkOpenGLBufferObject;
class vtkOpenGLVertexArrayObject;
class vtkOpenGLRenderer;
class vtkShaderProgram;
class vtkTextureObject;
class VTKRENDERINGOPENGL2_EXPORT vtkOpenGLFXAAFilter: public vtkObject
{
public:
static vtkOpenGLFXAAFilter* New();
vtkTypeMacro(vtkOpenGLFXAAFilter, vtkObject)
virtual void PrintSelf(ostream &os, vtkIndent indent);
// Description:
// Perform FXAA on the current render buffer in @a ren.
void Execute(vtkOpenGLRenderer *ren);
// Description:
// Release all OpenGL state.
void ReleaseGraphicsResources();
// Description:
// Threshold for applying FXAA to a pixel, relative to the maximum luminosity
// of its 4 immediate neighbors.
//
// The luminosity of the current pixel and it's NSWE neighbors is computed.
// The maximum luminosity and luminosity range (contrast) of all 5 pixels is
// found. If the contrast is less than RelativeContrastThreshold * maxLum,
// the pixel is not considered aliased and will not be affected by FXAA.
//
// Suggested settings:
// - 1/3: Too little
// - 1/4: Low quality
// - 1/8: High quality (default)
// - 1/16: Overkill
vtkSetClampMacro(RelativeContrastThreshold, float, 0.f, 1.f)
vtkGetMacro(RelativeContrastThreshold, float)
// Description:
// Similar to RelativeContrastThreshold, but not scaled by the maximum
// luminosity.
//
// If the contrast of the current pixel and it's 4 immediate NSWE neighbors is
// less than HardContrastThreshold, the pixel is not considered aliased and
// will not be affected by FXAA.
//
// Suggested settings:
// - 1/32: Visible limit
// - 1/16: High quality (default)
// - 1/12: Upper limit (start of visible unfiltered edges)
vtkSetClampMacro(HardContrastThreshold, float, 0.f, 1.f)
vtkGetMacro(HardContrastThreshold, float)
// Description:
// Subpixel aliasing is corrected by applying a lowpass filter to the current
// pixel. This is implemented by blending an average of the 3x3 neighborhood
// around the pixel into the final result. The amount of blending is
// determined by comparing the detected amount of subpixel aliasing to the
// total contrasting of the CNSWE pixels:
//
// SubpixelBlending = abs(lumC - lumAveNSWE) / (lumMaxCNSWE - lumMinCNSWE)
//
// This parameter sets an upper limit to the amount of subpixel blending to
// prevent the image from simply getting blurred.
//
// Suggested settings:
// - 1/2: Low amount of blending.
// - 3/4: Medium amount of blending (default)
// - 7/8: High amount of blending.
// - 1: Maximum amount of blending.
vtkSetClampMacro(SubpixelBlendLimit, float, 0.f, 1.f)
vtkGetMacro(SubpixelBlendLimit, float)
// Description:
// Minimum amount of subpixel aliasing required for subpixel antialiasing to
// be applied.
//
// Subpixel aliasing is corrected by applying a lowpass filter to the current
// pixel. This is implemented by blending an average of the 3x3 neighborhood
// around the pixel into the final result. The amount of blending is
// determined by comparing the detected amount of subpixel aliasing to the
// total contrasting of the CNSWE pixels:
//
// SubpixelBlending = abs(lumC - lumAveNSWE) / (lumMaxCNSWE - lumMinCNSWE)
//
// If SubpixelBlending is less than this threshold, no lowpass blending will
// occur.
//
// Suggested settings:
// - 1/2: Low subpixel aliasing removal
// - 1/3: Medium subpixel aliasing removal
// - 1/4: Default subpixel aliasing removal
// - 1/8: High subpixel aliasing removal
// - 0: Complete subpixel aliasing removal
vtkSetClampMacro(SubpixelContrastThreshold, float, 0.f, 1.f)
vtkGetMacro(SubpixelContrastThreshold, float)
// Description:
// Use an improved edge endpoint detection algorithm.
//
// If true, a modified edge endpoint detection algorithm is used that requires
// more texture lookups, but will properly detect aliased single-pixel lines.
//
// If false, the edge endpoint algorithm proposed by NVIDIA will by used. This
// algorithm is faster (fewer lookups), but will fail to detect endpoints of
// single pixel edge steps.
//
// Default setting is true.
virtual void SetUseHighQualityEndpoints(bool val);
vtkGetMacro(UseHighQualityEndpoints, bool)
vtkBooleanMacro(UseHighQualityEndpoints, bool)
// Description:
// Set the number of iterations for the endpoint search algorithm. Increasing
// this value will increase runtime, but also properly detect longer edges.
// The current implementation steps one pixel in both the positive and
// negative directions per iteration. The default value is 12, which will
// resolve endpoints of edges < 25 pixels long (2 * 12 + 1).
vtkSetClampMacro(EndpointSearchIterations, int, 0, VTK_INT_MAX)
vtkGetMacro(EndpointSearchIterations, int)
// Description:
// Debugging options that affect the output color buffer. See
// vtkFXAAFilterFS.glsl for details.
enum DebugOption
{
FXAA_NO_DEBUG = 0,
FXAA_DEBUG_SUBPIXEL_ALIASING,
FXAA_DEBUG_EDGE_DIRECTION,
FXAA_DEBUG_EDGE_NUM_STEPS,
FXAA_DEBUG_EDGE_DISTANCE,
FXAA_DEBUG_EDGE_SAMPLE_OFFSET,
FXAA_DEBUG_ONLY_SUBPIX_AA,
FXAA_DEBUG_ONLY_EDGE_AA
};
// Description:
// Debugging options that affect the output color buffer. See
// vtkFXAAFilterFS.glsl for details. Only one may be active at a time.
virtual void SetDebugOptionValue(DebugOption opt);
vtkGetMacro(DebugOptionValue, DebugOption)
protected:
vtkOpenGLFXAAFilter();
~vtkOpenGLFXAAFilter();
void Prepare();
void FreeGLObjects();
void CreateGLObjects();
void LoadInput();
void ApplyFilter();
void SubstituteFragmentShader(std::string &fragShader);
void Finalize();
void StartTimeQuery(unsigned int &queryId, bool &tracker);
void EndTimeQuery(unsigned int &queryId, bool &tracker);
bool GetTimeQueryResult(unsigned int &queryId, unsigned int &result);
void PrintBenchmark();
// Cache GL state that we modify
bool BlendState;
bool DepthTestState;
int Viewport[4]; // x, y, width, height
// Used to measure execution time:
bool PreparationTimeQueryActive;
bool FXAATimeQueryActive;
unsigned int PreparationTimeQuery;
unsigned int FXAATimeQuery;
unsigned int PreparationTime;
unsigned int FXAATime;
// Parameters:
float RelativeContrastThreshold;
float HardContrastThreshold;
float SubpixelBlendLimit;
float SubpixelContrastThreshold;
int EndpointSearchIterations;
bool UseHighQualityEndpoints;
DebugOption DebugOptionValue;
// Set to true when the shader definitions change so we know when to rebuild.
bool NeedToRebuildShader;
vtkOpenGLRenderer *Renderer;
vtkTextureObject *Input;
vtkShaderProgram *Program;
vtkOpenGLVertexArrayObject *VAO;
vtkOpenGLBufferObject *VBO;
private:
vtkOpenGLFXAAFilter(const vtkOpenGLFXAAFilter&) VTK_DELETE_FUNCTION;
void operator=(const vtkOpenGLFXAAFilter&) VTK_DELETE_FUNCTION;
};
#endif // vtkOpenGLFXAAFilter_h
......@@ -27,6 +27,7 @@ PURPOSE. See the above copyright notice for more information.
#include "vtkObjectFactory.h"
#include "vtkOpenGLCamera.h"
#include "vtkOpenGLError.h"
#include "vtkOpenGLFXAAFilter.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
......@@ -73,6 +74,7 @@ vtkOpenGLRenderer::vtkOpenGLRenderer()
this->PickInfo->NumPicked = 0;
this->PickedZ = 0;
this->FXAAFilter = 0;
this->DepthPeelingPass = 0;
this->ShadowMapPass = 0;
this->DepthPeelingHigherLayer=0;
......@@ -228,6 +230,33 @@ int vtkOpenGLRenderer::UpdateGeometry()
}
}
// Apply FXAA before volumes and overlays. Volumes don't need AA, and overlays
// are usually things like text, which are already antialiased.
if (this->UseFXAA)
{
if (!this->FXAAFilter)
{
this->FXAAFilter = vtkOpenGLFXAAFilter::New();
}
this->FXAAFilter->SetRelativeContrastThreshold(
this->FXAARelativeContrastThreshold);
this->FXAAFilter->SetHardContrastThreshold(
this->FXAAHardContrastThreshold);
this->FXAAFilter->SetSubpixelBlendLimit(
this->FXAASubpixelBlendLimit);
this->FXAAFilter->SetSubpixelContrastThreshold(
this->FXAASubpixelContrastThreshold);
this->FXAAFilter->SetEndpointSearchIterations(
this->FXAAEndpointSearchIterations);
this->FXAAFilter->SetUseHighQualityEndpoints(
this->FXAAUseHighQualityEndpoints);
this->FXAAFilter->SetDebugOptionValue(
static_cast<vtkOpenGLFXAAFilter::DebugOption>(this->FXAADebugOption));
this->FXAAFilter->Execute(this);
}
// loop through props and give them a chance to
// render themselves as volumetric geometry.
for ( i = 0; i < this->PropArrayCount; i++ )
......@@ -587,6 +616,10 @@ void vtkOpenGLRenderer::ReleaseGraphicsResources(vtkWindow *w)
{
this->Pass->ReleaseGraphicsResources(w);
}
if (this->FXAAFilter)
{
this->FXAAFilter->ReleaseGraphicsResources();
}
if (w && this->DepthPeelingPass)
{
this->DepthPeelingPass->ReleaseGraphicsResources(w);
......@@ -715,6 +748,12 @@ vtkOpenGLRenderer::~vtkOpenGLRenderer()
this->Pass = NULL;
}
if (this->FXAAFilter)
{
this->FXAAFilter->Delete();
this->FXAAFilter = 0;
}
if (this->ShadowMapPass)
{
this->ShadowMapPass->Delete();
......
......@@ -24,6 +24,7 @@
#include "vtkRenderer.h"
#include <vector> // STL Header
class vtkOpenGLFXAAFilter;
class vtkRenderPass;
class vtkOpenGLTexture;
class vtkTextureObject;
......@@ -107,6 +108,10 @@ protected:
friend class vtkOpenGLImageSliceMapper;
friend class vtkOpenGLImageResliceMapper;
// Description:
// FXAA is delegated to an instance of vtkOpenGLFXAAFilter
vtkOpenGLFXAAFilter *FXAAFilter;
// Description:
// Depth peeling is delegated to an instance of vtkDepthPeelingPass
vtkDepthPeelingPass *DepthPeelingPass;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment