From 582ada6077ff23df586032055fd6f6005d621437 Mon Sep 17 00:00:00 2001 From: Alvaro Sanchez <alvaro.sanchez@kitware.com> Date: Wed, 14 Sep 2016 16:59:28 -0400 Subject: [PATCH] vtkValuePass::FLOATING_POINT supports cell data. Added support for cell data arrays (Dave DeMarle). --- .../Cxx/TestValuePassFloatingPoint.cxx | 206 ++++++++------- .../TestValuePassFloatingPoint.png.md5 | 2 +- Rendering/Core/module.cmake | 1 - Rendering/OpenGL2/vtkOpenGLPolyDataMapper.cxx | 56 ++-- Rendering/OpenGL2/vtkValuePass.cxx | 19 +- Rendering/OpenGL2/vtkValuePass.h | 1 + Rendering/OpenGL2/vtkValuePassHelper.cxx | 239 ++++++++++++++---- Rendering/OpenGL2/vtkValuePassHelper.h | 33 ++- 8 files changed, 359 insertions(+), 198 deletions(-) diff --git a/Rendering/Core/Testing/Cxx/TestValuePassFloatingPoint.cxx b/Rendering/Core/Testing/Cxx/TestValuePassFloatingPoint.cxx index aada45a3b92..1f343530c47 100644 --- a/Rendering/Core/Testing/Cxx/TestValuePassFloatingPoint.cxx +++ b/Rendering/Core/Testing/Cxx/TestValuePassFloatingPoint.cxx @@ -15,59 +15,53 @@ // Description: // Tests vtkValuePass in FLOATING_POINT mode. The test generates a 3-component -// float array ("elevationVector") using the loaded polygonal data. Polygons -// are rendered with the ValuePass to its internal floating point frame-buffer. +// float array ("elevationVector") using the loaded polygonal data (points and cells). +// Polygons are rendered with the ValuePass to its internal floating point frame-buffer. // The rendered float image is then queried from the vtkValuePass and used to // generate a color image using vtkLookupTable, the color image is rendered with // an image actor on-screen. This is repeated for each component. -#include "vtkRegressionTestImage.h" -#include "vtkTestUtilities.h" #include "vtkActor.h" +#include "vtkArrayCalculator.h" +#include "vtkCamera.h" #include "vtkCameraPass.h" -#include "vtkCellArray.h" +#include "vtkCellData.h" #include "vtkElevationFilter.h" -#include "vtkInformation.h" +#include "vtkFloatArray.h" +#include "vtkImageActor.h" +#include "vtkImageData.h" +#include "vtkImageMapper3D.h" +#include "vtkInteractorStyleTrackballCamera.h" +#include "vtkLookupTable.h" #include "vtkOpenGLRenderer.h" -#include "vtkPLYReader.h" #include "vtkPointData.h" #include "vtkPointDataToCellData.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper.h" -#include "vtkOpenGLPolyDataMapper.h" +#include "vtkRegressionTestImage.h" #include "vtkRenderPassCollection.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkSequencePass.h" #include "vtkSmartPointer.h" +#include "vtkSphereSource.h" +#include "vtkTestUtilities.h" #include "vtkValuePass.h" -#include "vtkCamera.h" -#include "vtkInteractorStyleTrackballCamera.h" -#include "vtkAbstractMapper.h" -#include "vtkXMLPolyDataReader.h" -#include "vtkFloatArray.h" -#include "vtkLookupTable.h" -#include "vtkColorSeries.h" -#include "vtkImageData.h" -#include "vtkImageActor.h" -#include "vtkImageMapper3D.h" -#include "vtkArrayCalculator.h" - -void GenerateElevationArray(vtkSmartPointer<vtkPLYReader> reader) +void GenerateElevationArray(vtkSmartPointer<vtkPolyDataAlgorithm> source) { - vtkPolyData* data = reader->GetOutput(); + vtkPolyData* data = source->GetOutput(); double* bounds = data->GetBounds(); vtkSmartPointer<vtkElevationFilter> elevation = vtkSmartPointer<vtkElevationFilter>::New(); - elevation->SetInputConnection(reader->GetOutputPort()); + elevation->SetInputConnection(source->GetOutputPort()); - /// Use vtkElevation to generate an array per component. vtkElevation generates - /// a projected distance from each point in the dataset to the line, with respect to - /// the LowPoint ([0, 1] in this case. This is different from having the actual - /// coordinates of a given point. + // Use vtkElevation to generate an array per component. vtkElevation generates + // a projected distance from each point in the dataset to the line, with respect to + // the LowPoint ([0, 1] in this case. This is different from having the actual + // coordinates of a given point. for (int c = 0; c < 3; c++) { std::string name; @@ -93,7 +87,7 @@ void GenerateElevationArray(vtkSmartPointer<vtkPLYReader> reader) vtkPolyData* result = vtkPolyData::SafeDownCast(elevation->GetOutput()); int outCellFlag; - /// Enums defined in vtkAbstractMapper + // Enums defined in vtkAbstractMapper vtkDataArray* elevArray = vtkAbstractMapper::GetScalars(result, VTK_SCALAR_MODE_USE_POINT_FIELD_DATA, VTK_GET_ARRAY_BY_NAME/*acc mode*/, 0/*arr id*/, "Elevation"/*arr name*/, outCellFlag); @@ -107,10 +101,13 @@ void GenerateElevationArray(vtkSmartPointer<vtkPLYReader> reader) data->GetPointData()->AddArray(elevArray); } - /// Generate a 3-component vector array using the single components - /// form elevation. - vtkSmartPointer<vtkArrayCalculator> calc = vtkSmartPointer<vtkArrayCalculator>::New(); - calc->SetInputConnection(reader->GetOutputPort()); + // Generate a 3-component vector array using the single components + // form elevation + + // Point data + vtkSmartPointer<vtkArrayCalculator> calc = + vtkSmartPointer<vtkArrayCalculator>::New(); + calc->SetInputConnection(source->GetOutputPort()); calc->SetAttributeModeToUsePointData(); calc->AddScalarArrayName("delta_x"); calc->AddScalarArrayName("delta_y"); @@ -119,39 +116,68 @@ void GenerateElevationArray(vtkSmartPointer<vtkPLYReader> reader) calc->SetResultArrayName("elevationVector"); calc->Update(); - vtkPolyData* result = vtkPolyData::SafeDownCast(calc->GetOutput()); - int outCellFlag; - vtkDataArray* coordArray = vtkAbstractMapper::GetScalars(result, - VTK_SCALAR_MODE_USE_POINT_FIELD_DATA, VTK_GET_ARRAY_BY_NAME/*acc mode*/, - 0/*arr id*/, "elevationVector", outCellFlag); - if (!coordArray) + // Cell data + vtkSmartPointer<vtkPointDataToCellData> p2c = + vtkSmartPointer<vtkPointDataToCellData>::New(); + p2c->SetInputConnection(calc->GetOutputPort()); + p2c->PassPointDataOn(); + p2c->Update(); + + /// Include the elevation vector (point and cell data) in the original data + vtkPolyData* outputP2c = vtkPolyData::SafeDownCast(p2c->GetOutput()); + data->GetPointData()->AddArray(calc->GetOutput()->GetPointData()->GetArray( + "elevationVector")); + data->GetCellData()->AddArray(outputP2c->GetCellData()->GetArray("elevationVector")); +}; + +//------------------------------------------------------------------------------ +void RenderComponentImages(std::vector<vtkSmartPointer<vtkImageData> >& colorImOut, + vtkRenderWindow* window, vtkRenderer* renderer, + vtkValuePass* valuePass, int dataMode, char const* name) +{ + valuePass->SetInputArrayToProcess(dataMode, name); + + // Prepare a lut to map the floating point values + vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New(); + lut->SetAlpha(1.0); + lut->Build(); + + // Render each component in a separate image + for(int c = 0; c < 3; c++) { - std::cout << "->> Error: could not find array!" << std::endl; - return; - } + valuePass->SetInputComponentToProcess(c); + window->Render(); - /// Include the elevation vector in the original data - data->GetPointData()->AddArray(coordArray); -} + /// Get the resulting values + vtkFloatArray* result = valuePass->GetFloatImageDataArray(renderer); + std::vector<int> ext = valuePass->GetFloatImageExtents(); + // Map the resulting float image to a color table + vtkUnsignedCharArray* colored = lut->MapScalars(result, VTK_COLOR_MODE_DEFAULT, + 0/* single comp*/); + + // Create an image dataset to render in a quad. + vtkSmartPointer<vtkImageData> colorIm = vtkSmartPointer<vtkImageData>::New(); + colorIm->SetExtent(&(ext.front())); + colorIm->GetPointData()->SetScalars(colored); + colorImOut.push_back(colorIm); + } +}; /////////////////////////////////////////////////////////////////////////////// int TestValuePassFloatingPoint(int argc, char *argv[]) { // Load data - const char *fileName = - vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/dragon.ply"); - vtkSmartPointer<vtkPLYReader> reader = - vtkSmartPointer<vtkPLYReader>::New(); - reader->SetFileName(fileName); - reader->Update(); + vtkSmartPointer<vtkSphereSource> sphere = vtkSmartPointer<vtkSphereSource>::New(); + sphere->SetThetaResolution(8.0); + sphere->SetPhiResolution(8.0); + sphere->Update(); // Prepare a 3-component array (data will be appended to reader's output) - GenerateElevationArray(reader); - + GenerateElevationArray(sphere); vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); - mapper->SetInputConnection(reader->GetOutputPort()); + mapper->SetInputData(sphere->GetOutput()); mapper->ScalarVisibilityOn(); vtkSmartPointer<vtkActor> actor = @@ -168,7 +194,8 @@ int TestValuePassFloatingPoint(int argc, char *argv[]) vtkSmartPointer<vtkRenderWindow> window = vtkSmartPointer<vtkRenderWindow>::New(); - window->SetSize(320, 320); + window->SetMultiSamples(0); + window->SetSize(640, 640); vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New(); @@ -188,9 +215,11 @@ int TestValuePassFloatingPoint(int argc, char *argv[]) vtkSmartPointer<vtkValuePass>::New(); valuePass->SetRenderingMode(RenderingMode); valuePass->SetInputComponentToProcess(comp); - //valuePass->SetScalarRange(bounds[0], bounds[1]); /*using the full range*/ + // Initial data mode valuePass->SetInputArrayToProcess(VTK_SCALAR_MODE_USE_POINT_FIELD_DATA, "elevationVector"); + //valuePass->SetInputArrayToProcess(VTK_SCALAR_MODE_USE_CELL_FIELD_DATA, + // "elevationVector"); // 3. Add it to a sequence of passes vtkSmartPointer<vtkRenderPassCollection> passes = @@ -214,54 +243,53 @@ int TestValuePassFloatingPoint(int argc, char *argv[]) if (RenderingMode == vtkValuePass::FLOATING_POINT) { - // Prepare a lut to map the floating point values - vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New(); - lut->SetAlpha(1.0); - //lut->SetRange(elevRange[0], elevRange[1]); /*use the full range*/ - vtkSmartPointer<vtkColorSeries> series = vtkSmartPointer<vtkColorSeries>::New(); - series->SetColorScheme(vtkColorSeries::WARM); - //series->SetColorScheme(vtkColorSeries::BREWER_DIVERGING_SPECTRAL_11); - series->BuildLookupTable(lut, vtkColorSeries::ORDINAL); - - // Render each component in a separate image - std::vector<vtkSmartPointer<vtkImageData> > colorImages; - for(int c = 0; c < 3; c++) - { - valuePass->SetInputComponentToProcess(c); - window->Render(); - - /// Get the resulting values - vtkFloatArray* result = valuePass->GetFloatImageDataArray(renderer); - std::vector<int> ext = valuePass->GetFloatImageExtents(); - - // Map the resulting float image to a color table - vtkUnsignedCharArray* colored = lut->MapScalars(result, VTK_COLOR_MODE_DEFAULT, - 0/* single comp*/); - - // Create an image dataset to render in a quad. - vtkSmartPointer<vtkImageData> colorIm = vtkSmartPointer<vtkImageData>::New(); - colorIm->SetExtent(&(ext.front())); - colorIm->GetPointData()->SetScalars(colored); - colorImages.push_back(colorIm); - } + // Render point data images + std::vector<vtkSmartPointer<vtkImageData> > colorImagesPoint; + RenderComponentImages(colorImagesPoint, window, renderer, valuePass, + VTK_SCALAR_MODE_USE_POINT_FIELD_DATA, "elevationVector"); + + // Render cell data images + std::vector<vtkSmartPointer<vtkImageData> > colorImagesCell; + RenderComponentImages(colorImagesCell, window, renderer, valuePass, + VTK_SCALAR_MODE_USE_CELL_FIELD_DATA, "elevationVector"); - // Render the image on-screen + ////// Render results on-screen renderer->RemoveActor(actor); + // Add image actors to display the point dataArray's componets vtkSmartPointer<vtkImageActor> ia_x = vtkSmartPointer<vtkImageActor>::New(); - ia_x->GetMapper()->SetInputData(colorImages.at(0)); + ia_x->GetMapper()->SetInputData(colorImagesPoint.at(0)); renderer->AddActor(ia_x); vtkSmartPointer<vtkImageActor> ia_y = vtkSmartPointer<vtkImageActor>::New(); ia_y->RotateX(90); - ia_y->GetMapper()->SetInputData(colorImages.at(1)); + ia_y->GetMapper()->SetInputData(colorImagesPoint.at(1)); renderer->AddActor(ia_y); vtkSmartPointer<vtkImageActor> ia_z = vtkSmartPointer<vtkImageActor>::New(); ia_z->RotateY(-90); - ia_z->GetMapper()->SetInputData(colorImages.at(2)); + ia_z->GetMapper()->SetInputData(colorImagesPoint.at(2)); renderer->AddActor(ia_z); + // Add image actors to display cell dataArray's components + vtkSmartPointer<vtkImageActor> iacell_x = vtkSmartPointer<vtkImageActor>::New(); + iacell_x->SetPosition(-500, 600, 600); + iacell_x->GetMapper()->SetInputData(colorImagesCell.at(0)); + renderer->AddActor(iacell_x); + + vtkSmartPointer<vtkImageActor> iacell_y = vtkSmartPointer<vtkImageActor>::New(); + iacell_y->RotateX(90); + iacell_y->SetPosition(-500, 600, 600); + iacell_y->GetMapper()->SetInputData(colorImagesCell.at(1)); + renderer->AddActor(iacell_y); + + vtkSmartPointer<vtkImageActor> iacell_z = vtkSmartPointer<vtkImageActor>::New(); + iacell_z->RotateY(-90); + iacell_z->SetPosition(-500, 600, 600); + iacell_z->GetMapper()->SetInputData(colorImagesCell.at(2)); + renderer->AddActor(iacell_z); + + // Adjust viewpoint vtkCamera* cam = renderer->GetActiveCamera(); cam->SetPosition(2, 2, 2); cam->SetFocalPoint(0, 0, 1); diff --git a/Rendering/Core/Testing/Data/Baseline/TestValuePassFloatingPoint.png.md5 b/Rendering/Core/Testing/Data/Baseline/TestValuePassFloatingPoint.png.md5 index 0ccfda72e3a..7944dcc580b 100644 --- a/Rendering/Core/Testing/Data/Baseline/TestValuePassFloatingPoint.png.md5 +++ b/Rendering/Core/Testing/Data/Baseline/TestValuePassFloatingPoint.png.md5 @@ -1 +1 @@ -c482c9a67076037525ea716826d91077 +98596e51d1cd4844e528adc75f96d193 diff --git a/Rendering/Core/module.cmake b/Rendering/Core/module.cmake index 17b369e7912..6355e02a994 100644 --- a/Rendering/Core/module.cmake +++ b/Rendering/Core/module.cmake @@ -6,7 +6,6 @@ vtk_module(vtkRenderingCore vtkIOLegacy vtkIOParallel vtkIOXML - vtkIOPLY vtkTestingCore vtkTestingRendering vtkRendering${VTK_RENDERING_BACKEND} diff --git a/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.cxx b/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.cxx index 6f4f62b1f11..c8128739dcb 100644 --- a/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.cxx +++ b/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.cxx @@ -211,6 +211,9 @@ void vtkOpenGLPolyDataMapper::ReleaseGraphicsResources(vtkWindow* win) { this->CellNormalBuffer->ReleaseGraphicsResources(); } + + this->ValuePassHelper->ReleaseGraphicsResources(win); + if (this->AppleBugPrimIDBuffer) { this->AppleBugPrimIDBuffer->ReleaseGraphicsResources(); @@ -1487,16 +1490,6 @@ void vtkOpenGLPolyDataMapper::ReplaceShaderValues( //cout << "VS: " << shaders[vtkShader::Vertex]->GetSource() << endl; //cout << "GS: " << shaders[vtkShader::Geometry]->GetSource() << endl; //cout << "FS: " << shaders[vtkShader::Fragment]->GetSource() << endl; - -// std::string vertexShader = shaders[vtkShader::Vertex]->GetSource(); -// std::string fragmentShader = shaders[vtkShader::Fragment]->GetSource(); -// std::ofstream file("/home/alvaro/testShaders/PolyData_valuePass.frag"); -// file << fragmentShader; -// file.close(); -// -// file.open("/home/alvaro/testShaders/PolyData_valuePass.vert"); -// file << vertexShader; -// file.close(); } //----------------------------------------------------------------------------- @@ -1582,7 +1575,8 @@ bool vtkOpenGLPolyDataMapper::GetNeedToRebuildShaders( cellBO.ShaderSourceTime < this->CurrentInput->GetMTime() || cellBO.ShaderSourceTime < this->SelectionStateChanged || cellBO.ShaderSourceTime < renderPassMTime || - cellBO.ShaderSourceTime < this->LightComplexityChanged[&cellBO]) + cellBO.ShaderSourceTime < this->LightComplexityChanged[&cellBO] || + this->ValuePassHelper->RequiresShaderRebuild(actor)) { return true; } @@ -1616,32 +1610,6 @@ void vtkOpenGLPolyDataMapper::UpdateShaders( this->BuildShaders(shaders, ren, actor); - -// vtkInformation *info = actor->GetPropertyKeys(); -// if (info && info->Has(vtkValuePass::RENDER_VALUES())) -// { -// // Load shaders -// //--------------- -// std::string path = "/home/alvaro/testShaders/"; -// std::string filename = "pv_values"; -// -// std::string vfilepath = path + filename + ".vert"; -// std::ifstream file(vfilepath.c_str()); -// std::string vert = std::string(std::istreambuf_iterator<char>(file), -// std::istreambuf_iterator<char>()); -// file.close(); -// -// std::string ffilepath = path + filename + ".frag"; -// file.open(ffilepath.c_str()); -// std::string frag = std::string(std::istreambuf_iterator<char>(file), -// std::istreambuf_iterator<char>()); -// file.close(); -// -// shaders[vtkShader::Vertex]->SetSource(vert); -// shaders[vtkShader::Fragment]->SetSource(frag); -// } - - // compile and bind the program if needed vtkShaderProgram *newShader = renWin->GetShaderCache()->ReadyShaderProgram(shaders); @@ -1742,7 +1710,7 @@ void vtkOpenGLPolyDataMapper::SetMapperShaderParameters(vtkOpenGLHelper &cellBO, if (this->ValuePassHelper->GetRenderingMode() == vtkValuePass::FLOATING_POINT) { - this->ValuePassHelper->BindValueBuffer(cellBO); + this->ValuePassHelper->BindAttributes(cellBO); } cellBO.AttributeUpdateTime.Modified(); @@ -1796,6 +1764,11 @@ void vtkOpenGLPolyDataMapper::SetMapperShaderParameters(vtkOpenGLHelper &cellBO, cellBO.Program->SetUniformi("textureN", tunit); } + if (this->ValuePassHelper->GetRenderingMode() == vtkValuePass::FLOATING_POINT) + { + this->ValuePassHelper->BindUniforms(cellBO); + } + // Handle render pass setup: vtkInformation *info = actor->GetPropertyKeys(); if (info && info->Has(vtkOpenGLRenderPass::RenderPasses())) @@ -2344,7 +2317,7 @@ void vtkOpenGLPolyDataMapper::RenderPieceStart(vtkRenderer* ren, vtkActor *actor if (this->ValuePassHelper->GetRenderingMode() == vtkValuePass::FLOATING_POINT) { - this->ValuePassHelper->UploadValueData(actor, this->CurrentInput); + this->ValuePassHelper->RenderPieceStart(actor, this->CurrentInput); } // If we are coloring by texture, then load the texture map. @@ -2578,6 +2551,11 @@ void vtkOpenGLPolyDataMapper::RenderPieceFinish(vtkRenderer* ren, this->CellNormalTexture->Deactivate(); } + if (this->ValuePassHelper->GetRenderingMode() == vtkValuePass::FLOATING_POINT) + { + this->ValuePassHelper->RenderPieceFinish(); + } + this->UpdateProgress(1.0); } diff --git a/Rendering/OpenGL2/vtkValuePass.cxx b/Rendering/OpenGL2/vtkValuePass.cxx index d33824a1c06..a4212fb24e3 100644 --- a/Rendering/OpenGL2/vtkValuePass.cxx +++ b/Rendering/OpenGL2/vtkValuePass.cxx @@ -44,6 +44,7 @@ vtkInformationKeyMacro(vtkValuePass, ARRAY_ID, Integer); vtkInformationKeyMacro(vtkValuePass, ARRAY_NAME, String); vtkInformationKeyMacro(vtkValuePass, ARRAY_COMPONENT, Integer); vtkInformationKeyMacro(vtkValuePass, SCALAR_RANGE, DoubleVector); +vtkInformationKeyMacro(vtkValuePass, RELOAD_DATA, Integer); class vtkValuePass::vtkInternals { @@ -55,6 +56,7 @@ public: int Component; double ScalarRange[2]; bool ScalarRangeSet; + bool ReloadData; // Array holder for FLOATING_POINT mode. The result pixels are downloaded // into this array. @@ -74,6 +76,7 @@ public: this->ScalarRange[0] = 0.0; this->ScalarRange[1] = -1.0; this->ScalarRangeSet = false; + this->ReloadData = true; } }; @@ -111,6 +114,7 @@ void vtkValuePass::SetInputArrayToProcess(int fieldAssociation, this->Internals->FieldAssociation = fieldAssociation; this->Internals->FieldName = name; this->Internals->FieldNameSet = true; + this->Internals->ReloadData = true; this->Modified(); } } @@ -126,6 +130,7 @@ void vtkValuePass::SetInputArrayToProcess(int fieldAssociation, this->Internals->FieldAssociation = fieldAssociation; this->Internals->FieldAttributeType = fieldAttributeType; this->Internals->FieldNameSet = false; + this->Internals->ReloadData = true; this->Modified(); } } @@ -136,6 +141,7 @@ void vtkValuePass::SetInputComponentToProcess(int component) if (this->Internals->Component != component) { this->Internals->Component = component; + this->Internals->ReloadData = true; this->Modified(); } } @@ -153,7 +159,6 @@ void vtkValuePass::SetScalarRange(double min, double max) } } - // ---------------------------------------------------------------------------- // Description: // Perform rendering according to a render state \p s. @@ -199,6 +204,7 @@ void vtkValuePass::RenderOpaqueGeometry(const vtkRenderState *s) { keys.TakeReference(vtkInformation::New()); } + keys->Set(vtkValuePass::RENDER_VALUES(), this->RenderingMode); keys->Set(vtkValuePass::SCALAR_MODE(), this->Internals->FieldAssociation); keys->Set(vtkValuePass::ARRAY_MODE(), this->Internals->FieldNameSet); @@ -206,6 +212,11 @@ void vtkValuePass::RenderOpaqueGeometry(const vtkRenderState *s) keys->Set(vtkValuePass::ARRAY_NAME(), this->Internals->FieldName.c_str()); keys->Set(vtkValuePass::ARRAY_COMPONENT(), this->Internals->Component); keys->Set(vtkValuePass::SCALAR_RANGE(), this->Internals->ScalarRange, 2); + if (this->Internals->ReloadData) + { + keys->Set(vtkValuePass::RELOAD_DATA(), 1); + } + p->SetPropertyKeys(keys); int rendered = @@ -235,6 +246,12 @@ void vtkValuePass::RenderOpaqueGeometry(const vtkRenderState *s) keys->Remove(vtkValuePass::ARRAY_NAME()); keys->Remove(vtkValuePass::ARRAY_COMPONENT()); keys->Remove(vtkValuePass::SCALAR_RANGE()); + if (this->Internals->ReloadData) + { + keys->Remove(vtkValuePass::RELOAD_DATA()); + this->Internals->ReloadData = false; + } + p->SetPropertyKeys(keys); ++i; } diff --git a/Rendering/OpenGL2/vtkValuePass.h b/Rendering/OpenGL2/vtkValuePass.h index c92df7e7a8f..94973a48ab2 100644 --- a/Rendering/OpenGL2/vtkValuePass.h +++ b/Rendering/OpenGL2/vtkValuePass.h @@ -65,6 +65,7 @@ public: static vtkInformationStringKey *ARRAY_NAME(); static vtkInformationIntegerKey *ARRAY_COMPONENT(); static vtkInformationDoubleVectorKey *SCALAR_RANGE(); + static vtkInformationIntegerKey *RELOAD_DATA(); // Description: // Perform rendering according to a render state \p s. diff --git a/Rendering/OpenGL2/vtkValuePassHelper.cxx b/Rendering/OpenGL2/vtkValuePassHelper.cxx index 23363e13199..8d88c81b838 100644 --- a/Rendering/OpenGL2/vtkValuePassHelper.cxx +++ b/Rendering/OpenGL2/vtkValuePassHelper.cxx @@ -1,16 +1,17 @@ -#include "vtkValuePassHelper.h" +#include "vtkDataArray.h" +#include "vtkInformation.h" +#include "vtkMapper.h" #include "vtkObjectFactory.h" -#include "vtkRenderer.h" -#include "vtkShaderProgram.h" -#include "vtkOpenGLError.h" -#include "vtkOpenGLRenderWindow.h" #include "vtkOpenGLBufferObject.h" +#include "vtkOpenGLError.h" #include "vtkOpenGLHelper.h" +#include "vtkOpenGLRenderWindow.h" #include "vtkOpenGLVertexArrayObject.h" +#include "vtkRenderer.h" +#include "vtkShaderProgram.h" +#include "vtkTextureObject.h" #include "vtkValuePass.h" -#include "vtkDataArray.h" -#include "vtkInformation.h" -#include "vtkMapper.h" +#include "vtkValuePassHelper.h" vtkStandardNewMacro(vtkValuePassHelper) @@ -19,31 +20,98 @@ vtkStandardNewMacro(vtkValuePassHelper) vtkValuePassHelper::vtkValuePassHelper() : ValueBuffer(NULL) , ValuePassArray(NULL) +, CellFloatTexture(NULL) +, CellFloatBuffer(NULL) , RenderingMode(-1) +, ResourcesAllocated(false) +, CurrentDataArrayMode(VTK_SCALAR_MODE_USE_POINT_FIELD_DATA) +, LastDataArrayMode(VTK_SCALAR_MODE_USE_POINT_FIELD_DATA) { } //----------------------------------------------------------------------------- vtkValuePassHelper::~vtkValuePassHelper() { + // Graphics resources released previously by the parent mapper or after switching + // to INVERTIBLE_LUT mode if (this->ValueBuffer) + { this->ValueBuffer->Delete(); + this->ValueBuffer = NULL; + } + + if (this->CellFloatTexture) + { + this->CellFloatTexture->Delete(); + this->CellFloatTexture = NULL; + } + + if (this->CellFloatBuffer) + { + this->CellFloatBuffer->Delete(); + this->CellFloatBuffer = NULL; + } +} + +//----------------------------------------------------------------------------- +void vtkValuePassHelper::ReleaseGraphicsResources(vtkWindow *win) +{ + if (this->CellFloatTexture) + { + this->CellFloatTexture->ReleaseGraphicsResources(win); + this->CellFloatTexture->Delete(); + this->CellFloatTexture = NULL; + } + + if (this->CellFloatBuffer) + { + this->CellFloatBuffer->ReleaseGraphicsResources(); + this->CellFloatBuffer->Delete(); + this->CellFloatBuffer = NULL; + } + + if (this->ValueBuffer) + { + this->ValueBuffer->ReleaseGraphicsResources(); + this->ValueBuffer->Delete(); + this->ValueBuffer = NULL; + } + + this->ValuePassArray = NULL; + this->ResourcesAllocated = false; +} + +//----------------------------------------------------------------------------- +void vtkValuePassHelper::RenderPieceFinish() +{ + if (this->CurrentDataArrayMode == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA) + { + if (this->CellFloatTexture) + { + this->CellFloatTexture->Deactivate(); + } + } } //----------------------------------------------------------------------------- -void vtkValuePassHelper::UploadValueData(vtkActor* actor, vtkDataSet* input) +void vtkValuePassHelper::RenderPieceStart(vtkActor* actor, vtkDataSet* input) { vtkInformation *info = actor->GetPropertyKeys(); - // TODO: Check the Array number / name instead. info does not seem to update - // the timestamp. - //if (info->GetMTime() < this->ValueBufferTime) + // TODO It should only be necessary to upload the data if something has changed. + // In the parallel case however (ParaView with IceT), the solution below causes + // data not to be uploaded at all (leading to empty images). Because of this, data + // is uploaded on every render pass. + // + //if (info && info->Has(vtkValuePass::RELOAD_DATA())) + if (info) { int cellFlag = 0; typedef vtkValuePass vp; this->ValuePassArray = vtkAbstractMapper::GetScalars(input, info->Get(vp::SCALAR_MODE()), info->Get(vp::ARRAY_MODE()), info->Get(vp::ARRAY_ID()), info->Get(vp::ARRAY_NAME()), cellFlag); + if (!this->ValuePassArray) { vtkErrorMacro("Invalid data array from GetScalars()!"); @@ -64,10 +132,27 @@ void vtkValuePassHelper::UploadValueData(vtkActor* actor, vtkDataSet* input) } // Upload array data - this->ValueBuffer->Upload(&(this->Buffer.front()), numTuples, - vtkOpenGLBufferObject::ArrayBuffer); + if (this->CurrentDataArrayMode == VTK_SCALAR_MODE_USE_POINT_FIELD_DATA) + { + // Point data + this->ValueBuffer->Upload(&(this->Buffer.front()), static_cast<size_t>(numTuples), + vtkOpenGLBufferObject::ArrayBuffer); + } + else + { + // Cell data + this->CellFloatBuffer->Upload(&(this->Buffer.front()), numTuples, + vtkOpenGLBufferObject::TextureBuffer); - //this->ValueBufferTime.Modified(); + this->CellFloatTexture->CreateTextureBuffer(static_cast<unsigned int>(numTuples), + 1, VTK_FLOAT, this->CellFloatBuffer); + } + } + + // Bind textures + if (this->CurrentDataArrayMode == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA) + { + this->CellFloatTexture->Activate(); } } @@ -85,10 +170,17 @@ void vtkValuePassHelper::UpdateConfiguration(vtkRenderer* ren, vtkActor* act, // Configure the mapper's behavior if the ValuePass is active. if (this->RenderingMode > 0) { + vtkInformation *info = act->GetPropertyKeys(); + if (info) + { + // Since it has RENDER_VALUES it is assumed it has all the tags from ValuePass + this->CurrentDataArrayMode = info->Get(vtkValuePass::SCALAR_MODE()); + } + switch (this->RenderingMode) { case vtkValuePass::FLOATING_POINT: - this->AllocateBuffer(ren); + this->AllocateGraphicsResources(ren); break; case vtkValuePass::INVERTIBLE_LUT: @@ -107,41 +199,32 @@ void vtkValuePassHelper::UpdateConfiguration(vtkRenderer* ren, vtkActor* act, } else { - this->ReleaseBuffer(ren); + this->ReleaseGraphicsResources(ren->GetRenderWindow()); mapper->ClearInvertibleColor(); } } //----------------------------------------------------------------------------- -void vtkValuePassHelper::AllocateBuffer(vtkRenderer* ren) +void vtkValuePassHelper::AllocateGraphicsResources(vtkRenderer* ren) { - if (this->ValueBuffer) + if (this->ResourcesAllocated) + { return; + } + // For point data this->ValueBuffer = vtkOpenGLBufferObject::New(); this->ValueBuffer->SetType(vtkOpenGLBufferObject::ArrayBuffer); -} - -//----------------------------------------------------------------------------- -void vtkValuePassHelper::ReleaseBuffer(vtkRenderer* ren) -{ - if (!this->ValueBuffer) - return; - vtkRenderWindow* renWin = ren->GetRenderWindow(); - vtkOpenGLRenderWindow* glWin = static_cast<vtkOpenGLRenderWindow*>(renWin); - glWin->MakeCurrent(); + // For cell data + this->CellFloatTexture = vtkTextureObject::New(); + this->CellFloatTexture->SetContext + (static_cast<vtkOpenGLRenderWindow*>(ren->GetVTKWindow())); - // Cleanup GL buffer - if (this->ValueBuffer) - { - this->ValueBuffer->ReleaseGraphicsResources(); - this->ValueBuffer->Delete(); - this->ValueBuffer = NULL; - vtkOpenGLCheckErrorMacro("Failed to release ValueBuffer resources."); - } + this->CellFloatBuffer = vtkOpenGLBufferObject::New(); + this->CellFloatBuffer->SetType(vtkOpenGLBufferObject::TextureBuffer); - this->ValuePassArray = NULL; + this->ResourcesAllocated = true; } //----------------------------------------------------------------------------- @@ -151,7 +234,9 @@ void vtkValuePassHelper::UpdateShaders(std::string & VSSource, std::string & FSS // Pass the value pass attribute to the fragment shader. vtkShaderProgram::Substitute(VSSource, "//VTK::ValuePass::Dec", "attribute float dataAttribute;\n" - "varying float dataValue;\n"); + "varying float dataValue;\n" + "uniform samplerBuffer textureF;\n" + ); vtkShaderProgram::Substitute(VSSource, "//VTK::ValuePass::Impl", " dataValue = dataAttribute;\n"); @@ -160,32 +245,76 @@ void vtkValuePassHelper::UpdateShaders(std::string & VSSource, std::string & FSS // other sections of the fragment shader, so they are included for it to build // correctly). vtkShaderProgram::Substitute(FSSource, "//VTK::ValuePass::Dec", - "varying float dataValue;\n"); + "varying float dataValue;\n" + "uniform samplerBuffer textureF;\n"); + + if (this->CurrentDataArrayMode == VTK_SCALAR_MODE_USE_POINT_FIELD_DATA) + { + required += std::string + ( + " vec4 texColor = vec4(vec3(dataValue), 1.0);\n" + " gl_FragData[0] = texColor;\n" + " // Return right away since vtkValuePass::FLOATING_POINT mode is enabled\n" + " return;" + ); + } + else + { + required += std::string + ( + " gl_FragData[0] = texelFetchBuffer(textureF, gl_PrimitiveID + PrimitiveIDOffset);\n" + + " // Return right away since vtkValuePass::FLOATING_POINT mode is enabled\n" + " return;" + ); + } - required += std::string( - " vec4 texColor = vec4(vec3(dataValue), 1.0);\n" - " gl_FragData[0] = texColor;\n" - " // Return right away since vtkValuePass::FLOATING_POINT mode is enabled\n" - " return;"); vtkShaderProgram::Substitute(FSSource, "//VTK::Color::Impl", required); } //----------------------------------------------------------------------------- -void vtkValuePassHelper::BindValueBuffer(vtkOpenGLHelper& cellBO) +void vtkValuePassHelper::BindAttributes(vtkOpenGLHelper& cellBO) { - if (this->ValuePassArray) + if (this->CurrentDataArrayMode == VTK_SCALAR_MODE_USE_POINT_FIELD_DATA) { - if (cellBO.Program->IsAttributeUsed("dataAttribute")) + if (this->ValuePassArray) { - int const elementType = this->ValuePassArray->GetDataType(); - size_t const stride = sizeof(float); - - if (!cellBO.VAO->AddAttributeArray(cellBO.Program, this->ValueBuffer, - "dataAttribute", 0, stride, VTK_FLOAT, 1, false)) + if (cellBO.Program->IsAttributeUsed("dataAttribute")) { - vtkErrorMacro(<< "Error setting 'dataAttribute' in shader VAO."); + size_t const stride = sizeof(float); + + if (!cellBO.VAO->AddAttributeArray(cellBO.Program, this->ValueBuffer, + "dataAttribute", 0, stride, VTK_FLOAT, 1, false)) + { + vtkErrorMacro(<< "Error setting 'dataAttribute' in shader VAO."); + } } } } - vtkOpenGLCheckErrorMacro("Failed in SetupValueBuffer!"); +} + +//----------------------------------------------------------------------------- +void vtkValuePassHelper::BindUniforms(vtkOpenGLHelper& cellBO) +{ + if (this->CurrentDataArrayMode == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA) + { + if (cellBO.Program->IsAttributeUsed("textureF")) + { + int tunit = this->CellFloatTexture->GetTextureUnit(); + cellBO.Program->SetUniformi("textureF", tunit); + } + } +} + +//----------------------------------------------------------------------------- +bool vtkValuePassHelper::RequiresShaderRebuild(vtkActor* act) +{ + if (this->RenderingMode == vtkValuePass::FLOATING_POINT && + this->CurrentDataArrayMode != this->LastDataArrayMode) + { + this->LastDataArrayMode = this->CurrentDataArrayMode; + return true; + } + + return false; } diff --git a/Rendering/OpenGL2/vtkValuePassHelper.h b/Rendering/OpenGL2/vtkValuePassHelper.h index b49b184e263..14ed1c87162 100644 --- a/Rendering/OpenGL2/vtkValuePassHelper.h +++ b/Rendering/OpenGL2/vtkValuePassHelper.h @@ -4,16 +4,17 @@ #include "vtkRenderingOpenGL2Module.h" -class vtkOpenGLBufferObject; -//class vtkTimeStamp; -class vtkDataArray; -class vtkRenderer; class vtkActor; +class vtkDataArray; class vtkDataSet; -class vtkOpenGLHelper; class vtkFloatArray; class vtkMapper; - +class vtkOpenGLBufferObject; +class vtkOpenGLHelper; +class vtkRenderer; +class vtkTextureObject; +class vtkWindow; +class vtkValuePass; class VTKRENDERINGOPENGL2_EXPORT vtkValuePassHelper : public vtkObject { @@ -31,24 +32,32 @@ protected: vtkGetMacro(RenderingMode, int); void UpdateConfiguration(vtkRenderer* ren, vtkActor* act, vtkMapper* mapper); - void UploadValueData(vtkActor* actor, vtkDataSet* input); + void RenderPieceStart(vtkActor* actor, vtkDataSet* input); void UpdateShaders(std::string & VSSource, std::string & FSSource, std::string & required); - void BindValueBuffer(vtkOpenGLHelper& cellBO); + void BindAttributes(vtkOpenGLHelper& cellBO); + void BindUniforms(vtkOpenGLHelper& cellBO); + void ReleaseGraphicsResources(vtkWindow* win); + void RenderPieceFinish(); + bool RequiresShaderRebuild(vtkActor* actor); private: + void AllocateGraphicsResources(vtkRenderer* ren); + vtkValuePassHelper(const vtkValuePassHelper &); // Not implemented. void operator=(const vtkValuePassHelper &); // Not implemented. - void AllocateBuffer(vtkRenderer* ren); - void ReleaseBuffer(vtkRenderer* ren); - //////////////////////////////////////////////////////////////////////////////// - //vtkTimeStamp ValueBufferTime; vtkOpenGLBufferObject* ValueBuffer; vtkDataArray* ValuePassArray; std::vector<float> Buffer; + int CurrentDataArrayMode; + int LastDataArrayMode; int RenderingMode; + bool ResourcesAllocated; + + vtkTextureObject* CellFloatTexture; + vtkOpenGLBufferObject* CellFloatBuffer; }; -- GitLab