deferred shading question

Started by
15 comments, last by phil_t 9 years, 10 months ago


Now i have implemented deferred shading but where do i store material and light properties like diffuse, specular, ambient, reflect, specular power?

Um, well the diffuse color goes in your color buffer, that's what it's for. Specular color and power can be stuffed wherever you have space channels in your g-buffer. It's a bit of an art to try to minimize the size of your g-buffer while still getting the flexibility you need. Mine consists of 3 32-bit buffers:

(1) Albedo (RGB), and an emmissive value (A)

(2) Normal (RG), specular power (B), specular intensity (A) // I don't support a specular RGB color, just a single intensity value

(3) Depth (RG),object id (B), baked occlusion term (A)

I've managed to squeeze the normals into two 8-bit channels (using a spheremap transform), and 16-bit depth value into two 8-bit channels.

To start with though, I wouldn't bother with these optimizations, just make the buffers you need. If you just need spec power and a single spec intensity value, you could stuff them into the alpha channels of your color and normal buffers.

As for "ambient" and "reflect", I'm not sure what you mean. If these are light properties, they don't belong in the g-buffer. They are applied as you draw each light in your lighting pass (unless you're making a light pre-pass renderer (sometimes called deferred lighting), in which case you need to make a sort of g-buffer for lighting properties).


Also how do i use multiple lights with deferred shading?

You draw each light separately and additively blend then into your destination render target (your light accumulation buffer).

Advertisement

I know about specular power but what is specular intensity? I know its general meaning but i never used it before in my old lighting? Also i dont know about emissive value and why do you store depth in 2 channels? Isn't it sufficient to store it in single channel? Also your normal is in 2 channels so where is your z component of normal? and why object id?



Sorry for too many questions but i'm confused.

EDIT: I understood specular intensity but what what about other terms?


Also i dont know about emissive value

It's for when an object emits light (so it would show up even if no lights were shining on it).


and why do you store depth in 2 channels? Isn't it sufficient to store it in single channel?

Not if I'm using an 8 bit per channel render target format. But to start off with, I would just use a R32F format (32 bit floating point single channel).


Also your normal is in 2 channels so where is your z component of normal?

Normals are of unit length, so you only need to store 2 values. You can reconstruct the 3rd value in the shader, since you know the length of the normal is 1. (see http://aras-p.info/texts/CompactNormalStorage.html#method01xy)

But basically, get stuff working, and worry about all these kinds of optimizations at a later time.

OK. So I implemented lighting from this tutorial: http://www.catalinzima.com/xna/tutorials/deferred-rendering-in-xna/directional-lights/

Why do I've wrong specular highlights? directional light's direction is (0.0f, -1.0f, 0.0f)

it is straight down so why are specular hightlights wrong (at up)?

aM36OJb.png

My deferred renderer:


#include "LightHelper.fx"
 
//================================
//DeferredRenderer: Renders lighting info to gbuffers
//DefferedRenderer.fx by newtechnology
//================================
 
cbuffer cbPerObject
{
float4x4 gWorld;
float4x4 gWorldViewProj;
float4x4 gWorldInvTranspose;
float4x4 gTexTransform;
   
Material gMaterial;
};
 
 
cbuffer cbFixed
{
const float AOFactor = 0.4f;
const float SpecIntensity = 0.8f;
const float specPower = 0.5;
};
 
struct VertexIn
{
float3 PosL : POSITION;
float3 NormalL : NORMAL;
float2 Tex : TEXCOORD;
float3 TangentL : TANGENT;
};
 
struct VertexOut
{
float4 PosH : SV_POSITION;
float3 PosW : POSITION;
float3 NormalW : NORMAL;
float2 Tex : TEXCOORD;
float3 TangentW : TANGENT;
};
 
SamplerState samLinear
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};
 
Texture2D gDiffuseMap;
Texture2D gNormalMap;
 
VertexOut VS(VertexIn vin)
{
VertexOut vout;
 
vout.PosW     = mul(float4(vin.PosL, 1.0f), gWorld).xyz;
vout.NormalW  = mul(vin.NormalL, (float3x3)gWorldInvTranspose);
vout.TangentW = mul(vin.TangentL, (float3x3)gWorld);
vout.PosH = mul(float4(vin.PosL, 1.0f), gWorldViewProj);
vout.Tex = mul(float4(vin.Tex, 0.0f, 1.0f), gTexTransform).xy;
 
return vout;
}
 
 
struct PixelOut
{
float4 Color : SV_Target0;
float4 Normal : SV_Target1;
float4 Position : SV_Target2;
};
 
PixelOut PS(VertexOut pin) : SV_Target
{
PixelOut Out;
 
 
pin.NormalW = 0.5f * (normalize(pin.NormalW) + 1.0f);
 
float3 color = gDiffuseMap.Sample(samLinear, pin.Tex).rgb;
 
//output lighting info to gbuffer
Out.Color = float4(color, specPower);
Out.Normal = float4(pin.NormalW, SpecIntensity);
Out.Position = float4(pin.PosW, AOFactor);
  
return Out;
}
 
technique11 BuildGBuffers
{
pass P0
{
SetVertexShader( CompileShader(vs_4_0, VS() ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader(ps_4_0, PS() ) );
}
}

My Directional light:


#include "LightHelper.fx"
 
 
SamplerState samPoint
{
Filter = MIN_MAG_MIP_POINT;
AddressU = CLAMP;
AddressV = CLAMP;
};
 
cbuffer cbPerObject
{
float4x4 gWorldViewProj;
};
 
cbuffer cbPerFrame
{
float3 gEyePosW;
Material gMaterial;
DirectionalLight gLight;
};
 
 
//gbuffers
Texture2D gColorMap;
Texture2D gNormalsMap;
Texture2D gPositionMap;
 
struct VertexIn
{
float3 PosL : POSITION;
float2 tex : TEXCOORD;
};
 
struct VertexOut
{
float4 PosH : SV_POSITION;
float2 tex : TEXCOORD;
};
 
VertexOut VS(VertexIn vin)
{
VertexOut vout;
 
vout.PosH = mul(float4(vin.PosL, 1.0f), gWorldViewProj);
 
//no transformation required here
vout.tex = vin.tex;
 
return vout;
}
 
float4 PS(VertexOut pin) : SV_Target
{
//Sample textures (gbuffers)
float4 color = gColorMap.Sample(samPoint, pin.tex);
float4 normal = gNormalsMap.Sample(samPoint, pin.tex);
float4 position = gPositionMap.Sample(samPoint, pin.tex);
 
 
//extract material properties from alpha channel of all 3 textures
float specPower = color.a * 255;
float specIntensity = normal.a;
float AOFactor = position.a;
 
    float3 normalW = 2.0f * normal.rgb - 1.0f;
 
float3 lightVector = float3(0.0f, 1.0f, 0.0f); // -(0.0f, -1.0f, 0.0f) = (0.0f, 1.0f, 0.0f); -> -(-1) = +1
lightVector = normalize(lightVector);
 
float NdL = saturate(dot(lightVector, normalW));
 
float3 DirectionToCamera = normalize(gEyePosW - position.xyz);
 
float3 reflectionVector = normalize(reflect(lightVector, normalW));
 
float SpecularLight = specIntensity * pow(saturate(dot(reflectionVector, DirectionToCamera)), specPower);
 
// float3(1.0f, 1.0f, 1.0f) is light's color
float3 DiffuseLight = (NdL * float3(1.0f, 1.0f, 1.0f)) + AOFactor;
 
float3 finalcolor = color.rgb * DiffuseLight + SpecularLight;
 
return float4(finalcolor, 1.0f);
}
 
technique11 DeferredLighting
{
pass P0
{
SetVertexShader( CompileShader( vs_4_0, VS() ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader( ps_4_0, PS() ) );
}
};


it is straight down so why are specular hightlights wrong (at up)?

You need to use the vector pointing to the light source, similar like the vector pointing to the camera. Therefor the sun light direction needs to be reverted.


it is straight down so why are specular hightlights wrong (at up)?

You need to use the vector pointing to the light source, similar like the vector pointing to the camera. Therefor the sun light direction needs to be reverted.

I do invert it in pixel shader, look at the source code.


I do invert it in pixel shader, look at the source code.

Invert it again :-). reflect(L, N) will produce something that points (roughly) in the opposite direction of L with respect to the normal. i.e. if L points towards the surface, reflect will return something that points away.

This topic is closed to new replies.

Advertisement