This started as a ParaView discussion on visual properties for partitioned datasets, but seems more appropriate here.
Problem statement
Complex composite datasets do not get fine-grained control of their visual style. Partitioned-dataset collections can hold heterogenous data (i.e., some datasets may be surfaces, some may be polylines, some might be images or volumetric meshes). The controls that existing mappers – such as the vtkCompositePolyDataMapper – provide do not include per-dataset style.
ParaView – and presumably in some cases VTK – has scalability issues with large numbers of representations in a view. (In ParaView, each representation has client-server proxies that hold significant metadata.) This drives several applications being developed to present a single dataset (previously a multiblock, now a partitioned dataset collection) for rendering rather than a large number of individual datasets. Because of the heterogeneity, rendering and interacting with these datasets is challenging.
For example, typical CAD models can present thousands of surfaces, edges, and model vertices, each their own polydata; even splitting these into a single collection per dimension does not solve the issue since rendering styles for subsets of these datasets necessarily change frequently with user interaction.
Proposed solution
We propose a vtkRepresentation or vtkMapper for vtkDataAssembly that accepts cascading style sheets (CSS) to control the visual style and interaction (e.g., pickability).
- Separate content from presentation. The data assembly serves as a document-object model (DOM) much the same as a web-page’s HTML elements. CSS marks up HTML for the same reasons that our applications wish to control mapping of composite datasets: separating presentation from content.
-
Group data using selectors. The data assembly provides a hierarchy that can be exposed for use by CSS selectors. The names assigned to data-assembly entries are non-unique; they could be treated as tag names (3-D data equivalents of HTML tags such as
p
,div
,h1
) or as CSS classes. - Apply properties to groups/classes rather than data. CSS properties have a significant overlap with the visual properties VTK exposes through mappers and actors.
-
Interaction and animation. CSS provides pseudo-classes for interaction (like
:hover
) as well as simple transition animations as the classes assigned to an element are changed. Separating temporal updates to property values from the underlying rendering code modularizes the design.
In the longer term, one can imagine an entire scene (collection of renderers, render-windows, cameras, framebuffers, and render-passes) as having a DOM that might be marked up with CSS. In the short term, we’ll simply have a mapper or representation that accepts CSS as a configuration parameter.
Design decisions and rationale
There are many different ways we could expose CSS on a data assembly. This section discusses some alternatives and reasons for choosing between them.
Mapping a vtkDataAssembly
into a DOM
A vtkDataAssembly
is a tree whose nodes are assigned integer values. These integer values may have a list of 0 or more child integers. Each integer may be assigned a non-unique string “name”. The tree structure is amenable to the hierarchy of an HTML DOM, but the exact mapping between DOM elements, attributes, and classes is arbitrary.
- We could make each data-assembly entry a
div
element and pass the name assigned to the entry a class. This maximizes similarity to HTML by forcing all but the leaves of the tree to be valid HTML. However, HTML elements may have any number of string class names assigned to them; this mapping would provide only one (the name) or the name would have to be split using some separator (which could slow processing). Attributes (if any are allowed) would be stored separately. - We could treat each entry in the collection as an element whose type is its name. Classes and attributes would have to be stored as separate maps from integers to sets of strings (for classes) or maps from strings to variants (for attributes). It might also be necessary to index class and attribute names so that quick reverse lookups could be performed by selectors (e.g., generating a list of integer data-object IDs that are assigned the
highlighted
class).
Since vtkDataAssembly
names are non-unique, the latter approach seems preferable.
And, in fact, vtkDataAssembly
uses pugi-xml internally to store attributes and perform x-path searches – so the DOM already exists. Some API for adding/removing classes needs to be added (already have a branch for this).
Data assembly leaf-nodes
Beyond the hierarchy provided by a vtkDataAssembly, most VTK data objects provide structure that might be useful to expose. Particularly, the points, connectivity, and attributes (point/cell/node/arc/row/field data) could be exposed. Some options include
-
Use a simple transformation of each vtkObject’s class name to obtain an “element” name. For example,
lowercase(vtkObject::GetClassName()).substr(3)
would map “vtkPolyData” to “polydata”; “vtkUnstructuredGrid” to “unstructuredgrid”; and so on. -
For subclasses of
vtkDataSetAttributes
, the “active” attribute arrays might be marked with a pseudo-class (e.g.,polydata pointdata:scalars
would select the active point scalar array). NB: Because the concept of “active” arrays is being slowly deprecated, this may not be wise to expose. -
For subclasses of
vtkAbstractArray
, the array type and number of components might be presented as attributes (e.g.polydata celldata[type='uint64', components=1]
would select cell arrays storing 1 unsigned 64-bit integer per cell). -
It is possible that information keys held in the map returned by
vtkDataObject::GetInformation()
could also be presented in the DOM (perhaps as attributes?), although this will not be done in the first pass. -
For data objects that have cells (with either implicit or explicit connectivity), it may be useful to present it in the DOM. Specifically, this would cover use cases where a “decorator” of some sort is used to subset or transform the cells of a dataset before mapping. This supports a major use-case driving a CSS mapper: assigning separate visual styles to individual datasets.
- Mapping unstructured grids: extracting the external surface, all edges, or running other pipeline operations (such as a shrink filter) would allow datasets not typically mapped directly to be presented.
- Glyphing polydata points.
- Rendering polydata in wireframe vs surface mode.
It makes sense to apply any “decoration” property to the cell connectivity of a dataset. The decoration might refer to pseudo-objects representing pipelines that can be configured with CSS properties, e.g.:
/* extract the external surface of the mesh: */ unstructuredgrid cells { transform: '#extract-surface'; } #extract-surface { merge-points: true; } /* glyph vertices with spheres */ polydata verts { transform: '#glyph'; } #glyph { shape: 'sphere'; resolution: 32; }
This would need some fleshing out in order to support things like rendering both surfaces and edges, using the tube/sphere shaders for lines/points, and so on.
Supported properties
From this list of properties, we anticipate supporting:
- color: a fixed color and optionally opacity.
- cursor: a cursor to use when the mouse is over the given data
- height: scale a dataset to fit device coordinates (projected bounding box height constrained)
- opacity: a single opacity that modulates an entire dataset.
- outline: whether to render a bounding box around the object. The top/bottom/left/right keywords would not be used.
- rotate: accepts a 3-d rotational transform
- scale: accepts 1 or 3 scale factors
- translate: accepts 3-d transformation
- visibility: turn rendering on or off
- width: scale a dataset to fit device coordinates (projected bounding box width constrained)
Furthermore, we would add the following properties not present in CSS:
- color-by: one of
solid
(default),array
,texture
,shader
- color-array: a selector string identifying an array to color by
- color-map: specification of a
vtkScalarsToColors
object - line-width
- line-color: when rendering surfaces, if line-width is non-zero then bounding lines of surface cells should be rendered with the given (solid) color.
- ambient-color: ambient color for surface shading (overrides
color
if present). - diffuse-color: diffuse color for surface shading (overrides
color
if present). - specular-color: specular color for surface shading (overrides
color
if present). - ambient-coefficient: weighting of ambient to diffuse and specular components
- diffuse-coefficient: weighting of ambient to diffuse and specular components
- specular-coefficient: weighting of ambient to diffuse and specular components
- specular-power: the exponent used in Phong shading
- point-size
- point-color: when rendering lines and surfaces, if the point size is non-zero then corner points of cells should be rendered with the given (solid) color.