Light Shaders

Lighting in a 2D game feels built in: you place a light and Godot does the rest. Most people think that is where your control ends. It is not. Learn what the light function does for every pixel and what Godot hands it, then use it to build a sweeping lighthouse beam and a ring that spreads out from a lamp. Part of a…

8:54 video10 min readWatch on YouTube

Light Shaders

Lighting in a 2D game feels built in: you place a light and Godot does the rest. Most people think that is where your control ends. It is not. Learn what the light function does for every pixel and what Godot hands it, then use it to build a sweeping lighthouse beam and a ring that spreads out from a lamp. Part of a series on Godot shaders. Liam, in for Bear, narrates.

Chapters 0:00 Opening 0:08 The question 0:19 Key terms 0:39 I · Lights in 2D 2:12 II · The Light Function 4:11 III · Which Way Is the Light? 5:08 IV · A Lighthouse 6:14 V · Where Is the Light? 8:02 Recap 8:23 Your turn

Your turn. Paste this into Claude: Write a Godot canvas item shader with a light function, for a sprite. A narrow beam sweeps clockwise around the lamp, once every two seconds. Use the built-in light direction and the built-in time, and keep the lamp's soft edge, color and energy. Add a uniform called width. Then point me to the lines that decide where the beam is. Then check two things yourself.

  • Check: the beam turns clockwise, once every two seconds, by your own stopwatch.
  • Check: delete the light node, and the beam disappears.

Sources

  • Godot 4.7 documentation, read 2026-10-13: 2D lights and shadows, CanvasItem shaders, shader functions, shading language (docs.godotengine.org/en/stable).
  • Godot 4.7.2 itself: every result on screen is a scripted capture of a real run, with its renderer stated.

Honest notes. The narration is a synthetic voice (Liam, in for Bear) and has not yet been reviewed by ear. The Godot documentation passage shown at 1:14 is a quote card of the docs text, recorded 2026-10-13, not a screenshot of the page. The numbers in the film were run in Godot 4.7.2 on an Apple M4 Pro. The facts have not yet been signed off by Bear. Nobody has watched this film yet.

Made with the brutalist.art toolkit: Manim, Remotion and Kokoro, free and local. An independent educational film.

What this video covers

  • 0:00 — Opening
  • 0:08 — The question
  • 0:19 — Key terms
  • 0:39 — I · Lights in 2D
  • 2:12 — II · The Light Function
  • 4:11 — III · Which Way Is the Light?
  • 5:08 — IV · A Lighthouse
  • 6:14 — V · Where Is the Light?
  • 8:02 — Recap
  • 8:23 — Your turn

Transcript

A lightly formatted transcript of the video, with timestamps so you can jump to any section on YouTube.

Opening

[0:00] Light shaders, learn what the light function does and what Godot hands it, then use it to build a sweeping lighthouse beam and a ring that spreads from a lamp. Hello, this is Liam in for

The question

[0:10] Bear. Lighting in a 2D game feels built-in. You place a light and Godot does the rest. Most people think that is where your control ends. It is not. A shader can replace it. Six terms. A

Key terms

[0:20] Shader is a small program the graphics card runs to decide how something is drawn. A pixel is one dot of the picture. A texture is an image a shader can read. The canvas is the surface 2D things are drawn on. A vector is a bundle of two to four numbers. And a mask is a number from zero to one for each pixel saying how much of something to show.

I · Lights in 2D

[0:39] In a 2D game, a light is a soft glow. Same scene, same light, and one function later that glow is a beam sweeping the ground. The function is called light, and before this film ends, you will have written it. Godot has two kinds of 2D light. A point light shines out from one spot like a lamp. A directional light shines the same way everywhere like the sun. This film works mostly with the lamp. A light needs a dim scene to show against. A 2D scene starts fully lit, so a light can only brighten what is already bright. Add a canvas modulate node, which tints everything, and set it dim. That tint is the ambient light. A soft glow is a texture. Godot's docs give the recipe. Give the light a gradient texture, set its fill to radial, and run the gradient from opaque white to transparent

White. The transparent part becomes the soft edge. A point light has a few settings. Its texture sets its shape. Its scale sets how far it reaches. Color tints it, and energy is how strong it is. Change each one, and the same lamp lights the same ground differently. Lights add. Two lamps overlapping make the overlap brighter, and three make it brighter still. Underneath the dim ambient stays put, whether a light reaches a pixel or not. Godot's rule measured. The pixel is the surface color times the total of the ambient and every light. A gray surface of 1/2, an ambient of 0.2, two lamps of 0.4 each, the pixel reads 1/2. A 2D shader can have three functions. Vertex places corners and fragment colors each pixel. The third light runs for every pixel and every light that reaches it and asks, "How much does this lamp add here?"

II · The Light Function

[2:13] Add a function called light to a shader and it replaces Godot's default lighting for that sprite, even an empty one. The lamp still lights the blob, but the ground ignores it. The function belongs to the sprite, not to the lamp. The smallest light function returns one flat answer, 0.2 gray. Add a lamp and this card brightens by 0.2. Add another and it brightens again. Light runs once for each lamp and Godot adds the answers. Inside light, Godot hands you built-ins, values written in capital letters. Color is this pixel's own color and UV is its address. Light color and light energy describe the lamp. You hand back one value, also called light, what this lamp adds. Light runs last. Fragment runs

