Skip to content

Rocky (VSG geospatial): terrain physics (RockyGround) + map rendering (SceneRockyVisualizer)#1121

Open
tabgab wants to merge 8 commits into
vsg-lidar-pathlossfrom
vsg-rocky-geospatial
Open

Rocky (VSG geospatial): terrain physics (RockyGround) + map rendering (SceneRockyVisualizer)#1121
tabgab wants to merge 8 commits into
vsg-lidar-pathlossfrom
vsg-rocky-geospatial

Conversation

@tabgab

@tabgab tabgab commented Jul 6, 2026

Copy link
Copy Markdown

Adds real geospatial capability to INET via Rocky (the VulkanSceneGraph successor to osgEarth): real terrain elevation in the radio physics, and a real geospatial map rendered in the VSG 3D view.

RockyGround — terrain physics (headless)

An IGround backed by a GDAL-openable elevation source (a GeoTIFF DEM, …), sampled with rocky::ElevationSampler. Any consumer of physicalEnvironment.getGround() — e.g. TwoRayGroundReflection path loss — then sees the real surface with no changes to that consumer. Needs no viewer, so it runs in Cmdenv. Example: examples/environment/rockyground.

SceneRockyVisualizer — map in the 3D view

Renders a Rocky map (local GDAL files or online TMS tiles, e.g. readymap.org) in the Qtenv VSG 3D view, transformed into the scene's local ENU frame under the network nodes. Uses the VsgScene3DNode render hook from the companion omnetpp-dev PR. Example: examples/visualizer/vsgrockyGeneral (offline synthetic tile), RealMap (readymap San Francisco Bay), Communication (nodes exchanging UDP over the map, with signal spheres + packet routes).

Build

Opt-in WITH_ROCKY in src/makefrag (off by default — INET builds unchanged without it). Build with make WITH_ROCKY=yes ROCKY_ROOT=/path/to/rocky-install.

Docs

ROCKY-VSG-GUIDE.md — a developer guide covering both modules, building your own Rocky visualizations via the render hook, and the gotchas (topocentric/WGS84/cull-radius, ROCKY_FILE_PATH, the projection caveat).

Dependencies / stacking

A code-review pass fixed two use-after-free hazards (callbacks outliving the module; context destroyed before the map it owns) and documented a known limitation (the flat SimpleGeographicCoordinateSystem vs. the ellipsoidal map placement drifts with distance from the origin — a map-SRS-derived coordinate system would remove it).


Open in Devin Review

tabgab and others added 7 commits July 6, 2026 17:42
Detailed, phased, implementable plan for running INET sims on real
geospatial data (imagery + elevation) via Pelican Mapping's Rocky (the
VSG successor to osgEarth). Mirrors INET's existing OSG geospatial trio
(SceneOsgEarthVisualizer / OsgEarthGround / IGeographicCoordinateSystem)
for VSG. Front-loads two de-risking spikes (macOS/MoltenVK build; Rocky
rendering under our off-screen VSG path) with GO/NO-GO gates and a
physics-first fallback that reuses the LIDAR Heightfield + ground-mesh
render if live Rocky rendering proves infeasible off-screen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sgEarth successor)

New IGround backed by the Rocky SDK: opens a GDAL-openable elevation
source (e.g. a GeoTIFF DEM) and samples it with rocky::ElevationSampler,
converting scene<->geographic through an IGeographicCoordinateSystem —
the same pattern as OsgEarthGround, but headless and OSG-free. So
TwoRayGroundReflection and any other IGround consumer work over real
terrain with no changes to them.

Build wiring in src/makefrag: a WITH_ROCKY option (off by default) adds
Rocky's include/lib (ROCKY_ROOT prefix) and defines WITH_ROCKY via a -D
flag kept in the same CFLAGS as the include path. INET builds unchanged
with WITH_ROCKY unset.

Verified on macOS/arm64 against VSG 1.1.15 / Vulkan 1.4.350 / MoltenVK:
librocky links into libINET, and the examples/environment/rockyground
smoke test runs headlessly — RockyGround opens a DEM and returns the
correct ground elevation at sampled scene points in a live simulation.

