After following the previous tutorial we have a complete, though basic, version of Pong.
It looks a bit bland and flat however, so let’s add some lighting.
Ambient Light
Let’s start with the most basic light: an ambient light. This illuminates objects evenly across the scene, emulating environmental light that has no obvious source. Most scenes need at least a small amount of ambient light to avoid the unlit side of objects being too dark. Creating an ambient light – or any type of light – is very similar to creating the camera or a model. We attach a AmbientLightComponent to an Entity and place it in the scene. As with the others, a light component is created through the RenderComponentFactory.
Include ChilliSource/Rendering/Lighting.h in State.cpp and add the following to State::OnInit():
CSRendering::AmbientLightComponentSPtr ambientLightComponent = renderComponentFactory->CreateAmbientLightComponent();
ambientLightComponent->SetColour(CSCore::Colour(0.4f, 0.5f, 0.4f, 1.0f));
CSCore::EntitySPtr ambientLightEntity = CSCore::Entity::Create();
ambientLightEntity->AddComponent(ambientLightComponent);
GetScene()->Add(ambientLightEntity);
Directional Light
Our scene will still look bland and flat with just an ambient light, so let’s add a directional light. A directional light illuminates all objects in the scene from a given direction. This is useful for approximating distant lights such as sunlight.
Directional lights can also cast shadows. This is enabled by passing the size of the underlying shadow map to the factory method – for the sake of performance, this size should be a power of 2, i.e 2048. Passing a size of 0 (or not passing a value at all) will disable shadows.
If shadows are enabled, two additional things must be provided: the shadow volume and shadow tolerance. The shadow volume describes the box in the direction of the light in which shadows will be cast. The shadow tolerance is used to mitigate shadow “banding” issues.
With shadows off it doesn’t matter where in the scene the light is placed, only its direction matters. However, shadows are only cast in front of the light so if they are enabled the light must be positioned carefully. As with the camera, the SetLookAt() method in an Entity’s transform is useful for managing this.
Add the following to State::OnInit():
CSRendering::DirectionalLightComponentSPtr directionalLightComponent = renderComponentFactory->CreateDirectionalLightComponent(2048);
directionalLightComponent->SetColour(CSCore::Colour(0.5f, 0.6f, 0.5f, 1.0f));
directionalLightComponent->SetShadowVolume(150.0f, 150.0f, 5.0f, 100.0f);
directionalLightComponent->SetShadowTolerance(0.005f);
CSCore::EntitySPtr directionalLightEntity = CSCore::Entity::Create();
directionalLightEntity->AddComponent(directionalLightComponent);
directionalLightEntity->GetTransform().SetLookAt(CSCore::Vector3(-10.0f, 25.0f, -50.0f), CSCore::Vector3::k_zero, CSCore::Vector3::k_unitPositiveY);
GetScene()->Add(directionalLightEntity);
Lighting Materials
If you were to build the application now you would see no change to your scene. This is because, although there are lights in the scene, none of the objects have materials that allow them to be lit. There are two things that need to be changed to remedy this. First of all the lighting properties of the objects need to be described. This is achieved by adding the following to Models.csmaterial:
Secondly the material type needs to be changed to use lighting. There are a few different lighting types available, but in this case we want to use StaticBlinnShadowed:
Building this now should display our Pong game, nicely lit!