First and sets the pixel's color, which arrives in light as the built-in color. Then light runs once for each lamp and Godot adds all the answers to the dim ambient look. That sum is the pixel. Rebuild Godot's default. The color is the surface times the lamp's color times its energy. The fourth number, alpha, passes straight through. Rendered both ways, the same scene differs in no pixel at all. That fourth number is the lamp's soft edge. The texture fades from one to zero. Force it to one and every pixel the texture covers is lit at full strength. The soft glow becomes a hard square. Now reshape it, round the fade down to quarters, and the glow becomes bands like cell shading. Same

Lamp, same ground, only the light function changed how the light fades. Or let time shape it. Multiply the light by the absolute value of a sine of time and the lamp breathes. No animation player and no game code, the shader does it every frame. One more switch, put render mode unshaded at the top and And sprite ignores every light and the ambient tint, too. That is right for the lamp's own bulb, otherwise it goes dim with the room. One caution, this copy matches the default shadows included, but the default also reads normal maps, images that say which way each pixel faces, and this copy ignores them. The docs show the extra term that fixes it. Change one thing at a time.

III · Which Way Is the Light?

[4:12] Now, direction, light direction is a vector, an arrow from this pixel toward the lamp, always length one. A pixel left of the lamp gets an arrow pointing right. A pixel above it gets an arrow pointing down. To see a number, use it as brightness. Take the arrow's X number from minus one to one and squeeze it into zero to one. Multiply the lamp by it. Left of the lamp, full strength. Right of the lamp, nothing. Turn that number into a mask with step. Step gives zero below an edge and one at or above it. Use an edge of zero, multiply the light by the result, and only the left half of the lamp stays on. Take the absolute value and both sides count. Raise the edge close to one, and only pixels where the arrow is nearly sideways survive. That leaves a wedge on the left and a wedge on the right. A directional light is different. Its arrow is the same for every pixel on screen, and its position is always zero. So, a direction mask lights everything or nothing. For a beam, use a point light.

IV · A Lighthouse

[5:08] To aim a beam, you need an arrow of your own. Cosine and sine of an angle make one, always length one. Turn the angle and the arrow turns with it. Then, compare two arrows with the dot product. It is one when they point the same way, zero at right angles, and minus one when they point opposite ways. Keep the pixels where it is close to one. Let time turn the angle and the wedge turns with it, a lighthouse. Two details, our arrow points at the lamp, so flip its sign. And because Y points down, a growing angle turns the beam clockwise. Make the cutoff the number inside

Step a uniform, a dial your game sets from outside. Lower it and the beam widens. Raise it and the beam narrows. Swap step for smooth step, which ramps between two edges instead of cutting, and the edge of the beam goes soft. Same lamp, same beam, a better look. Add a second lamp and light runs again for it with its own arrows. Two beams from one shader, each starting at its own lamp, each in its own color, and no extra code. A beam exists only where a lamp reaches. Outside the lamp's texture, Godot never calls light at all. For a longer beam, scale the lamp, not the shader.

V · Where Is the Light?

[6:14] Two more numbers. Light position is where the lamp is, and light vertex is where this pixel is. Both are in screen space, pixels of the window, counted from the top left with Y growing downward. Subtract the lamp's position from the pixel's, and you get an arrow from the lamp to this pixel. Its length is the distance between them in pixels. That is what the length function measures. Use that distance as brightness. Nothing at the lamp, a little more with every step away. Now, every pixel knows exactly how far it is from the light. Step the distance against a radius and the ground splits in two, inside and outside. Do it for two radii, subtract one

From the other, and what is left is the band between them, a ring. Put it together and the lamp lights only a band of ground. The distance, two steps, one subtraction, multiplied into the light. The radius and the thickness are uniforms, so the game can change both. Now, the game drives it. A tween moves a value smoothly over time. Set the radius to zero from code, then tween it out to the edge of the lamp, and a ring spreads from the light. This run is scripted, not player input. One warning, these are window pixels, so the ring does not follow your world. Zoom the camera in and the ground doubles in size, but a ring

Of 450 pixels stays 450 pixels. One more tool, mod. It counts up to a number, then starts over. Mod the pixel's X by 128, keep the first 16, and you get stripes. They belong to the screen, not the sprite. Slide the ground and they stay put. Do the same for Y and join the two with max. You get a grid of light line 16 pixels wide every 128 pixels drawn only where the lamp reaches. So, when does a job belong in light? When it depends on a lamp, its direction, its distance, its color. A pattern on the surface alone belongs in fragment and a wobble in the corners in vertex. Ask where the effect comes from.

Recap

[8:02] Let's recap with Claude. A pixel is its surface times the total of the ambient and every light. Writing light replaces the default and you can rebuild it exactly. Light direction is an arrow from the pixel toward the lamp. Aim an arrow, compare it with a dot and a mask becomes a beam. Light position and light vertex give a distance and distance makes rings. Those positions are window pixels, so they ignore your camera zoom.

Your turn

[8:23] Your turn. Paste this into Claude. Write a Godot canvas item shader with a light function for sprite. A narrow beam sweeps clockwise around the lamp once every 2 seconds. Use the built-in light direction and the built-in time and keep the lamp's soft edge color and energy. Add a uniform called width then point me to the lines that decide where the beam is. Then check two things yourself. Does the beam turn clockwise once every 2 seconds by your own stopwatch? And when you delete the light node, does the beam disappear? Light shaders at Nick Bear Brown.

More from CSYE 7270 Virtual Environments and Real-Time 3D

Nik Bear Brown Poet and Songwriter