Isosurface raycasting

Met.3D does not extract isosurfaces into triangle meshes. Instead, the volume raycaster actor renders them directly from the 3-D data texture in a fragment shader, so an isovalue can be changed without any geometry being rebuilt on the CPU. The same actor also implements direct volume rendering (DVR), which shares most of the machinery.

Source code: src/actors/nwpvolumeraycasteractor.cpp, src/glsl/volume_raycaster.fx.glsl, src/glsl/volume_sample_utils.glsl, src/glsl/volume_render_utils.glsl, src/glsl/volume_acceleration_utils.glsl.

The basic loop

For every fragment covered by the data volume, a ray is cast from the camera through the volume and traversed front to back:

  1. Compute the entry and exit parameters of the ray for the data volume.

  2. Step along the ray with a fixed step size, sampling the scalar field at each position (see Sampling NWP grids on the GPU for what a “sample” costs).

  3. Detect a crossing of the isovalue by comparing the current and previous sample.

  4. Refine the crossing position by bisection (bisectionCorrection()), so that the surface position is accurate to well below one step.

  5. Compute the surface normal as the gradient of the scalar field at the crossing position, via central differences. The gradient computation is selected by a GLSL subroutine per level type (pressureLevelGradient(), hybridLevelGradient(), auxiliaryPressureGradient()), because the vertical neighbours of a sample position are found differently on each grid type.

  6. Shade the fragment with the Blinn-Phong model (getBlinnPhongColor()), using either a fixed colour, a colour from the transfer function of the isovalue, or a colour obtained by mapping a second scalar field through a transfer function — this is how a wind speed isosurface can be coloured by temperature or pressure elevation.

  7. Continue the ray if the surface was transparent, so that several nested isosurfaces composite correctly.

Multiple isosurfaces are supported in one raycaster; each has its own isovalue, colour mode and opacity.

Performance levers

Raycasting cost scales with the number of samples taken, so all optimisations reduce that number:

Empty-space skipping. A per-field min/max acceleration structure of 32 x 32 x 32 bricks lets the ray jump over regions that cannot contain the isovalue. Described in Sampling NWP grids on the GPU.

Interaction step size. The actor exposes a second, coarser step size that is used while the camera moves or a handle is being dragged. Image quality drops temporarily, frame rate rises. This is the single most effective setting for keeping a heavy scene interactive.

Level type. Raycasting a hybrid sigma-pressure grid or an auxiliary pressure grid is several times more expensive than raycasting a pressure level grid, because far more sampling takes place, see Sampling NWP grids on the GPU. Furthermore, depending on the level type, the interpolation cannot be done in hardware alone.

Shadows

The original implementation projected each actor’s geometry onto the ground surface to imitate a shadow. This has been replaced by a scene-wide shadow mechanism: isosurfaces participate in the SHADOW_MAPPING pass and are shadowed by, and cast shadows onto, all other actors. With DVR enabled the raycaster additionally computes a volumetric light map in the VOLUMETRIC_SHADOW_MAPPING pass. See Shadow mapping.