Switching From Deferred Shading To Deferred Lighting

Started by
8 comments, last by Hodgman 7 years, 9 months ago

Hi,

Unfortunately I haven't had much luck searching for information on this.

Basically I'm looking to take the source code to a game, take their deferred shading renderer, and switch it over to deferred lighting, or better yet, Tiled Index Deferred Lighting.

I'm very new to all this (still working through DirectX11 tutorials) but I've learned a lot in that time.

There are many reasons for wanting to switch the method of rendering, with the main one being adding a more complex BRDF system to the game.

Any help or useful links on this subject would be very much appreciated.

Advertisement

Well it highly depends on the source code that you've got, and how cleanly they've written their renderer.

A deferred shading renderer has two main steps:

1) Draw opaque objects to a gbuffer

2) Draw lights to lighting buffer

Your first step would be understanding enough of their source code to locate these functions and prepare to change them to:

1) Draw opaque objects to "thin gbuffer" -- change number of gbuffer textures and their formats, change this shader that writes to them.

2) Draw lights to intermediate lighting buffer -- change light shaders to read the new "thin gbuffer" format.

3) Draw opaque objects to lighting buffer -- using a new shader that uses the results in the intermediate lighting buffer.

Thanks :)

I just want to make sure I understand this 100%

Step 1: Create thin gbuffer: by "thin" I suppose you mean either less things in the gbuffer, a lower DXGI format, or both?
The current Gbuffer consists of Position, Normal, Diffuse Light, Specular Light, and Material type.

Step 2: Create intermediate lighting buffer, so include all lights here, and then have it read the necessary info from the thin Gbuffer?

Step 3: Draw opaque objects to light buffer: straightforward

As for how neat the code is, even though I'm a beginner I can tell that this game engine is pretty much held together by duct-tape. The renderer is a huge mess as well, but I know how to navigate around it.

Step 1: Create thin gbuffer: by "thin" I suppose you mean either less things in the gbuffer, a lower DXGI format, or both? The current Gbuffer consists of Position, Normal, Diffuse Light, Specular Light, and Material type.

It's not "Diffuse light" and "Specular light", but material properties of a pixel.

On this stage you are writing to GBuffer properties for each pixel.

These MATERIAL properties will be used with Light-related data on step 2.

Step 2: Create intermediate lighting buffer, so include all lights there, and then have it read the necessary info from the thin Gbuffer?

I've done it via packed structured buffer. Each type of light (direct, ambient, point, and spot) will be written to this kind of structure:


struct LightData
{
    uint   type;          //All lights
    float3 color;         //All lights

    float3 dirToLightVS;  //Directional, Spot
    float  innerAngleCos; //Spot

    float3 posVS;         //Point, Spot
    float  outerAngleCos; //Spot
}; //48 bytes 

StructuredBuffer<LightData> Lights;

The buffer will contain n elements (== light count + 1-last stub "LIGHT_NO" to break a loop).

The shader unpacks the data, calculate amount of light from each light source, and sum it with different light:


