Commit 189553d5 authored by Alvaro Sanchez's avatar Alvaro Sanchez Committed by Kitware Robot

Merge topic 'fix-jittering'

b3adde6e Fixed stochastic jittering and added API to customize noise settings.
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Merge-request: !2130
parents 41871ffc b3adde6e
......@@ -17,7 +17,6 @@ set (GenericVolumeCxxTests
TestGPURayCastFourComponentsMinIP.cxx
TestGPURayCastFourComponentsMIP.cxx
TestGPURayCastMapperBenchmark.cxx
TestGPURayCastMapperSampleDistance.cxx
TestGPURayCastMIPBinaryMask.cxx
TestGPURayCastMIPToComposite.cxx
TestGPURayCastNearestDataTypesMIP.cxx
......@@ -70,7 +69,10 @@ set (VolumeOpenGL2CxxTests
TestGPURayCastGradientOpacityLight.cxx
TestGPURayCastIndependentComponentsLightParameters.cxx
TestGPURayCastIndependentVectorMode.cxx
TestGPURayCastJittering.cxx
TestGPURayCastJitteringCustom.cxx
TestGPURayCastLargeColorTransferFunction.cxx
TestGPURayCastMapperSampleDistance.cxx
TestGPURayCastPositionalLights.cxx
TestGPURayCastReleaseResources.cxx
TestGPURayCastRenderDepthToImage.cxx
......
/*=========================================================================
Program: Visualization Toolkit
Module: TestGPURayCastJittering.cxx
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.
=========================================================================*/
/** Tests stochastic jittering by rendering a volume exhibiting aliasing due
* to a big sampling distance (low sampling frequency), a.k.a. wood-grain
* artifacts. The expected output is 'filtered' due to the noise introduced
* by jittering the entry point of the rays.
*/
#include <iostream>
#include <vtkCamera.h>
#include <vtkColorTransferFunction.h>
#include <vtkGPUVolumeRayCastMapper.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkNew.h>
#include <vtkPiecewiseFunction.h>
#include <vtkRegressionTestImage.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkStructuredPointsReader.h>
#include <vtkTestUtilities.h>
#include <vtkVolume.h>
#include <vtkVolumeProperty.h>
static const char* TestGPURayCastJitteringLog =
"# StreamVersion 1\n"
"EnterEvent 298 27 0 0 0 0 0\n"
"MouseWheelForwardEvent 200 142 0 0 0 0 0\n"
"LeaveEvent 311 71 0 0 0 0 0\n";
int TestGPURayCastJittering(int argc, char* argv[])
{
cout << "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)" << endl;
char* volumeFile = vtkTestUtilities::ExpandDataFileName(
argc, argv, "Data/ironProt.vtk");
vtkNew<vtkStructuredPointsReader> reader;
reader->SetFileName(volumeFile);
delete[] volumeFile;
vtkNew<vtkGPUVolumeRayCastMapper> mapper;
mapper->SetInputConnection(reader->GetOutputPort());
mapper->SetAutoAdjustSampleDistances(0);
mapper->SetSampleDistance(2.0);
mapper->UseJitteringOn();
vtkNew<vtkColorTransferFunction> color;
color->AddRGBPoint(0.0, 0.0, 0.0, 0.0);
color->AddRGBPoint(64.0, 1.0, 0.0, 0.0);
color->AddRGBPoint(128.0, 0.0, 0.0, 1.0);
color->AddRGBPoint(192.0, 0.0, 1.0, 0.0);
color->AddRGBPoint(255.0, 0.0, 0.2, 0.0);
vtkNew<vtkPiecewiseFunction> opacity;
opacity->AddPoint(0.0, 0.0);
opacity->AddPoint(255.0, 1.0);
vtkNew<vtkVolumeProperty> property;
property->SetColor(color.GetPointer());
property->SetScalarOpacity(opacity.GetPointer());
property->SetInterpolationTypeToLinear();
property->ShadeOff();
vtkNew<vtkVolume> volume;
volume->SetMapper(mapper.GetPointer());
volume->SetProperty(property.GetPointer());
vtkNew<vtkRenderWindow> renWin;
renWin->SetSize(400, 400);
renWin->SetMultiSamples(0);
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetRenderWindow(renWin.GetPointer());
vtkNew<vtkInteractorStyleTrackballCamera> style;
iren->SetInteractorStyle(style.GetPointer());
vtkNew<vtkRenderer> ren;
renWin->AddRenderer(ren.GetPointer());
ren->AddVolume(volume.GetPointer());
ren->ResetCamera();
ren->GetActiveCamera()->SetPosition(79.1817, 14.6622, 62.9264);
ren->GetActiveCamera()->SetFocalPoint(32.0598, 26.5308, 28.0257);
renWin->Render();
iren->Initialize();
int rv = vtkTesting::InteractorEventLoop(argc, argv, iren.GetPointer(),
TestGPURayCastJitteringLog);
return rv;
}
/*=========================================================================
Program: Visualization Toolkit
Module: TestGPURayCastJitteringCustom.cxx
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.
=========================================================================*/
/** Tests stochastic jittering by rendering a volume exhibiting aliasing due
* to a big sampling distance (low sampling frequency), a.k.a. wood-grain
* artifacts. The expected output is 'filtered' due to the noise introduced
* by a customized noise generator.
*/
#include <iostream>
#include <vtkCamera.h>
#include <vtkColorTransferFunction.h>
#include <vtkGPUVolumeRayCastMapper.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkNew.h>
#include <vtkOpenGLGPUVolumeRayCastMapper.h>
#include <vtkPerlinNoise.h>
#include <vtkPiecewiseFunction.h>
#include <vtkRegressionTestImage.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkStructuredPointsReader.h>
#include <vtkTestUtilities.h>
#include <vtkVolume.h>
#include <vtkVolumeProperty.h>
static const char* TestGPURayCastJitteringCustomLog =
"# StreamVersion 1\n"
"EnterEvent 298 27 0 0 0 0 0\n"
"MouseWheelForwardEvent 200 142 0 0 0 0 0\n"
"LeaveEvent 311 71 0 0 0 0 0\n";
int TestGPURayCastJitteringCustom(int argc, char* argv[])
{
cout << "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)" << endl;
char* volumeFile = vtkTestUtilities::ExpandDataFileName(
argc, argv, "Data/ironProt.vtk");
vtkNew<vtkStructuredPointsReader> reader;
reader->SetFileName(volumeFile);
delete[] volumeFile;
vtkNew<vtkGPUVolumeRayCastMapper> mapper;
mapper->SetInputConnection(reader->GetOutputPort());
mapper->SetAutoAdjustSampleDistances(0);
mapper->SetSampleDistance(2.0);
mapper->UseJitteringOn();
vtkNew<vtkColorTransferFunction> color;
color->AddRGBPoint(0.0, 0.0, 0.0, 0.0);
color->AddRGBPoint(64.0, 1.0, 0.0, 0.0);
color->AddRGBPoint(128.0, 0.0, 0.0, 1.0);
color->AddRGBPoint(192.0, 0.0, 1.0, 0.0);
color->AddRGBPoint(255.0, 0.0, 0.2, 0.0);
vtkNew<vtkPiecewiseFunction> opacity;
opacity->AddPoint(0.0, 0.0);
opacity->AddPoint(255.0, 1.0);
vtkNew<vtkVolumeProperty> property;
property->SetColor(color.GetPointer());
property->SetScalarOpacity(opacity.GetPointer());
property->SetInterpolationTypeToLinear();
property->ShadeOff();
vtkNew<vtkVolume> volume;
volume->SetMapper(mapper.GetPointer());
volume->SetProperty(property.GetPointer());
vtkNew<vtkRenderWindow> renWin;
renWin->SetSize(400, 400);
renWin->SetMultiSamples(0);
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetRenderWindow(renWin.GetPointer());
vtkNew<vtkInteractorStyleTrackballCamera> style;
iren->SetInteractorStyle(style.GetPointer());
vtkNew<vtkRenderer> ren;
renWin->AddRenderer(ren.GetPointer());
ren->AddVolume(volume.GetPointer());
ren->ResetCamera();
ren->GetActiveCamera()->SetPosition(79.1817, 14.6622, 62.9264);
ren->GetActiveCamera()->SetFocalPoint(32.0598, 26.5308, 28.0257);
renWin->Render();
iren->Initialize();
// Customize the noise function and texture size
vtkOpenGLGPUVolumeRayCastMapper* glMapper =
vtkOpenGLGPUVolumeRayCastMapper::SafeDownCast(mapper.GetPointer());
int texSize[2] = {600, 600};
glMapper->SetNoiseTextureSize(texSize);
vtkPerlinNoise* generator = vtkPerlinNoise::New();
generator->SetFrequency(1024.0, 1024.0, 1.0);
generator->SetAmplitude(0.5);
glMapper->SetNoiseGenerator(generator);
generator->Delete();
renWin->Render();
int rv = vtkTesting::InteractorEventLoop(argc, argv, iren.GetPointer(),
TestGPURayCastJitteringCustomLog);
return rv;
}
c7e9a85963c511e7ab5df6f7ee101d63
91d78e44c46c14aa2d132b8be076ec5f
0a7df901d35fd6a97b8fabcf1d6b1d2d
821a0e5598e9af3d084ab23820679702
......@@ -50,7 +50,7 @@ vtkGPUVolumeRayCastMapper::vtkGPUVolumeRayCastMapper()
this->RenderToImage = 0;
this->DepthImageScalarType = VTK_FLOAT;
this->ClampDepthToBackface = 0;
this->UseJittering = 1;
this->UseJittering = 0;
this->UseDepthPass = 0;
this->DepthPassContourValues = NULL;
this->SampleDistance = 1.0;
......
......@@ -103,7 +103,7 @@ public:
this->CubeIndicesId = 0;
this->InterpolationType = vtkTextureObject::Linear;
this->VolumeTextureObject = 0;
this->NoiseTextureObject = 0;
this->NoiseTextureObject = NULL;
this->DepthTextureObject = 0;
this->TextureWidth = 1024;
this->ActualSampleDistance = 1.0;
......@@ -127,7 +127,7 @@ public:
this->CurrentSelectionPass = vtkHardwareSelector::MIN_KNOWN_PASS - 1;
this->CellScale[0] = this->CellScale[1] = this->CellScale[2] = 0.0;
this->NoiseTextureData = 0;
this->NoiseTextureData = NULL;
this->NumberOfLights = 0;
this->LightComplexity = 0;
......@@ -173,37 +173,37 @@ public:
if (this->NoiseTextureObject)
{
this->NoiseTextureObject->Delete();
this->NoiseTextureObject = 0;
this->NoiseTextureObject = NULL;
}
if (this->DepthTextureObject)
{
this->DepthTextureObject->Delete();
this->DepthTextureObject = 0;
this->DepthTextureObject = NULL;
}
if (this->FBO)
{
this->FBO->Delete();
this->FBO = 0;
this->FBO = NULL;
}
if (this->RTTDepthBufferTextureObject)
{
this->RTTDepthBufferTextureObject->Delete();
this->RTTDepthBufferTextureObject = 0;
this->RTTDepthBufferTextureObject = NULL;
}
if (this->RTTDepthTextureObject)
{
this->RTTDepthTextureObject->Delete();
this->RTTDepthTextureObject = 0;
this->RTTDepthTextureObject = NULL;
}
if (this->RTTColorTextureObject)
{
this->RTTColorTextureObject->Delete();
this->RTTColorTextureObject = 0;
this->RTTColorTextureObject = NULL;
}
this->DeleteTransferFunctions();
......@@ -382,7 +382,6 @@ public:
std::vector<double> Bias;
float* NoiseTextureData;
GLint NoiseTextureSize;
float ActualSampleDistance;
......@@ -1344,64 +1343,82 @@ int vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::
void vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::CreateNoiseTexture(
vtkRenderer* ren)
{
vtkOpenGLRenderWindow* glWindow = vtkOpenGLRenderWindow::SafeDownCast(
ren->GetRenderWindow());
if (!this->NoiseTextureObject)
{
this->NoiseTextureObject = vtkTextureObject::New();
}
this->NoiseTextureObject->SetContext(glWindow);
this->NoiseTextureObject->SetContext(vtkOpenGLRenderWindow::SafeDownCast(
ren->GetRenderWindow()));
bool updateSize = false;
bool useUserSize = this->Parent->NoiseTextureSize[0] > 0 &&
this->Parent->NoiseTextureSize[1] > 0;
if (useUserSize)
{
int const twidth = this->NoiseTextureObject->GetWidth();
int const theight = this->NoiseTextureObject->GetHeight();
updateSize = this->Parent->NoiseTextureSize[0] != twidth ||
this->Parent->NoiseTextureSize[1] != theight;
}
if (!this->NoiseTextureObject->GetHandle())
if (!this->NoiseTextureObject->GetHandle() || updateSize ||
this->NoiseTextureObject->GetMTime() < this->Parent->NoiseGenerator->GetMTime())
{
GLsizei size = 128;
GLint maxSize;
int* winSize = ren->GetRenderWindow()->GetSize();
int sizeX = useUserSize ? this->Parent->NoiseTextureSize[0] : winSize[0];
int sizeY = useUserSize ? this->Parent->NoiseTextureSize[1] : winSize[1];
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
if (size > maxSize)
int const maxSize = vtkTextureObject::GetMaximumTextureSize(glWindow);
if (sizeX > maxSize || sizeY > maxSize)
{
size = maxSize;
sizeX = vtkMath::Max(sizeX, maxSize);
sizeY = vtkMath::Max(sizeY, maxSize);
}
if (this->NoiseTextureSize != size)
// Allocate buffer. After controlling for the maximum supported size sizeX/Y
// might have changed, so an additional check is needed.
int const twidth = this->NoiseTextureObject->GetWidth();
int const theight = this->NoiseTextureObject->GetHeight();
bool sizeChanged = sizeX != twidth || sizeY != theight;
if (sizeChanged || !this->NoiseTextureData)
{
delete[] this->NoiseTextureData;
this->NoiseTextureData = 0;
this->NoiseTextureData = NULL;
this->NoiseTextureData = new float[sizeX * sizeY];
}
if (this->NoiseTextureData == 0)
// Generate jitter noise
if (!this->Parent->NoiseGenerator)
{
this->NoiseTextureData = new float[size * size];
this->NoiseTextureSize = size;
vtkNew<vtkPerlinNoise> noiseGenerator;
noiseGenerator->SetFrequency(size, 1.0, 1.0);
noiseGenerator->SetPhase(0.0, 0.0, 0.0);
// -0.5 and 0.5 range
noiseGenerator->SetAmplitude(0.1);
int j = 0;
while(j < size)
{
int i = 0;
while(i < size)
{
this->NoiseTextureData[j * size + i] =
static_cast<float>(noiseGenerator->EvaluateFunction(i, j, 0.0) + 0.1);
++i;
}
++j;
}
// Use default settings
vtkPerlinNoise* perlinNoise = vtkPerlinNoise::New();
perlinNoise->SetPhase(0.0, 0.0, 0.0);
perlinNoise->SetFrequency(sizeX, sizeY, 1.0);
perlinNoise->SetAmplitude(0.5); /* [-n, n] */
this->Parent->NoiseGenerator = perlinNoise;
}
this->NoiseTextureObject->Create2DFromRaw(size,
size,
1,
VTK_FLOAT,
this->NoiseTextureData);
int const bufferSize = sizeX * sizeY;
for (int i = 0; i < bufferSize; i++)
{
int const x = i % sizeX;
int const y = i / sizeY;
this->NoiseTextureData[i] = static_cast<float>(
this->Parent->NoiseGenerator->EvaluateFunction(x, y, 0.0) + 0.1);
}
// Prepare texture
this->NoiseTextureObject->Create2DFromRaw(sizeX, sizeY, 1, VTK_FLOAT,
this->NoiseTextureData);
this->NoiseTextureObject->SetWrapS(vtkTextureObject::Repeat);
this->NoiseTextureObject->SetWrapT(vtkTextureObject::Repeat);
this->NoiseTextureObject->SetMagnificationFilter(vtkTextureObject::Nearest);
this->NoiseTextureObject->SetMinificationFilter(vtkTextureObject::Nearest);
this->NoiseTextureObject->SetBorderColor(0.0f, 0.0f, 0.0f, 0.0f);
this->NoiseTextureObject->Modified();
}
}
......@@ -2544,6 +2561,8 @@ vtkOpenGLGPUVolumeRayCastMapper::vtkOpenGLGPUVolumeRayCastMapper() :
this->Impl = new vtkInternal(this);
this->ReductionFactor = 1.0;
this->CurrentPass = RenderPass;
this->NoiseTextureSize[0] = this->NoiseTextureSize[1] = -1;
this->NoiseGenerator = NULL;
this->ResourceCallback = new vtkOpenGLResourceFreeCallback<vtkOpenGLGPUVolumeRayCastMapper>(this,
&vtkOpenGLGPUVolumeRayCastMapper::ReleaseGraphicsResources);
......@@ -2558,6 +2577,13 @@ vtkOpenGLGPUVolumeRayCastMapper::~vtkOpenGLGPUVolumeRayCastMapper()
delete this->ResourceCallback;
this->ResourceCallback = NULL;
}
if (this->NoiseGenerator)
{
this->NoiseGenerator->Delete();
this->NoiseGenerator = NULL;
}
delete this->Impl;
this->Impl = 0;
}
......@@ -3273,7 +3299,10 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren,
}
// Update noise sampler texture
this->Impl->CreateNoiseTexture(ren);
if (this->UseJittering)
{
this->Impl->CreateNoiseTexture(ren);
}
// Grab depth sampler buffer (to handle cases when we are rendering geometry
// and in_volume together
......@@ -3525,9 +3554,12 @@ void vtkOpenGLGPUVolumeRayCastMapper::DoGPURender(vtkRenderer* ren,
}
}
this->Impl->NoiseTextureObject->Activate();
prog->SetUniformi("in_noiseSampler",
this->Impl->NoiseTextureObject->GetTextureUnit());
if (this->Impl->NoiseTextureObject)
{
this->Impl->NoiseTextureObject->Activate();
prog->SetUniformi("in_noiseSampler",
this->Impl->NoiseTextureObject->GetTextureUnit());
}
// currently broken on ES
#if GL_ES_VERSION_3_0 != 1
......@@ -3792,7 +3824,10 @@ void vtkOpenGLGPUVolumeRayCastMapper::DoGPURender(vtkRenderer* ren,
// Undo binds and de-activate buffers
//--------------------------------------------------------------------------
this->Impl->VolumeTextureObject->Deactivate();
this->Impl->NoiseTextureObject->Deactivate();
if (this->Impl->NoiseTextureObject)
{
this->Impl->NoiseTextureObject->Deactivate();
}
this->Impl->DepthTextureObject->Deactivate();
for (int i = 0; i < numberOfSamplers; ++i)
......@@ -3825,3 +3860,7 @@ void vtkOpenGLGPUVolumeRayCastMapper::DoGPURender(vtkRenderer* ren,
vtkOpenGLCheckErrorMacro("failed after Render");
}
//----------------------------------------------------------------------------
vtkCxxSetObjectMacro(vtkOpenGLGPUVolumeRayCastMapper, NoiseGenerator,
vtkImplicitFunction);
......@@ -25,6 +25,7 @@ class vtkOpenGLCamera;
class vtkShaderProgram;
class vtkTextureObject;
class vtkGenericOpenGLResourceFreeCallback;
class vtkImplicitFunction;
//----------------------------------------------------------------------------
class VTKRENDERINGVOLUMEOPENGL2_EXPORT vtkOpenGLGPUVolumeRayCastMapper :
......@@ -73,6 +74,17 @@ public:
// the user.
vtkGetMacro(CurrentPass, int);
//@{
/**
* Sets a user defined function to generate the ray jittering noise.
* vtkPerlinNoise is used by default with a texture size equivlent to
* the window size. These settings will have no effect when UseJittering
* is Off.
*/
void SetNoiseGenerator(vtkImplicitFunction* generator);
vtkSetVector2Macro(NoiseTextureSize, int);
//@}
protected:
vtkOpenGLGPUVolumeRayCastMapper();
~vtkOpenGLGPUVolumeRayCastMapper();
......@@ -158,6 +170,9 @@ private:
class vtkInternal;
vtkInternal* Impl;
vtkImplicitFunction* NoiseGenerator;
int NoiseTextureSize[2];
vtkOpenGLGPUVolumeRayCastMapper(
const vtkOpenGLGPUVolumeRayCastMapper&) VTK_DELETE_FUNCTION;
void operator=(const vtkOpenGLGPUVolumeRayCastMapper&) VTK_DELETE_FUNCTION;
......
......@@ -339,9 +339,20 @@ namespace vtkvolume
\n g_dirStep = (ip_inverseTextureDataAdjusted *\
\n vec4(rayDir, 0.0)).xyz * in_sampleDistance;\
\n\
\n float jitterValue = (texture2D(in_noiseSampler, g_dataPos.xy).x);\
\n // 2D Texture fragment coordinates [0,1] from fragment coordinates.\
\n // The frame buffer texture has the size of the plain buffer but \
\n // we use a fraction of it. The texture coordinate is less than 1 if\
\n // the reduction factor is less than 1.\
\n // Device coordinates are between -1 and 1. We need texture\
\n // coordinates between 0 and 1. The in_noiseSampler and in_depthSampler\
\n // buffers have the original size buffer.\
\n vec2 fragTexCoord = (gl_FragCoord.xy - in_windowLowerLeftCorner) *\
\n in_inverseWindowSize;\
\n\
\n float jitterValue = 0;\
\n if (in_useJittering)\
\n {\
\n jitterValue = texture2D(in_noiseSampler, fragTexCoord).x;\
\n g_dataPos += g_dirStep * jitterValue;\
\n }\
\n else\
......@@ -1567,15 +1578,6 @@ namespace vtkvolume
\n // Flag to indicate if the raymarch loop should terminate \
\n bool stop = false;\
\n\
\n // 2D Texture fragment coordinates [0,1] from fragment coordinates \
\n // the frame buffer texture has the size of the plain buffer but \
\n // we use a fraction of it. The texture coordinates is less than 1 if \
\n // the reduction factor is less than 1. \
\n // Device coordinates are between -1 and 1. We need texture \
\n // coordinates between 0 and 1 the in_depthSampler buffer has the \
\n // original size buffer. \
\n vec2 fragTexCoord = (gl_FragCoord.xy - in_windowLowerLeftCorner) *\
\n in_inverseWindowSize;\
\n float l_terminatePointMax = 0.0;\
\n\
\n#ifdef GL_ES\
......
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