Rendering glitches when using vtkSSAOPass and vtkDepthPeelingPass

I there,

I just moved from VTK 9.3.0 to VTK 9.5.0 and I experiment rendering glitches when displaying a scene with vtkSSAOPass on MacOS:


I’m on an MacOS 15.4.1 (Sequoia) and using Xcode 16.3 (Apple clang version 17.0.0).

Here is a simple example to reproduce the issue:

#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkCubeSource.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkOpenGLRenderer.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderStepsPass.h>
#include <vtkSSAOPass.h>
#include <vtkOpaquePass.h>
#include <vtkProperty.h>

int main() {
    // Cube source
    vtkNew<vtkCubeSource> cube;
    cube->SetXLength(1.0);
    cube->SetYLength(1.0);
    cube->SetZLength(1.0);
    cube->Update();

    // Mapper and Actor
    vtkNew<vtkPolyDataMapper> mapper;
    mapper->SetInputConnection(cube->GetOutputPort());

    vtkNew<vtkActor> actor;
    actor->SetMapper(mapper);
    actor->GetProperty()->SetColor(1.0, 0.5, 0.3);
    actor->GetProperty()->SetInterpolationToPBR();
    actor->GetProperty()->SetMetallic(0.3);
    actor->GetProperty()->SetRoughness(0.5);

    // Renderer
    vtkNew<vtkOpenGLRenderer> renderer;
    renderer->SetBackground(0.1, 0.1, 0.1);
    renderer->AddActor(actor);

    // SSAO pass setup
    vtkNew<vtkSSAOPass> ssaoPass;
    vtkNew<vtkOpaquePass> opaquePass;
    ssaoPass->SetDelegatePass(opaquePass); // SSAO wraps opaque geometry

    vtkNew<vtkRenderStepsPass> stepsPass;
    stepsPass->SetOpaquePass(ssaoPass); // Inject SSAO into render pipeline

    renderer->SetPass(stepsPass); // Use composed render pass

    // Render window and interactor
    vtkNew<vtkRenderWindow> renderWindow;
    renderWindow->AddRenderer(renderer);
    renderWindow->SetSize(800, 600);

    vtkNew<vtkRenderWindowInteractor> interactor;
    interactor->SetRenderWindow(renderWindow);

    // Camera setup
    renderer->ResetCamera();
    renderer->GetActiveCamera()->Azimuth(30);
    renderer->GetActiveCamera()->Elevation(30);

    renderWindow->Render();
    interactor->Start();

    return EXIT_SUCCESS;
}
cmake_minimum_required(VERSION 3.16)

