Specular term banding (Deferred shading)

Started by
13 comments, last by mightypigeon 13 years, 5 months ago
I'm trying to do some still fairly basic deferred shading experiments in my DX11 framework.

One problem however are eluding my problem solving skills. I'm getting some banding in my specular term of the lighting. The higher power I raise the term to the worse it gets. I seams like a sampling / precision problem but I just cannot find where. I was hoping someone here could give some input on what could be causing it.

Specular term alias illustration:
http://img263.imageshack.us/img263/5167/64467714.png
http://img839.imageshack.us/img839/4169/89839862.png

Specular term calculation:
float3 f3ToEyeWS = normalize(m_f3CameraPosition - f4PosWS.xyz);float3 f3HalfWS = normalize(f3LightVectorWS + f3ToEyeWS);float fNdotH = max(0.0f, dot(f3NormalWS, f3HalfWS));float fSpecularTerm = fSpecIntensity * pow(fNdotH, fSpecPower);


I'm having a VERY hard time finding the problem here. I'm really hoping someone can help out atleast point me in a direction which could cause this to happen.

[Edited by - elurahu on October 23, 2010 6:11:23 PM]
Advertisement
How are you storing/reconstructing position? How are you storing your specular albedo/power in your G-Buffer?
Hey MJP - Thank you for responding!

I'm storing the depth in a 32bit float buffer and reconstructing using the inverse viewprojection matrix. (Yes I've read your blog - But right now I'm keeping things as simple as I can get it).

Depth write:

VS:
// Pass depthOut.Depth.x = Out.Position.z;Out.Depth.y = Out.Position.w;


PS:
// Depth (z / w)Out.RT2.r = In.Depth.x / In.Depth.y;


Directional light shader recontruction:
// Depthfloat fDepth = m_kRT2.Sample(m_kPointSampler, In.TexCoord).x;// Convert to world space posfloat4 f4PosWS;f4PosWS.x = (In.TexCoord.x * 2.0f) - 1.0f;f4PosWS.y = -((In.TexCoord.y * 2.0f) - 1.0f);f4PosWS.z = fDepth;f4PosWS.w = 1.0f;f4PosWS = mul(f4PosWS, m_kInvViewProjection);f4PosWS /= f4PosWS.w;


Specular calculation:
// Specular light termfloat3 f3ToEyeWS = normalize(m_f3CameraPosition - f4PosWS.xyz);float3 f3HalfWS = normalize(f3LightVectorWS + f3ToEyeWS);float fNdotH = max(0.0f, dot(f3NormalWS, f3HalfWS));float fSpecularTerm = saturate(fSpecIntensity * pow(fNdotH, fSpecPower));


The specular power is stored in the alpha component of the alpha component of a 8 bit DXGI_FORMAT_R8G8B8A8_UNORM texture.
How are you storing your normals? Small errors in your normal will show up mostly in specular lighting, and will get worse the higher your specular power.
"Math is hard" -Barbie
Normal are stored in a PF_R8G8B8A8 with all 3 components.

Storage -

VS:
// Transform normals to worldOut.Normal = mul( In.Normal, (float3x3)m_kWorld );

PS:
// NormalsOut.RT1.rgb = 0.5f * (normalize(In.Normal) + 1.0f);


Usage -

// Get normalfloat3 f3NormalWS = 2.0f * f4RT1Sample.xyz - 1.0f;
Have you tried storing them at floating point precision? Also you should try a compression method like reconstructing z or Cryteks idea (modify the length of the normal to fit it better into the 8 bit precision).
I would bet that's your problem - 8 bits is really not enough for normals. There are lots of good suggestions for normal storage (with code) here.
"Math is hard" -Barbie
Thanks all - I guess it's my normals which are causing the problems. I'm going to give it a go again tomorrow and report back!
try the format DXGI_FORMAT_R10G10B10A2_UNORM you get 2 more bits per component, or go with the DXGI_FORMAT_R16G16_FLOAT and reconstruct the z.
Wisdom is knowing when to shut up, so try it.
--Game Development http://nolimitsdesigns.com: Reliable UDP library, Threading library, Math Library, UI Library. Take a look, its all free.
Quote:Original post by Pragma
I would bet that's your problem - 8 bits is really not enough for normals. There are lots of good suggestions for normal storage (with code) here.


8 bits actually is enough. But since normals all have a length of 1, they all describe positions of the unit sphere. Just by that fact you loose about 98% of the theoretical memory 8 bits per channel could save. Take a look at Cryteks Siggraph 2010 paper where they describe how they solved that problem.

This topic is closed to new replies.

Advertisement