Actors

Actors are the visual elements of a Met.3D scene. Each actor is a C++ class that owns its OpenGL resources, a set of user-configurable properties, and one or more render methods. All actors derive from MActor; actors that read gridded data from the pipeline derive from MNWPMultiVarActor.

Source code: src/gxfw/mactor.h, src/gxfw/nwpmultivaractor.h.

For step-by-step instructions on implementing a new actor, see Extending Met.3D.

Class hierarchy

MActor                               (base for all actors)
 └── MBaseMapActor                   (renders a static basemap into the view)
 └── MNWPMultiVarActor               (adds managed data variables)
      ├── MNWPHorizontalSectionActor (renders data on horizontal sections)
      └── … (most NWP actors)

All actors also inherit from QObject for Qt signal/slot support.

MActor

MActor is the abstract base class for every actor. It provides the property tree, the render call interface, OpenGL resource management, shader loading helpers, label management, and support for actor components.

Base properties

Every actor automatically receives the following properties in its property group, regardless of what the subclass adds:

  • Enabled: if unchecked, all render calls return immediately without drawing.

  • Render as wireframe: switches all geometry to wireframe mode.

  • Shadow controls: cast shadows, receive shadows, shadow opacity.

  • Label properties: font size and colour settings for any text labels the actor places in the scene.

Rendering interface

MSceneViewGLWidget calls the public render wrappers on each actor during its render pass. Each wrapper checks whether the actor is enabled, delegates to the corresponding protected virtual method on the actor, then forwards to all attached components:

Public wrapper (called by scene view)

Protected virtual to override

Purpose

render()

renderToCurrentContext()

3-D geometry in world-space lon/lat/pressure coordinates.

renderToFullScreen()

renderToCurrentFullScreenContext()

Full-screen 2-D overlay. Opt in by calling setActorSupportsFullScreenVisualisation(true) in the constructor.

renderToUiLayer()

renderToCurrentContextUiLayer()

2-D UI elements drawn on top of the 3-D scene.

The default implementations of all three protected virtuals are no-ops. Only override those that apply to your actor. See Rendering for how these passes fit into the overall render pipeline.

Render pass selection

Before invoking any render method, MSceneViewGLWidget checks the actor’s getRenderPasses() return value against the current pass. An actor is skipped entirely in passes it did not opt into.

Pass flag (MRenderPass)

What is rendered

SHADOW_MAPPING

Geometry that casts shadows (rendered from the light’s point of view).

VOLUMETRIC_SHADOW_MAPPING

Volumetric shadows computed via DVR; only relevant for volume actors.

RENDER_SCENE

The main 3-D scene pass (world-space geometry).

RENDER_DVR

Direct volume rendering pass for 3-D volume actors.

RENDER_UI

2-D UI elements drawn on top of the 3-D scene.

The base-class default opts into SHADOW_MAPPING | RENDER_SCENE | RENDER_UI. Override getRenderPasses() to restrict or extend this: Inside a render method, query sceneView->renderStep() to find out which pass is currently active.

Resource initialisation

One virtual method handles the OpenGL resource setup:

initializeActorResources()

Called once when the actor is initialised. Use this for OpenGL objects like shader programs, textures, buffer objects. This is also where you call MGLResourcesManager::generateEffectProgram() to register compiled shaders with the resource manager.

Shader loading

Shaders are GLSL effect files (*.fx.glsl) compiled at runtime. The framework uses a two-step approach:

Compilation (Step 1): Override reloadShaderEffects() to compile your shader files. Use the beginCompileShaders / compileShadersFromFileWithProgressDialog / endCompileShaders helpers so the UI shows a progress indicator:

void MMyActor::reloadShaderEffects()
{
    beginCompileShaders(1);
    compileShadersFromFileWithProgressDialog(
        myShader, "src/glsl/myactor.fx.glsl");
    endCompileShaders();
}

beginCompileShaders(n) registers n progress-bar steps. endCompileShaders() is a no-op in the base class but is provided as an extension point.

Register shaders (Step 2): In initializeActorResources(), call MGLResourcesManager::generateEffectProgram() to retrieve the compiled shader from the resource manager (or trigger compilation if it has not happened yet):

void MMyActor::initializeActorResources()
{
    MGLResourcesManager *glRM = MGLResourcesManager::getInstance();
    bool loadShaders = glRM->generateEffectProgram("myactor_shader", myShader);
    if (loadShaders) reloadShaderEffects();
}

