3D Visualization explained

In VTK, we have 3 main types of objects that are key for understanding its visualization principals.
First we have the View which is just a container for any Representation of DataSource that you want to see.

View

The view is a 3D View that can do Geometry rendering for meshes or Volume rendering for 3D images.
The view can be configured to act as a 2D one when using parallel projection and preventing rotation when interacting with it. The View component can be configured with the following set of properties.

dash_vtk.View(
  id='vtk-view',
  background=[0, 0, 0],           # RGB array of floating point values between 0 and 1.
  interactorSettings=[...],       # Binding of mouse events to camera action (Rotate, Pan, Zoom...)
  cameraPosition=[x,y,z],         # Where the camera should be initially placed in 3D world
  cameraViewUp=[dx, dy, dz],      # Vector to use as your view up for your initial camera
  cameraParallelProjection=False, # Should we see our 3D work with perspective or flat with no depth perception
  triggerRender=0,                # Timestamp meant to trigger a render when different
  triggerResetCamera=0,           # Timestamp meant to trigger a reset camera when different
  # clickInfo,                    # Read-only property to retrieve picked representation id and picking information
  # hoverInfo                     # Read-only property to retrieve picked representation id and picking information
)

For the interactorSettings we expect a list of mouse event type linked to an action. The example below is what is used as default:

interactorSettings=[
  {
    button: 1,
    action: 'Rotate',
  }, {
    button: 2,
    action: 'Pan',
  }, {
    button: 3,
    action: 'Zoom',
    scrollEnabled: true,
  }, {
    button: 1,
    action: 'Pan',
    shift: true,
  }, {
    button: 1,
    action: 'Zoom',
    alt: true,
  }, {
    button: 1,
    action: 'ZoomToMouse',
    control: true,
  }, {
    button: 1,
    action: 'Roll',
    alt: true,
    shift: true,
  }
]

A mouse event can be identified with the following set of properties:
- button: 1/2/3 # Which button should be down
- shift: True/False # Is the Shift key down
- alt: True/False # Is the Alt key down
- control: True/False # Is the Ctrl key down
- scrollEnabled: True/False # Some action could also be triggered by scroll
- dragEnabled: True/False # Mostly used to disable default drag behavior

And the action could be one of the following:
- Pan: Will pan the object on the plane normal to the camera
- Zoom: Will zoom closer or further from the object based on the drag direction
- Roll: Will rotate the object around the view direction
- ZoomToMouse: Will zoom while keeping the location that was initially under the mouse at the same spot

Representation

A representation is responsible for converting a DataSource into something visual that will be available inside the View.

So far we are exposing to dash_vtk 3 core types of Representation:
- GeometryRepresentation: The geometry representation will expect a mesh and will render it as geometry rendering (think triangle sets).
- VolumeRepresentation: The volume representation will expect a 3D image and will render it using a Volume Rendering technique that will let you see through (foggy object).
- SliceRepresentation: The slice representation will expect a 3D image and will slice it along a given axis.

Representations should be put inside the children of a View.

DataSource

A DataSource can be many things but it is mostly something that can produce data. In other words it could be a dataset or a filter that consume some data and generate new ones or even a reader that will read somekind of input (file, url…) and produce some data. Any DataSource can be placed inside the children of another DataSource that will act as a filter or simply passed to a Representation.

In dash_vtk we have several objects that falls into that category. The list below gives you an overview of those but more details information can be found later.
- Algorithm: Allows you to instantiate a vtk.js algorithm that could either be a filter (vtkWarpScalar) or a source (vtkLineSource, vtkConeSource, vtkPlaneSource, vtkSphereSource, vtkCylinderSource).
- ImageData: What we’ve been calling a 3D image so far. This element will let you define each piece that comprises a 3D image.
- PolyData: A surface mesh (points, triangles…). This element will let you define the various piece of a mesh.
- Reader: Similar to an Algorithm except that readers have a common API and this element lets you leverage those.
- ShareDataSet: Allows you to capture any DataSource and make it available in another processing pipeline or representation without duplicating the data that gets sent from the server to the client.
- Mesh: Similar to PolyData except that it has a Python helper function to help you map a vtkDataSet into a single property of the Mesh.
- Volume: Similar to ImageData except that it has a Python helper function to help you map a vtkImageData into a single property of the Volume.

Geometry Rendering

Now that we have those core concepts down we can show some examples of rendering a mesh using dash-vtk.

View full code

from dash import Dash, html

import dash_vtk
from dash_vtk.utils import to_mesh_state

try:
    # VTK 9+
    from vtkmodules.vtkImagingCore import vtkRTAnalyticSource
except ImportError:
    # VTK =< 8
    from vtk.vtkImagingCore import vtkRTAnalyticSource

# Use VTK to get some data
data_source = vtkRTAnalyticSource()
data_source.Update()  # <= Execute source to produce an output
dataset = data_source.GetOutput()

# Use helper to get a mesh structure that can be passed as-is to a Mesh
# RTData is the name of the field
mesh_state = to_mesh_state(dataset)

content = dash_vtk.View([
    dash_vtk.GeometryRepresentation([
        dash_vtk.Mesh(state=mesh_state)
    ]),
])

# Dash setup
app = Dash(__name__)
server = app.server

app.layout = html.Div(
    style={"width": "100%", "height": "400px"},
    children=[content],
)

if __name__ == "__main__":
    app.run(debug=True)
# Use helper to get a mesh structure that can be passed as-is to a Mesh
from dash_vtk.utils import to_mesh_state
mesh_state = to_mesh_state(dataset)

content = dash_vtk.View([
    dash_vtk.GeometryRepresentation([
        dash_vtk.Mesh(state=mesh_state)
    ]),
])

# Dash setup
app = Dash(__name__)
server = app.server

app.layout = html.Div(
    style={"width": "100%", "height": "calc(100vh - 15px)"},
    children=[content],
)

if __name__ == "__main__":
    app.run(debug=True)

Volume Rendering

The previous example was using a 3D image and extracting its mesh to render. Let’s keep the same data but show it as Volume Rendering.

from dash import Dash, html

import dash_vtk
from dash_vtk.utils import to_volume_state

try:
    # VTK 9+
    from vtkmodules.vtkImagingCore import vtkRTAnalyticSource
except ImportError:
    # VTK =< 8
    from vtk.vtkImagingCore import vtkRTAnalyticSource

# Use VTK to get some data
data_source = vtkRTAnalyticSource()
data_source.Update()  # <= Execute source to produce an output
dataset = data_source.GetOutput()

# Use helper to get a volume structure that can be passed as-is to a Volume
volume_state = to_volume_state(dataset)  # No need to select field

content = dash_vtk.View([
    dash_vtk.VolumeRepresentation([
        # GUI to control Volume Rendering
        # + Setup good default at startup
        dash_vtk.VolumeController(),
        # Actual volume
        dash_vtk.Volume(state=volume_state),
    ]),
])

# Dash setup
app = Dash(__name__)
server = app.server

app.layout = html.Div(
    style={"width": "100%", "height": "400px"},
    children=[content],
)

if __name__ == "__main__":
    app.run(debug=True)