We’ll start by creating a new folder in our “ProjectVanquish” project. Locate the “Core” folder and create a new folder called “Lights”. Create a class called “PointLight” in this folder and once created, add the following namespace:
using Microsoft.Xna.Framework;
Now, alter the class declaration so that it is public.
public class PointLight
And declare the following variables:
Vector3 position;
Color color;
float lightRadius, lightIntensity;
Pretty simple in what we are trying to achieve here. Just a simple class to store the position, color, radius and intensity of the light. Let’s add a constructor:
public PointLight(Vector3 position, Color color, float radius, float intensity)
{
this.position = position;
this.color = color;
lightRadius = radius;
lightIntensity = intensity;
}
And to finish this class off, we just need to declare some properties the the “LightManager” class can use:
public Color Color { get { return color; } }
public float Radius { get { return lightRadius; } }
public float Intensity { get { return lightIntensity; } }
public Vector3 Position { get { return position; } }
We need to make some big modifications to our “LightManager” class now. In our “DrawLights” method, where we have our “DrawPointLight” call, we need to change this to the following:
foreach (PointLight light in pointLights)
DrawPointLight(light, colorRT, normalRT, depthRT, camera);
There is a new variable there, called “pointLights”. This is a list of all of the instantiated Point lights. Let’s add this variable:
IList<PointLight> pointLights = new List<PointLight>();
We will also need to include the new namespace, else we can’t use the “PointLight” class:
using ProjectVanquish.Core.Lights;
Going back to our “DrawPointLight” method, our declaration has changed some what. We are now passing in a “PointLight” object. Amend the “DrawPointLight” method to:
void DrawPointLight(PointLight light, RenderTarget2D colorRT, RenderTarget2D normalRT, RenderTarget2D depthRT, FreeCamera camera)
The last thing to change in this code is all of the parameters where we used to have them passed in. These are now part of the “PointLight” object. I’ve included the final version of the “DrawPointLight” to save time:
void DrawPointLight(PointLight light, RenderTarget2D colorRT, RenderTarget2D normalRT, RenderTarget2D depthRT, FreeCamera camera)
{
// Set the G-Buffer parameters
pointLightEffect.Parameters["colorMap"].SetValue(colorRT);
pointLightEffect.Parameters["normalMap"].SetValue(normalRT);
pointLightEffect.Parameters["depthMap"].SetValue(depthRT);
// Compute the Light World matrix
// Scale according to Light radius and translate it to Light position
Matrix sphereWorldMatrix = Matrix.CreateScale(light.Radius) * Matrix.CreateTranslation(light.Position);
pointLightEffect.Parameters["World"].SetValue(sphereWorldMatrix);
pointLightEffect.Parameters["View"].SetValue(camera.View);
pointLightEffect.Parameters["Projection"].SetValue(camera.Projection);
// Light position
pointLightEffect.Parameters["lightPosition"].SetValue(light.Position);
// Set the color, radius and Intensity
pointLightEffect.Parameters["Color"].SetValue(light.Color.ToVector3());
pointLightEffect.Parameters["lightRadius"].SetValue(light.Radius);
pointLightEffect.Parameters["lightIntensity"].SetValue(light.Intensity);
// Parameters for specular computations
pointLightEffect.Parameters["cameraPosition"].SetValue(camera.Position);
pointLightEffect.Parameters["InvertViewProjection"].SetValue(Matrix.Invert(camera.View * camera.Projection));
// Size of a halfpixel, for texture coordinates alignment
pointLightEffect.Parameters["halfPixel"].SetValue(halfPixel);
// Calculate the distance between the camera and light center
float cameraToCenter = Vector3.Distance(camera.Position, light.Position);
// If we are inside the light volume, draw the sphere's inside face
if (cameraToCenter < light.Radius)
device.RasterizerState = RasterizerState.CullClockwise;
else
device.RasterizerState = RasterizerState.CullCounterClockwise;
device.DepthStencilState = DepthStencilState.None;
pointLightEffect.Techniques[0].Passes[0].Apply();
foreach (ModelMesh mesh in sphere.Meshes)
{
foreach (ModelMeshPart meshPart in mesh.MeshParts)
{
device.Indices = meshPart.IndexBuffer;
device.SetVertexBuffer(meshPart.VertexBuffer);
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, meshPart.NumVertices, meshPart.StartIndex, meshPart.PrimitiveCount);
}
}
device.RasterizerState = RasterizerState.CullCounterClockwise;
device.DepthStencilState = DepthStencilState.Default;
}
All being well, the project will compile without any issues. Let’s add the final method to the “LightManager” class:
public void AddLight(PointLight light)
{
pointLights.Add(light);
}
This method will allow the “DeferredRenderer” class to be able to add new Point lights, but we can’t access this method from outside of the “DeferredRenderer” class. So, in our “DeferredRenderer” class, we add the following method:
public void AddLight(PointLight light)
{
lightManager.AddLight(light);
}
Build the solution and once it’s finished, we’ll be able to add Point lights from our “Game1″ class. To do so, in the “Game1″ class, we’ll need to add the new “Lights” namespace:
using ProjectVanquish.Core.Lights;
Locate the “LoadContent” method. Under the renderer.AddModel() line, add:
renderer.AddLight(new PointLight(new Vector3(-30, 1, -70), Color.Red, 30, 5));
renderer.AddLight(new PointLight(new Vector3(0, 1, -70), Color.Green, 30, 5));
renderer.AddLight(new PointLight(new Vector3(30, 1, -70), Color.Blue, 30, 5));
Here we are creating 3 Point lights (Red, Green and Blue), positioned in a line which should produce the following output:

In the next post, we’ll add a simple Frames Per Second counter so we can see how well the engine is performing.