The project is still alive…

It has been a while since I have posted, but I have been rather busy at home which has restricted my development time. I’m still looking into the Light Manager at the moment and will get another post out soon.


Introducing the Light Manager…

I have finally managed to get round to implementing the LightManager. This post will explain how this in implemented into the engine and how to use the new class.

Back in the earlier version of this project, I wrote a simple Light Manager. This new LightManager class is based on the old one, but with a few new modifications. Start by creating a class in the Core folder called LightManager. Add the following namespaces:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using ProjectVanquish.Renderers;
using ProjectVanquish.Cameras;

Declare the class as public and then add the following fields:

Effect directionalLightEffect, hemisphericLightEffect, pointLightEffect;
Model sphereModel;
QuadRenderer fullscreenQuad;
Vector2 halfPixel;
Texture2D hemisphericColorMap;
static Lights.DirectionalLight light;
static IList<Lights.PointLight> pointLights;

Here we are taking some of the fields from the DeferredRenderer class, so we can delete them from there. We can now add the constructor:

public LightManager(Game game)
    // Load Effects, Models and Quad Renderer
    directionalLightEffect = game.Content.Load("Shaders/Lights/DirectionalLight");
    pointLightEffect = game.Content.Load("Shaders/Lights/PointLight");
    hemisphericLightEffect = game.Content.Load("Shaders/Lights/HemisphericLight");
    sphereModel = game.Content.Load("Models/Sphere");
    fullscreenQuad = new QuadRenderer(game);
    halfPixel = new Vector2()
        X = 0.5f / (float)game.GraphicsDevice.PresentationParameters.BackBufferWidth,
        Y = 0.5f / (float)game.GraphicsDevice.PresentationParameters.BackBufferHeight

    // Load the Color Map for the Hemispheric Light
    hemisphericColorMap = game.Content.Load("Textures/ColorMap");

    // Make our directional light source
    light = new Lights.DirectionalLight();
    light.Direction = new Vector3(-1, -1, -1);
    light.Color = new Vector3(0.7f, 0.7f, 0.7f);

    // Instantiate the PointLights List
    pointLights = new List();

Back in the DeferredRenderer class, we had all of the old DrawLights code. We’ll start adding this into this class.

void DrawDirectionalLight(RenderTarget2D colorRT, RenderTarget2D normalRT, RenderTarget2D depthRT, Camera camera)
    // Set all parameters
    directionalLightEffect.Parameters["InvertViewProjection"].SetValue(Matrix.Invert(camera.ViewMatrix * camera.ProjectionMatrix));

    // Apply the Effect

    // Draw a FullscreenQuad
    fullscreenQuad.Render(Vector2.One * -1, Vector2.One);

You’ll notice that the method declaration is different from the old one. This is because we don’t have direct access to the required fields like we did before, and I’d like to keep it that way. We’ll be passing them through the modified DrawLights method, which we’ll get to shortly. The next method to move is the DrawHemisphericLight:

void DrawHemisphericLight(GraphicsDevice device, SceneManager scene, Camera camera)
    device.BlendState = BlendState.Opaque;

    // Only apply the effect to those models in the Frustum
    foreach (Models.Actor actor in scene.Models.Where(a => camera.BoundingFrustum.Intersects(a.BoundingSphere)))
        foreach (ModelMesh mesh in actor.Model.Meshes)
            foreach (ModelMeshPart part in mesh.MeshParts)
                // Set the Effect Parameters
                hemisphericLightEffect.Parameters["matWorldViewProj"].SetValue(actor.World * camera.ViewMatrix * camera.ProjectionMatrix);
                hemisphericLightEffect.Parameters["vLightDirection"].SetValue(new Vector4(light.Direction, 1));
                hemisphericLightEffect.Parameters["SkyColor"].SetValue(new Vector4(light.Color, 1));

                // Apply the Effect

                // Render the Primitives
                device.SetVertexBuffer(part.VertexBuffer, part.VertexOffset);
                device.Indices = part.IndexBuffer;
                device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, part.NumVertices, part.StartIndex, part.PrimitiveCount);

    device.BlendState = BlendState.AlphaBlend;

Before moving onto the DrawLights method, we’ll implement the DrawPointLights method:

