Commit edc24bde authored by Ken Martin's avatar Ken Martin

Improve the capabilities of the vtkPointGaussianMapper

Add support for opacity arrays, cells and shader overrides
Add a test that covers some of this code
parent 13a4f1c7
......@@ -14,14 +14,20 @@
#include "vtkPointGaussianMapper.h"
#include "vtkObjectFactory.h"
#include "vtkPiecewiseFunction.h"
//-----------------------------------------------------------------------------
vtkAbstractObjectFactoryNewMacro(vtkPointGaussianMapper)
vtkCxxSetObjectMacro(vtkPointGaussianMapper, ScalarOpacityFunction, vtkPiecewiseFunction);
//-----------------------------------------------------------------------------
vtkPointGaussianMapper::vtkPointGaussianMapper()
{
this->ScaleArray = 0;
this->OpacityArray = 0;
this->SplatShaderCode = 0;
this->ScalarOpacityFunction = 0;
this->DefaultRadius = 1.0;
this->Emissive = 1;
}
......@@ -30,6 +36,9 @@ vtkPointGaussianMapper::vtkPointGaussianMapper()
vtkPointGaussianMapper::~vtkPointGaussianMapper()
{
this->SetScaleArray(0);
this->SetOpacityArray(0);
this->SetSplatShaderCode(0);
this->SetScalarOpacityFunction(0);
}
//-----------------------------------------------------------------------------
......@@ -38,6 +47,8 @@ void vtkPointGaussianMapper::PrintSelf(ostream& os, vtkIndent indent)
this->Superclass::PrintSelf(os, indent);
os << indent << "Scale Array: " << (this->ScaleArray ? this->ScaleArray : "(none)") << "\n";
os << indent << "Opacity Array: " << (this->OpacityArray ? this->OpacityArray : "(none)") << "\n";
os << indent << "SplatShaderCode: " << (this->SplatShaderCode ? this->SplatShaderCode : "(none)") << "\n";
os << indent << "Default Radius: " << this->DefaultRadius << "\n";
os << indent << "Emissive: " << this->Emissive << "\n";
}
......@@ -23,6 +23,8 @@
#include "vtkRenderingCoreModule.h" // For export macro
#include "vtkPolyDataMapper.h"
class vtkPiecewiseFunction;
class VTKRENDERINGCORE_EXPORT vtkPointGaussianMapper : public vtkPolyDataMapper
{
public:
......@@ -49,11 +51,39 @@ public:
vtkGetMacro(Emissive, int);
vtkBooleanMacro(Emissive, int);
// Description:
// Set/Get the optional opacity transfer function. This is only
// used when an OpacityArray is also specified.
void SetScalarOpacityFunction(vtkPiecewiseFunction *);
vtkGetObjectMacro(ScalarOpacityFunction,vtkPiecewiseFunction);
// Description:
// Method to set the optional opacity array. If specified this
// array will be used to generate the opacity values.
vtkSetStringMacro(OpacityArray);
vtkGetStringMacro(OpacityArray);
// Description:
// Method to override the fragment shader code for the splat. You can
// set this to draw other shapes. For the OPenGL2 backend some of
// the variables you can use and/or modify include,
// opacity - 0.0 to 1.0
// diffuseColor - vec3
// ambientColor - vec3
// offsetVCVSOutput - vec2 offset in view coordinates from the splat center
vtkSetStringMacro(SplatShaderCode);
vtkGetStringMacro(SplatShaderCode);
protected:
vtkPointGaussianMapper();
~vtkPointGaussianMapper();
char *ScaleArray;
char *OpacityArray;
char *SplatShaderCode;
vtkPiecewiseFunction *ScalarOpacityFunction;
double DefaultRadius;
int Emissive;
......
vtk_add_test_cxx(${vtk-module}CxxTests tests
#TestRenderWidget.cxx # Very experimental, fails, does nothing useful yet.
TestPointGaussianMapper.cxx
TestPointGaussianMapperOpacity.cxx
TestVBOPLYMapper.cxx
TestVBOPointsLines.cxx
TestGaussianBlurPass.cxx
......
/*=========================================================================
Program: Visualization Toolkit
Module: TestSprites.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.
=========================================================================*/
// .SECTION Thanks
// <verbatim>
//
// This file is part of the PointSprites plugin developed and contributed by
//
// Copyright (c) CSCS - Swiss National Supercomputing Centre
// EDF - Electricite de France
//
// John Biddiscombe, Ugo Varetto (CSCS)
// Stephane Ploix (EDF)
//
// </verbatim>
// .SECTION Description
// this program tests the point sprite support by vtkPointSpriteProperty.
#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkColorTransferFunction.h"
#include "vtkDataObject.h"
#include "vtkDataSetAttributes.h"
#include "vtkNew.h"
#include "vtkPiecewiseFunction.h"
#include "vtkPointGaussianMapper.h"
#include "vtkPointSource.h"
#include "vtkProperty.h"
#include "vtkRandomAttributeGenerator.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkSphereSource.h"
#include "vtkTimerLog.h"
#include "vtkTestUtilities.h"
#include "vtkRegressionTestImage.h"
int TestPointGaussianMapperOpacity(int argc, char *argv[])
{
int desiredPoints = 1.0e4;
vtkNew<vtkPointSource> points;
points->SetNumberOfPoints(desiredPoints);
points->SetRadius(pow(desiredPoints,0.33)*10.0);
points->Update();
vtkNew<vtkRandomAttributeGenerator> randomAttr;
randomAttr->SetInputConnection(points->GetOutputPort());
vtkNew<vtkPointGaussianMapper> mapper;
vtkNew<vtkRenderer> renderer;
renderer->SetBackground(0.0, 0.0, 0.0);
vtkNew<vtkRenderWindow> renderWindow;
renderWindow->SetSize(300, 300);
renderWindow->SetMultiSamples(0);
renderWindow->AddRenderer(renderer.Get());
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetRenderWindow(renderWindow.Get());
vtkNew<vtkActor> actor;
actor->SetMapper(mapper.Get());
renderer->AddActor(actor.Get());
randomAttr->SetDataTypeToFloat();
randomAttr->GeneratePointScalarsOn();
randomAttr->GeneratePointVectorsOn();
randomAttr->GeneratePointArrayOn();
randomAttr->Update();
mapper->SetInputConnection(randomAttr->GetOutputPort());
mapper->SetColorModeToMapScalars();
mapper->SetScalarModeToUsePointFieldData();
mapper->SelectColorArray("RandomPointVectors");
mapper->SetInterpolateScalarsBeforeMapping(0);
mapper->SetScaleArray("RandomPointScalars");
mapper->SetOpacityArray("RandomPointArray");
mapper->EmissiveOff();
// show other shader examples
mapper->SetSplatShaderCode(
// this first line keeps the default color opacity calcs
// which you can then modify with additional code below
"//VTK::Color::Impl\n"
// example of a circle with black edges
// " float dist = sqrt(dot(offsetVCVSOutput.xy,offsetVCVSOutput.xy));\n"
// " if (dist > 1.1) { discard; }\n"
// " if (dist < 0.5) { discard; }\n"
// // apply a black edge around the circle
// " if (dist > 1.0 || dist < 0.6) { diffuseColor = vec3(0,0,0); ambientColor = vec3(0,0,0); }\n"
// example for a square
" if (abs(offsetVCVSOutput.x) > 1.0 || abs(offsetVCVSOutput.y) > 1.0) { discard; }\n"
" if (abs(offsetVCVSOutput.x) < 0.6 && abs(offsetVCVSOutput.y) < 0.6) { discard; }\n"
);
vtkNew<vtkColorTransferFunction> ctf;
ctf->AddHSVPoint(0.0,0.1,0.7,1.0);
ctf->AddHSVPoint(1.0,0.9,0.7,1.0);
ctf->SetColorSpaceToHSV();
ctf->HSVWrapOff();
mapper->SetLookupTable(ctf.Get());
vtkNew<vtkPiecewiseFunction> otf;
otf->AddPoint(0.0,0.3);
otf->AddPoint(1.0,1.0);
mapper->SetScalarOpacityFunction(otf.Get());
vtkNew<vtkTimerLog> timer;
timer->StartTimer();
renderWindow->Render();
timer->StopTimer();
double firstRender = timer->GetElapsedTime();
cerr << "first render time: " << firstRender << endl;
timer->StartTimer();
int numRenders = 85;
for (int i = 0; i < numRenders; ++i)
{
renderer->GetActiveCamera()->Azimuth(1);
renderer->GetActiveCamera()->Elevation(1);
renderWindow->Render();
}
timer->StopTimer();
double elapsed = timer->GetElapsedTime();
int numPts = mapper->GetInput()->GetPoints()->GetNumberOfPoints();
cerr << "interactive render time: " << elapsed / numRenders << endl;
cerr << "number of points: " << numPts << endl;
cerr << "points per second: " << numPts*(numRenders/elapsed) << endl;
renderer->GetActiveCamera()->SetPosition(0,0,1);
renderer->GetActiveCamera()->SetFocalPoint(0,0,0);
renderer->GetActiveCamera()->SetViewUp(0,1,0);
renderer->ResetCamera();
// renderer->GetActiveCamera()->Print(cerr);
renderer->GetActiveCamera()->Zoom(10.0);
renderWindow->Render();
int retVal = vtkRegressionTestImage( renderWindow.Get() );
if ( retVal == vtkRegressionTester::DO_INTERACTOR)
{
iren->Start();
}
return !retVal;
}
......@@ -15,6 +15,7 @@
#include "vtkOpenGLHelper.h"
#include "vtkCellArray.h"
#include "vtkHardwareSelector.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
......@@ -25,6 +26,7 @@
#include "vtkOpenGLPolyDataMapper.h"
#include "vtkOpenGLVertexArrayObject.h"
#include "vtkOpenGLVertexBufferObject.h"
#include "vtkPiecewiseFunction.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkProperty.h"
......@@ -83,6 +85,9 @@ protected:
virtual void RenderPieceDraw(vtkRenderer *ren, vtkActor *act);
// create the array for opacity values
void BuildOpacityArray(vtkPolyData *);
// Description:
// Does the shader source need to be recomputed
virtual bool GetNeedToRebuildShaders(vtkOpenGLHelper &cellBO,
......@@ -90,6 +95,8 @@ protected:
bool UsingPoints;
vtkUnsignedCharArray *OpacityData;
private:
vtkOpenGLPointGaussianMapperHelper(const vtkOpenGLPointGaussianMapperHelper&); // Not implemented.
void operator=(const vtkOpenGLPointGaussianMapperHelper&); // Not implemented.
......@@ -102,6 +109,7 @@ vtkStandardNewMacro(vtkOpenGLPointGaussianMapperHelper)
vtkOpenGLPointGaussianMapperHelper::vtkOpenGLPointGaussianMapperHelper()
{
this->Owner = NULL;
this->OpacityData = 0;
}
......@@ -159,20 +167,25 @@ void vtkOpenGLPointGaussianMapperHelper::ReplaceShaderColor(
{
if (!this->UsingPoints)
{
std::string VSSource = shaders[vtkShader::Vertex]->GetSource();
std::string FSSource = shaders[vtkShader::Fragment]->GetSource();
vtkShaderProgram::Substitute(FSSource,"//VTK::Color::Impl",
// compute the eye position and unit direction
"//VTK::Color::Impl\n"
" float dist2 = dot(offsetVCVSOutput.xy,offsetVCVSOutput.xy);\n"
" if (dist2 > 9.0) { discard; }\n"
" float gaussian = exp(-0.5*dist2);\n"
" opacity = opacity*gaussian;"
// " opacity = opacity*0.5;"
, false);
shaders[vtkShader::Vertex]->SetSource(VSSource);
if (this->Owner->GetSplatShaderCode())
{
vtkShaderProgram::Substitute(FSSource,"//VTK::Color::Impl",
this->Owner->GetSplatShaderCode(), false);
}
else
{
vtkShaderProgram::Substitute(FSSource,"//VTK::Color::Impl",
// compute the eye position and unit direction
"//VTK::Color::Impl\n"
" float dist2 = dot(offsetVCVSOutput.xy,offsetVCVSOutput.xy);\n"
" if (dist2 > 9.0) { discard; }\n"
" float gaussian = exp(-0.5*dist2);\n"
" opacity = opacity*gaussian;"
// " opacity = opacity*0.5;"
, false);
}
shaders[vtkShader::Fragment]->SetSource(FSSource);
}
......@@ -216,6 +229,11 @@ bool vtkOpenGLPointGaussianMapperHelper::GetNeedToRebuildShaders(
//-----------------------------------------------------------------------------
vtkOpenGLPointGaussianMapperHelper::~vtkOpenGLPointGaussianMapperHelper()
{
if (this->OpacityData)
{
this->OpacityData->Delete();
this->OpacityData = 0;
}
}
//-----------------------------------------------------------------------------
......@@ -283,68 +301,168 @@ void vtkOpenGLPointGaussianMapperHelper::SetMapperShaderParameters(vtkOpenGLHelp
namespace
{
// internal function called by CreateVBO
// if verts are provided then we only draw those points
// otherwise we draw all the points
template< typename PointDataType, typename SizeDataType >
void vtkOpenGLPointGaussianMapperHelperPackVBOTemplate2(
std::vector< float >::iterator& it,
PointDataType* points, vtkIdType numPts,
vtkCellArray *verts,
unsigned char *colors, int colorComponents,
SizeDataType* sizes, float defaultSize)
SizeDataType* sizes, float defaultSize,
unsigned char* opacityData)
{
PointDataType *pointPtr;
unsigned char *colorPtr;
unsigned char white[4] = {255, 255, 255, 255};
vtkucfloat rcolor;
int count = 0;
// if there are no per point sizes and the default size is zero
// then just render points, saving memory and speed
if (!sizes && defaultSize == 0.0)
{
unsigned char white[4] = {255, 255, 255, 255};
for (vtkIdType i = 0; i < numPts; ++i)
if (verts->GetNumberOfCells())
{
pointPtr = points + i*3;
colorPtr = colors ? (colors + i*colorComponents) : white;
// Vertices
*(it++) = pointPtr[0];
*(it++) = pointPtr[1];
*(it++) = pointPtr[2];
*(it++) = *reinterpret_cast<float *>(colorPtr);
vtkIdType* indices(NULL);
vtkIdType npts(0);
for (verts->InitTraversal(); verts->GetNextCell(npts, indices); )
{
for (int i = 0; i < npts; ++i)
{
pointPtr = points + indices[i]*3;
colorPtr = colors ? (colors + indices[i]*colorComponents) : white;
rcolor.c[0] = *(colorPtr++);
rcolor.c[1] = *(colorPtr++);
rcolor.c[2] = *(colorPtr++);
rcolor.c[3] = *(colorPtr++);
if (opacityData)
{
rcolor.c[3] = opacityData[count];
}
// Vertices
*(it++) = pointPtr[0];
*(it++) = pointPtr[1];
*(it++) = pointPtr[2];
*(it++) = rcolor.f;
count++;
}
}
}
else
{
for (vtkIdType i = 0; i < numPts; ++i)
{
pointPtr = points + i*3;
colorPtr = colors ? (colors + i*colorComponents) : white;
rcolor.c[0] = *(colorPtr++);
rcolor.c[1] = *(colorPtr++);
rcolor.c[2] = *(colorPtr++);
rcolor.c[3] = *(colorPtr++);
if (opacityData)
{
rcolor.c[3] = opacityData[i];
}
// Vertices
*(it++) = pointPtr[0];
*(it++) = pointPtr[1];
*(it++) = pointPtr[2];
*(it++) = rcolor.f;
}
}
}
else // otherwise splats
{
float cos30 = cos(vtkMath::RadiansFromDegrees(30.0));
unsigned char white[4] = {255, 255, 255, 255};
for (vtkIdType i = 0; i < numPts; ++i)
if (verts->GetNumberOfCells())
{
pointPtr = points + i*3;
colorPtr = colors ? (colors + i*colorComponents) : white;
float radius = sizes ? sizes[i] : defaultSize;
radius *= 3.0;
// Vertices
*(it++) = pointPtr[0];
*(it++) = pointPtr[1];
*(it++) = pointPtr[2];
*(it++) = *reinterpret_cast<float *>(colorPtr);
*(it++) = -2.0f*radius*cos30;
*(it++) = -radius;
*(it++) = pointPtr[0];
*(it++) = pointPtr[1];
*(it++) = pointPtr[2];
*(it++) = *reinterpret_cast<float *>(colorPtr);
*(it++) = 2.0f*radius*cos30;
*(it++) = -radius;
*(it++) = pointPtr[0];
*(it++) = pointPtr[1];
*(it++) = pointPtr[2];
*(it++) = *reinterpret_cast<float *>(colorPtr);
*(it++) = 0.0f;
*(it++) = 2.0f*radius;
vtkIdType* indices(NULL);
vtkIdType npts(0);
for (verts->InitTraversal(); verts->GetNextCell(npts, indices); )
{
for (int i = 0; i < npts; ++i)
{
pointPtr = points + indices[i]*3;
colorPtr = colors ? (colors + indices[i]*colorComponents) : white;
rcolor.c[0] = *(colorPtr++);
rcolor.c[1] = *(colorPtr++);
rcolor.c[2] = *(colorPtr++);
rcolor.c[3] = *(colorPtr++);
if (opacityData)
{
rcolor.c[3] = opacityData[count];
}
float radius = sizes ? sizes[indices[i]] : defaultSize;
radius *= 3.0;
// Vertices
*(it++) = pointPtr[0];
*(it++) = pointPtr[1];
*(it++) = pointPtr[2];
*(it++) = rcolor.f;
*(it++) = -2.0f*radius*cos30;
*(it++) = -radius;
*(it++) = pointPtr[0];
*(it++) = pointPtr[1];
*(it++) = pointPtr[2];
*(it++) = rcolor.f;
*(it++) = 2.0f*radius*cos30;
*(it++) = -radius;
*(it++) = pointPtr[0];
*(it++) = pointPtr[1];
*(it++) = pointPtr[2];
*(it++) = rcolor.f;
*(it++) = 0.0f;
*(it++) = 2.0f*radius;
count++;
}
}
}
else
{
for (vtkIdType i = 0; i < numPts; ++i)
{
pointPtr = points + i*3;
colorPtr = colors ? (colors + i*colorComponents) : white;
rcolor.c[0] = *(colorPtr++);
rcolor.c[1] = *(colorPtr++);
rcolor.c[2] = *(colorPtr++);
rcolor.c[3] = *(colorPtr++);
if (opacityData)
{
rcolor.c[3] = opacityData[i];
}
float radius = sizes ? sizes[i] : defaultSize;
radius *= 3.0;
// Vertices
*(it++) = pointPtr[0];
*(it++) = pointPtr[1];
*(it++) = pointPtr[2];
*(it++) = rcolor.f;
*(it++) = -2.0f*radius*cos30;
*(it++) = -radius;
*(it++) = pointPtr[0];
*(it++) = pointPtr[1];
*(it++) = pointPtr[2];
*(it++) = rcolor.f;
*(it++) = 2.0f*radius*cos30;
*(it++) = -radius;
*(it++) = pointPtr[0];
*(it++) = pointPtr[1];
*(it++) = pointPtr[2];
*(it++) = rcolor.f;
*(it++) = 0.0f;
*(it++) = 2.0f*radius;
}
}
}
}
......@@ -353,8 +471,10 @@ template< typename PointDataType >
void vtkOpenGLPointGaussianMapperHelperPackVBOTemplate(
std::vector< float >::iterator& it,
PointDataType* points, vtkIdType numPts,
vtkCellArray *verts,
unsigned char *colors, int colorComponents,
vtkDataArray* sizes, float defaultSize)
vtkDataArray* sizes, float defaultSize,
unsigned char *opacityData)
{
if (sizes)
{
......@@ -362,25 +482,27 @@ void vtkOpenGLPointGaussianMapperHelperPackVBOTemplate(
{
vtkTemplateMacro(
vtkOpenGLPointGaussianMapperHelperPackVBOTemplate2(
it, points, numPts, colors, colorComponents,
it, points, numPts, verts, colors, colorComponents,
static_cast<VTK_TT*>(sizes->GetVoidPointer(0)),
defaultSize)
defaultSize, opacityData)
);
}
}
else
{
vtkOpenGLPointGaussianMapperHelperPackVBOTemplate2(
it, points, numPts, colors, colorComponents,
static_cast<float*>(NULL), defaultSize);
it, points, numPts, verts, colors, colorComponents,
static_cast<float*>(NULL), defaultSize, opacityData);
}
}