Skip to content

feat(ecs): wire ECS components into render scene and light pipeline - #656

Merged
JeanPhilippeKernel merged 9 commits into
developfrom
feat/ecs-render-bridge
Aug 24, 2026
Merged

feat(ecs): wire ECS components into render scene and light pipeline#656
JeanPhilippeKernel merged 9 commits into
developfrom
feat/ecs-render-bridge

Conversation

@JeanPhilippeKernel

@JeanPhilippeKernel JeanPhilippeKernel commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Summary

Three commits — ECS → rendering bridge for issues #642, #643, and a follow-on default light.

TransformComponent → RenderScene (#642)

  • ECS::Systems::SyncECSToRenderScene(Scene&, float alpha, RenderScene&) — iterates TransformComponent + MeshComponent, interpolates position with fixed-timestep alpha, builds Mat4f via ComposeTransformMatrix, calls SetInstanceTransform
  • Called from Engine::MainThreadRun after the fixed-step loop, before PrepareScene

LightComponent → LightArrayUBO (#643)

  • ECS::Systems::SyncECSToLights(Scene&, RenderScene&) — iterates LightComponent + TransformComponent
  • Directional: extracts forward direction from rotation matrix column 2 (YXZ Euler)
  • Point: uses entity world position
  • Writes LightArrayUBO into RenderScene::PendingLights
  • AppRenderPipeline::RenderScene uploads PendingLights to GPU — replaces the hardcoded directional light

Default directional light

  • EditorScene::Initialize spawns a default DirectionalLight actor (white, intensity 3, -60° pitch / 30° yaw) so new scenes open lit

Test plan

  • Debug build clean
  • Import a GLB — mesh visible and lit without manual setup
  • Move actor via gizmo — transform updates correctly
  • Spawn a second light entity — both lights contribute
  • No light entities (delete default) → scene unlit (correct)

Closes #642
Closes #643

Add ECS::Systems::SyncECSToRenderScene — iterates all entities with
both TransformComponent and MeshComponent each frame, interpolates
position using the fixed-timestep alpha (PreviousPosition→Position),
builds a Mat4f via ComposeTransformMatrix, and calls
RenderScene::SetInstanceTransform for every registered instance.

Called from Engine::MainThreadRun after the fixed-step loop and before
PrepareScene, so the render thread always sees up-to-date transforms.

Closes #642
@JeanPhilippeKernel JeanPhilippeKernel self-assigned this Aug 24, 2026
@JeanPhilippeKernel JeanPhilippeKernel added area-rendering area-linux Work on Linux system area-window Work on Window system area-macOS Work on macOS system labels Aug 24, 2026
Add ECS::Systems::SyncECSToLights — iterates all entities with
LightComponent + TransformComponent each frame. Directional lights
extract their forward direction from the rotation matrix (column 2,
YXZ Euler order). Point lights use the entity's world position.
Writes the assembled LightArrayUBO into RenderScene::PendingLights.

AppRenderPipeline::RenderScene uploads PendingLights to the GPU
LightBuffer each frame, replacing the hardcoded directional light.

Closes #643
@JeanPhilippeKernel JeanPhilippeKernel changed the title feat(ecs): wire ECS TransformComponent/MeshComponent into RenderScene feat(ecs): wire ECS components into render scene and light pipeline Aug 24, 2026
New scenes no longer open dark after the hardcoded sun was removed.
EditorScene::Initialize spawns a directional light actor (intensity 3,
white, -60 pitch / 30 yaw) so geometry is visible without the user
manually adding a light first.
Add BuiltinMeshes.h/.cpp with CreateDirectionalLightMesh — generates
a 12-gon disc + 8 diamond rays in the local XY plane (the source face)
and a cross-section arrow along local +Z (light travel direction) for
360-degree visibility without a billboard shader.

EditorScene::Initialize ingests the mesh via AssetManager and gives the
default DirectionalLight actor a MeshComponent so the icon appears in
the viewport and rotates with the entity transform.
…zmo jitter

SyncECSToRenderScene ran after g_app->Update (where the gizmo fires),
overwriting the exact gizmo-set transform with an interpolated position
between PreviousPosition and Position — causing visible jitter whenever
an object was moved.

Two fixes:
  - TransformSyncSystem uses Position directly; alpha interpolation is
    deferred until fixed-timestep physics systems are active.
  - HierarchyViewUIComponent gizmo sets PreviousPosition = new_pos
    (not old_pos) so there is no divergence for SnapshotTransforms
    to amplify on subsequent frames.
Replace the one-off CreateDirectionalLightMesh free function with a
scalable table-driven system:
  - BuiltinMeshID enum (editor icons + future primitive shapes)
  - kBuiltinMeshTable: one entry per ID holds mesh UUID, material UUID,
    BuildMesh fn, and BuildMaterial fn
  - static_assert enforces table size == BuiltinMeshID::COUNT
  - RegisterBuiltinMeshes ingests all materials then all meshes in one call
  - BuiltinMeshUUIDParsed / BuiltinMaterialUUIDParsed for call-site lookup

UUID collision guarantee: third group '0000' is structurally impossible
for v4 random UUIDs (importers always emit third group starting with '4').

DirectionalLightIcon gains a yellow emissive material (ff000000-0001)
instead of borrowing whatever sits at slot 0.

EditorScene::Initialize simplified to two lines:
  RegisterBuiltinMeshes(&LocalArena)
  BuiltinMeshUUIDParsed(BuiltinMeshID::DirectionalLightIcon)
@JeanPhilippeKernel
JeanPhilippeKernel merged commit 4bacf04 into develop Aug 24, 2026
33 of 34 checks passed
@JeanPhilippeKernel
JeanPhilippeKernel deleted the feat/ecs-render-bridge branch August 24, 2026 10:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-linux Work on Linux system area-macOS Work on macOS system area-rendering area-window Work on Window system

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(rendering): wire LightComponent into LightArrayUBO feat(ecs): wire ECS TransformComponent/MeshComponent into RenderScene

1 participant