DEV NOTES (for upstreaming): ROCKY_ROOT is a hardcoded local prefix
(use pkg-config/a configure check instead); Rocky itself currently needs
three local source patches on macOS (a GDAL 3.13 CSLConstList fix, ImGui-off
build guards, and a CoreFoundation/Security link line) that should go
upstream to pelicanmapping/rocky. A .oppfeatures feature and the live-map
SceneRockyVisualizer (needs an omnetpp-dev viewer hook) are follow-ups.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… 3D view

Renders real geospatial imagery + terrain in Qtenv's VSG view using Rocky (the
VSG successor to osgEarth), the rendering counterpart to RockyGround's physics.
Extends SceneVsgVisualizer, so all the usual scene setup still applies; on top of
it the Rocky map is built against the live vsg::Viewer and placed under the nodes.

How it works:
 - The OSG plugin pages terrain from the OSG viewer's own frame loop; Rocky (VSG)
   instead needs the live viewer (to build a VSGContext) and an explicit per-frame
   update() to page/compile tiles. Both come through the VsgScene3DNode render hook
   the backend now publishes (omnetpp-dev): onViewerChanged -> (re)build the map;
   a per-frame callback -> vsgcontext->update().
 - Layers are GDAL files (imageFile/elevationFile) and/or online TMS endpoints
   (imageUrl/elevationUrl, e.g. readymap.org), so it works offline from a local
   GeoTIFF or streams real Earth tiles over the network.
 - Rocky's geocentric (ECEF) map is transformed into the scene's local ENU frame,
   anchored at an IGeographicCoordinateSystem's origin, so it sits under the nodes.
 - ROCKY_FILE_PATH (rockyResourcePath) is set so Rocky finds its shaders.

examples/visualizer/vsgrocky: RockyMapShowcase with a synthetic-tile [General]
config (offline) and a [Config RealMap] that streams San Francisco Bay imagery +
elevation from readymap.org.

Verified on macOS/arm64: real Earth imagery + terrain render in Qtenv, hosts
georeferenced on the map, no teardown crash. KNOWN LIMITATIONS (navigation, not
physics): the generic orbit camera fights Rocky's globe-oriented tile paging, so
zoomed-out framing and tile LOD are rough; node billboards show the clear colour
in their background. Both are follow-ups; the geospatial rendering itself works.
Needs INET built with WITH_ROCKY=yes and the omnetpp-dev VSG viewer hook.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Set the camera manipulator to OVERVIEW so the Rocky map opens looking straight
down and stays top-down through wheel zoom, so panning out shows more map rather
than the horizon (with the omnetpp-dev fix that honors the manipulator on the
initial view). Pairs with the sky-colour backdrop already set here.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- SceneRockyVisualizer: insert the map at the FRONT of the scene so the opaque
  terrain draws before the transparent node icons; otherwise the icons write
  depth that occludes the map in their billboard quad and their transparent
  pixels show the background clear colour instead of the map.
- examples/visualizer/vsgrocky: add a [Config Communication] where three hosts
  actually exchange UDP traffic over the real map (idealized unit-disk radios,
  deterministic 4 km range) with the radio signals, communication ranges and
  packet route drawn on the map. Make the network's radioMedium swappable
  (like IRadioMedium) so the config can select the idealized medium.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The idealized unit-disk radio does not produce the transmission waveform the
