|
FhSim
3.1.0
Marine systems simulation
|
| ID | 0021 |
| Class | BUG |
| Severity | 2 |
| Status | ready |
| Models | VisualFlowPlane |
| Found | 2026-09-23 during the design of the baked scalar-field visualisers |
Every FlowPlane builds its mesh against the one material named FlowPlaneHeatmap (src/environment/visual/FlowPlane.cpp:44), then writes its own ColorRange, VisibleRange and AlphaRange into that material's vertex-program parameters (src/environment/visual/FlowPlane.cpp:56-60):
Ogre::SubEntity::getMaterial() hands back the MaterialPtr the submesh was created with; nothing clones it. The mesh name is per-instance ("FlowPlaneMesh" + instanceString, FlowPlane.cpp:44), but the material name in that same call is the literal "FlowPlaneHeatmap", declared once in data/resources/ogre/assets/other/FlowPlane.material:18. The three uniforms are param_named defaults of the shared FlowPlaneVP program (FlowPlane.material:7-9), not per-renderable constants, so the write is global.
Each VisualFlowPlane SimObject constructs exactly one FlowPlane (src/environment/VisualFlowPlane.cpp:197), so two such SimObjects in one input file are two writers of the same three uniforms.
With two or more VisualFlowPlane objects in a scene, the last one constructed wins: every plane is then coloured and thresholded by that plane's ColorRange, VisibleRange and AlphaRange, whatever its own XML said. A user who gives a temperature plane ColorRange 4,12 and a current plane ColorRange 0,1 sees both drawn with 0,1 — the temperature plane saturates to a single colour, and with a mismatched VisibleRange a plane can vanish entirely. Nothing is logged; the parameters are read and accepted, they simply have no lasting effect.
The severity is limited to the picture: no state, no output port and no recorded result is affected, and a single-plane scene — which is every test and example in the repository — is correct.
FlowPlane constructor: material->clone("FlowPlaneHeatmap_" + instanceString), assign the clone to the sub-entity with m_entity->getSubEntity(0)->setMaterial(clone), and set the uniforms on the clone. The destructor then removes the clone via Ogre::MaterialManager::getSingleton().remove(...) — which depends on ENV-0022, since FlowPlane has no destructor body today. This is the option the new baked visualisers are specified to use.default_params and into per-renderable custom parameters (Renderable::setCustomParameter plus param_named_auto custom), which avoids a material per plane. Cheaper in material count, but it changes the shader and the .material file, and the same change would have to be made for any future visualiser sharing the program.Option 1 is the smaller, more local change and matches the precedent being set elsewhere.
An Ogre-backed (_NEEDS_GUI) test that constructs two FlowPlane objects with different colorRange values and then reads the named constant back from each sub-entity's material pass: today both report the second plane's range, and the two MaterialPtr values compare equal. After the fix the pointers differ and each reports its own range.
Cloning a material per plane costs one material and one GPU program instance per VisualFlowPlane; with the handful of planes a scene realistically carries this is negligible, but the clone must be removed on destruction or it becomes a per-run leak in a long session that creates and destroys planes. Any out-of-repo material that overrode FlowPlaneHeatmap by name would still be picked up, since the clone is taken from the looked-up material rather than built from scratch.