for (each pixel/sample)
{
    for (uint i = 0; i < 102400; ++i) // i - index of Light in LightBuffer
    {
        if (lights[i].type == LIGHT_NO)
            break; //No more lights

        DiffSpec curr = (DiffSpec)0;

        switch (lights[i].type)
        {
        //Sorted by occurrence
        case LIGHT_POINT:
            curr = CalcPoint(Lights[i], ...);
            break;

        case LIGHT_SPOT:
            curr = CalcSpot(Lights[i], ...);
            break;

        case LIGHT_DIRECTIONAL:
            curr = CalcDirectional(Lights[i], ...);
            break;

        case LIGHT_AMBIENT:
            curr = CalcAmbient(Lights[i], ...);
            break;

        case LIGHT_SHADOW_PRIM:
            curr = CalcDirectional(Lights[i], ...);
            break;
        } 
        totalLight += curr;
     } 

Step 1: Create thin gbuffer: by "thin" I suppose you mean either less things in the gbuffer, a lower DXGI format, or both? The current Gbuffer consists of Position, Normal, Diffuse Light, Specular Light, and Material type.

It's not "Diffuse light" and "Specular light", but material properties of a pixel.

On this stage you are writing to GBuffer properties for each pixel.

These MATERIAL properties will be used with Light-related data on step 2.

Step 2: Create intermediate lighting buffer, so include all lights there, and then have it read the necessary info from the thin Gbuffer?

I've done it via packed structured buffer. Each type of light (direct, ambient, point, and spot) will be written to this kind of structure:


struct LightData
{
    uint   type;          //All lights
    float3 color;         //All lights

    float3 dirToLightVS;  //Directional, Spot
    float  innerAngleCos; //Spot

    float3 posVS;         //Point, Spot
    float  outerAngleCos; //Spot
}; //48 bytes 

StructuredBuffer<LightData> Lights;

The buffer will contain n elements (== light count + 1-last stub "LIGHT_NO" to break a loop).

The shader unpacks the data, calculate amount of light from each light source, and sum it with different light:


for (each pixel/sample)
{
    for (uint i = 0; i < 102400; ++i) // i - index of Light in LightBuffer
    {
        if (lights[i].type == LIGHT_NO)
            break; //No more lights

        DiffSpec curr = (DiffSpec)0;

        switch (lights[i].type)
        {
        //Sorted by occurrence
        case LIGHT_POINT:
            curr = CalcPoint(Lights[i], ...);
            break;

        case LIGHT_SPOT:
            curr = CalcSpot(Lights[i], ...);
            break;

        case LIGHT_DIRECTIONAL:
            curr = CalcDirectional(Lights[i], ...);
            break;

        case LIGHT_AMBIENT:
            curr = CalcAmbient(Lights[i], ...);
            break;

        case LIGHT_SHADOW_PRIM:
            curr = CalcDirectional(Lights[i], ...);
            break;
        } 
        totalLight += curr;
     } 

You're awesome (same with Hodgman) :) This is very helpful, thank you so much!

My small share;
Maybe it's a bit in the details, but I think terms are a bit mixed together, deferred lightning and deferred shading I believe are not interchangable.

I believe for lighting you can go for:
- forward lighting (1 pass)
- deferred rendering/ lighting (using a gbuffer etc)

Then there's shading, for example:
- blinn phong "N dot L" stuff
- physical based shading/ rendering (different Material properties, roughness, albedo etc)

In practice I believe some parts of PBR are only possible combined with deferred lighting.

I believe tile based rendering is also a form processing the lights in your scene.

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

Hi, yes I likely butchered the terms.

Basically, what I am looking for, is to be able to assign a special shader to a given material that I have, like you said, PBR.

I'll just go ahead and say that the project I'm working on is with Xray Engine 1.6 (note: I have "unofficial" permission to be using their source code, I am not doing anything illegal/immoral, GSC just won't come right out and say it's ok due to 3rd party code it contains [which is being removed]). To clarify, I did contact GSC about it.

The whole renderer, and well, the whole engine, is a total mess.

So I guess I have a question for a moderator rather than creating a brand new topic: would it be ok if I make a topic where I ask someone that has experience to look through the rendering code, and let me know of what needs to be fixed and improved for it's DX11 renderer? I don't expect anyone to do any work for me, I just would like some hints in the right direction.

My small share;
Maybe it's a bit in the details, but I think terms are a bit mixed together, deferred lightning and deferred shading I believe are not interchangable.

Deferred shading is the common gbuffer technique that everyone uses.
Deferred lighting is another name for light-pre-pass, where you only store normals and roughness in the gbuffer and do a second geometry pass after lighting to combine the lighting buffer with the rest of the material properties... Which is actually a terrible fit for PBR.

I assumed the OP knew these terms and had a good reason to do this switch...

Swartz, what's the final end result that you want from these engine mods? What's the high level goal?

I assumed the OP knew these terms and had a good reason to do this switch... But it seems I assumed wrong

I don't care if you're a moderator: you're a dick.

Hey, no offence intended. I was self deprecating for simply answering your original question and failing to ask why you would need to switch to LPP.
You said above that you want PBR, which isn't compatible with LPP, so the first advice that I gave you is not helpful.

This topic is closed to new replies.

Advertisement