




















































In this article by Matt Smith and Chico Queiroz, authors of Unity 5.x Cookbook, we will cover the following topics:
(For more resources related to this topic, see here.)
Whether you're willing to make a better-looking game, or add interesting features, lights and effects can boost your project and help you deliver a higher quality product. In this article, we will look at the creative ways of using lights and effects, and also take a look at some of Unity's new features, such as Procedural Skyboxes, Reflection Probes, Light Probes, and custom Reflection Sources.
Lighting is certainly an area that has received a lot of attention from Unity, which now features real-time Global Illumination technology provided by Enlighten. This new technology provides better and more realistic results for both real-time and baked lighting. For more information on Unity's Global Illumination system, check out its documentation at http://docs.unity3d.com/Manual/GIIntro.html.
There are many ways of creating light sources in Unity. Here's a quick overview of the most common methods.
Lights are placed into the scene as game objects, featuring a Light component. They can function in Realtime, Baked, or Mixed modes. Among the other properties, they can have their Range, Color, Intensity, and Shadow Type set by the user. There are four types of lights:
For an overview of the light types, check Unity's documentation at http://docs.unity3d.com/Manual/Lighting.html.
Different types of lights
Unity's Environment Lighting is often achieved through the combination of a Skybox material and sunlight defined by the scene's Directional Light. Such a combination creates an ambient light that is integrated into the scene's environment, and which can be set as Realtime or Baked into Lightmaps.
When applied to static objects, materials featuring the Emission colors or maps will cast light over surfaces nearby, in both real-time and baked modes, as shown in the following screenshot:
As its name suggests, a Projector can be used to simulate projected lights and shadows, basically by projecting a material and its texture map onto the other objects.
Lightmaps are basically texture maps generated from the scene's lighting information and applied to the scene's static objects in order to avoid the use of processing-intensive real-time lighting.
Light Probes are a way of sampling the scene's illumination at specific points in order to have it applied onto dynamic objects without the use of real-time lighting.
The Lighting window, which can be found through navigating to the Window | Lighting menu, is the hub for setting and adjusting the scene's illumination features, such as Lightmaps, Global Illumination, Fog, and much more. It's strongly recommended that you take a look at Unity's documentation on the subject, which can be found at http://docs.unity3d.com/Manual/GlobalIllumination.html.
As it can be seen in many first-person shooters and survival horror games, lights and shadows can add a great deal of realism to a scene, helping immensely to create the right atmosphere for the game. In this recipe, we will create a cloudy outdoor environment using cookie textures. Cookie textures work as masks for lights. It functions by adjusting the intensity of the light projection to the cookie texture's alpha channel. This allows for a silhouette effect (just think of the bat-signal) or, as in this particular case, subtle variations that give a filtered quality to the lighting.
If you don't have access to an image editor, or prefer to skip the texture map elaboration in order to focus on the implementation, please use the image file called cloudCookie.tga, which is provided inside the 1362_06_01 folder.
To simulate a cloudy outdoor environment, follow these steps:
Learning about the Alpha channel is useful, but you could get the same result without it. Skip steps 3 to 7, save your image as cloudCookie.png and, when changing texture type in step 9, leave Alpha from Greyscale checked.
using UnityEngine;
using System.Collections;
public class MovingShadows : MonoBehaviour{
public float windSpeedX;
public float windSpeedZ;
private float lightCookieSize;
private Vector3 initPos;
void Start(){
initPos = transform.position;
lightCookieSize = GetComponent<Light>().cookieSize;
}
void Update(){
Vector3 pos = transform.position;
float xPos= Mathf.Abs (pos.x);
float zPos= Mathf.Abs (pos.z);
float xLimit = Mathf.Abs(initPos.x) + lightCookieSize;
float zLimit = Mathf.Abs(initPos.z) + lightCookieSize;
if (xPos >= xLimit)
pos.x = initPos.x;
if (zPos >= zLimit)
pos.z = initPos.z;
transform.position = pos;
float windX = Time.deltaTime * windSpeedX;
float windZ = Time.deltaTime * windSpeedZ;
transform.Translate(windX, 0, windZ, Space.World);
}
}
With our script, we are telling the Directional Light to move across the X and Z axis, causing the Light Cookie texture to be displaced as well. Also, we reset the light object to its original position whenever it traveled a distance that was either equal to or greater than the Light Cookie Size. The light position must be reset to prevent it from traveling too far, causing problems in real-time render and lighting. The Light Cookie Size parameter is used to ensure a smooth transition.
The reason we are not enabling shadows is because the light angle for the X axis must be 90 degrees (or there will be a noticeable gap when the light resets to the original position). If you want dynamic shadows in your scene, please add a second Directional Light.
In this recipe, we have applied a cookie texture to a Directional Light. But what if we were using the Spot or Point Lights?
Unity documentation has an excellent tutorial on how to make the Spot Light cookies. This is great to simulate shadows coming from projectors, windows, and so on. You can check it out at http://docs.unity3d.com/Manual/HOWTO-LightCookie.html.
If you want to use a cookie texture with a Point Light, you'll need to change the Light Type in the Texture Importer section of the Inspector.
Whereas Unity Legacy Shaders use individual Reflection Cubemaps per material, the new Standard Shader gets its reflection from the scene's Reflection Source, as configured in the Scene section of the Lighting window. The level of reflectiveness for each material is now given by its Metallic value or Specular value (for materials using Specular setup). This new method can be a real time saver, allowing you to quickly assign the same reflection map to every object in the scene. Also, as you can imagine, it helps keep the overall look of the scene coherent and cohesive. In this recipe, we will learn how to take advantage of the Reflection Source feature.
For this recipe, we will prepare a Reflection Cubemap, which is basically the environment to be projected as a reflection onto the material. It can be made from either six or, as shown in this recipe, a single image file.
To help us with this recipe, it's been provided a Unity package, containing a prefab made of a 3D object and a basic Material (using a TIFF as Diffuse map), and also a JPG file to be used as the reflection map. All these files are inside the 1362_06_02 folder.
To add Reflectiveness and Specularity to a material, follow these steps:
While it is the material's specular map that allows for a reflective look, including the intensity and smoothness of the reflection, the refection itself (that is, the image you see on the reflection) is given by the Cubemap that we have created from the image file.
Reflection Cubemaps can be achieved in many ways and have different mapping properties.
The Cylindrical mapping that we applied was well-suited for the photograph that we used. However, depending on how the reflection image is generated, a Cubic or Spheremap-based mapping can be more appropriate. Also, note that the Fixup Edge Seams option will try to make the image seamless.
You might have noticed that the reflection is somewhat blurry compared to the original image; this is because we have ticked the Glossy Reflections box. To get a sharper-looking reflection, deselect this option; in which case, you can also leave the Filter Mode option as default (Bilinear).
At 512 x 512 pixels, our reflection map will probably run fine on the lower-end machines. However, if the quality of the reflection map is not so important in your game's context, and the original image dimensions are big (say, 4096 x 4096), you might want to change the texture's Max Size at the Import Settings to a lower number.
Although using GUI elements, such as a cross-hair, is a valid way to allow players to aim, replacing (or combining) it with a projected laser dot might be a more interesting approach. In this recipe, we will use the Projector and Line components to implement this concept.
To help us with this recipe, it's been provided with a Unity package containing a sample scene featuring a character holding a laser pointer, and also a texture map named LineTexture. All files are inside the 1362_06_03 folder. Also, we'll make use of the Effects assets package provided by Unity (which you should have installed when installing Unity).
To create a laser dot aim with a Projector, follow these steps:
The reason for editing the shader for the laser was to make it stronger by changing its blend type to Additive. However, if you want to learn more about it, check out Unity's documentation on the subject, which is available at http://docs.unity3d.com/Manual/SL-Reference.html.
using UnityEngine;
using System.Collections;
public class LaserAim : MonoBehaviour {
public float lineWidth = 0.2f;
public Color regularColor = new Color (0.15f, 0, 0, 1);
public Color firingColor = new Color (0.31f, 0, 0, 1);
public Material lineMat;
private Vector3 lineEnd;
private Projector proj;
private LineRenderer line;
void Start () {
line = gameObject.AddComponent<LineRenderer>();
line.material = lineMat;
line.material.SetColor("_TintColor", regularColor);
line.SetVertexCount(2);
line.SetWidth(lineWidth, lineWidth);
proj = GetComponent<Projector> ();
}
void Update () {
RaycastHit hit;
Vector3 fwd = transform.TransformDirection(Vector3.forward);
if (Physics.Raycast (transform.position, fwd, out hit))
{
lineEnd = hit.point;
float margin = 0.5f;
proj.farClipPlane = hit.distance + margin;
} else {
lineEnd = transform.position + fwd * 10f;
}
line.SetPosition(0, transform.position);
line.SetPosition(1, lineEnd);
if(Input.GetButton("Fire1")){
float lerpSpeed = Mathf.Sin (Time.time * 10f);
lerpSpeed = Mathf.Abs(lerpSpeed);
Color lerpColor = Color.Lerp(regularColor,
firingColor, lerpSpeed);
line.material.SetColor("_TintColor", lerpColor);
}
if(Input.GetButtonUp("Fire1")){
line.material.SetColor("_TintColor", regularColor);
}
}
}
In this recipe, the width of the laser beam and its aim dot have been exaggerated. Should you need a more realistic thickness for your beam, change the Line Width field of the Laser Aim component to 0.05, and the Orthographic Size of the Projector component to 0.025. Also, remember to make the beam more opaque by setting the Regular Color of the Laser Aim component brighter.
The laser aim effect was achieved by combining two different effects: a Projector and Line Renderer.
A Projector, which can be used to simulate light, shadows, and more, is a component that projects a material (and its texture) onto other game objects. By attaching a projector to the Laser Pointer object, we have ensured that it will face the right direction at all times. To get the right, vibrant look, we have edited the projector material's Shader, making it brighter. Also, we have scripted a way to prevent projections from going through objects, by setting its Far Clip Plane on approximately the same level of the first object that is receiving the projection. The line of code that is responsible for this action is—proj.farClipPlane = hit.distance + margin;.
Regarding the Line Renderer, we have opted to create it dynamically, via code, instead of manually adding the component to the game object. The code is also responsible for setting up its appearance, updating the line vertices position, and changing its color whenever the fire button is pressed, giving it a glowing/pulsing look.
For more details on how the script works, don't forget to check out the commented code, available within the 1362_06_03 | End folder.
If you want your scene's environment to be reflected by game objects, featuring reflective materials (such as the ones with high Metallic or Specular levels), then you can achieve such effect using Reflection Probes. They allow for real-time, baked, or even custom reflections through the use of Cubemaps.
Real-time reflections can be expensive in terms of processing; in which case, you should favor baked reflections, unless it's really necessary to display dynamic objects being reflected (mirror-like objects, for instance). Still, there are some ways real-time reflections can be optimized. In this recipe, we will test three different configurations for reflection probes:
For this recipe, we have prepared a basic scene, featuring three sets of reflective objects: one is constantly moving, one is static, and one moves whenever it is interacted with. The Probes.unitypackage package that is containing the scene can be found inside the 1362_06_04 folder.
To reflect the surrounding objects using the Reflection probes, follow these steps:
using UnityEngine;
using System.Collections;
public class UpdateProbe : MonoBehaviour {
private ReflectionProbe probe;
void Awake () {
probe = GetComponent<ReflectionProbe> ();
probe.RenderProbe();
}
public void RefreshProbe(){
probe.RenderProbe();
}
}
private GameObject probe;
private UpdateProbe up;
void Awake(){
probe = GameObject.Find("OnDemandProbe");
up = probe.GetComponent<UpdateProbe>();
}
up.RefreshProbe();
The Reflection Probes element act like omnidirectional cameras that render Cubemaps and apply them onto the objects within their constraints. When creating Reflection Probes, it's important to be aware of how the different types work:
There are a number of additional settings that can be tweaked, such as Importance, Intensity, Box Projection, Resolution, HDR, and so on. For a complete view on each of these settings, we strongly recommend that you read Unity's documentation on the subject, which is available at http://docs.unity3d.com/Manual/class-ReflectionProbe.html.
Besides the traditional 6 Sided and Cubemap, Unity now features a third type of skybox: the Procedural Skybox. Easy to create and setup, the Procedural Skybox can be used in conjunction with a Directional Light to provide Environment Lighting to your scene. In this recipe, we will learn about different parameters of the Procedural Skybox.
For this recipe, you will need to import Unity's Standard Assets Effects package, which you should have installed when installing Unity.
To set up an Environment Lighting using the Procedural Skybox and Directional Light, follow these steps:
using UnityEngine;
using System.Collections;
public class RotateLight : MonoBehaviour {
public float speed = -1.0f;
void Update () {
transform.Rotate(Vector3.right * speed * Time.deltaTime);
}
}
Ultimately, the appearance of Unity's native Procedural Skyboxes depends on the five parameters that make them up:
It is important to notice that the Skybox appearance will respond to the scene's Directional Light, playing the role of the Sun. In this case, rotating the light around its X axis can create dawn and sunset scenarios, whereas rotating it around its Y axis will change the position of the sun, changing the cardinal points of the scene.
Also, regarding the Environment Lighting, note that although we have used the Skybox as the Ambient Source, we could have chosen a Gradient or a single Color instead—in which case, the scene's illumination wouldn't be attached to the Skybox appearance.
Finally, also regarding the Environment Lighting, please note that we have set the Ambient GI to Realtime. The reason for this was to allow the real-time changes in the GI, promoted by the rotating Directional Light. In case we didn't need these changes at runtime, we could have chosen the Baked alternative.
In this article you have learned and had hands-on approach to a number Unity's lighting system features, such as cookie textures, Reflection maps, Lightmaps, Light and Reflection probes, and Procedural Skyboxes. The article also demonstrated the use of Projectors.
Further resources on this subject: