Beautiful real-time illumination in video games greatly impacts the productivity, which can be critical for mobile devices. Therefore developers have to look for the ways to solve this problem. Lightmapping is a technology, that stores the lighting information in a texture, which saves a lot of computing resources. In this article I’ll explain how does the lighting in games work, I’ll also describe the process of creating a lightmap in Unity 5. Besides I’ll share a few tips on lighting.
Over the last few years I’ve been dealing with lightmapping a lot on both my job and my own indie-project. When your team is pretty small and you don’t have a lot of time to create unique graphics for your game locations, the lighting becomes one of the things, that help spice the game up.
Lighting in computer graphics divides into two categories:
There’s lots of ways to simulate realistic indirect light, 2 most well-known of them are Global Illumination (GI) and Final Gather (FG). You can use them separately, but you’ll get the best of them when used together. However, with great power comes great responsibility: rendering (i.e. the process of calculating and visualizing complex lighting) takes up huge amount of time.
Global Illumination (GI) is “the fairest” way to simulate the complex behavior of the light as it bounces and interacts with the world. Light source emits photons, i.e. particles carrying information about the color and brightness of the light. When striking a surface photons light it up, at the same time losing part of their energy, which alters the data (about color and brightness) they carry. Then the photons bounce off the surface and strike another surface, losing part of the energy again. It happens a few times depending on the rendering settings.
Final Gather (FG) This method scatters points (final gather points) around the scene, then the points cast around light rays (instead of photons). Rays sample the surrounding area and bring the brightness and color values back to the point. Picture that: late evening, the sun has almost set over the horizon; it’s getting dark, but small part of the room is still lit by orange sunset light. A final gather point on the floor casts around a few rays, some of which reach the lit part of the room and bring the information back to the point, at the same time slightly illuminating the floor with the indirect orange light. It’s not that “fair” compared to GI, but it gives good results, and is widely used to set up beautiful soft light for the scene.
For the following image I cranked up the indirect light parameters so you could see, how light particles bounce off the objects.
Besides the indirect light you need to know about Ambient Occlusion (AO). This is the effect of shading in the corners and cracks. Imagine a light ray striking a room corner: it will repeatedly reflect from both walls, gradually fading away. The farther away a corner is, the less light reaches there.
Usually Ambient Occlusion is used to artistically highlight the shading effect. In the reality light rays don’t lose their energy that fast for the room corners to be as dark, as we can see in games. If you are rendering physically correct lighting, your engine calculates the rate of energy loss for you, so you don’t need to render an Ambient Occlusion map for that. But you still can do it, if you need it to implement an artistic concept.
By the way, some 2D-artists like imitating this effect when drawing. Their work process is generally similar to creating 3D-graphics.
Another term you have to know is texture atlas. In a nutshell it’s a big texture, that holds smaller textures. Texture atlases are most often used to save computing resources. For example, there’s a tavern in your game. It has 20 wooden objects inside (tables, chairs, spoons etc.). Each of them has its own texture. As a result your CPU will request the GPU to render each object separately (20 times). If we assign one sole material to all 20 wooden objects, querying one texture atlas, that holds all 20 textures, the GPU will be able to render objects using only1 draw call (I’ll share interesting links on that topic in the end of the article).
In case of lightmapping there’s a small texture, created for every object in the scene. The lighting information is baked into each texture. After that thousands of small textures for different objects are put into bigger texture atlases. As well as with the wooden objects, the productivity increases.
Working with Unity
Let’s get back to the lightmapping in Unity. First of all arm yourself with patience and get a powerful computer, if you can. Rendering process usually takes up all processor and memory resources, that’s why I run it before I go to work or turn in. This way when I get back to the computer, the rendering process is already done.
Let me warn you that Unity is caching all the intermediate results of calculating. If you notice that your system disk decreased in size for10 Gb – that’s exactly it! To customize caching go to Edit — Preferences — GI Cache. You can set the path for saving and define maximum cache size. You might want to turn the compression off, it will take up more disk space, but the process will speed up. You can also clean cache, but be aware that if you have a scene with already calculated lightmaps, the lightmaps will be erased too. Be careful!
Unity provides us with 5 light source types:
All objects in Unity are either dynamic or static. Static objects are the ones that don’t move during the game. We can use baking for this type of objects. On the other hand dynamic objects are the ones, that move during the game. This includes heroes, monsters, a waving flag, a rolling stone etc. You can’t use lightmapping for this kind of objects, instead they are illuminated by either real-time light sources or using light probes (more details on this subject in the end).
Light source properties
Here I’ll highlight a few key properties of light sources (some light sources may have or not have particular properties).
Scene lighting properties
The Lighting Window (Window — Lighting) consists of 3 tabs: Object, Scene, Lightmaps. To run the rendering process click the “Build” button at the bottom of the window. There’s an “Auto” check too. This one helps you run rendering automatically every time you make changes to the scene; only check it if you have a powerful computer.
A bit lower the information about count and size of lightmaps is shown, it appears once the lightmapping process is finished.
The Object tab contains settings for a particular object. If you select an environmental object on the scene, you’ll see a list of properties and parameters. If the object is static, the “Lightmap Static” check is checked. The field you will use most often is “Scale in Lightmap”. As I already mentioned, every object gets its lighting baked into a separate little texture, which is later placed into a big lightmap-atlas. By changing this value, you can alter the amount of space the texture will take. Sure thing, the less space it takes, the worse baked lighting quality it’s going to have. The default value is 1.0, but if you know that the object is hardly and/or rarely seen, or it’s located far away, you can readily decrease this value down to 0.1 or even less.
The Scene tab contains all the key lighting settings. I am explaining ABCs of working with lighting, plus I’m sharing my experience on lightmapping particularly for mobile platforms. That’s why I intentionally leave out the things like Real-time GI and HDR-textures usage.
In Ambient Source you customize Ambient Light (the light that is present all around the scene and doesn’t come from any specific source object). You can choose either one of Skybox (sky is a texture), Color (uses a flat color for all ambient light in the scene), or Gradient (gradient based skies).
I prefer using the Gradient option. It lets you set 3 colors – sky, horizon and ground, which will create a pretty complex and interesting ambient light effect for your scene. Ambient Intensity sets the brightness of ambient light. Depending on your artistic idea, you can even have a really bright scene, only illuminated by Ambient Light itself.
In the Baked GI section you can find basic lighting quality settings for both direct and indirect light, including GI and FG.
Before we continue let me give you a little tip. You should always keep in mind, that when setting up light sources in the scene, customizing shadows and Ambient Light, eventually (after the lightmaps rendering is done) you will get something completely different from what you’ve expected, slightly reminding the image you’ve seen in the scene. Therefore I recommend you working iteratively:
1) set lighting quality to minimum, so the rendering process runs quickly; 2) check out the result; 3) make changes and restart the rendering process. When you’re close to being satisfied with the result, you can increase the rendering quality and turn on the Final Gather. It’s gonna take a while, so I recommend running it before you are going to leave the computer for a relatively long period of time.
All Baked GI settings operate with a unit called “texel”. In a nutshell texel is a pixel, but not on the screen, rather in the texture space of a 3D model. Anyway, don't worry about the theory behind it, I can’t tell how Unity operates texels and how do they depend on the objects’ scale, so just go ahead and experiment! E.g. when doing final rendering for my mobile RPG I set Baked Resolution to 25.
Before I explain you more about the parameters you need to know something. If you run rendering in Unity, in the bottom right corner you can see what the engine is currently doing. At the very end of rendering process it’ll read “Compositing”.
The thing is a lightmap is generated by layers. A few separate textures are generated during the rendering. I don’t know what exact maps does Unity create, but the list probably contains either all or some of these: Diffuse (direct light), Global Illumination, Final Gather, Ambient Occlusion. After that the engine merges the maps together (laying them on top of one another). For example, Diffuse can be a base map, then on top of it an FG layer is laid using Lighten blend mode (just like in Photoshop), on top of that an AO layer is laid using Multiply mode… As a result the layers merge into an image and eventually you get a final lightmap.
Baked GI tab Section
General GI section
Let’s take a look at some of the settings from the General GI section:
Finally, the Fog! This has nothing to do with the lighting rendering, it can be turned on and off at any time. It’s pretty simple, go ahead and experiment! Just let me notice that the fog works as a pretty powerful artistic trick. You can drastically change the scene by using fog, making a sunny scene sunnier and a dark scene darker.
Besides the fog can be used as a tool to increase productivity. E.g. you may switch off textures for the far objects and hide them with the fog. In the old versions of World of Warcraft you couldn’t help but notice what heavy fog they used.
The third section is called Lightmaps. That’s where the rendered lightmaps will be shown. If you have a lot of atlases, you won’t be able to see all of them in the top part of the section, because you can’t use scrolling in that window. That’s why drag the mouse to the bottom part of the window and then scroll.
The important thing is to see to what extent is the last lightmap-atlas filled with textures. If it’s almost empty, increase the lightmap quality to fill the entire atlas, or decrease the quality to get rid of the last (almost empty) atlas. The following image has 2 “good” atlases and one atlas, that’s half empty.
Lightmaps are stored in EXR files, that have 32-bit color depth.
As I promised I’m telling you about the Light Probes. They can be thought of as little spheres, that absorb the information about lighting. If their quantity is big enough, they make up kind of a map of your level or location illumination. Then they are used to light up dynamic objects, that can’t reap benefits of baking.
For better understanding I’ll give you an example. You have one Point Light in your scene, that is used for baking (Baking parameter is set to Baked). You don’t set it to Real-time, because it’s expensive in terms of productivity, leaving out the fact that many mobile devices don’t even support this kind of light source at all. After that you lightmap the scene and see that your Point Light is lighting up the space around it. But if you take a monster and put it next to the light source, it will still remain dark, because the monster is a dynamic object, and your Point Light only affects static objects.
What you do next is set up a network of Light Maps around the light source, then bake again. Wow! Now the monster can walk around the Point Light and get illuminated by it! This is very efficient and “cheap” way of imitating lighting. In order to add light probes to the scene choose Game Object — Light — Light Probe Group. A cube of 4 spheres now appears. To choose a sphere use Ctrl + click. Inspector will change, so you’d be able to add or delete spheres. You can also use Ctrl + D for sphere duplicating.
Set up the Light Probes neatly and thoughtfully. To avoid graphic artefacts and flickering light make sure that Light Probes make up a smooth, good-looking network.
Below you can see a screenshot of a correctly set up network. If you look closer, you can notice that Light Probes are not just randomly scattered. They surround light sources trying to “catch” the transition between light and shadow and vica versa.
In the end I’ll give you a tip about creating environmental models for lightmapping. When creating game content I knew beforehand where would the camera shoot from, so to optimize the game I had deleted back parts of some objects. At the time I had a rendering experience in Maya, but not in Unity. As it turned out in Unity during the lighting rendering, next to the objects with the “holes” (i.e. deleted polygons) really bad artefacts are created. Take this into consideration.
Explanation of physically based rendering system, written for 3D-artists.
For more information on draw calls and graphics optimization, check out this great article for non-programmers - render hell 2.0. There’s also a good ⦁ description of Unity lighting system on Unity official web-site.
All data posted on the site represents accessible information that can be browsed and downloaded for free from the web.