Skip to content

Add initial 2d lighting support - #26053

Draft
jgayfer wants to merge 14 commits into
bevyengine:mainfrom
jgayfer:sprite-lights
Draft

jgayfer wants to merge 14 commits into
bevyengine:mainfrom
jgayfer:sprite-lights

Conversation

@jgayfer

@jgayfer jgayfer commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Objective

This PR aims to showcase what the first step of first-party 2d lighting in Bevy could look like. This initial version adds 2d ambient light and 2d point lights.

While the solution is complete and usable, it's not (at this stage at least) intended as a merge candidate, but rather to help bring to life the approach outlined in the design doc.

Solution

For a full rundown, see the design doc on hackmd.

Testing

Lighting can be tested with the new 2d lighting example:

cargo run --example lighting_2d --features bevy_sprite_light

Showcase

2026-10-07.11-41-08.mp4

Claude Code was used in the research phase, specifically to compare and contrast a lot of the prior art that exists, and how they do or don't support the design goals outlined in the above document. The code was written by me, with some assistance from Claude Code, most notably to help put together the example. Documentation was written by me (with some of it lifted from how I originally wrote it in bevy_light_2d).

@jgayfer jgayfer added the A-Rendering Drawing game state to the screen label Oct 7, 2026
@jgayfer jgayfer mentioned this pull request Oct 7, 2026
@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible M-Release-Note Work that should be called out in the blog due to impact S-Needs-Goal This should have a C-Goal and should not continue until it has one labels Oct 7, 2026
Comment thread crates/bevy_sprite_render/src/tilemap_chunk/tilemap_chunk_material.wesl Outdated
jgayfer added 14 commits October 8, 2026 09:19
There's almost certainly more we'll want on a point light, but this is the
bare minimum we need to get something working with a reasonably sane API.
Not really needed yet, but might as well get all our patterns setup.
bevy_sprite_render does all our sprite rendering work, so it needs to
be the one to consume bevy_sprite_light.

This adds a top level flag for 2d lighting, so that it can remain opt in
until it's at the point where we can start including it in our 2d profile.
Nothing sophisticated going on here yet, but it's a good starting point.
To avoid breaking every 2d game ever, we're keeping the brightness at
full. This means users will need to turn down ambient light for lights
to have an effect, but I think I'm okay with that (especially when
compared to breaking everything is the alternative).
Because we don't need a different data shape (like a transform), we can
just extract the main world type.
We're sticking with a uniform buffer for now, as it gets us WebGL2 support
for free.

Obviously it's nice to not have a limit imposed on us here, but in reality
we'll likely need something more sophisticated than "one big storage buffer"
to get decent performance with that many lights anyway. Happy to kick
that down the road for now.
This gets a little bit messy with the feature flag, but should be
something we can remove soon.
Our builtin 2d materials all go through the same mesh 2d pipeline, so
it's mostly just a one line change (minus the shaderdef) to apply
lighting to each one.

Ambient light is already multiplied by it's brightness in the prepare
step, so we can just multiply it by the output color directly.
Now that the pieces are in place, let's render some lights.

Nothing too crazy here. For each vertex, check if we're in range of each
light. If we are, add in the amount of light, using the attenuation formula.

I used this same formula in bevy_light_2d, and have been pretty happy with
how it works. Though adding it back in made me realize we need to have a
falloff setting on the light itself.
This adds a level of customization to lights that really lets you make
them your own.

We changed from a Vec4 to Vec3 on our color to keep everything within 32
bytes. We weren't using the alpha on the color, so no harm done.
This color was changed so it's not really final. Renamed to output_color
to match how the sprite and material shaders work.

This branch has not been deployed

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

Labels

A-Rendering Drawing game state to the screen C-Feature A new feature, making something new possible M-Release-Note Work that should be called out in the blog due to impact S-Needs-Goal This should have a C-Goal and should not continue until it has one

Projects

Status: Needs SME Triage

Development

Successfully merging this pull request may close these issues.

3 participants