Skip to content

Improve lights - #265

Merged
tychedelia merged 4 commits into
processing:mainfrom
tychedelia:lights-fixup
Nov 11, 2026
Merged

tychedelia merged 4 commits into
processing:mainfrom
tychedelia:lights-fixup

Conversation

@tychedelia

Copy link
Copy Markdown
Member

There were some weirdness with how lights previously worked:

  • We were spawning retained lights into the world without any boundaries around which graphics they applied to or when.
  • We had no way to do immediate mode lighting (see p5 spotLight and friends for example).
  • We had no ways to despawn lights or have a light handle.

The solution is to add the immediate mode methods as well as a light draw method that uses the light for a given frame. We keep track of these "frame lights" and create them as needed for a given flush. This is important because we need to be aware of when the transform changes, or when there are multiple flushes in a single frame. In other words, the light the user creates is more like a light descriptor and they can create as many light instances they want by calling light, weaving transform changes in between if they so choose.

Also cleans up some life cycles. We now have DrawTransient and FlushTransient which exist at different boundaries. So geometries get cleaned up inside a flush boundary but lights stick around for the entire draw frame.

Most of the changes in this diff are in the examples and can be ignored.

@tychedelia
tychedelia requested a review from catilac November 5, 2026 05:52
@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Visual regression: 2 changed of 43 cases

case status detail
py_flocking_gpu ❌ changed 7.92% of pixels differ
py_gltf_load ❌ changed 10.75% of pixels differ

If these changes are intentional, add the deliberate-rendering-change label.

baseline 94daefc7f8 · adapter llvmpipe (LLVM 20.1.2, 256 bits) (Vulkan, Mesa 25.2.8-0ubuntu0.24.04.4 (LLVM 20.1.2))

Open the visual report · workflow run

@catilac

catilac commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

the light gets dropped mid frame in certain edge cases. Here is a sketch to reproduce it:

My LLM suggested that using DrawTransient instead. But I can't validate this right now. Let me know what you think!

from processing_py import *

# Run once per value: "stored", "temp", "local"
MODE = "temp"

kept = None

def make():
    return create_directional_light((1.0, 1.0, 1.0), 4000.0,
                                    position=(0, 0, 1), look_at=(0, 0, 0))

def setup():
    global kept
    size(640, 360)
    mode_3d()
    no_stroke()
    fill(0.8)
    roughness(0.6)  # lit material; the default is unlit
    if MODE == "stored":
        kept = make()

def draw():
    background(0.2)
    if MODE == "stored":
        light(kept)          # control: the light is kept in a global
    elif MODE == "temp":
        light(make())        # freed as soon as light() returns
    elif MODE == "local":
        l = make()           # freed when draw() returns
        light(l)
    sphere(120, 60, 60)


run()

@catilac

catilac commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

mentioned this in discord, but adding here: tychedelia#4

@tychedelia

Copy link
Copy Markdown
Member Author

@catilac Yup that makes sense, I changed it to tag the light with DrawTransient in drop rather than immediately despawn. This makes sure it will get cleaned up before the next frame but matches our frame bound semantics for lights.

@tychedelia
tychedelia merged commit 803c75c into processing:main Nov 11, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants