vtkCellPicker ignores block visibility in vtkMultiBlockDataSet

Hi everyone !

When hiding a block of a vtkMultiBlockDataSet using vtkCompositeDataDisplayAttributes.SetBlockVisibility(block, False), vtkCellPicker still picks the hidden block when a pick operation is performed.

It seems the picker intersects the raw input dataset directly without checking block visibility set on the composite mapper. Is this behavior expected, and is there a built-in way to avoid picking hidden blocks?

Reproduction Code :

import vtkmodules.vtkInteractionStyle
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonDataModel import vtkMultiBlockDataSet
from vtkmodules.vtkFiltersSources import vtkSphereSource
from vtkmodules.vtkRenderingOpenGL2 import vtkCompositePolyDataMapper2
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkCompositeDataDisplayAttributes,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer,
    vtkCellPicker
)

def main():
    # 1. Create a MultiBlockDataSet with two concentric spheres
    root = vtkMultiBlockDataSet()

    # Inner sphere
    sphere1 = vtkSphereSource()
    sphere1.SetCenter(0, 0, 0)
    sphere1.SetRadius(1.0)
    sphere1.Update()
    root.SetBlock(0, sphere1.GetOutput())

    # Outer sphere 2
    sphere2 = vtkSphereSource()
    sphere2.SetCenter(0, 0, 0)
    sphere2.SetRadius(2.0)
    sphere2.Update()
    root.SetBlock(1, sphere2.GetOutput())

    # Setup rendering using the composite mapper
    renderer = vtkRenderer()
    renderWindow = vtkRenderWindow()
    renderWindow.AddRenderer(renderer)
    
    renderWindowInteractor = vtkRenderWindowInteractor()
    renderWindowInteractor.SetRenderWindow(renderWindow)

    mapper = vtkCompositePolyDataMapper2()
    mapper.SetInputDataObject(root)

    # Hide the outer sphere (block 1) using display attributes
    attributes = vtkCompositeDataDisplayAttributes()
    mapper.SetCompositeDataDisplayAttributes(attributes)
    attributes.SetBlockVisibility(root.GetBlock(1), False)

    actor = vtkActor()
    actor.SetMapper(mapper)
    renderer.AddActor(actor)
    renderer.ResetCamera()
    renderWindow.Render()

    # Pick at the center of the window
    picker = vtkCellPicker()
    size = renderWindow.GetSize()
    picker.Pick(size[0] / 2, size[1] / 2, 0, renderer)
    
    print("Flat block index picked:", picker.GetFlatBlockIndex())
    # Expected: 1 (the visible inner sphere)
    # Actual: 2 (the hidden outer sphere)

    renderWindowInteractor.Start()

if __name__ == '__main__':
    main()

Welcome to VTK, @MaxNumerique!

Looking at the source for vtkCellPicker and vtkPicker, neither considers the visibilities for individual blocks in vtkCompositeDataDisplayAttributes when making the pick - they consider only the visibility and pickability of the entire actor for the composite dataset. That definitely sounds like a bug, and an understandable one since pickers predate the composite data display attributes in VTK’s development.

As a workaround, you could try to swap in vtkHardwarePicker for your vtkCellPicker, which should take into account block visibility in the picking process.

Thank you very much for the explanation and suggestion!

Here is the workaround I was using to filter the pick result:

  • Perform the pick with vtkCellPicker.Pick(…).
  • Retrieve the flat block index using picker.GetFlatBlockIndex().
  • Locate the corresponding block vtkDataObject from the composite dataset.
  • Retrieve the attributes using mapper.GetCompositeDataDisplayAttributes().
  • Check if the block is visible with attributes.GetBlockVisibility(block). If it returns False, I discard the pick result.

This works, but I will test swapping the picker to vtkHardwarePicker as you suggested to see if it natively handles block visibility.

Thanks again!

Hi,

Thank you for the suggestion to try vtkHardwarePicker. I tested it, but unfortunately, it is not reliable for thin geometries in my dataset (such as lines/edges only a few pixels wide) where picking was quite capricious compared to vtkCellPicker.

As a result, I had to stick to vtkCellPicker and implement a custom workaround: when block visibility changes, I construct a pruned vtkMultiBlockDataSet physically removing the hidden blocks and feed it to a dedicated pick_mapper. During the pick, I temporarily swap the actor’s mapper to this pick_mapper to prevent the picker from intersecting hidden geometry.

It would be nice to track this bug/limitation, @MaxNumerique do you think you can open an issue here ?

Sure !

I’ve created the issue :

https://gitlab.kitware.com/vtk/vtk/-/work_items?sort=created_date&state=opened&first_page_size=20&show=eyJpaWQiOiIyMDA4MyIsImZ1bGxfcGF0aCI6InZ0ay92dGsiLCJpZCI6NTMzNjk5fQ%3D%3D