diff --git a/Rendering/Core/vtkPointGaussianMapper.cxx b/Rendering/Core/vtkPointGaussianMapper.cxx index b9b289094895c54da2206f6ecab38a9c86c5e352..15faefe4712f771b055c5c836a4adf25ae08df2e 100644 --- a/Rendering/Core/vtkPointGaussianMapper.cxx +++ b/Rendering/Core/vtkPointGaussianMapper.cxx @@ -14,15 +14,28 @@ #include "vtkPointGaussianMapper.h" #include "vtkObjectFactory.h" +#include "vtkPiecewiseFunction.h" //----------------------------------------------------------------------------- vtkAbstractObjectFactoryNewMacro(vtkPointGaussianMapper) +vtkCxxSetObjectMacro(vtkPointGaussianMapper, ScaleFunction, vtkPiecewiseFunction); +vtkCxxSetObjectMacro(vtkPointGaussianMapper, ScalarOpacityFunction, vtkPiecewiseFunction); + //----------------------------------------------------------------------------- vtkPointGaussianMapper::vtkPointGaussianMapper() { this->ScaleArray = 0; - this->DefaultRadius = 1.0; + this->OpacityArray = 0; + this->SplatShaderCode = 0; + + this->ScaleFunction = 0; + this->ScaleTableSize = 1024; + + this->ScalarOpacityFunction = 0; + this->OpacityTableSize = 1024; + + this->ScaleFactor = 1.0; this->Emissive = 1; } @@ -30,6 +43,10 @@ vtkPointGaussianMapper::vtkPointGaussianMapper() vtkPointGaussianMapper::~vtkPointGaussianMapper() { this->SetScaleArray(0); + this->SetOpacityArray(0); + this->SetSplatShaderCode(0); + this->SetScalarOpacityFunction(0); + this->SetScaleFunction(0); } //----------------------------------------------------------------------------- @@ -38,6 +55,10 @@ void vtkPointGaussianMapper::PrintSelf(ostream& os, vtkIndent indent) this->Superclass::PrintSelf(os, indent); os << indent << "Scale Array: " << (this->ScaleArray ? this->ScaleArray : "(none)") << "\n"; - os << indent << "Default Radius: " << this->DefaultRadius << "\n"; + os << indent << "Opacity Array: " << (this->OpacityArray ? this->OpacityArray : "(none)") << "\n"; + os << indent << "SplatShaderCode: " << (this->SplatShaderCode ? this->SplatShaderCode : "(none)") << "\n"; + os << indent << "ScaleFactor: " << this->ScaleFactor << "\n"; os << indent << "Emissive: " << this->Emissive << "\n"; + os << indent << "OpacityTableSize: " << this->OpacityTableSize << "\n"; + os << indent << "ScaleTableSize: " << this->ScaleTableSize << "\n"; } diff --git a/Rendering/Core/vtkPointGaussianMapper.h b/Rendering/Core/vtkPointGaussianMapper.h index 1a7aa02c2c3e1af80d31c24d70b1ac9a6390ac24..079eb18ed0f160ba4bdedfc497a4ec17cebff44a 100644 --- a/Rendering/Core/vtkPointGaussianMapper.h +++ b/Rendering/Core/vtkPointGaussianMapper.h @@ -23,6 +23,8 @@ #include "vtkRenderingCoreModule.h" // For export macro #include "vtkPolyDataMapper.h" +class vtkPiecewiseFunction; + class VTKRENDERINGCORE_EXPORT vtkPointGaussianMapper : public vtkPolyDataMapper { public: @@ -30,18 +32,32 @@ public: vtkTypeMacro(vtkPointGaussianMapper, vtkPolyDataMapper) void PrintSelf(ostream& os, vtkIndent indent); + // Description: + // Set/Get the optional scale transfer function. This is only + // used when a ScaleArray is also specified. + void SetScaleFunction(vtkPiecewiseFunction *); + vtkGetObjectMacro(ScaleFunction,vtkPiecewiseFunction); + + // Description: + // The size of the table used in computing scale, used when + // converting a vtkPiecewiseFunction to a table + vtkSetMacro(ScaleTableSize, int); + vtkGetMacro(ScaleTableSize, int); + // Description: // Convenience method to set the array to scale with. vtkSetStringMacro(ScaleArray); vtkGetStringMacro(ScaleArray); // Description: - // Set the default radius of the point gaussians. This is used if the - // array to scale with has not been set or is set to NULL. If there - // is no scale array and the default radius is set to zero then - // the splats wil be rendered as simple points requiring less memory. - vtkSetMacro(DefaultRadius,double); - vtkGetMacro(DefaultRadius,double); + // Set the default scale factor of the point gaussians. This + // defaults to 1.0. All radius computations will be scaled by the factor + // including the ScaleArray. If a vtkPiecewideFunction is used the + // scaling happens prior to the function lookup. + // A scale factor of 0.0 indicates that the splats should be rendered + // as simple points. + vtkSetMacro(ScaleFactor,double); + vtkGetMacro(ScaleFactor,double); // Description: // Treat the points/splats as emissive light sources. The default is true. @@ -49,12 +65,50 @@ 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: + // The size of the table used in computing opacities, used when + // converting a vtkPiecewiseFunction to a table + vtkSetMacro(OpacityTableSize, int); + vtkGetMacro(OpacityTableSize, int); + + // 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; - double DefaultRadius; + char *OpacityArray; + char *SplatShaderCode; + + vtkPiecewiseFunction *ScaleFunction; + int ScaleTableSize; + + vtkPiecewiseFunction *ScalarOpacityFunction; + int OpacityTableSize; + + double ScaleFactor; int Emissive; private: diff --git a/Rendering/OpenGL2/Testing/Cxx/CMakeLists.txt b/Rendering/OpenGL2/Testing/Cxx/CMakeLists.txt index 407b121b84f2fc26ab320171c606726e3a4a9b6b..5a0841e1aa09be68bdc276314a03b25d763f84aa 100644 --- a/Rendering/OpenGL2/Testing/Cxx/CMakeLists.txt +++ b/Rendering/OpenGL2/Testing/Cxx/CMakeLists.txt @@ -1,6 +1,7 @@ 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 diff --git a/Rendering/OpenGL2/Testing/Cxx/TestPointGaussianMapper.cxx b/Rendering/OpenGL2/Testing/Cxx/TestPointGaussianMapper.cxx index b30dbafccf547df81f20b95c8d69b2efe3ff362f..b84ee9099c19bf56284e9caf506027f9f4e398c5 100644 --- a/Rendering/OpenGL2/Testing/Cxx/TestPointGaussianMapper.cxx +++ b/Rendering/OpenGL2/Testing/Cxx/TestPointGaussianMapper.cxx @@ -16,7 +16,8 @@ // .SECTION Thanks // // -// This file is part of the PointSprites plugin developed and contributed by +// This file is based loosely on the PointSprites plugin developed +// and contributed by // // Copyright (c) CSCS - Swiss National Supercomputing Centre // EDF - Electricite de France @@ -25,8 +26,6 @@ // Stephane Ploix (EDF) // // -// .SECTION Description -// this program tests the point sprite support by vtkPointSpriteProperty. #include "vtkActor.h" diff --git a/Rendering/OpenGL2/Testing/Cxx/TestPointGaussianMapperOpacity.cxx b/Rendering/OpenGL2/Testing/Cxx/TestPointGaussianMapperOpacity.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b8afe014a84eda2ac1d8904cf1a6fc4eeb11e27c --- /dev/null +++ b/Rendering/OpenGL2/Testing/Cxx/TestPointGaussianMapperOpacity.cxx @@ -0,0 +1,163 @@ +/*========================================================================= + + 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 +// +// +// This file is based loosely on 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) +// +// + +#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 points; + points->SetNumberOfPoints(desiredPoints); + points->SetRadius(pow(desiredPoints,0.33)*10.0); + points->Update(); + + vtkNew randomAttr; + randomAttr->SetInputConnection(points->GetOutputPort()); + + vtkNew mapper; + + vtkNew renderer; + renderer->SetBackground(0.0, 0.0, 0.0); + vtkNew renderWindow; + renderWindow->SetSize(300, 300); + renderWindow->SetMultiSamples(0); + renderWindow->AddRenderer(renderer.Get()); + vtkNew iren; + iren->SetRenderWindow(renderWindow.Get()); + + vtkNew 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 + // the fragment that is rendered is that of a triangle + // large enough to encompass a circle of radius 3 + 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 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 otf; + otf->AddPoint(0.0,0.3); + otf->AddPoint(1.0,1.0); + mapper->SetScalarOpacityFunction(otf.Get()); + + vtkNew 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; +} diff --git a/Rendering/OpenGL2/Testing/Data/Baseline/TestPointGaussianMapperOpacity.png.md5 b/Rendering/OpenGL2/Testing/Data/Baseline/TestPointGaussianMapperOpacity.png.md5 new file mode 100644 index 0000000000000000000000000000000000000000..2d04e419e31f8326db76c2710625090fb6a23fea --- /dev/null +++ b/Rendering/OpenGL2/Testing/Data/Baseline/TestPointGaussianMapperOpacity.png.md5 @@ -0,0 +1 @@ +b666713a87d680a410bdc29aea9f5174 diff --git a/Rendering/OpenGL2/vtkOpenGLPointGaussianMapper.cxx b/Rendering/OpenGL2/vtkOpenGLPointGaussianMapper.cxx index 06964bd3fdc50446bd8760f5fc48d7885e690489..fa2944f31a63a3c5e0baed7d4ef8427840b9a7e6 100644 --- a/Rendering/OpenGL2/vtkOpenGLPointGaussianMapper.cxx +++ b/Rendering/OpenGL2/vtkOpenGLPointGaussianMapper.cxx @@ -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" @@ -46,6 +48,15 @@ public: vtkPointGaussianMapper *Owner; + bool UsingPoints; + float *OpacityTable; // the table + float OpacityScale; // used for quick lookups + float OpacityOffset; // used for quick lookups + + float *ScaleTable; // the table + float ScaleScale; // used for quick lookups + float ScaleOffset; // used for quick lookups + protected: vtkOpenGLPointGaussianMapperHelper(); ~vtkOpenGLPointGaussianMapperHelper(); @@ -83,13 +94,17 @@ protected: virtual void RenderPieceDraw(vtkRenderer *ren, vtkActor *act); + // create the table for opacity values + void BuildOpacityTable(vtkPolyData *); + + // create the table for scale values + void BuildScaleTable(vtkPolyData *); + // Description: // Does the shader source need to be recomputed virtual bool GetNeedToRebuildShaders(vtkOpenGLHelper &cellBO, vtkRenderer *ren, vtkActor *act); - bool UsingPoints; - private: vtkOpenGLPointGaussianMapperHelper(const vtkOpenGLPointGaussianMapperHelper&); // Not implemented. void operator=(const vtkOpenGLPointGaussianMapperHelper&); // Not implemented. @@ -102,6 +117,8 @@ vtkStandardNewMacro(vtkOpenGLPointGaussianMapperHelper) vtkOpenGLPointGaussianMapperHelper::vtkOpenGLPointGaussianMapperHelper() { this->Owner = NULL; + this->OpacityTable = 0; + this->ScaleTable = 0; } @@ -112,10 +129,7 @@ void vtkOpenGLPointGaussianMapperHelper::GetShaderTemplate( { this->Superclass::GetShaderTemplate(shaders,ren,actor); - vtkPolyData *poly = this->CurrentInput; - bool hasScaleArray = this->Owner->GetScaleArray() != NULL && - poly->GetPointData()->HasArray(this->Owner->GetScaleArray()); - if (!hasScaleArray && this->Owner->GetDefaultRadius() == 0.0) + if (this->Owner->GetScaleFactor() == 0.0) { this->UsingPoints = true; } @@ -159,20 +173,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 +235,16 @@ bool vtkOpenGLPointGaussianMapperHelper::GetNeedToRebuildShaders( //----------------------------------------------------------------------------- vtkOpenGLPointGaussianMapperHelper::~vtkOpenGLPointGaussianMapperHelper() { + if (this->OpacityTable) + { + delete [] this->OpacityTable; + this->OpacityTable = 0; + } + if (this->ScaleTable) + { + delete [] this->ScaleTable; + this->ScaleTable = 0; + } } //----------------------------------------------------------------------------- @@ -282,69 +311,135 @@ 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( +void vtkOpenGLPointGaussianMapperHelperPackVBOTemplate3( std::vector< float >::iterator& it, - PointDataType* points, vtkIdType numPts, + PointDataType* points, + SizeDataType* sizes, + vtkIdType index, + vtkOpenGLPointGaussianMapperHelper *self, unsigned char *colors, int colorComponents, - SizeDataType* sizes, float defaultSize) + vtkDataArray *opacities, float defaultScale) { PointDataType *pointPtr; unsigned char *colorPtr; + unsigned char white[4] = {255, 255, 255, 255}; + vtkucfloat rcolor; + // 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}; + pointPtr = points + index*3; + colorPtr = colors ? (colors + index*colorComponents) : white; + rcolor.c[0] = *(colorPtr++); + rcolor.c[1] = *(colorPtr++); + rcolor.c[2] = *(colorPtr++); - for (vtkIdType i = 0; i < numPts; ++i) + if (opacities) + { + float opacity = opacities->GetComponent(index,0); + if (self->OpacityTable) { - pointPtr = points + i*3; - colorPtr = colors ? (colors + i*colorComponents) : white; - - // Vertices - *(it++) = pointPtr[0]; - *(it++) = pointPtr[1]; - *(it++) = pointPtr[2]; - *(it++) = *reinterpret_cast(colorPtr); + float tindex = (opacity - self->OpacityOffset)*self->OpacityScale; + int itindex = static_cast(tindex); + opacity = (1.0 - tindex + itindex)*self->OpacityTable[itindex] + + (tindex - itindex)*self->OpacityTable[itindex+1]; } + rcolor.c[3] = opacity*255.0; + } + else + { + rcolor.c[3] = (colorComponents == 4 ? *colorPtr : 255); + } + + if (self->UsingPoints) + { + // 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}; + float radius = sizes ? sizes[index] : 1.0; + radius *= defaultScale; + if (self->ScaleTable) + { + float tindex = (radius - self->ScaleOffset)*self->ScaleScale; + int itindex = static_cast(tindex); + radius = (1.0 - tindex + itindex)*self->ScaleTable[itindex] + + (tindex - itindex)*self->ScaleTable[itindex+1]; + } + + 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; + } +} +// 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, + vtkOpenGLPointGaussianMapperHelper *self, + vtkCellArray *verts, + unsigned char *colors, int colorComponents, + SizeDataType* sizes, vtkDataArray *opacities) +{ + float defaultSize = self->Owner->GetScaleFactor(); + + // iterate over cells or not + if (verts->GetNumberOfCells()) + { + vtkIdType* indices(NULL); + vtkIdType npts(0); + for (verts->InitTraversal(); verts->GetNextCell(npts, indices); ) + { + for (int i = 0; i < npts; ++i) + { + vtkOpenGLPointGaussianMapperHelperPackVBOTemplate3( + it, points, sizes, indices[i], self, + colors, colorComponents, opacities, defaultSize); + } + } + } + else + { for (vtkIdType i = 0; i < numPts; ++i) { - 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(colorPtr); - *(it++) = -2.0f*radius*cos30; - *(it++) = -radius; - - *(it++) = pointPtr[0]; - *(it++) = pointPtr[1]; - *(it++) = pointPtr[2]; - *(it++) = *reinterpret_cast(colorPtr); - *(it++) = 2.0f*radius*cos30; - *(it++) = -radius; - - *(it++) = pointPtr[0]; - *(it++) = pointPtr[1]; - *(it++) = pointPtr[2]; - *(it++) = *reinterpret_cast(colorPtr); - *(it++) = 0.0f; - *(it++) = 2.0f*radius; + vtkOpenGLPointGaussianMapperHelperPackVBOTemplate3( + it, points, sizes, i, self, + colors, colorComponents, opacities, defaultSize); } } } @@ -353,88 +448,35 @@ template< typename PointDataType > void vtkOpenGLPointGaussianMapperHelperPackVBOTemplate( std::vector< float >::iterator& it, PointDataType* points, vtkIdType numPts, + vtkOpenGLPointGaussianMapperHelper *self, + vtkCellArray *verts, unsigned char *colors, int colorComponents, - vtkDataArray* sizes, float defaultSize) + vtkDataArray* sizes, vtkDataArray *opacities) { if (sizes) { switch (sizes->GetDataType()) { - vtkTemplateMacro( + vtkTemplateMacro( vtkOpenGLPointGaussianMapperHelperPackVBOTemplate2( - it, points, numPts, colors, colorComponents, - static_cast(sizes->GetVoidPointer(0)), - defaultSize) + it, points, numPts, + self, verts, + colors, colorComponents, + static_cast(sizes->GetVoidPointer(0)), opacities) ); } } else { vtkOpenGLPointGaussianMapperHelperPackVBOTemplate2( - it, points, numPts, colors, colorComponents, - static_cast(NULL), defaultSize); + it, points, numPts, + self, verts, + colors, colorComponents, + static_cast(NULL), opacities); } } -void vtkOpenGLPointGaussianMapperHelperCreateVBO( - vtkPoints* points, unsigned char* colors, int colorComponents, - vtkDataArray* sizes, float defaultSize, - vtkOpenGLVertexBufferObject *VBO, - bool usingPoints) -{ - // Figure out how big each block will be, currently 6 floats. - int blockSize = 3; // x y z - VBO->VertexOffset = 0; - VBO->NormalOffset = 0; - VBO->TCoordOffset = 0; - VBO->TCoordComponents = 0; - VBO->ColorComponents = colorComponents; - VBO->ColorOffset = sizeof(float) * blockSize; - ++blockSize; // color - - if (usingPoints) - { - VBO->Stride = sizeof(float) * blockSize; - - // Create a buffer, and copy the data over. - VBO->PackedVBO.resize(blockSize * points->GetNumberOfPoints()); - std::vector::iterator it = VBO->PackedVBO.begin(); - - switch(points->GetDataType()) - { - vtkTemplateMacro( - vtkOpenGLPointGaussianMapperHelperPackVBOTemplate( - it, static_cast(points->GetVoidPointer(0)), - points->GetNumberOfPoints(),colors,colorComponents, - sizes,defaultSize)); - } - VBO->Upload(VBO->PackedVBO, vtkOpenGLBufferObject::ArrayBuffer); - VBO->VertexCount = points->GetNumberOfPoints(); - } - else - { - // two more floats - blockSize += 2; // offset - VBO->Stride = sizeof(float) * blockSize; - - // Create a buffer, and copy the data over. - VBO->PackedVBO.resize(blockSize * points->GetNumberOfPoints() * 3); - std::vector::iterator it = VBO->PackedVBO.begin(); - - switch(points->GetDataType()) - { - vtkTemplateMacro( - vtkOpenGLPointGaussianMapperHelperPackVBOTemplate( - it, static_cast(points->GetVoidPointer(0)), - points->GetNumberOfPoints(),colors,colorComponents, - sizes,defaultSize)); - } - VBO->Upload(VBO->PackedVBO, vtkOpenGLBufferObject::ArrayBuffer); - VBO->VertexCount = points->GetNumberOfPoints() * 3; - } - return; -} -} +} // anonymous namespace //------------------------------------------------------------------------- bool vtkOpenGLPointGaussianMapperHelper::GetNeedToRebuildBufferObjects( @@ -445,27 +487,102 @@ bool vtkOpenGLPointGaussianMapperHelper::GetNeedToRebuildBufferObjects( if (this->VBOBuildTime < this->GetMTime() || this->VBOBuildTime < act->GetMTime() || this->VBOBuildTime < this->CurrentInput->GetMTime() || - this->VBOBuildTime < this->Owner->GetMTime()) + this->VBOBuildTime < this->Owner->GetMTime() || + (this->Owner->GetScalarOpacityFunction() && + this->VBOBuildTime < this->Owner->GetScalarOpacityFunction()->GetMTime()) || + (this->Owner->GetScaleFunction() && + this->VBOBuildTime < this->Owner->GetScaleFunction()->GetMTime()) + ) { return true; } return false; } +//------------------------------------------------------------------------- +void vtkOpenGLPointGaussianMapperHelper::BuildOpacityTable(vtkPolyData *poly) +{ + vtkDataArray *oda = + poly->GetPointData()->GetArray(this->Owner->GetOpacityArray()); + double range[2]; + oda->GetRange(range,0); + + // if a piecewise function was provided, use it to map the opacities + vtkPiecewiseFunction *pwf = this->Owner->GetScalarOpacityFunction(); + int tableSize = this->Owner->GetOpacityTableSize(); + + if (this->OpacityTable) + { + delete [] this->OpacityTable; + } + this->OpacityTable = new float [tableSize+1]; + if (pwf) + { + // build the interpolation table + pwf->GetTable(range[0],range[1],tableSize,this->OpacityTable); + // duplicate the last value for bilinear interp edge case + this->OpacityTable[tableSize] = this->OpacityTable[tableSize-1]; + this->OpacityScale = (tableSize - 1.0)/(range[1] - range[0]); + this->OpacityOffset = range[0]; + } + +} + +//------------------------------------------------------------------------- +void vtkOpenGLPointGaussianMapperHelper::BuildScaleTable(vtkPolyData *poly) +{ + vtkDataArray *oda = + poly->GetPointData()->GetArray(this->Owner->GetScaleArray()); + double range[2]; + oda->GetRange(range,0); + + // if a piecewise function was provided, use it to map the opacities + vtkPiecewiseFunction *pwf = this->Owner->GetScaleFunction(); + int tableSize = this->Owner->GetScaleTableSize(); + + if (this->ScaleTable) + { + delete [] this->ScaleTable; + } + this->ScaleTable = new float [tableSize+1]; + if (pwf) + { + // build the interpolation table + pwf->GetTable(range[0],range[1],tableSize,this->ScaleTable); + // duplicate the last value for bilinear interp edge case + this->ScaleTable[tableSize] = this->ScaleTable[tableSize-1]; + this->ScaleScale = (tableSize - 1.0)/(range[1] - range[0]); + this->ScaleOffset = range[0]; + } +} + //------------------------------------------------------------------------- void vtkOpenGLPointGaussianMapperHelper::BuildBufferObjects( vtkRenderer *vtkNotUsed(ren), vtkActor *vtkNotUsed(act)) { vtkPolyData *poly = this->CurrentInput; - if (poly == NULL)// || !poly->GetPointData()->GetNormals()) + if (poly == NULL) { return; } bool hasScaleArray = this->Owner->GetScaleArray() != NULL && - poly->GetPointData()->HasArray(this->Owner->GetScaleArray()); - if (!hasScaleArray && this->Owner->GetDefaultRadius() == 0.0) + poly->GetPointData()->HasArray(this->Owner->GetScaleArray()); + if (hasScaleArray && this->Owner->GetScaleFunction()) + { + this->BuildScaleTable(poly); + } + else + { + if (this->ScaleTable) + { + delete [] this->ScaleTable; + this->ScaleTable = 0; + } + } + + if (this->Owner->GetScaleFactor() == 0.0) { this->UsingPoints = true; } @@ -474,6 +591,23 @@ void vtkOpenGLPointGaussianMapperHelper::BuildBufferObjects( this->UsingPoints = false; } + // if we have an opacity array then get it and if we have + // a ScalarOpacityFunction map the array through it + bool hasOpacityArray = this->Owner->GetOpacityArray() != NULL && + poly->GetPointData()->HasArray(this->Owner->GetOpacityArray()); + if (hasOpacityArray && this->Owner->GetScalarOpacityFunction()) + { + this->BuildOpacityTable(poly); + } + else + { + if (this->OpacityTable) + { + delete [] this->OpacityTable; + this->OpacityTable = 0; + } + } + // For vertex coloring, this sets this->Colors as side effect. // For texture map coloring, this sets ColorCoordinates // and ColorTextureMap as a side effect. @@ -482,16 +616,54 @@ void vtkOpenGLPointGaussianMapperHelper::BuildBufferObjects( // then the scalars do not have to be regenerted. this->MapScalars(1.0); - // Iterate through all of the different types in the polydata, building OpenGLs - // and IBOs as appropriate for each type. - vtkOpenGLPointGaussianMapperHelperCreateVBO( - poly->GetPoints(), - this->Colors ? (unsigned char *)this->Colors->GetVoidPointer(0) : (unsigned char*)NULL, - this->Colors ? this->Colors->GetNumberOfComponents() : 0, - hasScaleArray ? poly->GetPointData()->GetArray( - this->Owner->GetScaleArray()) : (vtkDataArray*)NULL, - this->Owner->GetDefaultRadius(), - this->VBO, this->UsingPoints); + // Figure out how big each block will be, currently 6 floats. + int blockSize = 3; // x y z + this->VBO->VertexOffset = 0; + this->VBO->NormalOffset = 0; + this->VBO->TCoordOffset = 0; + this->VBO->TCoordComponents = 0; + this->VBO->ColorComponents = 4; + this->VBO->ColorOffset = sizeof(float) * blockSize; + ++blockSize; // color + + int splatCount = poly->GetPoints()->GetNumberOfPoints(); + if (poly->GetVerts()->GetNumberOfCells()) + { + splatCount = poly->GetVerts()->GetNumberOfConnectivityEntries() - + poly->GetVerts()->GetNumberOfCells(); + } + if (!this->UsingPoints) + { + // two more floats + blockSize += 2; // offset + splatCount *= 3; + } + + this->VBO->PackedVBO.resize(blockSize * splatCount); + this->VBO->Stride = sizeof(float) * blockSize; + + // Create a buffer, and copy the data over. + std::vector::iterator it = this->VBO->PackedVBO.begin(); + + switch(poly->GetPoints()->GetDataType()) + { + vtkTemplateMacro( + vtkOpenGLPointGaussianMapperHelperPackVBOTemplate( + it, static_cast(poly->GetPoints()->GetVoidPointer(0)), + poly->GetPoints()->GetNumberOfPoints(), + this, + poly->GetVerts(), + this->Colors ? (unsigned char *)this->Colors->GetVoidPointer(0) : (unsigned char*)NULL, + this->Colors ? this->Colors->GetNumberOfComponents() : 0, + hasScaleArray ? poly->GetPointData()->GetArray( + this->Owner->GetScaleArray()) : (vtkDataArray*)NULL, + hasOpacityArray ? poly->GetPointData()->GetArray( + this->Owner->GetOpacityArray()) : (vtkDataArray*)NULL + )); + } + this->VBO->Upload(this->VBO->PackedVBO, vtkOpenGLBufferObject::ArrayBuffer); + + this->VBO->VertexCount = splatCount; // we use no IBO this->Points.IBO->IndexCount = 0;