From 3997393f897ceae999152047a74a9966e23a4f34 Mon Sep 17 00:00:00 2001 From: Julien Schueller Date: Fri, 10 Nov 2023 18:21:38 +0100 Subject: [PATCH 1/9] CMake: Fix Remoting::Views cross-compilation (cherry picked from commit 007844c2a5e249f47e340485fff2ead2e6f39a9f) --- Remoting/Views/CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Remoting/Views/CMakeLists.txt b/Remoting/Views/CMakeLists.txt index 94b1fce20a4..771c4cd2c02 100644 --- a/Remoting/Views/CMakeLists.txt +++ b/Remoting/Views/CMakeLists.txt @@ -212,8 +212,9 @@ endif() add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/vtkSMTransferFunctionPresetsBuiltin.h" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/ColorMaps.json" - ParaView::ProcessXML - COMMAND ParaView::ProcessXML + "$" + COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} + "$" "${CMAKE_CURRENT_BINARY_DIR}/vtkSMTransferFunctionPresetsBuiltin.h" vtkSMTransferFunctionPresets JSON JSON "${CMAKE_CURRENT_SOURCE_DIR}/ColorMaps.json" -- GitLab From 747f050c1b5f57778b851a7a34ef93693d37d3da Mon Sep 17 00:00:00 2001 From: Jaswant Panchumarti Date: Mon, 30 Oct 2023 17:48:37 -0400 Subject: [PATCH 2/9] StreamLineRepresentation: Fix z-ordering - The vtkStreamLinesMapper is now aware of VTK render passes. - This mapper now also writes the depth values into depth attachment. - Report that this mapper has translucent geometry as well as opaque geometry. - By doing so, the VTK renderer will run a dual depth peeling pass on the fragment shader outputs which fix z-ordering artifacts with multiple translucent/opaque geometry. (cherry picked from commit 23652c3e12fdbb38bae0cedbf1fbd316c52638f9) --- .../shaders/vtkStreamLinesBlending_fs.glsl | 15 +- .../shaders/vtkStreamLinesCopy_fs.glsl | 10 +- .../Representations/vtkStreamLinesMapper.cxx | 498 +++++++++++++----- .../Representations/vtkStreamLinesMapper.h | 2 +- 4 files changed, 376 insertions(+), 149 deletions(-) diff --git a/Plugins/StreamLinesRepresentation/Representations/shaders/vtkStreamLinesBlending_fs.glsl b/Plugins/StreamLinesRepresentation/Representations/shaders/vtkStreamLinesBlending_fs.glsl index 46508004ec0..37855cfc6f5 100644 --- a/Plugins/StreamLinesRepresentation/Representations/shaders/vtkStreamLinesBlending_fs.glsl +++ b/Plugins/StreamLinesRepresentation/Representations/shaders/vtkStreamLinesBlending_fs.glsl @@ -4,12 +4,25 @@ varying vec2 tcoordVC; uniform sampler2D prev; +uniform sampler2D prevDepth; uniform sampler2D current; +uniform sampler2D currentDepth; uniform float alpha; void main(void) { vec4 pc = texture2D(prev, tcoordVC); vec4 cc = texture2D(current, tcoordVC); - gl_FragData[0] = pc * alpha + cc; + gl_FragData[0] = pc + cc; + gl_FragData[0].a *= alpha; + float pd = texture2D(prevDepth, tcoordVC).x; // previous depth + float cd = texture2D(currentDepth, tcoordVC).x; // current depth + if (cd < 1.0) + { + gl_FragDepth = cd; + } + else + { + gl_FragDepth = pd; + } } diff --git a/Plugins/StreamLinesRepresentation/Representations/shaders/vtkStreamLinesCopy_fs.glsl b/Plugins/StreamLinesRepresentation/Representations/shaders/vtkStreamLinesCopy_fs.glsl index 176fc20662c..685976d3269 100644 --- a/Plugins/StreamLinesRepresentation/Representations/shaders/vtkStreamLinesCopy_fs.glsl +++ b/Plugins/StreamLinesRepresentation/Representations/shaders/vtkStreamLinesCopy_fs.glsl @@ -1,11 +1,19 @@ //VTK::System::Dec //VTK::Output::Dec - +//VTK::DepthPeeling::Dec varying vec2 tcoordVC; uniform sampler2D source; +uniform sampler2D depthSource; void main(void) { + gl_FragDepth = texture2D(depthSource, tcoordVC).x; + //VTK::DepthPeeling::PreColor gl_FragData[0] = texture2D(source, tcoordVC); + if (gl_FragData[0].a <= 0.0) + { + discard; + } + //VTK::DepthPeeling::Impl } diff --git a/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.cxx b/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.cxx index c48125106d8..ddca67c5b51 100644 --- a/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.cxx +++ b/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.cxx @@ -23,6 +23,7 @@ #include "vtkOpenGLCamera.h" #include "vtkOpenGLError.h" #include "vtkOpenGLFramebufferObject.h" +#include "vtkOpenGLRenderPass.h" #include "vtkOpenGLRenderUtilities.h" #include "vtkOpenGLRenderWindow.h" #include "vtkOpenGLRenderer.h" @@ -79,6 +80,8 @@ void ReleaseVTKGLObject(T*& object) object = nullptr; } } +float s_quadTCoords[8] = { 0.f, 0.f, 1.f, 0.f, 1.f, 1.f, 0.f, 1.f }; +float s_quadVerts[12] = { -1.f, -1.f, 0.f, 1.f, -1.f, 0.f, 1.f, 1.f, 0.f, -1.f, 1.f, 0.f }; } //---------------------------------------------------------------------------- @@ -90,14 +93,13 @@ public: void ReleaseGraphicsResources(vtkWindow* renWin) { ReleaseVTKGLObject(this->VBOs, renWin); - ReleaseVTKGLObject(this->BlendingProgram, renWin); + ReleaseVTKGLObject(this->StreamLineColorBlendProgram, renWin); ReleaseVTKGLObject(this->CurrentBuffer, renWin); ReleaseVTKGLObject(this->CurrentTexture, renWin); ReleaseVTKGLObject(this->FrameBuffer, renWin); ReleaseVTKGLObject(this->FrameTexture, renWin); - ReleaseVTKGLObject(this->Program, renWin); - ReleaseVTKGLObject(this->TextureProgram, renWin); - ReleaseVTKGLObject(this->IndexBufferObject); + ReleaseVTKGLObject(this->StreamLineSegmentProgram, renWin); + ReleaseVTKGLObject(this->FinalImageBlendProgram, renWin); } void SetMapper(vtkStreamLinesMapper* mapper) { this->Mapper = mapper; } @@ -106,8 +108,23 @@ public: void SetData(vtkDataSet*, vtkDataArray*, vtkDataArray*); + // Get the mtime of all renderpasses + vtkMTimeType GetRenderPassStageMTime(vtkActor* actor); + // Get whether the "image copy" program needs to be rebuilt, typically done in different stages of + // a render pass. + bool GetNeedToRebuidFinalImageCopyShader(vtkActor* actor); + // Ask the render passes to paste source code in our "image copy" program. + void ReplaceShaderRenderPass( + std::string& vss, std::string& gss, std::string& fss, vtkActor* act, bool prePass); + // Build fbos, textures and shader programs. + bool PrepareGLBuffers(vtkRenderer*, vtkActor*); + // Pass 1: Render segment to current buffer FBO void DrawParticles(vtkRenderer*, vtkActor*, bool); - + // Pass 2: Blend current and previous frame in the frame buffer FBO + void BlendStreamlineColor(vtkRenderer*, vtkActor*, bool); + // Pass 3: Finally draw the FBO onto the screen + void BlendFinalImage(vtkRenderer*, vtkActor*); + // Move particles along the flow. void UpdateParticles(); protected: @@ -115,7 +132,6 @@ protected: ~Private() override; void InitParticle(int); - bool PrepareGLBuffers(vtkRenderer*, vtkActor*); bool InterpolateSpeedAndColor(double[3], double[3], vtkIdType); inline double Rand(double vmin = 0., double vmax = 1.) @@ -125,22 +141,23 @@ protected: } vtkCellLocator* Locator; - vtkOpenGLBufferObject* IndexBufferObject; vtkOpenGLFramebufferObject* CurrentBuffer; vtkOpenGLFramebufferObject* FrameBuffer; vtkOpenGLShaderCache* ShaderCache; vtkOpenGLVertexBufferObjectGroup* VBOs; - vtkShaderProgram* BlendingProgram; - vtkShaderProgram* Program; - vtkShaderProgram* TextureProgram; + vtkShaderProgram* StreamLineColorBlendProgram; + vtkShaderProgram* StreamLineSegmentProgram; + vtkShaderProgram* FinalImageBlendProgram; vtkSmartPointer RandomNumberSequence; vtkStreamLinesMapper* Mapper; vtkTextureObject* CurrentTexture; + vtkTextureObject* CurrentDepthTexture; vtkTextureObject* FrameTexture; + vtkTextureObject* FrameDepthTexture; vtkNew TempMatrix4; + vtkNew LastRenderPassInfo; double Bounds[6]; - std::vector Indices; std::vector ParticlesTTL; vtkDataArray* InterpolationArray; vtkDataArray* Scalars; @@ -152,11 +169,11 @@ protected: vtkSmartPointer InterpolationScalarArray; vtkMTimeType ActorMTime; vtkMTimeType CameraMTime; + vtkTimeStamp FinalImageBlendProgramSourceTime; bool AreCellScalars; bool AreCellVectors; bool ClearFlag; - bool RebuildBufferObjects; bool CreateWideLines; private: @@ -177,20 +194,19 @@ vtkStreamLinesMapper::Private::Private() this->CurrentBuffer = nullptr; this->FrameBuffer = nullptr; this->CurrentTexture = nullptr; + this->CurrentDepthTexture = nullptr; this->FrameTexture = nullptr; - this->Program = nullptr; - this->BlendingProgram = nullptr; - this->TextureProgram = nullptr; - this->IndexBufferObject = nullptr; + this->FrameDepthTexture = nullptr; + this->StreamLineSegmentProgram = nullptr; + this->StreamLineColorBlendProgram = nullptr; + this->FinalImageBlendProgram = nullptr; this->Particles->SetDataTypeToFloat(); - this->RebuildBufferObjects = true; this->InterpolationArray = nullptr; this->InterpolationScalarArray = nullptr; this->Vectors = nullptr; this->Scalars = this->Particles->GetData(); this->DataSet = nullptr; this->ClearFlag = true; - this->RebuildBufferObjects = true; this->Locator = nullptr; this->ActorMTime = 0; this->CameraMTime = 0; @@ -223,19 +239,10 @@ void vtkStreamLinesMapper::Private::SetNumberOfParticles(int nbParticles) { this->Particles->SetNumberOfPoints(nbParticles * 2); this->ParticlesTTL.resize(nbParticles, 0); - this->Indices.resize(nbParticles * 2); if (this->InterpolationScalarArray) { this->InterpolationScalarArray->Resize(nbParticles * 2); } - - // Build indices array - for (int i = 0; i < nbParticles * 2; i++) - { - this->Indices[i] = i; - } - - this->RebuildBufferObjects = true; } //----------------------------------------------------------------------------- @@ -372,11 +379,6 @@ void vtkStreamLinesMapper::Private::UpdateParticles() //---------------------------------------------------------------------------- void vtkStreamLinesMapper::Private::DrawParticles(vtkRenderer* ren, vtkActor* actor, bool animate) { - if (!this->PrepareGLBuffers(ren, actor)) - { - return; - } - vtkOpenGLCamera* cam = vtkOpenGLCamera::SafeDownCast(ren->GetActiveCamera()); this->ClearFlag = this->ClearFlag || this->Mapper->Alpha == 0. || @@ -399,8 +401,6 @@ void vtkStreamLinesMapper::Private::DrawParticles(vtkRenderer* ren, vtkActor* ac cam->GetKeyMatrices(ren, wcvc, norms, vcdc, wcdc); this->ActorMTime = actor->GetMTime(); - //////////////////////////////////////////////// - // Pass 1: Render segment to current buffer FBO this->CurrentBuffer->SetContext(renWin); this->CurrentBuffer->SaveCurrentBindingsAndBuffers(); this->CurrentBuffer->Bind(); @@ -410,12 +410,12 @@ void vtkStreamLinesMapper::Private::DrawParticles(vtkRenderer* ren, vtkActor* ac this->CurrentBuffer->AddColorAttachment( this->CurrentBuffer->GetBothMode(), 0, this->CurrentTexture); #endif - this->CurrentBuffer->AddDepthAttachment(); // auto create depth buffer + this->CurrentBuffer->AddDepthAttachment(this->CurrentDepthTexture); this->CurrentBuffer->ActivateBuffer(0); this->CurrentBuffer->Start(this->CurrentTexture->GetWidth(), this->CurrentTexture->GetHeight()); - this->ShaderCache->ReadyShaderProgram(this->Program); - if (this->Program->IsUniformUsed("MCDCMatrix")) + this->ShaderCache->ReadyShaderProgram(this->StreamLineSegmentProgram); + if (this->StreamLineSegmentProgram->IsUniformUsed("MCDCMatrix")) { actor->ComputeMatrix(); if (!actor->GetIsIdentity()) @@ -424,11 +424,11 @@ void vtkStreamLinesMapper::Private::DrawParticles(vtkRenderer* ren, vtkActor* ac vtkMatrix3x3* anorms; static_cast(actor)->GetKeyMatrices(mcwc, anorms); vtkMatrix4x4::Multiply4x4(mcwc, wcdc, this->TempMatrix4.Get()); - this->Program->SetUniformMatrix("MCDCMatrix", this->TempMatrix4.Get()); + this->StreamLineSegmentProgram->SetUniformMatrix("MCDCMatrix", this->TempMatrix4.Get()); } else { - this->Program->SetUniformMatrix("MCDCMatrix", wcdc); + this->StreamLineSegmentProgram->SetUniformMatrix("MCDCMatrix", wcdc); } } @@ -438,27 +438,17 @@ void vtkStreamLinesMapper::Private::DrawParticles(vtkRenderer* ren, vtkActor* ac color[0] = static_cast(col[0]); color[1] = static_cast(col[1]); color[2] = static_cast(col[2]); - this->Program->SetUniform3f("color", color); - this->Program->SetUniformi("scalarVisibility", useScalars); + this->StreamLineSegmentProgram->SetUniform3f("color", color); + this->StreamLineSegmentProgram->SetUniformi("scalarVisibility", useScalars); - if (this->CreateWideLines && this->Program->IsUniformUsed("lineWidthNVC")) + if (this->CreateWideLines && this->StreamLineSegmentProgram->IsUniformUsed("lineWidthNVC")) { int vp[4]; ostate->vtkglGetIntegerv(GL_VIEWPORT, vp); float lineWidth[2]; lineWidth[0] = 2.0 * actor->GetProperty()->GetLineWidth() / vp[2]; lineWidth[1] = 2.0 * actor->GetProperty()->GetLineWidth() / vp[3]; - this->Program->SetUniform2f("lineWidthNVC", lineWidth); - } - - // Setup the IBO - this->IndexBufferObject->Bind(); - if (this->RebuildBufferObjects) - { - // We upload the indices only when number of particles changed - this->IndexBufferObject->Upload( - &this->Indices[0], nbParticles * 2, vtkOpenGLBufferObject::ElementArrayBuffer); - this->RebuildBufferObjects = false; + this->StreamLineSegmentProgram->SetUniform2f("lineWidthNVC", lineWidth); } vtkSmartPointer colors = nullptr; @@ -481,100 +471,278 @@ void vtkStreamLinesMapper::Private::DrawParticles(vtkRenderer* ren, vtkActor* ac // Setup the VAO vtkNew vao; vao->Bind(); - this->VBOs->AddAllAttributesToVAO(this->Program, vao.Get()); + this->VBOs->AddAllAttributesToVAO(this->StreamLineSegmentProgram, vao.Get()); - // Perform rendering + // Write to depth buffer and color buffer + vtkOpenGLState::ScopedglEnableDisable depthSaver(ostate, GL_DEPTH_TEST); + ostate->vtkglEnable(GL_DEPTH_TEST); ostate->vtkglClearColor(0.0, 0.0, 0.0, 0.0); - ostate->vtkglClear(GL_COLOR_BUFFER_BIT); - ostate->vtkglDisable(GL_DEPTH_TEST); + ostate->vtkglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (!this->CreateWideLines) { glLineWidth(actor->GetProperty()->GetLineWidth()); } glDrawArrays(GL_LINES, 0, nbParticles * 2); vtkOpenGLCheckErrorMacro("Failed after rendering"); - - this->IndexBufferObject->Release(); vao->Release(); this->CurrentBuffer->UnBind(); this->CurrentBuffer->RestorePreviousBindingsAndBuffers(); +} - static float s_quadTCoords[8] = { 0.f, 0.f, 1.f, 0.f, 1.f, 1.f, 0.f, 1.f }; - static float s_quadVerts[12] = { -1.f, -1.f, 0.f, 1.f, -1.f, 0.f, 1.f, 1.f, 0.f, -1.f, 1.f, 0.f }; +//---------------------------------------------------------------------------- +void vtkStreamLinesMapper::Private::BlendStreamlineColor( + vtkRenderer* ren, vtkActor* actor, bool animate) +{ + vtkOpenGLCamera* cam = vtkOpenGLCamera::SafeDownCast(ren->GetActiveCamera()); - //////////////////////////////////////////////////////////////////// - // Pass 2: Blend current and previous frame in the frame buffer FBO - if (animate) + this->ClearFlag = this->ClearFlag || this->Mapper->Alpha == 0. || + this->ActorMTime < actor->GetMTime() || this->CameraMTime < cam->GetMTime(); + + if (this->ClearFlag && !animate) { - this->FrameBuffer->SetContext(renWin); - this->FrameBuffer->SaveCurrentBindingsAndBuffers(); - this->FrameBuffer->Bind(); + return; + } + + vtkOpenGLRenderWindow* renWin = vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()); + vtkOpenGLState* ostate = renWin->GetState(); + + if (!animate) + { + return; + } + this->FrameBuffer->SetContext(renWin); + this->FrameBuffer->SaveCurrentBindingsAndBuffers(); + this->FrameBuffer->Bind(); #ifdef VTK_UPDATED_FRAMEBUFFER - this->FrameBuffer->AddColorAttachment(0, this->FrameTexture); + this->FrameBuffer->AddColorAttachment(0, this->FrameTexture); #else - this->FrameBuffer->AddColorAttachment(this->FrameBuffer->GetBothMode(), 0, this->FrameTexture); + this->FrameBuffer->AddColorAttachment(this->FrameBuffer->GetBothMode(), 0, this->FrameTexture); #endif - this->FrameBuffer->AddDepthAttachment(); // auto create depth buffer - this->FrameBuffer->ActivateBuffer(0); - this->FrameBuffer->Start(this->FrameTexture->GetWidth(), this->FrameTexture->GetHeight()); + this->FrameBuffer->AddDepthAttachment(this->FrameDepthTexture); + this->FrameBuffer->ActivateBuffer(0); + this->FrameBuffer->Start(this->FrameTexture->GetWidth(), this->FrameTexture->GetHeight()); + // We do not want depth testing at all. Instead, we only want to write to the depth buffer. + // The call to vtkOpenGLFramebufferObject::Start above disables GL_DEPTH_TEST. + // OpenGL says that writing to depth buffer is disabled with depth testing turned off. + ostate->vtkglEnable(GL_DEPTH_TEST); + vtkOpenGLState::ScopedglDepthFunc depthFuncSaver(ostate); + ostate->vtkglDepthFunc(GL_ALWAYS); + if (this->ClearFlag) + { + // Clear frame buffer if camera changed + ostate->vtkglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + this->CameraMTime = cam->GetMTime(); + this->ClearFlag = false; + } + + this->ShaderCache->ReadyShaderProgram(this->StreamLineColorBlendProgram); + vtkNew vaotb; + vaotb->Bind(); + this->FrameTexture->Activate(); + this->FrameDepthTexture->Activate(); + this->CurrentTexture->Activate(); + this->CurrentDepthTexture->Activate(); + double alpha = + 1.0 - (1.0 / (this->Mapper->MaxTimeToLive * std::max(0.00001, this->Mapper->Alpha))); + this->StreamLineColorBlendProgram->SetUniformf("alpha", alpha); + this->StreamLineColorBlendProgram->SetUniformi("prev", this->FrameTexture->GetTextureUnit()); + this->StreamLineColorBlendProgram->SetUniformi("current", this->CurrentTexture->GetTextureUnit()); + this->StreamLineColorBlendProgram->SetUniformi( + "prevDepth", this->FrameDepthTexture->GetTextureUnit()); + this->StreamLineColorBlendProgram->SetUniformi( + "currentDepth", this->CurrentDepthTexture->GetTextureUnit()); + vtkOpenGLRenderUtilities::RenderQuad( + ::s_quadVerts, ::s_quadTCoords, this->StreamLineColorBlendProgram, vaotb.Get()); + this->CurrentTexture->Deactivate(); + this->CurrentDepthTexture->Deactivate(); + vaotb->Release(); + + this->FrameBuffer->UnBind(); + this->FrameBuffer->RestorePreviousBindingsAndBuffers(); +} + +//---------------------------------------------------------------------------- +void vtkStreamLinesMapper::Private::BlendFinalImage(vtkRenderer* ren, vtkActor* actor) +{ + vtkOpenGLCamera* cam = vtkOpenGLCamera::SafeDownCast(ren->GetActiveCamera()); + + this->ClearFlag = this->ClearFlag || this->Mapper->Alpha == 0. || + this->ActorMTime < actor->GetMTime() || this->CameraMTime < cam->GetMTime(); + + if (this->ClearFlag) + { + return; + } + vtkOpenGLRenderWindow* renWin = vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()); + vtkOpenGLState* ostate = renWin->GetState(); - if (this->ClearFlag) + if (this->GetNeedToRebuidFinalImageCopyShader(actor)) + { + std::string vss = vtkTextureObjectVS; + std::string fss = vtkStreamLinesCopy_fs; + std::string gss; + this->ReplaceShaderRenderPass(vss, gss, fss, actor, /*prePass=*/true); + this->ReplaceShaderRenderPass(vss, gss, fss, actor, /*prePass=*/false); + this->FinalImageBlendProgram->UnRegister(this); + this->FinalImageBlendProgram = + this->ShaderCache->ReadyShaderProgram(vss.c_str(), fss.c_str(), gss.c_str()); + this->FinalImageBlendProgram->Register(this); + } + this->ShaderCache->ReadyShaderProgram(this->FinalImageBlendProgram); + vtkNew vaot; + vaot->Bind(); + this->FrameTexture->Activate(); + this->FrameDepthTexture->Activate(); + this->FinalImageBlendProgram->SetUniformi("source", this->FrameTexture->GetTextureUnit()); + this->FinalImageBlendProgram->SetUniformi( + "depthSource", this->FrameDepthTexture->GetTextureUnit()); + // Handle render pass setup + vtkInformation* info = actor->GetPropertyKeys(); + if (info && info->Has(vtkOpenGLRenderPass::RenderPasses())) + { + int numRenderPasses = info->Length(vtkOpenGLRenderPass::RenderPasses()); + for (int i = 0; i < numRenderPasses; ++i) { - // Clear frame buffer if camera changed - ostate->vtkglClear(GL_COLOR_BUFFER_BIT); - this->CameraMTime = cam->GetMTime(); - this->ClearFlag = false; + vtkObjectBase* rpBase = info->Get(vtkOpenGLRenderPass::RenderPasses(), i); + vtkOpenGLRenderPass* renderPass = static_cast(rpBase); + if (!renderPass->SetShaderParameters(this->FinalImageBlendProgram, this->Mapper, actor, vaot)) + { + vtkErrorMacro( + "RenderPass::SetShaderParameters failed for renderpass: " << renderPass->GetClassName()); + } } - - this->ShaderCache->ReadyShaderProgram(this->BlendingProgram); - vtkNew vaotb; - vaotb->Bind(); - this->FrameTexture->Activate(); - this->CurrentTexture->Activate(); - double alpha = - 1.0 - (1.0 / (this->Mapper->MaxTimeToLive * std::max(0.00001, this->Mapper->Alpha))); - this->BlendingProgram->SetUniformf("alpha", alpha); - this->BlendingProgram->SetUniformi("prev", this->FrameTexture->GetTextureUnit()); - this->BlendingProgram->SetUniformi("current", this->CurrentTexture->GetTextureUnit()); - vtkOpenGLRenderUtilities::RenderQuad( - s_quadVerts, s_quadTCoords, this->BlendingProgram, vaotb.Get()); - this->CurrentTexture->Deactivate(); - vaotb->Release(); - - this->FrameBuffer->UnBind(); - this->FrameBuffer->RestorePreviousBindingsAndBuffers(); - } - - //////////////////////////////////////////////// - // Pass 3: Finally draw the FBO onto the screen - if (!this->ClearFlag) - { - this->ShaderCache->ReadyShaderProgram(this->TextureProgram); - vtkNew vaot; - vaot->Bind(); - this->FrameTexture->Activate(); - this->TextureProgram->SetUniformi("source", this->FrameTexture->GetTextureUnit()); - // Setup blending equation - int prevBlendParams[4]; - ostate->vtkglGetIntegerv(GL_BLEND_SRC_RGB, &prevBlendParams[0]); - ostate->vtkglGetIntegerv(GL_BLEND_DST_RGB, &prevBlendParams[1]); - ostate->vtkglGetIntegerv(GL_BLEND_SRC_ALPHA, &prevBlendParams[2]); - ostate->vtkglGetIntegerv(GL_BLEND_DST_ALPHA, &prevBlendParams[3]); - ostate->vtkglEnable(GL_BLEND); - ostate->vtkglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - vtkOpenGLRenderUtilities::RenderQuad( - s_quadVerts, s_quadTCoords, this->TextureProgram, vaot.Get()); - - // Restore blending equation state - ostate->vtkglBlendFuncSeparate( - prevBlendParams[0], prevBlendParams[1], prevBlendParams[2], prevBlendParams[3]); - - this->FrameTexture->Deactivate(); - vaot->Release(); } + vtkOpenGLCheckErrorMacro("failed after UpdateShader"); + // Setup blending equation + int prevBlendParams[4]; + ostate->vtkglGetIntegerv(GL_BLEND_SRC_RGB, &prevBlendParams[0]); + ostate->vtkglGetIntegerv(GL_BLEND_DST_RGB, &prevBlendParams[1]); + ostate->vtkglGetIntegerv(GL_BLEND_SRC_ALPHA, &prevBlendParams[2]); + ostate->vtkglGetIntegerv(GL_BLEND_DST_ALPHA, &prevBlendParams[3]); + ostate->vtkglEnable(GL_BLEND); + ostate->vtkglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + // Setup depth test ostate->vtkglEnable(GL_DEPTH_TEST); + vtkOpenGLRenderUtilities::RenderQuad( + s_quadVerts, s_quadTCoords, this->FinalImageBlendProgram, vaot.Get()); + + // Restore blending equation state + ostate->vtkglBlendFuncSeparate( + prevBlendParams[0], prevBlendParams[1], prevBlendParams[2], prevBlendParams[3]); + + this->FrameTexture->Deactivate(); + this->FrameDepthTexture->Deactivate(); + vaot->Release(); +} + +//----------------------------------------------------------------------------- +vtkMTimeType vtkStreamLinesMapper::Private::GetRenderPassStageMTime(vtkActor* actor) +{ + vtkInformation* info = actor->GetPropertyKeys(); + vtkMTimeType renderPassMTime = 0; + + int curRenderPasses = 0; + if (info && info->Has(vtkOpenGLRenderPass::RenderPasses())) + { + curRenderPasses = info->Length(vtkOpenGLRenderPass::RenderPasses()); + } + + int lastRenderPasses = 0; + if (this->LastRenderPassInfo->Has(vtkOpenGLRenderPass::RenderPasses())) + { + lastRenderPasses = this->LastRenderPassInfo->Length(vtkOpenGLRenderPass::RenderPasses()); + } + else // have no last pass + { + if (!info) // have no current pass + { + return 0; // short circuit + } + } + + // Determine the last time a render pass changed stages: + if (curRenderPasses != lastRenderPasses) + { + // Number of passes changed, definitely need to update. + // Fake the time to force an update: + renderPassMTime = VTK_MTIME_MAX; + } + else + { + // Compare the current to the previous render passes: + for (int i = 0; i < curRenderPasses; ++i) + { + vtkObjectBase* curRP = info->Get(vtkOpenGLRenderPass::RenderPasses(), i); + vtkObjectBase* lastRP = this->LastRenderPassInfo->Get(vtkOpenGLRenderPass::RenderPasses(), i); + + if (curRP != lastRP) + { + // Render passes have changed. Force update: + renderPassMTime = VTK_MTIME_MAX; + break; + } + else + { + // Render passes have not changed -- check MTime. + vtkOpenGLRenderPass* renderPass = static_cast(curRP); + renderPassMTime = std::max(renderPassMTime, renderPass->GetShaderStageMTime()); + } + } + } + + // Cache the current set of render passes for next time: + if (info) + { + this->LastRenderPassInfo->CopyEntry(info, vtkOpenGLRenderPass::RenderPasses()); + } + else + { + this->LastRenderPassInfo->Clear(); + } + + return renderPassMTime; +} + +//------------------------------------------------------------------------------ +bool vtkStreamLinesMapper::Private::GetNeedToRebuidFinalImageCopyShader(vtkActor* actor) +{ + // Have the renderpasses changed? + vtkMTimeType renderPassMTime = this->GetRenderPassStageMTime(actor); + return (this->FinalImageBlendProgram == nullptr || + this->FinalImageBlendProgramSourceTime < renderPassMTime); +} + +//------------------------------------------------------------------------------ +void vtkStreamLinesMapper::Private::ReplaceShaderRenderPass( + std::string& vss, std::string& gss, std::string& fss, vtkActor* act, bool prePass) +{ + vtkInformation* info = act->GetPropertyKeys(); + if (info && info->Has(vtkOpenGLRenderPass::RenderPasses())) + { + int numRenderPasses = info->Length(vtkOpenGLRenderPass::RenderPasses()); + for (int i = 0; i < numRenderPasses; ++i) + { + vtkObjectBase* rpBase = info->Get(vtkOpenGLRenderPass::RenderPasses(), i); + vtkOpenGLRenderPass* renderPass = static_cast(rpBase); + if (prePass) + { + if (!renderPass->PreReplaceShaderValues(vss, gss, fss, this->Mapper, act)) + { + vtkErrorMacro( + "vtkOpenGLRenderPass::ReplaceShaderValues failed for " << renderPass->GetClassName()); + } + } + else + { + if (!renderPass->PostReplaceShaderValues(vss, gss, fss, this->Mapper, act)) + { + vtkErrorMacro( + "vtkOpenGLRenderPass::ReplaceShaderValues failed for " << renderPass->GetClassName()); + } + } + } + } } //---------------------------------------------------------------------------- @@ -610,6 +778,22 @@ bool vtkStreamLinesMapper::Private::PrepareGLBuffers(vtkRenderer* ren, vtkActor* this->ClearFlag = true; } + if (!this->CurrentDepthTexture) + { + this->CurrentDepthTexture = vtkTextureObject::New(); + this->CurrentDepthTexture->SetContext(renWin); + } + + if (this->CurrentDepthTexture->GetWidth() != width || + this->CurrentDepthTexture->GetHeight() != height) + { + this->CurrentDepthTexture->SetWrapS(vtkTextureObject::Repeat); + this->CurrentDepthTexture->SetWrapT(vtkTextureObject::Repeat); + this->CurrentDepthTexture->SetMinificationFilter(vtkTextureObject::Nearest); + this->CurrentDepthTexture->SetMagnificationFilter(vtkTextureObject::Nearest); + this->CurrentDepthTexture->AllocateDepth(width, height, vtkTextureObject::Fixed24); + } + if (!this->FrameTexture) { this->FrameTexture = vtkTextureObject::New(); @@ -622,6 +806,22 @@ bool vtkStreamLinesMapper::Private::PrepareGLBuffers(vtkRenderer* ren, vtkActor* this->ClearFlag = true; } + if (!this->FrameDepthTexture) + { + this->FrameDepthTexture = vtkTextureObject::New(); + this->FrameDepthTexture->SetContext(renWin); + } + + if (this->FrameDepthTexture->GetWidth() != width || + this->FrameDepthTexture->GetHeight() != height) + { + this->FrameDepthTexture->SetWrapS(vtkTextureObject::Repeat); + this->FrameDepthTexture->SetWrapT(vtkTextureObject::Repeat); + this->FrameDepthTexture->SetMinificationFilter(vtkTextureObject::Nearest); + this->FrameDepthTexture->SetMagnificationFilter(vtkTextureObject::Nearest); + this->FrameDepthTexture->AllocateDepth(width, height, vtkTextureObject::Fixed24); + } + if (!this->ShaderCache) { this->ShaderCache = renWin->GetShaderCache(); @@ -631,40 +831,35 @@ bool vtkStreamLinesMapper::Private::PrepareGLBuffers(vtkRenderer* ren, vtkActor* this->CreateWideLines = actor->GetProperty()->GetLineWidth() > 1.0 && actor->GetProperty()->GetLineWidth() > renWin->GetMaximumHardwareLineWidth(); - if (!this->Program || (prevCreateWideLines != this->CreateWideLines)) + if (!this->StreamLineSegmentProgram || (prevCreateWideLines != this->CreateWideLines)) { this->ShaderCache->ReleaseCurrentShader(); - if (this->Program) + if (this->StreamLineSegmentProgram) { - ReleaseVTKGLObject(this->Program, renWin); + ReleaseVTKGLObject(this->StreamLineSegmentProgram, renWin); } - this->Program = this->ShaderCache->ReadyShaderProgram( + this->StreamLineSegmentProgram = this->ShaderCache->ReadyShaderProgram( vtkStreamLines_vs, vtkStreamLines_fs, this->CreateWideLines ? vtkStreamLines_gs : ""); - this->Program->Register(this); + this->StreamLineSegmentProgram->Register(this); } - if (!this->BlendingProgram) + if (!this->StreamLineColorBlendProgram) { - this->BlendingProgram = + this->StreamLineColorBlendProgram = this->ShaderCache->ReadyShaderProgram(vtkTextureObjectVS, vtkStreamLinesBlending_fs, ""); - this->BlendingProgram->Register(this); + this->StreamLineColorBlendProgram->Register(this); } - if (!this->TextureProgram) + if (!this->FinalImageBlendProgram) { - this->TextureProgram = + this->FinalImageBlendProgram = this->ShaderCache->ReadyShaderProgram(vtkTextureObjectVS, vtkStreamLinesCopy_fs, ""); - this->TextureProgram->Register(this); - } - - if (!this->IndexBufferObject) - { - this->IndexBufferObject = vtkOpenGLBufferObject::New(); - this->IndexBufferObject->SetType(vtkOpenGLBufferObject::ElementArrayBuffer); + this->FinalImageBlendProgram->Register(this); } - return this->CurrentTexture && this->FrameTexture && this->ShaderCache && this->Program && - this->BlendingProgram && this->TextureProgram && this->IndexBufferObject; + return this->CurrentTexture && this->FrameTexture && this->ShaderCache && + this->StreamLineSegmentProgram && this->StreamLineColorBlendProgram && + this->FinalImageBlendProgram; } namespace @@ -847,13 +1042,17 @@ void vtkStreamLinesMapper::Render(vtkRenderer* ren, vtkActor* actor) // Set processing dataset and arrays this->Internal->SetData(inData, inVectors, inScalars); + if (!this->Internal->PrepareGLBuffers(ren, actor)) + { + return; + } bool animate = true; for (int i = 0; i < this->NumberOfAnimationSteps && animate; i++) { animate = this->Animate && (this->NumberOfAnimationSteps == 1 || (this->NumberOfAnimationSteps > 1 && this->AnimationSteps < this->NumberOfAnimationSteps)); - if (animate) + if (animate && !actor->IsRenderingTranslucentPolygonalGeometry()) { // Move particles this->Internal->UpdateParticles(); @@ -863,8 +1062,15 @@ void vtkStreamLinesMapper::Render(vtkRenderer* ren, vtkActor* actor) } } - // Draw updated particles in a buffer - this->Internal->DrawParticles(ren, actor, animate); + if (!actor->IsRenderingTranslucentPolygonalGeometry()) + { + this->Internal->DrawParticles(ren, actor, animate); + this->Internal->BlendStreamlineColor(ren, actor, animate); + } + else + { + this->Internal->BlendFinalImage(ren, actor); + } } } diff --git a/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.h b/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.h index 54064880773..033b4bfa897 100644 --- a/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.h +++ b/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.h @@ -92,7 +92,7 @@ public: * on a specific rendering pass. */ bool HasOpaqueGeometry() override { return true; } - bool HasTranslucentPolygonalGeometry() override { return false; } + bool HasTranslucentPolygonalGeometry() override { return true; } ///@} /** -- GitLab From 901f542363ae41848fc755971584a152e56cf92b Mon Sep 17 00:00:00 2001 From: Jaswant Panchumarti Date: Tue, 14 Nov 2023 13:43:53 -0500 Subject: [PATCH 3/9] Add unit test for StreamLinesRepresentation z-order (cherry picked from commit dcdfaf0eb31bdb95b445380de89590d5f46285fd) --- .../fix-streamlines-representation-z-order.md | 4 +++ .../Testing/CMakeLists.txt | 5 +++ ...StreamLinesRepresentationZOrder.png.sha512 | 1 + .../StreamLinesRepresentationZOrder.xml | 33 +++++++++++++++++++ 4 files changed, 43 insertions(+) create mode 100644 Documentation/release/dev/fix-streamlines-representation-z-order.md create mode 100644 Plugins/StreamLinesRepresentation/Testing/Data/Baseline/StreamLinesRepresentationZOrder.png.sha512 create mode 100644 Plugins/StreamLinesRepresentation/Testing/StreamLinesRepresentationZOrder.xml diff --git a/Documentation/release/dev/fix-streamlines-representation-z-order.md b/Documentation/release/dev/fix-streamlines-representation-z-order.md new file mode 100644 index 00000000000..6b774061e21 --- /dev/null +++ b/Documentation/release/dev/fix-streamlines-representation-z-order.md @@ -0,0 +1,4 @@ +# Fixed Z Ordering Bug With StreamLines Representation + +The StreamLinesRepresentation plugin is now capable of rendering streamlines +with correct z-order when there are multiple objects in a render view. diff --git a/Plugins/StreamLinesRepresentation/Testing/CMakeLists.txt b/Plugins/StreamLinesRepresentation/Testing/CMakeLists.txt index 4c579b0e830..b378f360966 100644 --- a/Plugins/StreamLinesRepresentation/Testing/CMakeLists.txt +++ b/Plugins/StreamLinesRepresentation/Testing/CMakeLists.txt @@ -14,4 +14,9 @@ if (BUILD_SHARED_LIBS) BASELINE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Data/Baseline" TEST_DATA_TARGET ParaViewData TEST_SCRIPTS StreamLinesRepresentationTransform.xml) + paraview_add_client_tests( + LOAD_PLUGIN "StreamLinesRepresentation" + BASELINE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Data/Baseline" + TEST_DATA_TARGET ParaViewData + TEST_SCRIPTS StreamLinesRepresentationZOrder.xml) endif () diff --git a/Plugins/StreamLinesRepresentation/Testing/Data/Baseline/StreamLinesRepresentationZOrder.png.sha512 b/Plugins/StreamLinesRepresentation/Testing/Data/Baseline/StreamLinesRepresentationZOrder.png.sha512 new file mode 100644 index 00000000000..0d7261dcb66 --- /dev/null +++ b/Plugins/StreamLinesRepresentation/Testing/Data/Baseline/StreamLinesRepresentationZOrder.png.sha512 @@ -0,0 +1 @@ +60b11e22da1701ee06cd3f33b7db01cc0b3aedc24a6b466d8cbe63bd9787caec98d0269eb13126ed451998acc1d6ab9d67064c8855066c3ffb0d80b2cd48ada6 diff --git a/Plugins/StreamLinesRepresentation/Testing/StreamLinesRepresentationZOrder.xml b/Plugins/StreamLinesRepresentation/Testing/StreamLinesRepresentationZOrder.xml new file mode 100644 index 00000000000..4ef14131168 --- /dev/null +++ b/Plugins/StreamLinesRepresentation/Testing/StreamLinesRepresentationZOrder.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- GitLab From d50722b64ebf9cbec4db9054f04d38da04d75d86 Mon Sep 17 00:00:00 2001 From: Jaswant Panchumarti Date: Tue, 14 Nov 2023 13:07:28 -0500 Subject: [PATCH 4/9] StreamLinesRepresentation: minor nit picks - clean up variable names - use std::array when possible to do so - use std::string for string comparisons instead of strcmp (cherry picked from commit 73e47539890b7e0f82b09e75cb6d2c119e1833a8) --- .../Representations/vtkStreamLinesMapper.cxx | 54 ++++++++++--------- .../pqStreamLinesAnimationManager.cxx | 4 +- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.cxx b/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.cxx index ddca67c5b51..8aa1e31d2ca 100644 --- a/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.cxx +++ b/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.cxx @@ -132,7 +132,8 @@ protected: ~Private() override; void InitParticle(int); - bool InterpolateSpeedAndColor(double[3], double[3], vtkIdType); + bool InterpolateSpeedAndColor( + std::array& position, std::array& velocity, vtkIdType particleId); inline double Rand(double vmin = 0., double vmax = 1.) { @@ -247,7 +248,7 @@ void vtkStreamLinesMapper::Private::SetNumberOfParticles(int nbParticles) //----------------------------------------------------------------------------- bool vtkStreamLinesMapper::Private::InterpolateSpeedAndColor( - double pos[3], double outSpeed[3], vtkIdType pid) + std::array& position, std::array& velocity, vtkIdType particleId) { int subId; double pcoords[3]; @@ -256,11 +257,12 @@ bool vtkStreamLinesMapper::Private::InterpolateSpeedAndColor( vtkIdType cellId = 0; if (!this->Locator) { - cellId = this->DataSet->FindCell(pos, nullptr, -1, 1e-10, subId, pcoords, weights); + cellId = this->DataSet->FindCell(position.data(), nullptr, -1, 1e-10, subId, pcoords, weights); } else { - cellId = this->Locator->FindCell(pos, 0., this->GenericCell.Get(), pcoords, weights); + cellId = + this->Locator->FindCell(position.data(), 0., this->GenericCell.Get(), pcoords, weights); } if (cellId < 0) @@ -278,14 +280,14 @@ bool vtkStreamLinesMapper::Private::InterpolateSpeedAndColor( { if (this->AreCellVectors) { - this->Vectors->GetTuple(cellId, outSpeed); + this->Vectors->GetTuple(cellId, velocity.data()); } else { this->InterpolationArray->InterpolateTuple(0, this->IdList.Get(), this->Vectors, weights); - this->InterpolationArray->GetTuple(0, outSpeed); + this->InterpolationArray->GetTuple(0, velocity.data()); } - double speed = vtkMath::Norm(outSpeed); + double speed = vtkMath::Norm(velocity.data()); if (speed == 0. || vtkMath::IsInf(speed) || vtkMath::IsNan(speed)) { // Null speed area @@ -297,12 +299,12 @@ bool vtkStreamLinesMapper::Private::InterpolateSpeedAndColor( { if (this->AreCellScalars) { - this->InterpolationScalarArray->SetTuple(pid, this->Scalars->GetTuple(cellId)); + this->InterpolationScalarArray->SetTuple(particleId, this->Scalars->GetTuple(cellId)); } else { this->InterpolationScalarArray->InterpolateTuple( - pid, this->IdList.Get(), this->Scalars, weights); + particleId, this->IdList.Get(), this->Scalars, weights); } } return true; @@ -315,21 +317,21 @@ void vtkStreamLinesMapper::Private::InitParticle(int pid) do { // Sample a new seed location - double pos[3]; - pos[0] = this->Rand(this->Bounds[0], this->Bounds[1]); - pos[1] = this->Rand(this->Bounds[2], this->Bounds[3]); - pos[2] = this->Rand(this->Bounds[4], this->Bounds[5]); - this->Particles->SetPoint(pid * 2 + 0, pos); - this->Particles->SetPoint(pid * 2 + 1, pos); + std::array position; + position[0] = this->Rand(this->Bounds[0], this->Bounds[1]); + position[1] = this->Rand(this->Bounds[2], this->Bounds[3]); + position[2] = this->Rand(this->Bounds[4], this->Bounds[5]); + this->Particles->SetPoint(pid * 2 + 0, position.data()); + this->Particles->SetPoint(pid * 2 + 1, position.data()); this->ParticlesTTL[pid] = this->Rand(1, this->Mapper->MaxTimeToLive); // Check speed at this location - double speedVec[9]; - if (this->InterpolateSpeedAndColor(pos, speedVec, pid * 2)) + std::array velocity; + if (this->InterpolateSpeedAndColor(position, velocity, pid * 2)) { this->InterpolationScalarArray->SetTuple( pid * 2 + 1, this->InterpolationScalarArray->GetTuple(pid * 2)); - double speed = vtkMath::Norm(speedVec); + double speed = vtkMath::Norm(velocity.data()); // Do not sample in no-speed areas added = (speed != 0. && !vtkMath::IsInf(speed) && !vtkMath::IsNan(speed)); } @@ -348,20 +350,20 @@ void vtkStreamLinesMapper::Private::UpdateParticles() this->ParticlesTTL[i]--; if (this->ParticlesTTL[i] > 0) { - double pos[3]; - this->Particles->GetPoint(i * 2 + 1, pos); + std::array position; + this->Particles->GetPoint(i * 2 + 1, position.data()); - // Update prevpos with last pos - this->Particles->SetPoint(i * 2 + 0, pos); + // Advance particle position. + this->Particles->SetPoint(i * 2 + 0, position.data()); this->InterpolationScalarArray->SetTuple( i * 2 + 0, this->InterpolationScalarArray->GetTuple(i * 2 + 1)); // Move the particle and fetch its color - double speedVec[3]; - if (this->InterpolateSpeedAndColor(pos, speedVec, i * 2 + 1)) + std::array velocity; + if (this->InterpolateSpeedAndColor(position, velocity, i * 2 + 1)) { - this->Particles->SetPoint(2 * i + 1, pos[0] + dt * speedVec[0], pos[1] + dt * speedVec[1], - pos[2] + dt * speedVec[2]); + this->Particles->SetPoint(2 * i + 1, position[0] + dt * velocity[0], + position[1] + dt * velocity[1], position[2] + dt * velocity[2]); } else { diff --git a/Plugins/StreamLinesRepresentation/pqStreamLinesAnimationManager.cxx b/Plugins/StreamLinesRepresentation/pqStreamLinesAnimationManager.cxx index 2547490bb0a..ddb57b38302 100644 --- a/Plugins/StreamLinesRepresentation/pqStreamLinesAnimationManager.cxx +++ b/Plugins/StreamLinesRepresentation/pqStreamLinesAnimationManager.cxx @@ -43,9 +43,9 @@ void pqStreamLinesAnimationManager::onRenderEnded() vtkSMRepresentationProxy* repr = vtkSMRepresentationProxy::SafeDownCast(reprs[i]->getProxy()); if (repr && repr->GetProperty("Representation")) { - const char* rs = vtkSMPropertyHelper(repr, "Representation").GetAsString(); + const char* representation = vtkSMPropertyHelper(repr, "Representation").GetAsString(); const int visible = vtkSMPropertyHelper(repr, "Visibility").GetAsInt(); - if (rs && !strcmp(rs, "Stream Lines") && visible) + if (representation && (std::string(representation) == "Stream Lines") && visible) { // This view as a visible StreamLines representation. // Let's ask for a new render! -- GitLab From 147473f13d6d2defecd750b88e719c16f4cbf62e Mon Sep 17 00:00:00 2001 From: Jaswant Panchumarti Date: Tue, 14 Nov 2023 15:53:17 -0500 Subject: [PATCH 5/9] StreamLinesRepresentation: Fix memory leak (cherry picked from commit 13eaf99bc852c646c98f6a05218f50f6fbf8f742) --- .../Representations/vtkStreamLinesMapper.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.cxx b/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.cxx index 8aa1e31d2ca..a87be1e30b8 100644 --- a/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.cxx +++ b/Plugins/StreamLinesRepresentation/Representations/vtkStreamLinesMapper.cxx @@ -96,8 +96,10 @@ public: ReleaseVTKGLObject(this->StreamLineColorBlendProgram, renWin); ReleaseVTKGLObject(this->CurrentBuffer, renWin); ReleaseVTKGLObject(this->CurrentTexture, renWin); + ReleaseVTKGLObject(this->CurrentDepthTexture, renWin); ReleaseVTKGLObject(this->FrameBuffer, renWin); ReleaseVTKGLObject(this->FrameTexture, renWin); + ReleaseVTKGLObject(this->FrameDepthTexture, renWin); ReleaseVTKGLObject(this->StreamLineSegmentProgram, renWin); ReleaseVTKGLObject(this->FinalImageBlendProgram, renWin); } -- GitLab From 4a0be2f646491993e5893548a5602919bd424066 Mon Sep 17 00:00:00 2001 From: Jules BOURDAIS Date: Thu, 30 Nov 2023 11:42:38 +0100 Subject: [PATCH 6/9] fix typo: replace selectIDsHelper with _selectIDsHelper (cherry picked from commit 60987bda81617c037231b249edfd947ddbac3257) --- Wrapping/Python/paraview/selection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Wrapping/Python/paraview/selection.py b/Wrapping/Python/paraview/selection.py index 990b54cb4b5..9f78b1e2369 100644 --- a/Wrapping/Python/paraview/selection.py +++ b/Wrapping/Python/paraview/selection.py @@ -402,7 +402,7 @@ def SelectCompositeDataIDs(IDs=[], FieldType='POINT', ContainingCells=False, Sou - Modifier - 'ADD', 'SUBTRACT', 'TOGGLE', or None to define whether and how the selection should modify the existing selection. """ - selectIDsHelper('CompositeDataIDSelectionSource', **locals()) + _selectIDsHelper('CompositeDataIDSelectionSource', **locals()) def SelectHierarchicalDataIDs(IDs=[], FieldType='POINT', ContainingCells=False, Source=None, Modifier=None): -- GitLab From a33c2ba39834e4279887de64b87aa351d1139643 Mon Sep 17 00:00:00 2001 From: Jules BOURDAIS Date: Mon, 8 Jan 2024 15:15:16 +0100 Subject: [PATCH 7/9] test SelectCompositeDataIDs + fix CheckSelection logic (cherry picked from commit 69727c00e7cf8fbb921cf4d692cdaacaf6aad04d) --- .../Testing/Python/PythonSelection.py | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/Remoting/Application/Testing/Python/PythonSelection.py b/Remoting/Application/Testing/Python/PythonSelection.py index a92ae070cf9..9fbaac67e11 100644 --- a/Remoting/Application/Testing/Python/PythonSelection.py +++ b/Remoting/Application/Testing/Python/PythonSelection.py @@ -36,9 +36,9 @@ def CheckSelection(numPoints=None, numCells=None): es.UpdatePipeline() info = es.GetDataInformation() print("Points and cells:", info.GetNumberOfPoints(), info.GetNumberOfCells()) - if numPoints: + if numPoints is not None: assert numPoints == info.GetNumberOfPoints() - if numCells: + if numCells is not None: assert numCells == info.GetNumberOfCells() del es @@ -84,6 +84,34 @@ Render() SelectSurfaceBlocks(Rectangle=[100, 100, 200, 200]) CheckSelection(numPoints=61, numCells=107) +# Composite data ids selection +Hide(s) +SetActiveSource(g) +Show(g) +Render() + +# Should make selection within the whole dataset (0 is the root block id) +SelectCompositeDataIDs(IDs=[0, 0, 0], FieldType="POINT") +CheckSelection(numPoints=2, numCells=2) + +Hide(s) +SetActiveSource(g) +Show(g) +Render() + +# Should make selection within the first subblock +SelectCompositeDataIDs(IDs=[1, 0, 0], FieldType="POINT") +CheckSelection(numPoints=1, numCells=1) + +Hide(s) +SetActiveSource(g) +Show(g) +Render() + +# Should make selection within the second subblock +SelectCompositeDataIDs(IDs=[2, 0, 0], FieldType="POINT") +CheckSelection(numPoints=1, numCells=1) + try: SelectSurfacePoints(Rectangle=[0, 0], Polygon=[0, 0]) sys.exit(1) # Should not get here -- GitLab From 0848807f28603a2e9c46719470708067b2c42002 Mon Sep 17 00:00:00 2001 From: Guillaume Peillex Date: Thu, 21 Dec 2023 15:01:42 +0100 Subject: [PATCH 8/9] Fix pole centering when autopole is off When autopole is off, initialize the pole position so that values entered in the Transform section of the Polar Axes Edit gui are taken into account. Check the behavior of Polar Axes translation when AutoPole is off Sending baseline image to ExternalData repo Reformat according to clang-format Adds newline at the end of file Fix image size. Removes sha of the old images. Adds new image Replaces image by its sha Removes old sha Update the reference image (cherry picked from commit 769f4a5a94521bdc78eeab5d2482417f1c6b85a7) --- ...PolarAxesAutoPoleOffTranslation.png.sha512 | 1 + Remoting/Views/Testing/Python/CMakeLists.txt | 5 ++ .../Python/PolarAxesAutoPoleOffTranslation.py | 57 +++++++++++++++++++ Remoting/Views/vtkPolarAxesRepresentation.cxx | 7 ++- 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 Remoting/Views/Testing/Data/Baseline/PolarAxesAutoPoleOffTranslation.png.sha512 create mode 100644 Remoting/Views/Testing/Python/PolarAxesAutoPoleOffTranslation.py diff --git a/Remoting/Views/Testing/Data/Baseline/PolarAxesAutoPoleOffTranslation.png.sha512 b/Remoting/Views/Testing/Data/Baseline/PolarAxesAutoPoleOffTranslation.png.sha512 new file mode 100644 index 00000000000..2ccb640424f --- /dev/null +++ b/Remoting/Views/Testing/Data/Baseline/PolarAxesAutoPoleOffTranslation.png.sha512 @@ -0,0 +1 @@ +222a2ec5f6f9ef0757a5994c1882a83617840dce27b69191141f0bbfbeefddb31d78eabfdc4edfb64e72d457ff1621d0a256c664e48c34826f1ca09898f946d3 diff --git a/Remoting/Views/Testing/Python/CMakeLists.txt b/Remoting/Views/Testing/Python/CMakeLists.txt index e36bc2ae429..0a15f524fc7 100644 --- a/Remoting/Views/Testing/Python/CMakeLists.txt +++ b/Remoting/Views/Testing/Python/CMakeLists.txt @@ -81,3 +81,8 @@ paraview_add_test_python( JUST_VALID ${PY_TESTS} ) + +paraview_add_test_python( + NO_RT + PolarAxesAutoPoleOffTranslation.py +) diff --git a/Remoting/Views/Testing/Python/PolarAxesAutoPoleOffTranslation.py b/Remoting/Views/Testing/Python/PolarAxesAutoPoleOffTranslation.py new file mode 100644 index 00000000000..7fd75a96a06 --- /dev/null +++ b/Remoting/Views/Testing/Python/PolarAxesAutoPoleOffTranslation.py @@ -0,0 +1,57 @@ +from paraview.simple import * +paraview.simple._DisableFirstRenderCameraReset() + +sphere1 = Sphere(registrationName='Sphere1') +renderView1 = GetActiveViewOrCreate('RenderView') +sphere1Display = Show(sphere1, renderView1, 'GeometryRepresentation') +sphere1Display.Representation = 'Surface' +renderView1.ResetCamera(False, 0.9) +renderView1.Update() + +transform1 = Transform(registrationName='Transform1', Input=sphere1) +transform1.Transform.Translate = [5.0, 2.0, 1.0] +transform1Display = Show(transform1, renderView1, 'GeometryRepresentation') +transform1Display.Representation = 'Surface' +Hide(sphere1, renderView1) + +renderView1.Update() +renderView1.ResetCamera(False, 0.9) + +HideInteractiveWidgets(proxy=transform1.Transform) + +transform1Display.PolarAxes.Visibility = 1 +transform1Display.PolarAxes.AutoPole = 0 +transform1Display.PolarAxes.Translation = [5.0, 2.0, 1.0] + +# Properties modified on transform1Display.DataAxesGrid +transform1Display.DataAxesGrid.GridAxesVisibility = 1 + +# Properties modified on transform1Display.DataAxesGrid +transform1Display.DataAxesGrid.UseCustomBounds = 1 +transform1Display.DataAxesGrid.CustomBounds = [0.0, 5.0, 0.0, 2.0, 0.0, 1.0] + +renderView1.ResetCamera(False, 0.9) + +layout1 = GetLayout() +layout1.SetSize(300, 300) + +renderView1.InteractionMode = '2D' +renderView1.CameraPosition = [5.511463174995544, 4.012063174995544, 27.256085151235204] +renderView1.CameraFocalPoint = [5.511463174995544, 4.012063174995544, 0.7498] +renderView1.CameraParallelScale = 6.86033141205782 + +Render(renderView1) + +import os +import sys +try: + baselineIndex = sys.argv.index('-B')+1 + baselinePath = sys.argv[baselineIndex] +except: + print("Could not get baseline directory. Test failed.") +baseline_file = os.path.join(baselinePath, "PolarAxesAutoPoleOffTranslation.png") +from paraview.vtk.test import Testing +from paraview.vtk.util.misc import vtkGetTempDir +Testing.VTK_TEMP_DIR = vtkGetTempDir() +Testing.compareImage(renderView1.GetRenderWindow(), baseline_file, threshold=40) +Testing.interact() diff --git a/Remoting/Views/vtkPolarAxesRepresentation.cxx b/Remoting/Views/vtkPolarAxesRepresentation.cxx index 054a4a82aea..953b89ee6f2 100644 --- a/Remoting/Views/vtkPolarAxesRepresentation.cxx +++ b/Remoting/Views/vtkPolarAxesRepresentation.cxx @@ -425,7 +425,7 @@ void vtkPolarAxesRepresentation::UpdateBounds() this->PolarAxesActor->SetBounds(bds); - double pole[3] = { 0.0 }; + double pole[3] = { 0.0, 0.0, 0.0 }; double center[2] = { (bds[0] + bds[1]) * 0.5, (bds[2] + bds[3]) * 0.5 }; double maxRadius = 0.0; double minRadius = EnableCustomRadius ? this->MinRadius : 0.0; @@ -440,6 +440,11 @@ void vtkPolarAxesRepresentation::UpdateBounds() } else { + for (std::size_t ind{ 0 }; ind < 3; ++ind) + { + pole[ind] = position[ind]; + } + this->PolarAxesActor->SetPole(pole); // Compute the max length between pole and bounds for maximum radius -- GitLab From d41098fcf9a4d1715c38c3d2293b9e4f871c7459 Mon Sep 17 00:00:00 2001 From: Guillaume Peillex Date: Thu, 21 Dec 2023 10:34:42 +0100 Subject: [PATCH 9/9] Fix Change File action requiring extension hint When using Change File, use readerFactory object to retrieve admissible file extensions for the current reader. Previous implementation was inspecting xml reader definition and was focusing only on extension hint. It seems that going through the ReaderFactory object allows to get directly the allowed file extensions, may them be defined through extensions hints or other hints such as filename_patterns. Adds test ReplaceReaderFileNameNoExtensions This test is an adaptation of ReplaceReaderFileName for a reader that have filename_patterns but no extensions hints When Changing File, allows to select mulitples files and dirs Raises warnings in case of pbs If no reader or more than one reader for the current source are found then abort the process and explains the user why Replaces images suffixes _0, _1 with _A and _B Removes old references Adds new baseline images Do not use image comparison anymore To check the correct databases are loaded just check the expected fields are not None. (cherry picked from commit 5ed54e0e8aaad888964bada876f81d0cbf8cf2df) --- .../ParaView/Testing/Python/CMakeLists.txt | 1 + .../ReplaceReaderFileNameNoExtensions.py | 43 ++++++++++++ .../pqChangeFileNameReaction.cxx | 70 +++++++++++++------ 3 files changed, 92 insertions(+), 22 deletions(-) create mode 100644 Clients/ParaView/Testing/Python/ReplaceReaderFileNameNoExtensions.py diff --git a/Clients/ParaView/Testing/Python/CMakeLists.txt b/Clients/ParaView/Testing/Python/CMakeLists.txt index 750db5acc41..2ea9af85ca3 100644 --- a/Clients/ParaView/Testing/Python/CMakeLists.txt +++ b/Clients/ParaView/Testing/Python/CMakeLists.txt @@ -107,6 +107,7 @@ paraview_add_test_python( SaveDataWithArrayAndBlockSelection.py ReadTimeArray.py ReplaceReaderFileName.py + ReplaceReaderFileNameNoExtensions.py ) # These tests could run safely in serial and parallel. diff --git a/Clients/ParaView/Testing/Python/ReplaceReaderFileNameNoExtensions.py b/Clients/ParaView/Testing/Python/ReplaceReaderFileNameNoExtensions.py new file mode 100644 index 00000000000..bdfb0cd8af9 --- /dev/null +++ b/Clients/ParaView/Testing/Python/ReplaceReaderFileNameNoExtensions.py @@ -0,0 +1,43 @@ +import sys + +from paraview.simple import * + +#### disable automatic camera reset on 'Show' +paraview.simple._DisableFirstRenderCameraReset() + +for i, arg in enumerate(sys.argv): + if arg == "-D" and i+1 < len(sys.argv): + double_mach = sys.argv[i+1] + '/Testing/Data/double_mach_reflection/plt00030.temp' + amrex_mfix = sys.argv[i+1] + '/Testing/Data/AMReX-MFIX/plt00005' +try: + baselineIndex = sys.argv.index('-B')+1 + baselinePath = sys.argv[baselineIndex] +except: + print ("Could not get baseline directory. Test failed.") + +# Create a new 'AMReXBoxLibGrid Reader' +amrex_mfix_ref = AMReXBoxLibGridReader(registrationName='amrex_mfix_ref', FileNames=[amrex_mfix]) +amrex_mfix_ref.CellArrayStatus = ['ep_g', 'mu_g', 'p_g', 'ro_g', 'rop_g', 'u_g', 'v_g', 'volfrac', 'vort', 'w_g'] + +# Check the source is loaded +assert(FindSource("amrex_mfix_ref") is not None) + +# Check that the loaded source is the correct one +for field in ('ep_g', 'mu_g', 'p_g', 'ro_g', 'rop_g', 'u_g', 'v_g', 'volfrac', 'vort', 'w_g'): + assert(amrex_mfix_ref.CellData.GetArray(field) is not None) + +# Change file +ReplaceReaderFileName(amrex_mfix_ref, [double_mach], 'FileNames') + +# Check that previous source does not exist anymore +assert(FindSource("amrex_mfix_ref") is None) + +# Check that new source is loaded +double_mach_ref = FindSource('plt00030.temp') +assert(double_mach_ref is not None) + +double_mach_ref.CellArrayStatus = ['Temp', 'density', 'pressure', 'rho_E', 'rho_X', 'rho_e', 'xmom', 'ymom', 'zmom'] + +# Check that the new loaded source is the correct one (i.e different from the previous one) +for field in ('Temp', 'density', 'pressure', 'rho_E', 'rho_X', 'rho_e', 'xmom', 'ymom', 'zmom'): + assert(double_mach_ref.CellData.GetArray(field) is not None) diff --git a/Qt/ApplicationComponents/pqChangeFileNameReaction.cxx b/Qt/ApplicationComponents/pqChangeFileNameReaction.cxx index de0d32dccbd..2e0cebfbbfe 100644 --- a/Qt/ApplicationComponents/pqChangeFileNameReaction.cxx +++ b/Qt/ApplicationComponents/pqChangeFileNameReaction.cxx @@ -16,14 +16,18 @@ #include "vtkNew.h" #include "vtkPVXMLElement.h" #include "vtkSMCoreUtilities.h" +#include "vtkSMProxyManager.h" +#include "vtkSMReaderFactory.h" #include "vtkSMSourceProxy.h" #include "vtkSMStringVectorProperty.h" #include "vtkSMTrace.h" #include #include +#include #include +#include #include #include #include @@ -73,51 +77,73 @@ void pqChangeFileNameReaction::changeFileName() } pqServer* server = pqActiveObjects::instance().activeServer(); - - vtkNew collection; - vtkPVXMLElement* hints = proxy->GetHints(); - hints->FindNestedElementByName("ReaderFactory", collection); - - if (!collection->GetNumberOfItems()) + if (!server) { return; } - vtkPVXMLElement* readerFactory = vtkPVXMLElement::SafeDownCast(collection->GetItemAsObject(0)); - + vtkSMReaderFactory* readerFactory = vtkSMProxyManager::GetProxyManager()->GetReaderFactory(); if (!readerFactory) { return; } - const char* extensions = readerFactory->GetAttribute("extensions"); - if (!extensions) + const auto& filtersDetailed = readerFactory->GetSupportedFileTypesDetailed(server->session()); + + const auto& currentReaderName = proxy->GetXMLName(); + + const auto& currentReaderMatch = + std::count_if(std::begin(filtersDetailed), std::end(filtersDetailed), + [currentReaderName](const FileTypeDetailed& ftd) { return ftd.Name == currentReaderName; }); + + if (currentReaderMatch == 0) { - qWarning("Extensions are not specified for the reader. Ignoring File Name Change Request"); + QString warningTitle(tr("Change File operation aborted")); + QMessageBox::warning(pqCoreUtilities::mainWidget(), warningTitle, + tr("No reader associated to the selected source was found!"), QMessageBox::Ok); return; } + if (currentReaderMatch > 1) + { + QString warningTitle(tr("Change File operation aborted")); + QMessageBox::warning(pqCoreUtilities::mainWidget(), warningTitle, + tr("More than one reader associated to the selected source were found!"), QMessageBox::Ok); + return; + } + + const auto& currentReaderFound = + std::find_if(std::begin(filtersDetailed), std::end(filtersDetailed), + [currentReaderName](const FileTypeDetailed& ftd) { return ftd.Name == currentReaderName; }); - std::vector extensionList; - vtksys::SystemTools::Split(extensions, extensionList, ' '); + // In theory it should never append as we checked exactly one reader exists + assert(currentReaderFound != std::end(filtersDetailed) && + "No current reader found when exaclty one exists!"); + + const auto& extensionList = currentReaderFound->FilenamePatterns; QString qExtensions = QString("Supported files ("); for (const std::string& extension : extensionList) { - qExtensions += QString("*.") + QString(extension.c_str()) + QString(" "); + qExtensions += QString(extension.c_str()) + QString(" "); } qExtensions += QString(")"); pqFileDialog fileDialog( - server, pqCoreUtilities::mainWidget(), tr("Open File:"), QString(), qExtensions, false); + server, pqCoreUtilities::mainWidget(), QString(), QString(), qExtensions, true); fileDialog.setObjectName("FileOpenDialog"); - fileDialog.setFileMode(pqFileDialog::ExistingFile); + fileDialog.setFileMode(pqFileDialog::ExistingFilesAndDirectories); if (fileDialog.exec() == QDialog::Accepted) { - QStringList files = fileDialog.getSelectedFiles(); - std::vector filesStd(files.size()); - std::transform(files.constBegin(), files.constEnd(), filesStd.begin(), - [](const QString& str) -> std::string { return str.toStdString(); }); + QList allFiles = fileDialog.getAllSelectedFiles(); + std::vector allFilesStd{}; + for (const auto& currentFiles : allFiles) + { + for (const auto& file : currentFiles) + { + allFilesStd.push_back(file.toStdString()); + } + } for (const auto propertyName : { "FileName", "FileNames" }) { @@ -126,9 +152,9 @@ void pqChangeFileNameReaction::changeFileName() SM_SCOPED_TRACE(CallFunction) .arg("ReplaceReaderFileName") .arg(proxy) - .arg(filesStd) + .arg(allFilesStd) .arg(propertyName); - vtkSMCoreUtilities::ReplaceReaderFileName(proxy, filesStd, propertyName); + vtkSMCoreUtilities::ReplaceReaderFileName(proxy, allFilesStd, propertyName); CLEAR_UNDO_STACK(); break; } -- GitLab