void DrawPointLight(GraphicsDevice device, RenderTarget2D colorRT, RenderTarget2D normalRT, RenderTarget2D depthRT, Camera camera, Lights.PointLight pointLight)
    // Set the G-Buffer parameters

    // Compute the light world matrix
    // scale according to light radius, and translate it to light position
    Matrix sphereWorldMatrix = Matrix.CreateScale(pointLight.Range) * Matrix.CreateTranslation(pointLight.Position);

    // Light position

    // Set the color, radius and Intensity

    // Parameters for specular computations
    pointLightEffect.Parameters["InvertViewProjection"].SetValue(Matrix.Invert(camera.ViewMatrix * camera.ProjectionMatrix));

    // Size of a halfpixel, for texture coordinates alignment

    // Calculate the distance between the camera and light center
    float cameraToCenter = Vector3.Distance(camera.Position, pointLight.Position);

    // If we are inside the light volume, draw the sphere's inside face
    if (cameraToCenter < pointLight.Range)
        device.RasterizerState = RasterizerState.CullClockwise;
        device.RasterizerState = RasterizerState.CullCounterClockwise;

    // Reset DepthStencilState
    device.DepthStencilState = DepthStencilState.None;

    // Apply the Effect

    // Draw the Sphere mesh
    foreach (ModelMesh mesh in sphereModel.Meshes)
        foreach (ModelMeshPart meshPart in mesh.MeshParts)
            device.SetVertexBuffer(meshPart.VertexBuffer, meshPart.VertexOffset);
            device.Indices = meshPart.IndexBuffer;
            device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, meshPart.NumVertices, meshPart.StartIndex, meshPart.PrimitiveCount);

    // Reset RenderStates
    device.RasterizerState = RasterizerState.CullCounterClockwise;
    device.DepthStencilState = DepthStencilState.Default;

You may have noticed some changes to this method. We are now using a pointLight object. We’ll need to modify the PointLight class to allow for the new properties, but we’ll finish this class first. Lastly, we’ll add the modified DrawLights method:

public void DrawLights(GraphicsDevice device, RenderTarget2D colorRT, RenderTarget2D normalRT, RenderTarget2D depthRT, RenderTarget2D lightRT, Camera camera, SceneManager scene)
    // Set the Light RenderTarget

    // Clear all components to 0
    device.BlendState = BlendState.AlphaBlend;
    device.DepthStencilState = DepthStencilState.None;

    // Render either the Directional or Hemispheric light
    if (UseHemisphericLight)
        DrawHemisphericLight(device, scene, camera);
        DrawDirectionalLight(colorRT, normalRT, depthRT, camera);

    // Render each PointLight
    foreach (Lights.PointLight pointLight in pointLights)
        DrawPointLight(device, colorRT, normalRT, depthRT, camera, pointLight);

    // Reset RenderStates
    device.BlendState = BlendState.Opaque;
    device.DepthStencilState = DepthStencilState.None;
    device.RasterizerState = RasterizerState.CullCounterClockwise;

    // Reset the RenderTarget

We have now got our new LightManager class ready, so we can plug this into the DeferredRenderer class. In the DeferredRenderer class, add a new field:

private LightManager lightManager;

In the LoadContent method, we’ll instantiate the LightManager:

// Instantiate the LightManager
lightManager = new LightManager(Game);

We are reaching the final goal posts. There is one big change to the DeferredRenderer class. As we have modified the DrawLights call, we need to build a new method:

void CombineFinal(RenderTarget2D shadowOcclusion)
    // If SSAO is enabled, set the RenderTarget
    if (SSAORenderer.Enabled)

    // Set the effect parameters

    // Apply the Effect

    // Render a full-screen quad
    quadRenderer.Render(Vector2.One * -1, Vector2.One);

This will create our final scene. In the Draw method, we need to alter it to use the new LightManager.DrawLights method, and also include the new method. Place the following after the Render Shadows call:

// Draw Lights
lightManager.DrawLights(GraphicsDevice, colorRT, normalRT, depthRT, lightRT, camera, scene);

// Combine the Final scene

Before we can compile this, we need to modify the PointLight class. Below is the complete listing for the PointLight class:

protected float intensity = 0.0f;
protected float range = 0.0f; 

public PointLight(Vector3 position, Vector3 color, float range, float intensity)
    : base()
    Position = position;
    Color = color;
    Range = range;
    Intensity = intensity;

public float Intensity
    get { return intensity; }
    set { intensity = value;}

public Vector3 Position
    get { return worldMatrix.Translation; }
    set { worldMatrix.Translation = value; }

