Vienna-WebGPU-Engine

Scene Editor

A dockable, live scene editor built on the engine (examples/scene_editor/). It renders the scene to an off-screen texture inside a viewport panel, lets you build and edit a scene graph, configure materials/shaders/engine settings, save and load projects, and compile a project into a standalone game.

This guide describes how to use it and how it maps onto the engine APIs. It is a companion to GettingStarted, EngineArchitecture and NodeTypeSystem.


Build and run

:: Windows
scripts\build-example.bat scene_editor Debug WGPU
examples\build\scene_editor\Windows\Debug\SceneEditor.exe
# Linux / macOS
scripts/build-example.sh scene_editor Debug WGPU

In Debug builds the engine resolves paths against the repo via the DEBUG_ROOT_DIR / ASSETS_ROOT_DIR compile definitions, so the editor’s Resources root is <repo>/resources and its Assets root is examples/scene_editor/assets.

If a build’s final link fails with LNK1168: cannot open SceneEditor.exe, an instance is still running - close it (or taskkill /F /IM SceneEditor.exe) and rebuild.


The interface

The editor uses an ImGui dockspace. Panels are toggled from the Window menu; Window → Reset Layout restores the default arrangement and re-shows them all.

Panel Purpose
Viewport The rendered scene (off-screen texture). Camera navigation, gizmo, picking.
Hierarchy The scene graph tree. Add / delete / reparent / rename nodes.
Inspector Edit the selected node: name, enabled, transform, and type-specific data (light / camera / model + material).
Assets File browser over Resources (read-only) and Assets (editable), plus model import and shader creation.
Settings Engine settings (frame / physics / rendering / window / audio) + project name, startup scene, per-scene override.
Log Captured spdlog output: sortable, filterable, copyable.

Each panel’s close button (and the Window-menu checkbox) hides/shows it.


A camera selector sits at the top-right of the Viewport:

Focus (F) frames the editor camera on the selected node (free-fly only).

Camera input reaches the editor even while the viewport is focused because the engine forwards input unless an ImGui text field is active (it gates on io.WantTextInput, not the broader capture flags).


Selecting and transforming

Gizmo shortcuts default to Ctrl+1 / Ctrl+2 / Ctrl+3 (move/rotate/scale) and Ctrl+4 (toggle space); rebind them in Edit → Keyboard Shortcuts.


The scene graph (Hierarchy)

The editor camera and its controller are flagged non-serializable, so they never appear in saved scenes.


Materials and textures

The Inspector’s Material section (for a ModelRenderNode) reads the material on the model’s first submesh:

If you assign a texture that lives outside the asset/resource roots, a Copy Into Assets dialog offers to copy it into assets/textures/ and use the portable engine path, keeping the project self-contained.

Material edits propagate automatically: Material::setTexture/setShader/... bump a version that the per-material GPU bind group syncs from next frame.


Shaders

Assets → New Shader starts a shader from a known-good template (a Material or Post-process base, with the engine includes + lighting already filled in), writes it under resources/shaders/, builds it via the reflection-driven ShaderDescriptor path, and registers it so it appears in the material shader picker.


The asset browser

Two roots:

Per file: double-click opens it (Resources → your editor; Assets → the OS file browser), and right-click gives Open / Rename / Delete plus Show in Explorer and Copy asset/resource path. Open with selects the editor used (OS default app or VS Code).

Listings are cached; Reload re-reads now and Auto-refresh polls every ~2 s so externally-added files appear on their own. Drag a file from either tree onto an input field or material slot to assign it.

Paths and engine tokens

Asset references are stored as portable engine path tokens:

The inspector shows the relative engine path; right-click it to copy as asset/resource path, relative path, or absolute path. Resolution is case/separator-robust on Windows (PathProvider::toEnginePath / resolveEnginePath).


Scenes vs Projects

A Scene (scene.json) is a node tree. A Project (project.json) ties together the engine settings, the list of scenes, and the startup scene.

Scene (File menu):

Project (Project menu): New / Open / Save Project, and Build Game….

Settings and per-scene overrides

The Settings panel edits the project’s engine settings; Apply pushes them to the running engine and stores them on the project. Tick Override engine settings for the current scene to store the values on the active scene instead. The effective settings a scene runs with are:

effective = project settings  (+ that scene's override, if present)

GameEngineOptions is JSON-serializable (engine::settings::toJson/fromJson); the runtime-changeable fields (vsync, frame cap, MSAA, window, …) apply live via GameEngine::setOptions.


Build Game (compile to a standalone game)

Project → Build Game… compiles the current project into a runnable game:

  1. Saves the project (project.json + the current scene).
  2. On a background thread, builds the runtime player in Release (scripts/build-example.bat runtime_player Release WGPU), streaming the build output into the Log (lines prefixed [build]).
  3. Stages the engine resources/ + the project’s assets/ + project.json next to the produced RuntimePlayer.exe.

The result is a self-contained folder (examples/build/runtime_player/Windows/Release/) whose RuntimePlayer.exe loads assets/project.json, applies the settings, and runs the startup scene - no editor.

Requirements / caveats:


The Log panel

Captures all spdlog output through an editor sink. The table is sortable (Time / Level / Module / Message), filterable by minimum level and text, Copy-able (whole filtered view, or a single line via right-click), and auto-scrolls when at the bottom. Clear empties it.

On an unhandled crash the editor writes a recovery scene to crash_recovery/scene.json so work is not lost.


Keyboard shortcuts

Action Shortcut
New scene Ctrl+N
Open scene Ctrl+O
Save scene Ctrl+S
Duplicate node Ctrl+D
Focus selected F
Gizmo: move / rotate / scale Ctrl+1 / Ctrl+2 / Ctrl+3 (rebindable)
Gizmo: toggle World/Local Ctrl+4 (rebindable)
Camera look / move / up-down / sprint Right Mouse / WASD / Q-E / Shift

(See Edit → Keyboard Shortcuts for the live reference and to rebind the gizmo keys.)


Under the hood

The editor is engine-thin: it drives public engine APIs and adds no serialization logic of its own.

Concern Engine API
Scene save/load, clone, export engine::scene::SceneSerializer (save, load, exportSelfContained, cloneNode)
Node types + missing-type fallback engine::scene::NodeTypeRegistry, PlaceholderNode
Project file engine::Project + engine::ProjectSerializer
Engine settings (de)serialize engine::settings::toJson/fromJson, GameEngine::getOptions/setOptions
Portable paths engine::core::PathProvider engine path tokens
Off-screen viewport CameraNode::setOffscreenOnly/setRenderSize, Renderer::getCameraOutputTexture
Standalone game examples/runtime_player

Editor source (examples/scene_editor/):

Native helpers are confined to the example: tinyfiledialogs (file/save dialogs, message boxes) is only compiled/linked into SceneEditor/RuntimePlayer, not the engine library.


Known limitations