Horizontal and vertical sections
The two section actors were the original bridge from traditional 2-D forecast products into the 3-D context: they reproduce the look of the corresponding 2-D map and cross-section products, but are embedded in the 3-D scene and can be moved interactively in real time. Both are built from the same three steps — place a triangle grid, sample the data field once per grid point, then render contours from the cached result.
Source code: src/actors/nwphorizontalsectionactor.cpp,
src/actors/nwpverticalsectionactor.cpp, src/glsl/hsec_*.fx.glsl,
src/glsl/vsec_*.fx.glsl.
Horizontal sections
Geometry. A horizontal section on a pressure surface p is a grid of triangles whose vertices sit at the horizontal positions of the data grid points and at the vertical position corresponding to p.
Sampling. The expensive part — finding the value of the field at p — is done
once per grid point and cached, not once per fragment. A compute shader
(hsec_verticalinterpolation.fx.glsl) is dispatched over the grid points and
writes its result into a 2-D image (crossSectionGrid, format r32f). For
each grid column it
performs a binary search for the two levels k and k+1 enclosing p in that column, and
interpolates the scalar value linearly in ln(p) between them.
The binary search is necessary because on hybrid sigma-pressure grids the levels enclosing a given pressure differ from column to column; see panel (a) of the figure in Sampling NWP grids on the GPU. Interpolating in ln(p) rather than in p follows the ECMWF FULLPOS interpolation routines.
The cached cross-section only has to be recomputed when the section pressure, the data field, or the region changes; not when the camera moves.
Filled contours are rendered by drawing the triangle grid and assigning a
colour per fragment (hsec_filledcontours.fx.glsl). The scalar value comes from
the cached cross-section texture with hardware interpolation, and the colour from
the 1-D texture that the attached transfer function actor provides as a lookup
table.
Line contours are generated by a marching squares implementation in a
geometry shader (hsec_marching_squares.fx.glsl). Every cell of the cached
cross-section texture is examined in parallel, and where the isoline crosses the
cell, a line segment is emitted.
Wind barbs and arrows are generated in a geometry shader as well
(hsec_vectorglyphs.fx.glsl, programs WindBarbs and Arrows): one input
point per glyph position, with the geometry of the barb (shaft, pennants, full
and half barbs) emitted on the GPU given the u and v components. Size and
density can be scaled automatically with the zoom level, so that the glyph density
stays legible while the user navigates.
Streambarbs are integrated on the CPU, inside the data pipeline.
MHorizontalStreamBarbsDataSource produces an MStreamBarbsData item.
Because this is an ordinary asynchronous pipeline request, the UI thread stays
responsive while the streamlines are computed, and the result is cached and
memory-managed like any other data item. Only the drawing happens on the
GPU, from the resulting vertex buffers (streambarbs_draw.fx.glsl).
Vertical sections
A vertical section is drawn along a path through an arbitrary number of waypoints. The geometry is again a triangle grid: one column of vertices for each of a number of interpolation points along the path (their spacing is a user setting), and one row for each vertical level of the data grid.
Here the sampling happens in the vertex shader
(vsec_interpolation_filledcontours.fx.glsl):
The vertical position of each vertex is computed for the level it belongs to. For pressure level data this is a lookup; for hybrid sigma-pressure data the surface pressure is interpolated to the vertex position and the level pressure is computed from the \(a_k\) / \(b_k\) coefficients. This is why the bottom of a vertical section follows the orography — panel (d) of the figure in Sampling NWP grids on the GPU.
The scalar value is interpolated horizontally on that level.
The result is cached in a 2-D texture as well, and refreshed when a waypoint is moved. Filled and line contours are then generated exactly as for the horizontal section.