VTK Cell Coloring Techniques: Interpolation Strategies and Rendering Effects

Three approaches to color mapping in VTK produce visibly distinct rendering results for the same quadrilateral geometry with scalar values {0.1, 20, 99, 80}. All implementations share identical geometry setup, lookup table configuration, scalar bar, and rendering window—differing only in how color interpolation is handled during rasterization.

Fragment-Side Scalar Interpolation (Default Behavior)

// ... geometry and LUT setup ...
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputData(poly);
mapper->ScalarVisibilityOn();
mapper->SetScalarRange(0.0, 100.0);
mapper->SetLookupTable(lut);
mapper->SetInterpolateScalarsBeforeMapping(false); // default

With InterpolateScalarsBeforeMapping set to false, scalar are interpolated across fragments after rasterization, then mapped through the lookup table in the fragment shader. This yields smooth color transitions and leverages VTK’s built-in Phong lighting model, which includes ambient, diffuse, and specular components. Normals are derived via screen-space derivatives (dFdx/dFdy), making it well-suited for planar or low-complexity surfaces.

Vertex-Side Color Interpolation

mapper->SetInterpolateScalarsBeforeMapping(true); // key change

When enabled, VTK evaluates the lookup table at each vertex to obtain RGB values, then interpolates these colors across the primitive. This results in linear color blending between vertices and visible banding or "contour breaks" along diagonals, especially when scalar gradients are non-uniform.

Custom Shader with Nonlinear Mapping

// Map scalar as vertex attribute
mapper->MapDataArrayToVertexAttribute("vertexScalar", "PointScalars",
                                      vtkDataObject::FIELD_ASSOCIATION_POINTS, 0);

// Generate nonlinear value stops (asinh spacing)
auto stops = generateAsinh(0.f, 100.f, 25);

// Pass LUT samples and thresholds as uniforms
shad->GetFragmentCustomUniforms()->SetUniform1fv("value_tb", 25, value_tb);
shad->GetFragmentCustomUniforms()->SetUniform4fv("color_tb", 25, &color_tb[0][0]);

shad->SetVertexShaderCode(R"(
  #version 330 core
  in vec4 vertexMC;
  in float vertexScalar;
  out float fragScalar;
  uniform mat4 MCDCMatrix;
  void main() {
    gl_Position = MCDCMatrix * vertexMC;
    fragScalar = vertexScalar;
  }
)"");

shad->SetFragmentShaderCode(R"(
  #version 330 core
  in float fragScalar;
  out vec4 fragColor;
  uniform int colornum;
  uniform float value_tb[25];
  uniform vec4 color_tb[25];
  
  vec4 getColor(float v) {
    for (int i = 0; i < colornum; ++i)
      if (v < value_tb[i]) return color_tb[i];
    return color_tb[colornum - 1];
  }
  
  void main() {
    fragColor = getColor(fragScalar);
  }
)"");

This method bypasses VTK’s interpolation logic entirely. Scalars are passed as vertex attributes and interpolated by OpenGL. The fragment shader performs a manual lookup using a precomputed nonlinear scale (here, inverse hyperbolic sine). This enables custom transfer functions, thresholding, or perceptually uniform color mappings not achievable with standard LUT interpolation.

Comparison Summary

Method Interpolation Stage Color Mapping Key Control
Fragment-side scalar interp. Post-rasterization vtkLookupTable in shader SetInterpolateScalarsBeforeMapping(false)
Vertex-side color interp. Pre-rasterization RGB interpolated per-vertex SetInterpolateScalarsBeforeMapping(true)
Custom shader Manual (fragment) Uniform-based LUT Full GLSL override

Visual and Performance Characteristics

  • Smoothness: Fragment-side interpolation provides continuous gradients; vertex-side shows linear bands; custom shaders depend on implementation.
  • Artifacts: Vertex interpolation may introduce diagonal discontinuities on quads due to bilinear interpolation limitations.
  • Performence: Vertex interpolation slightly redduces fragment workload (~0.71 ms vs 0.78 ms per frame). Custom shaders with loops incur minor overhead (~0.82 ms).

Practical Recommendations

  • Use fragment-side interpolation for general scientific visualization requiring smooth color transitions.
  • Prefer vertex-side interpolation for large meshes on constrained hardware or stereo VR where consistent performance matters more than gradient fidelity.
  • Implement custom shaders when nonlinear mappings (log, asinh), piecewise definitions, or dynamic thresholding are required.

Tags: VTK scientific visualization color mapping OpenGL Shader Programming

Posted on Wed, 19 Aug 2026 16:51:52 +0000 by MoldRat