Godot Light Sensor 3D
Do you need to find the total amount of light reaching a point in your Godot 4 3D project? Then you've come to the right place.
This asset contains a "light sensor" -- a tiny camera pointing at a tiny white plane that can be queried to determine how much light is reaching that plane. You can check the color, too, if you care about that.
How to Use
- Create a new node of type LightSensor3D.
- Move it to the point you want to measure light.
- Configure the layer.
- Call the refresh() method on it periodically, e.g. every second.
- Query it using the available properties, functions, and signals.
Positioning and Orientation
The sensor is not a single point in space, capable of reading detecting light in a sphere. It's a plane, which means a couple things:
- It's recommended to place the sensor low to the ground of your game.
- It's recommended to orient the sensor so the sensor is pointing "downwards" (this is the default).
These suggestions are assuming you're measuring the amount of light some point on the ground is receiving.
Configuring the Layer
The internal sensor mesh uses the layer you configure on the light sensor itself. You'll want to choose layer(s) based on the following principles:
- The layer shouldn't be visible to your main camera, otherwise you'll see a small white plane near the center of the sensor.
- The layer should be visible to the lights you want to register on the light sensor, otherwise you won't get the desired readings.
Calling the refresh()
Method
Refreshing the sensor's state is pretty expensive, since it requires downloading data from the GPU back to the CPU (see Texture2D#get_image). In my tests, it takes on the order of 0.2ms, which is potentially a big chunk of the frame budget if you have multiple sensors updating every frame. Therefore, it's recommended to only update as often as you need -- once every 250ms or even less often.
Calling refresh()
is left up to you. The easiest way to do this is to add a child node of the LightSensor3D of type Timer that:
- has a wait time of 1 second, or whatever your update frequency need is.
- does not have one-shot enabled.
- does have autostart enabled.
- and lastly and most importantly, triggers the parent node's
refresh()
method in thetimeout
signal.
There's an included example scene that does this that you can also check out.
Sanity Check
Things not quite working?
Check:
- that your light source is on the correct layer(s) and shadows are enabled. Layers are in the VisualInstance3D subsection, and shadows under Light3D > Shadow.
- that your shadow-casting meshes (e.g. MeshInstance3D) are on the expected layer, configured under VisualInstance3D again.
- that your LightSensor3D is targeting the layer that's casting light/receiving shadows configured above.
Outputs
name | type | description | |||
---|---|---|---|---|---|
property | color |
Color | This is the current color the sensor is seeing. | ||
property | light_level |
float | This is the luminance seen by the sensor. 0=dark, 1=bright. | ||
signal | color_updated | (color: Color) | Emitted when the current color changes. | ||
signal | light_level_updated | (luminance: float) | Emitted when the light level changes. | ||
Note that all of these require you to call refresh() before they'll be updated and triggered. |