public float Range
    get { return range; }
    set { range = value; }

Because the SpotLight class is inherited from the PointLight class, we’ll need to modify the constructor of that too. Here is the modified version:

public SpotLight(Vector3 position, Vector3 color, float range, float intensity)
    : base(position, color, range, intensity)

Now, compiling the project shouldn’t give you any errors and you’ll be ok to run it, albeit without Point Lights as these are not yet implemented into the LightManager class yet. The full sourcecode can be downloaded from the Codeplex page, and the source code is found here.

Some interesting findings

Whilst I was so eager to get the Sky dome rendering working, I hadn’t realised but I had broken the PointLight implementation. I had changed the RenderTarget settings so that the new Moon functionality would work, but this is where it all went wrong. For now, I’ve commented out the DrawGlow and DrawMoon methods and reinstated the correct RenderTarget settings:

Correct settings:

colorRT = new RenderTarget2D(GraphicsDevice, backBufferWidth, backBufferHeight, false, SurfaceFormat.Color, DepthFormat.Depth24);
normalRT = new RenderTarget2D(GraphicsDevice, backBufferWidth, backBufferHeight, false, SurfaceFormat.Color, DepthFormat.None);
depthRT = new RenderTarget2D(GraphicsDevice, backBufferWidth, backBufferHeight, false, SurfaceFormat.Single, DepthFormat.None);
depthTexture = new RenderTarget2D(GraphicsDevice, backBufferWidth, backBufferHeight, false, SurfaceFormat.Single, DepthFormat.Depth24);
lightRT = new RenderTarget2D(GraphicsDevice, backBufferWidth, backBufferHeight, false, SurfaceFormat.Color, DepthFormat.None);
sceneRT = new RenderTarget2D(GraphicsDevice, backBufferWidth, backBufferHeight, false, SurfaceFormat.Color, DepthFormat.Depth24);

That's fixed the Sky brightness

Adding new hemispheric light

It’s been a short while since I’ve posted, so I thought I’d let you know what I’ve been working on. Whilst I’ve managed to finish of the SSAO implementation, I have been trying to implement a new light. So far, it’s going well, but I have a problem with the models appearing transparent.

So, I’m looking into this at that moment and will post news as it happens.

SSAO is now back…

and easier to use!

The small debug output windows are the SSAO before and after the blur process. I’ve made this a lot simpler to use as well. So, in your Game class, you can turn on SSAO with the following code:

SSAORenderer.Enabled = true;

There are two more properties that are now available in the SSAORenderer class. There are:


Set these values to get your desired look, and that’s it. The SSAORenderer is disabled by default, so you’ll have to enable it if you want to use it. Sourcecode available at Codeplex, changeset 15588.

SSAO Re-implementation

Just a quick post to say that I have started work on re-implementing the SSAO Renderer. I have made some tweaks to it so that you can now enable/disable from your Game class using a static Enabled property. This means that you have full-control over the renderer. I’ll also be adding two new properties that will allow you to change the SampleRadius and DistanceScale variables. This will allow the renderer to be more flexible and you can find the right look for your game.

I’m hoping to get this all sorted out this week, and I’ll make the source code available over at the Codeplex page.

New BoundingBox Renderer

I had a bit of spare time before I start to re-implement the SSAO, so I went on the hunt for some good articles about Bounding Boxes. I finally found a good article by Tim Jones which explained everything and had a great code example. I read through the article and wondered how I’d get away from creating a DrawableGameComponent for each model so I have modified the BoundingBoxComponent code in order to remove this.

With a slight shuffle of the code, it is now instantiated in the Actor class and the SceneManager class now has a new property, ShowBoundingBoxes. Set this to true and you’ll see them 🙂

No Bounding Boxes

Bounding Boxes

Big clean up

So, I decided to have a big tidy up with regards the project. This was sparked by the problems with the Shadow Rendering. In order to get the Shadows rendering correctly, I had to strip the project back to its bare-minimum. I then had issues with Source Control so I needed to resolve that as well. This was a good time to get everything sorted out in one go. The latest changeset (15378) has the stripped down version of the engine and also corrected the Source Control.  I have also released this code as a full release.

Shadow Renderer fixed!

It has taken a lot longer than I originally thought, but I have finally got the Shadow Renderer working.

PCF 2x2

Sorry for the long delay with this. The latest version of the source code can be found over at the Codeplex page.

PCF set to 5x5 with no directional light