Non-linear cells are natively used by simulations from the get-go, simply because p-refinement is often better than h-refinement. Higher polynomial orders yield better accuracy more quickly. While users can increase the number of linear cells to approximate curves in a mesh, curved faces and lines are not only more realistic—they also improve simulation convergence and visuals.
The current pain point is that VTK, as a scientific visualization library rather than a simple 3D viewer, often fails to faithfully render non-linear geometry. Currently, it performs fixed subdivision on the CPU. It would be far more efficient to dynamically subdivide on the GPU, allowing a quadratic face closer to the camera to have higher subdivision levels while distant faces use lower levels. This approach was demonstrated in vtkCellGrid (vtk/vtk!11009).
If vtkPolyData can store non-linear edges, triangles, quads, and polygons, we can upgrade vtkOpenGLPolyDataMapper to dynamically tessellate higher-order geometry based on its distance from the camera.
The dynamic tessellation logic used by vtkCellGrid shaders (see source) follows this pattern:
// 1. Transform each vertex into eye space
vec4 eyeSpacePos0 = MCVCMatrix * gl_in[0].gl_Position;
vec4 eyeSpacePos1 = MCVCMatrix * gl_in[1].gl_Position;
// 2. Scale "distance" from camera between 0 and 1
float distance0 = clamp((abs(eyeSpacePos0.z)) / (max_distance), 0.0f, 1.0f);
float distance1 = clamp((abs(eyeSpacePos1.z)) / (max_distance), 0.0f, 1.0f);
// 3. Interpolate edge tessellation level based on the closer vertex
float tessLevel0 = mix(max_tl, min_tl, min(distance1, distance0));
// 4. Set the corresponding outer edge tessellation levels
gl_TessLevelOuter[0] = 1;
gl_TessLevelOuter[1] = tessLevel0;
I see three potential paths forward:
- Handle it in the rendering layer: This involves writing a new set of mappers to draw 1D and 2D non-linear geometry from a
vtkUnstructuredGrid. However, handling composite datasets with mixedPolyDataandUnstructuredGridbecomes complicated. - Pragmatic: Extend
vtkPolyDatawith 4 additionalvtkCellArrayinstances and update the polydata mapper to support them.vtkPolyData: - Verts - Lines - Polys - Strips - NonLinearLines (new) - NonLinearTris (new) - NonLinearQuads (new) - NonLinearPolys (new) - Long term better: Reparent
vtkPolyDatatovtkUnstructuredGrid. This would grant the polydata mappers access to non-linear edges and faces. We would need to enforce cell insertion order (verts, lines, polys, strips, etc.) and strictly block 3D cells invtkPolyData. If implemented correctly, this maintains backward compatibility while potentially reducing duplicate filters within VTK.
Since option 3 is a significant architectural change, i want to list the pros and cons of that:
Pros
- It eliminates the style of development where filters must be written once for
vtkPolyDataand again forvtkUnstructuredGrid. - Since
vtkUnstructuredGridalready supports non-linear cells (quadratic edges, tri6, quad8, etc.),vtkPolyDatawould inherit this capability “for free” at the data structure level. - Many filters like
vtkClipDataSetandvtkThresholdhave specializedPolyDataversions. Merging the hierarchy could allow for a single, optimized implementation. - Users wouldn’t need to constantly use
vtkGeometryFilterjust to convert an unstructured surface mesh into a format the mapper accepts.
Cons & Risks
vtkPolyDatais highly optimized for 2D topologies because it stores the cell connectivity arrays separately.vtkUnstructuredGridwill have a heavier memory footprint because it clumps all cells into onevtkCellArray.vtkCompositeArraywill be the way to go if we want to keep those benefits.- Backward Compatibility: This is a nuclear option. Any external plugin or wrapped code that expects
vtkPolyDatato be a direct child ofvtkPointSetwill break. - By definition,
vtkPolyDatashould not contain 3D cells (tetrahedrons, hexes). Reparenting would require strict API “shimming” to throw errors or warnings if a user tries to insert a 3D cell.
Option 1 vs Option 2 vs. Option 3
| Feature | Option 1 (new mappers) | Option 2 (Extend PolyData) | Option 3 (Reparent) |
|---|---|---|---|
| Implementation Effort | atrociously high | moderate | high |
| Risk of Breaking API | low | low | high |
| Filter Compatibility | — | Requires updating filters | Native support |
If you want to add anything, please comment.