Feat/light source component#2007
Open
Dogebusters wants to merge 11 commits into
Open
Conversation
Registers the new `light_source` component module so it is compiled and can be imported by the rest of the crate. Signed-off-by: MeanGreenDoge <118309896+Dogebusters@users.noreply.github.com>
Added `LightSource` to `SceneUpdateState` so the scene runner can process light component updates in order with the rest of the SDK components. Signed-off-by: MeanGreenDoge <118309896+Dogebusters@users.noreply.github.com>
Adds `LightSource` to the scene processing loop so light component updates are applied through the regular time-budgeted component pipeline. Signed-off-by: MeanGreenDoge <118309896+Dogebusters@users.noreply.github.com>
Adds a Lights Debug section to the Dev Tools settings panel with controls for enabling lights, shadows, debug gizmos, auto activation range, global light budget, and max active lights. + seperator for LiveKit Signed-off-by: MeanGreenDoge <118309896+Dogebusters@users.noreply.github.com>
The local avatar periodically updates `DclLightSourceComponent` with its global position, which is used as the reference point for light activation range and budget decisions. Signed-off-by: MeanGreenDoge <118309896+Dogebusters@users.noreply.github.com>
This PR adds the runtime side of the DCL Light Source component. The new `DclLightSourceComponent` is responsible for creating and updating Godot lights from scene-authored light data, while keeping rendering controlled by runtime settings, avatar distance, and a global light budget. ### What this adds - Adds support for runtime-created DCL point and spot lights. - Point lights are represented as `OmniLight3D`. - Spot lights are represented as `SpotLight3D`. - The component keeps the authored entity transform as the source of truth and does not apply extra local rotation to the generated Godot light. - Adds global runtime light settings. - Lights can be enabled or disabled globally from the settings/debug UI. - Shadows can be toggled separately from light rendering. - The maximum number of active DCL lights can be changed at runtime. - Debug gizmos, auto activation range, and global light budget can be toggled independently. - Adds avatar-distance-based light activation. - DCL lights only render when the local avatar is inside the calculated activation range. - The activation range uses the authored light range, and can optionally be expanded based on intensity. - Debug gizmos remain visible even when the actual `Light3D` is not rendering, making it easier to inspect inactive lights. - Adds a global light budget. - All registered DCL lights are ranked by distance to the local avatar. - Only the closest `max_active_dcl_lights` candidates are allowed to render. - Lights outside the avatar activation range are excluded from the budget. - This avoids enabling too many real Godot lights at once while still allowing scenes to define multiple lights. - Adds projector texture support for spot lights. - Spot lights can receive a projector texture. - Projector textures are loaded from local resources or HTTP URLs. - HTTP-loaded projector textures are cached globally to avoid loading the same texture multiple times. - Loaded projector textures are resized to a fixed resolution before being assigned. - Handles the Godot projector/shadow limitation. - Godot requires `shadow_enabled = true` for `light_projector` to work. - Because of that, disabling DCL light shadows does not always disable `shadow_enabled` directly. - Instead, dynamic shadow casting is disabled through `shadow_caster_mask`. - This allows projector lights to keep working while still preventing dynamic shadow casters when shadows are disabled. - Adds debug visualization for DCL lights. - Spot lights show fixed-size outer and inner cone gizmos. - Point lights show a fixed-size sphere gizmo. - The gizmos intentionally do not scale to the real light range, so they stay readable in the scene. - A status marker shows whether a light is active, out of range, or inside range but blocked by the light budget. - Debug labels show intensity, authored range, computed activation range, projector texture path, and budget rank/distance. - Adds runtime state separation. - Rust/runtime code can disable individual lights without fighting the avatar-range and global settings logic. - The component keeps separate flags for global system state, rendering state, per-light runtime state, shadow state, range activation, and budget activation. ### Why DCL scenes can now define Light Source components, but enabling every authored light directly would be too expensive and difficult to debug. This implementation adds the rendering bridge to Godot while also introducing runtime controls to keep the feature safe for performance. The activation range and global light budget make sure only relevant nearby lights are rendered. The debug gizmos make it possible to inspect scene-authored lights even when the real `Light3D` is currently disabled by range, budget, or global settings. Signed-off-by: MeanGreenDoge <118309896+Dogebusters@users.noreply.github.com>
This adds the Rust-side processing for the SDK `LightSource` component and connects it to the Godot runtime component. The new `light_source.rs` module reads dirty `LIGHT_SOURCE` CRDT updates, creates a `LightSource` Godot node when needed, updates it when the component changes, and removes it when the component is deleted from the entity. ### What this does - Processes dirty `LIGHT_SOURCE` LWW component updates from the scene CRDT state. - Ensures each entity with a `LightSource` component has a matching Godot `LightSource` child node. - Instantiates `res://src/decentraland_components/light_source_component.tscn` for new light components. - Calls into the GDScript `DclLightSourceComponent` API to configure the actual runtime light. - Removes and frees the Godot light node when the SDK component is removed. - Respects the scene processing time budget by stopping mid-batch and re-queuing the remaining dirty light updates. ### Light mapping The SDK light data is mapped into the Godot runtime component as follows: - `PbLightSource.color` is converted into a Godot `Color`. - `intensity` falls back to `300.0` when not provided. - `range` falls back to `15.0` when not provided. - `Point` lights call `set_point(...)` on the Godot component. - `Spot` lights call `set_spot(...)` with inner and outer angles. - Unknown or missing light types fall back to point lights. ### Projector / shadow mask texture support For spot lights with `shadow_mask_texture`, this code resolves the authored texture source into a usable Godot texture path. - Scene-local paths are resolved through the scene content mapping. - If a matching content hash is found, the final URL is built from the scene content base URL. - The original authored path is also passed to Godot as the display path for debug labels. - The Godot component only reloads the projector texture when the resolved path changes. This keeps runtime texture loading in GDScript while Rust remains responsible for resolving scene content paths. ### Why the node is added before setting texture/debug data When a new light node is created, it is added to the entity node before configuration: ```rust node_3d.add_child(&new_light_node.clone().upcast::<Node>()); Signed-off-by: MeanGreenDoge <118309896+Dogebusters@users.noreply.github.com>
Added a new Lights Debug section to the Dev Tools settings panel. This exposes runtime controls for the Light Source system: - Enable / disable scene lights rendering. - Enable / disable light shadows. - Toggle light debug gizmos. - Toggle automatic activation range calculation. - Toggle the global light budget system. - Adjust the maximum number of active lights using a stepper control. The settings UI now syncs its initial state from `DclLightSourceComponent.get_light_settings()` and applies changes through `DclLightSourceComponent.apply_light_settings(...)`, so all existing light instances are updated immediately when a setting changes. The max active lights control is clamped between 0 and 64 and its plus / minus buttons are disabled at the boundaries. The stepper layout also adapts for portrait mode. Signed-off-by: MeanGreenDoge <118309896+Dogebusters@users.noreply.github.com>
I accidentally placed the file in the wrong path initially, so I moved it to `scene_runner/components/light_source.rs`. Signed-off-by: MeanGreenDoge <118309896+Dogebusters@users.noreply.github.com>
kuruk-mm
requested changes
May 11, 2026
kuruk-mm
left a comment
Member
There was a problem hiding this comment.
Hi @Dogebusters! Thank you for the contribution! This looks amazing.
We are not planning to implement Light Source at the moment due to performance concerns.
We plan to work on Renderer performance improvements over the coming weeks/months, as this is our current priority.
If you really want this to be merged, please:
- Publish benchmark metrics so we can understand how much performance drops with lights enabled compared to without lights. You can check our current benchmarks in the code. Usually @manuelmaceira runs them, so you can look at his PRs and the tooling we have for that in the repo.
- Add an option to enable/disable lights in the graphics settings, and make sure it is turned off by default. Please do not attach it to any profile.
Once we have benchmarks that validate the performance impact is acceptable, we can review the code.
Another option is to wait, and we can revisit this PR after July/August or after the performance improvements are completed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Scene LightSource support, runtime controls, and debug tooling
Summary
This PR adds runtime support and debugging tools for scene-authored
LightSourcecomponents.It introduces a Godot-side
LightSourcecomponent that renders scene-authored point and spot lights, supports projector / shadow-mask textures for spot lights, and exposes runtime controls through Settings. The goal is to make scene lighting visible, testable, and safe to run on mobile.The implementation focuses on three areas:
Runtime LightSource rendering
Performance guardrails
Developer validation tools
What was added
LightSource component support
This PR adds a reusable
LightSourcescene node backed byDclLightSourceComponent.The component supports:
OmniLight3D,SpotLight3D,LightSourcecomponent is removed from CRDT state.The Rust scene update pipeline now processes the
LightSourcecomponent as part of the regular scene update state machine, creates the Godot light node when needed, updates it when CRDT data changes, and removes it when the component is cleared.Runtime light controls
Settings now expose runtime controls for scene lights.
These controls are intentionally runtime-editable, so developers can test lighting behavior without restarting the client or changing scene code.
Runtime behavior
Player/avatar-based activation range
Scene lights are only rendered when the player/avatar reference position is inside the light activation range.
The activation range can come from either:
This keeps lights outside the relevant player area disabled, while still allowing important bright lights to become active even if their authored range is small.
Auto Activation Range
Some scenes author lights with high intensity but relatively small range values. In practice, those lights may still need to be considered relevant from farther away.
When Auto Activation Range is enabled, the component computes an additional intensity-based activation range and uses the larger of:
This helps bright lights activate more consistently without forcing every authored light to be active globally.
Global light budget
The global light budget keeps only the closest eligible lights active up to the configured limit.
A light is considered eligible when:
Eligible lights are sorted by distance to the avatar/player reference position. Only the closest
max_active_lightsare allowed to render.This prevents scenes with many authored lights from enabling all of them at once, which is especially important on mobile.
Shadow handling
The implementation separates light visibility from dynamic shadow casting.
This is needed because Godot requires
shadow_enabled = trueforSpotLight3D.light_projectorto work. If shadows are disabled by the developer setting, projector lights may still keepshadow_enabled = trueso the projector texture works, while dynamic shadow casters are removed throughshadow_caster_mask.This allows:
Projector / shadow-mask textures
Spot lights can use a projector texture from the authored
shadow_mask_texture.The implementation:
SpotLight3D.light_projector.This is useful for scenes that rely on shaped light masks, projected patterns, or authored spotlight effects.
Light Debug Gizmos
Light Debug Gizmos make scene-authored lights visible in the world for validation.
The gizmos show:
The status marker uses:
This makes it much easier to debug scenes where lights are invisible, too far away, budgeted out, hidden inside scene geometry, or unexpectedly expensive.
Settings integration
The Light Debug tools are exposed through the Dev Tools section in Settings.
This gives developers a quick way to validate lighting behavior without code changes:
The UI also adapts the max-active-lights stepper size for portrait vs. landscape layout.
Why this is needed
Some scenes already author
LightSourcedata, but without runtime support and debugging tools it is difficult to validate whether lights are:This PR makes scene-authored lighting visible and controllable while adding guardrails for performance.
The result is a safer path to enabling scene-authored lighting across desktop and mobile.
Validation scope
Visual validation was performed across multiple scenes and coordinates:
rituals.dcl.ethdoriangray.dcl.eth41,55 4RCjeffgoldblum.dcl.eth148,49 RAGEMobile screenshots were captured on Nothing Phone (1).
Visual validation
Dev Tools UI
The Light Debug tools are exposed through the Dev Tools section in Settings.
Lighting state validation
The same scene setup was validated with lighting disabled, lighting enabled without shadows, and lighting enabled with shadows.
Light Debug Gizmos reveal hidden or hard-to-identify lights
Activating Light Debug Gizmos makes previously hidden or hard-to-identify light entities visible in the scene. In some scenes, there are more authored lights than expected. Genesis Plaza is a good example: even with light rendering disabled, these LightSource entities still exist and have to be created, tracked, and updated, so they can still add scene overhead before they ever contribute visible lighting.
Mobile visual validation
All screenshots below were captured on Nothing Phone (1).
rituals.dcl.ethOpen scene: rituals.dcl.eth
Scene comparison A
Scene comparison B
doriangray.dcl.ethOpen scene: doriangray.dcl.eth
Low graphics
Medium graphics
High graphics
41,55/4RCOpen scene: 41,55
jeffgoldblum.dcl.ethOpen scene: jeffgoldblum.dcl.eth
148,49/RAGEOpen scene: 148,49
Light Debug Gizmos enabled
Medium graphics comparison