The myShader member is a std::shared_ptr<GL::MShaderEffect>.

Session save and load

Override saveConfiguration() / loadConfiguration() (and their Header variants for the first-pass header read) to persist actor state to session files. Properties that have a configuration key set are saved and loaded automatically (see Property Framework) and do not need to be listed here. Use saveConfiguration for additional state that is not stored in properties. Always call the base-class implementation first:

void MMyActor::saveConfiguration(QSettings *settings)
{
    MActor::saveConfiguration(settings);
    settings->setValue("myParam", myParam);
}

void MMyActor::loadConfiguration(QSettings *settings)
{
    MActor::loadConfiguration(settings);
    myParam = settings->value("myParam", defaultValue).toFloat();
}

Loading order

MActor::loadActorConfiguration() drives the load sequence in a fixed order. Understanding this order matters when one step depends on state set by a previous one — for example, loadConfigurationHeader() may create components or allocate arrays whose size the property callbacks then rely on.

participant "MActor" as actor
participant "Specific actor" as sub
participant "Property tree" as props
participant "MActorComponent" as comp

-> actor : loadActorConfiguration(settings)
activate actor

actor -> sub : loadConfigurationHeader(settings)
activate sub
note right
  Structural state: Here anything
  is loaded that must be known before
  properties are loaded.
end note
sub --> actor
deactivate sub

actor -> props : loadAllFromConfiguration(settings)
activate props
note right
  Restores every property that has
  a configuration key. Each property fires
  its valueChanged callback.
end note
props --> actor
deactivate props

actor -> sub : loadConfiguration(settings)
activate sub
note right
  Additional non-property state loading
  implemented by the specific actor
  (e.g., backwards-compatibility if keys
  have changed).
end note
sub --> actor
deactivate sub

loop for each actor component
  actor -> comp : loadConfiguration(settings)
  activate comp
  comp --> actor
  deactivate comp
end

<-- actor
deactivate actor

Fig. 43 Sequence diagram of the loading procedure of an actor.

Note

Actor updates are suppressed (enableActorUpdates(false)) for the entire duration of the load. The actor is redrawn once after enableActorUpdates(true) is called, not after each individual setting is restored.

MNWPMultiVarActor

MNWPMultiVarActor extends MActor for actors that visualise gridded fields. It manages a list of MNWPActorVariable objects and takes care of the user interface for adding variables, issuing data requests, and synchronising time and ensemble member controls. Subclasses only need to describe what level types they support and how to create the appropriate variable object; everything else is handled by the base class.

Actor variables

Each MNWPActorVariable holds the complete state for one data field attached to the actor:

  • Data source ID, level type, and variable name (set when the user adds a variable).

  • The current MStructuredGrid in the grid member: the grid that was most recently delivered by the pipeline for the current time step and ensemble member.

  • A reference to the active transfer function.

  • GPU texture handles for the grid data and coordinate arrays.

  • Synchronisation state (valid time, ensemble member, init time).

Typed variable subclasses (src/gxfw/actorvartype.h) add render-mode presets and specialised 2-D/3-D methods on top of the base:

Class

Purpose

MGenericActorVariable

Generic; no render-mode presets.

MNWP2DSectionActorVariable

Shared base for 2-D section variables.

MNWP2DHorizontalActorVariable

Horizontal section; contouring and colouring helpers.

MNWP2DVerticalActorVariable

Vertical section.

MNWP3DVolumeActorVariable

3-D volume / isosurface.

The actor’s variables list (QList<MNWPActorVariable*>) is the primary access point in render methods. Always call hasData() before accessing grid.

Data flow

  1. A change in time step, ensemble member, or init time triggers a new data request on all variables via the pipeline.

  2. When a variable’s new grid arrives, the base class calls dataFieldChangedEvent() on the actor.

  3. Override dataFieldChangedEvent() to update GPU buffers, recompute any derived state, and call emitActorChangedSignal() to schedule a redraw.

Variable list events

The base class calls these virtual methods when the variable list changes. Override them to keep internal structures in sync, and always call the base-class version first:

  • onAddActorVariable(MNWPActorVariable *var): a variable was added.

  • onChangeActorVariable(MNWPActorVariable *var): variable has been exchanged.

  • onDeleteActorVariable(MNWPActorVariable *var): a variable is about to be removed.

Actor components

MActor supports optional components (MActorComponent) that attach reusable functionality (for example extra properties, render contributions, interaction handling) to actors without requiring subclassing. See Actor components for the component API.