Lysa Nodes  0.0
Lysa Nodes — Scene Graph for the Lysa Engine
Scene tree

lysa::nodes::SceneTree

SceneTree extends the engine's lysa::Scene (the GPU-facing scene container) and adds the node lifecycle, event wiring, and render-view management.

RotatingAssetScene derives from SceneTree directly; no intermediate custom class is needed:

class RotatingAssetScene : public lysa::nodes::SceneTree {
public:
explicit RotatingAssetScene(const lysa::RenderingWindow& window);
void onProcess(double alpha) override;
void onPhysicsProcess(double delta) override;
bool onInput(const lysa::InputEvent& event) override;
// ...
};

Attaching to a window

SceneTree::attach(renderingWindow) binds the scene tree to a rendering window. Internally it:

  1. Stores a pointer to the window and its render target.
  2. Calls subscribeEvents() which subscribes to PHYSICS_PROCESS, PROCESS, INPUT, RESIZED, PAUSED, and RESUMED.
  3. Adds the initial RenderView to the render target.
  4. Calls onAttach() and onReady() on the scene tree.
  5. Calls _ready() on every child already in the tree.

The attach call is made in the constructor of RotatingAssetScene after all other nodes except the camera hierarchy have been added:

RotatingAssetScene::RotatingAssetScene(const lysa::RenderingWindow& window):
SceneTree() {
addChild(std::make_shared<Environment>(...));
addChild(dirLight);
addChild(omniLight);
addChild(assetRoot);
// attach() first: the render target must be active so Camera::_attachToScene
// can read the aspect ratio and subscribe to RESIZED.
attach(window);
// Camera hierarchy added after attach.
addChild(cameraAttachment);
}
Note
The camera must be added after attach(). Camera::_attachToScene reads SceneTree::isAttached() to decide whether to set the initial aspect ratio. If attach() has not been called yet, isAttached() is false and the aspect ratio is never initialised, resulting in a zero-size projection matrix.

Event dispatch

Once attached, SceneTree owns all event subscriptions. Each tick it:

  1. Calls child->_physicsProcess(delta) on all top-level children (which cascades recursively), then calls onPhysicsProcess(delta) on itself.
  2. Calls child->_process(alpha) on all top-level children, then calls onProcess(alpha) on itself, then calls updateInstance on all MeshInstance descendants to push the new transforms to the GPU.
  3. Forwards InputEvent to onInput() and to all children via _input().
  4. On RESIZED, calls onResize().

The Application only needs to subscribe to PROCESS for the render() call:

lysa::ctx().events.subscribe(
lysa::MainLoopEvent::PROCESS,
[&](const lysa::Event&) {
window.getRenderTarget().render();
});

Because the scene tree subscribed to PROCESS before the Application (during attach()), the scene's handler — which updates all node transforms and GPU instance data — always runs before render().

SceneConfiguration

Pass a lysa::SceneConfiguration to the SceneTree constructor to tune GPU buffer sizes for large scenes:

lysa::SceneConfiguration sceneConfiguration {
.maxLights = 20,
.maxMeshInstances = 10000,
.maxPipelines = 50,
};
SceneTree(sceneConfiguration);

The default configuration suits scenes up to several thousand instances.

Next : Camera