Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

[Unity3D] Realtime changes in baked light probes

A topic by Xelart game studio created Sep 17, 2020 Views: 3,782
Viewing posts 1 to 1
(1 edit) (+2)

Today we want to share with you about realtime changes in baked light probes in unity. It is something that is not very well known by unity developers but it improves the realism of your scenes without any major computational cost associated. Our new game Boliscape performs realtime changes in baked light probes for the old gold mine levels.

Before proceding let's see the scenario envolved here:

1 - You are developing a mobile game with the universal render pipeline (URP).

2 - You have light points in your scene that can change their position in runtime. Since there is no indirect realtime light bounces for light points in URP android, the faces of your dynamic objects that are not directly lit by the light points will receive zero light contribution from that light point. Look below how the top face of the cube in front of the oil lamp appears completely black. The same for the top faces of the wooden boards on both sides:

3 - You are not creating meshes in runtime so you are using baked lighting in your scene: your static objects get their lighting data from the lightmaps and your dynamic objects from the light probes you have configured.

With that being said, let's see below the entrance of the mine of the level considering that all static objects (mine rocks, wooden board supports were lightmapped using the static sun directional light):

As expected, as you can imagine that as you move inside the tunnel, it gets quickly darker and darker.

Since we want to "simulate" indirect lighting inside the tunnel when our light point moves inside it, we will, in realtime, increase the ambient light data of each light probe that appear close enough to the light point Also, when the light probe is considered too far from the light point, we do not increase the ambient light contribution of that light probe: this mean the light probe uses its default value: the one that was calculated by the global baked lighting algorithm and assigned to that light probe. With that said, you may understand now that the top of the dynamic cube will not appear fully dark anymore:

You may have noticed from the image above, that also the top faces of the side wooden boards do not appear fully dark anymore. But how is it possible since these objects were marked as static??  You are right to ask since static objects with contribute GI checked do not receive global lighting data from light probes but only from their lightmaps. In fact, if you want the result shown above for the rocks and the wooden boards that were marked as static at the time of baking, we need to uncheck the option: contribute GI for these static objects, as done below:

This will make these static objects to not get its global lighting data from the lightmap anymore but now from lightprobes. For this tweak to work, you should not rebake the scene. If you rebake the scene,  all the light probes data will be recomputed and since all the mine rocks and wooden board supports would not be considered anymore as occluder for the baked lighting algorithm, the volume inside the mine tunnel would not appear dark anymore.

Yeah! Congratulations to make it till here! Now let's look at the fun part: the script that makes possible all we talked about above.

As you can see at line 3, we will use unity APIs from UnityEngine.Rendering namescape. These API calls will make it possible to modify the baked light probes data at runtime. Color AmbientLightColor is a color we set in the unity editor that represents the max ambient light contribution made by the light point (tipically when the distance between the light point and the light probe is zero).  Field PointLight is set in the editor and represents the dynamic light point.

Field PointLightMinDistancePerformedToUpdateLightProbes can be seen as the light probes realtime refresh rate. Basically, for performance issues, we do not want to update the lighting data of all the light probes in our scene at every frame or so. We only refresh the light probes data after the light point has moved a distance we consider to be acceptable in our scene.

We also have a ratio that allow us to tweak the intensity of AmbientLightColor, called MineMaxAmbientLightIntensityContributionFromPointLight. Its value was also set in the editor.

MinePointLightMaxDistanceToLightProbe is a getter property that simply gives us the reach of the light point.

Field _pointLightLastPositionLightProbesUpdated stores the last position of the light point when the light probes were refreshed. We use this field to check if in the current frame we should refresh or not the light probes. The remaining fields contain the light probes data: their positions, their current lighting values and their default lighting values (calculated by the lightmapper, as we mentioned before).

As you can see above, when the script gets disabled (method OnDisabled()), we restore the light probes to their default value. Why we do that? Well, the changes performed in runtime are kept between multiple gaming sessions. This means that if you have other scene that uses the same lighting data, that scene will use the light probes data as modified at the last time by this script.

As you can see in method UpdateLightProbes(), we iterate over the different light probes and the ambient light contribution is linearly interpolated considering the distance between the position of light probe and the position of the realtime light point. Finally, in the last line of code of this method, we specify that from this frame and forward, use the realtime changes performed.

If you have seen the video above, you may have noticed that the light point intensity is not constant. We have not talked about it in this article since it is an easy effect to achieve: with a simple script, at every frame, interpolate the light intensity between two values: the desired lowest intensity and the desired highest intensity.

That's all for now! If you have any question, please leave a comment or send us an email to xelart.studio@gmail.com