project(vtk-test-app VERSION 1.0.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(CMAKE_BUILD_TYPE Debug)

# Note: Update path to VTK
set(CMAKE_PREFIX_PATH "../vtk/install/lib/cmake")

find_package(VTK REQUIRED COMPONENTS
  CommonCore
  FiltersSources
  InteractionStyle
  RenderingCore
  RenderingOpenGL2
  RenderingFreeType
  RenderingVolumeOpenGL2
  RenderingSceneGraph
)

if (NOT VTK_FOUND)
  message(FATAL_ERROR "Unable to find the VTK build folder.")
endif()

set(CMAKE_AUTOUIC OFF)

file(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)

add_executable(vtk-test-app ${SRC_FILES})

target_link_libraries(vtk-test-app PRIVATE ${VTK_LIBRARIES})

# vtk_module_autoinit is needed
vtk_module_autoinit(
  TARGETS vtk-test-app
  MODULES ${VTK_LIBRARIES}
)

I had no issue running the example with VTK 9.3.0.

Is this a bug or did I miss something following the update ?

Thanks a lot,

Clément

1 Like

It’s definitively a bug, @LucasGandel does that ring a bell ?

1 Like

Your render passes setup looks weird to me. The steps pass should be the delegate of the ssao pass. Here is how the VTK test initializes the render passes:

  vtkNew<vtkRenderStepsPass> basicPasses;

  vtkNew<vtkSSAOPass> ssao;
  ssao->SetRadius(0.05);
  ssao->SetKernelSize(128);
  ssao->SetDelegatePass(basicPasses);

  vtkOpenGLRenderer* glrenderer = vtkOpenGLRenderer::SafeDownCast(renderer);
  glrenderer->SetPass(ssao);

Is the result the same if you use this code?

Thanks for the replies.

You are right, your configuration works to display the SSAO, however when I add a depth peeling pass, the SSAO doesn’t work anymore I get the following warning:

vtkOpenGLState.cxx:623 WARN| Attempt to set draw buffers from a Framebuffer Object that is not bound.

I guess there is something wrong in the way I set up the rendering passes, here is my updated code:

#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkCubeSource.h>
#include <vtkDepthPeelingPass.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkOBJReader.h>
#include <vtkOpaquePass.h>
#include <vtkOpenGLRenderer.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderStepsPass.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSSAOPass.h>

#include <array>
#include <string>

vtkSmartPointer<vtkActor> read(const std::string& filename, std::array<double, 4> color)
{
    // Read the OBJ file
    vtkNew<vtkOBJReader> reader;
    reader->SetFileName(filename.c_str());
    reader->Update();

    // Mapper and Actor
    vtkNew<vtkPolyDataMapper> mapper;
    mapper->SetInputConnection(reader->GetOutputPort());

    const auto actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
    actor->GetProperty()->SetColor(color[0], color[1], color[2]);
    actor->GetProperty()->SetOpacity(color[3]);
    actor->GetProperty()->SetInterpolationToPBR();
    actor->GetProperty()->SetMetallic(0);
    actor->GetProperty()->SetRoughness(0.5);

    return actor;
}


int main() {

    // Renderer
    vtkNew<vtkOpenGLRenderer> renderer;
    renderer->SetBackground(0.1, 0.1, 0.1);

    // Load meshes
    renderer->AddActor(read("Bronchus.obj", { 1, 0.9, 0.9, 1 }));
    renderer->AddActor(read("Pulmonary_Artery.obj", { 1, 0.1, 0.1, 1 }));
    renderer->AddActor(read("Pulmonary_Vein.obj", { 0.2, 0.4, 1, 1 }));
    renderer->AddActor(read("Left_Lung.obj", { 1, 0.8, 0.9, 0.4 }));

    // Create steps pass
    vtkNew<vtkRenderStepsPass> stepsPass;

    // Depth Peeling pass
    vtkNew<vtkDepthPeelingPass> depthPeelingPass;
    depthPeelingPass->SetMaximumNumberOfPeels(8);
    depthPeelingPass->SetOcclusionRatio(0);
    depthPeelingPass->SetTranslucentPass(stepsPass->GetTranslucentPass());
    stepsPass->SetTranslucentPass(depthPeelingPass);

    // SSAO pass setup
    vtkNew<vtkSSAOPass> ssaoPass;
    ssaoPass->SetDelegatePass(stepsPass);
    ssaoPass->SetRadius(20);
    ssaoPass->SetKernelSize(256);

    // Use SSAO pass as render pass
    renderer->SetPass(ssaoPass);

    // Render window and interactor
    vtkNew<vtkRenderWindow> renderWindow;
    renderWindow->AddRenderer(renderer);
    renderWindow->SetSize(800, 600);

    vtkNew<vtkRenderWindowInteractor> interactor;
    interactor->SetRenderWindow(renderWindow);

    // Camera setup
    renderer->ResetCamera();
    renderer->GetActiveCamera()->Elevation(-90);

    renderWindow->Render();
    interactor->Start();

    return EXIT_SUCCESS;
}

And this is the result with and without depth peeling:

Any clue on what is wrong with my configuration ?

Thanks a lot,

Clément

Alright, I managed to make it work by using a custom vtkRenderPassCollection and a dedicated SSAO camera pass.

Someone had a similar issue in python:

For anyone interested this is my final setup to make SSAO & Depth Peeling work together:

    vtkNew<vtkOpaquePass> opaque;

    vtkNew<vtkCameraPass> ssaoCameraPass;
    ssaoCameraPass->SetDelegatePass(opaque);

    vtkNew<vtkSSAOPass> ssaoPass;
    ssaoPass->SetDelegatePass(ssaoCameraPass);  // SSAO applies to opaque geometry
    ssaoPass->SetRadius(20);
    ssaoPass->SetKernelSize(256);

    // Depth peeling for translucent geometry
    vtkNew<vtkDepthPeelingPass> peelingPass;
    peelingPass->SetMaximumNumberOfPeels(16);
    peelingPass->SetOcclusionRatio(0.01);

    vtkNew<vtkTranslucentPass> translucentPass;
    peelingPass->SetTranslucentPass(translucentPass);

    vtkNew<vtkLightsPass> lights;

    // Compose the sequence
    vtkNew<vtkRenderPassCollection> passes;
    passes->AddItem(lights);
    passes->AddItem(ssaoPass);     // SSAO for opaque geometry
    passes->AddItem(peelingPass);  // Depth peeling for translucent

    vtkNew<vtkSequencePass> sequence;
    sequence->SetPasses(passes);

    // Wrap it into a camera pass
    vtkNew<vtkCameraPass> cameraPass;
    cameraPass->SetDelegatePass(sequence);

    // Set the final pass
    renderer->SetPass(cameraPass);

Thanks for the help,

Clément

1 Like

Nice, thanks for sharing!

1 Like