medium visualizer's signal spheres animate, and the config was missing
signalWaveShader entirely - so no spheres appeared. Switch the Communication
config to the same wireless + visualizer recipe as the vsglidar drone demo,
whose spheres render correctly: realistic 802.11 ad-hoc radios (the network's
default Ieee80211ScalarRadioMedium + Ieee80211MgmtAdhoc, transmit power boosted
to bridge the ~1 km node spacing) and signalWaveShader = true, with
signalFadingDistance / signalWaveLength scaled up so the pulsing spheres are
sized for the km-scale map. Hosts moved into a ~800 m triangle so all links are
in range. Verified: host3 receives host1's UDP packets and the signal spheres
render over the map.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes found in code review:
 - Guard the callbacks registered on the (parent-owned, longer-lived)
   VsgScene3DNode with a shared 'alive' flag, cleared in a new destructor, so
   they no-op instead of using freed memory after the visualizer submodule is
   destroyed (submodules are destroyed before their parent -> use-after-free).
 - In the resize/rebuild path, release the old MapNode BEFORE recreating the
   VSGContext it depends on (the old code destroyed the context/device while the
   old map's GPU resources were still alive -> Vulkan validation error/leak).
 - Clearer error when the canvas has no 3D scene at all vs. a wrong backend.
 - Document the ellipsoidal-map vs. flat-SimpleGeographicCoordinateSystem
   projection mismatch that grows with distance from the origin.

Add ROCKY-VSG-GUIDE.md: a developer guide covering RockyGround (terrain physics),
SceneRockyVisualizer (map in the 3D view), the VsgScene3DNode render hook for
custom Rocky visualizations, and the gotchas (topocentric/WGS84/cull-radius,
ROCKY_FILE_PATH, no raw VSG lines off-screen, the projection caveat).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Open in Devin Review

Comment thread src/makefrag Outdated
# DEV NOTE: ROCKY_ROOT below is a local development default; for upstreaming, resolve
# it via pkg-config / a configure check instead of a hardcoded path.
WITH_ROCKY ?= no
ROCKY_ROOT ?= /Users/gabortabi/rocky-install

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Developer-specific hardcoded path in makefrag default

The ROCKY_ROOT default at src/makefrag:89 is set to /Users/gabortabi/rocky-install, a developer-specific macOS path. While it uses ?= (overridable) and has a comment acknowledging it's a "local development default", this should be cleaned up before merging to avoid confusion. Other optional dependencies in this file (VoipStream, Z3) use pkg-config or system defaults rather than hardcoded developer paths.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

*.visualizer.sceneVisualizer.coordinateSystemModule = "^.^.coordinateSystem"
*.visualizer.sceneVisualizer.imageFile = "img.tif"
*.visualizer.sceneVisualizer.elevationFile = "dem.tif"
*.visualizer.sceneVisualizer.rockyResourcePath = "/Users/gabortabi/rocky-install/share/rocky"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Same developer-specific path hardcoded in example ini

The rockyResourcePath at line 16 is hardcoded to /Users/gabortabi/rocky-install/share/rocky. This will fail for any other developer or CI system. Consider using an environment variable fallback or a relative path, or at minimum documenting that this must be changed.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- src/makefrag: ROCKY_ROOT defaults to pkg-config's prefix or /usr/local instead
  of a developer-specific path, and is meant to be overridden on the command line;
  add a friendly $(error) when WITH_ROCKY=yes but the Rocky SDK is not found under
  ROCKY_ROOT (instead of a cryptic compiler failure).
- examples/visualizer/vsgrocky: drop the hardcoded rockyResourcePath; document
  setting the ROCKY_FILE_PATH environment variable instead (portable / CI-safe).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@tabgab

tabgab commented Jul 6, 2026

Copy link
Copy Markdown
Author

Thanks — both valid, fixed in bbf9915:

  1. src/makefrag hardcoded ROCKY_ROOT — no longer a developer-specific path. It now defaults to pkg-config --variable=prefix rocky (if Rocky ships a .pc) or the standard /usr/local, is meant to be overridden on the make command line (make WITH_ROCKY=yes ROCKY_ROOT=/path/to/rocky-install), and a $(error …) with a helpful message now fires if WITH_ROCKY=yes but the Rocky SDK isn't found under ROCKY_ROOT (instead of a cryptic compiler failure).
  2. examples/visualizer/vsgrocky/omnetpp.ini hardcoded rockyResourcePath — dropped; the example now documents setting the ROCKY_FILE_PATH environment variable instead (portable / CI-safe).

The same personal paths existed in the companion omnetpp-dev PR (the vsg-satellites sample makefrag + ini) and are fixed there too — omnetpp/omnetpp-dev#8 (59be657d99).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant