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 |
|---|---|---|
|
|
3-D geometry in world-space lon/lat/pressure coordinates. |
|
|
Full-screen 2-D overlay. Opt in by calling
|
|
|
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 ( |
What is rendered |
|---|---|
|
Geometry that casts shadows (rendered from the light’s point of view). |
|
Volumetric shadows computed via DVR; only relevant for volume actors. |
|
The main 3-D scene pass (world-space geometry). |
|
Direct volume rendering pass for 3-D volume actors. |
|
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.
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
MStructuredGridin thegridmember: 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 |
|---|---|
|
Generic; no render-mode presets. |
|
Shared base for 2-D section variables. |
|
Horizontal section; contouring and colouring helpers. |
|
Vertical section. |
|
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
A change in time step, ensemble member, or init time triggers a new data request on all variables via the pipeline.
When a variable’s new grid arrives, the base class calls
dataFieldChangedEvent()on the actor.Override
dataFieldChangedEvent()to update GPU buffers, recompute any derived state, and callemitActorChangedSignal()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.