Confused: Standard Shader Deferred Pass & BRDF

Hello,

I try to really understand the deferred shading pipeline and its implementation.
The manual says:

  • G-buffer Pass: objects are rendered to produce screen-space buffers with diffuse color, specular color, smoothness, world space normal, emission and depth.
  • Lighting pass: the previously generated buffers are used to add lighting into emission buffer.

I was browsing the source code for the standard shader and found the deferred pass, where all the buffers are filled (UnityStandardCore.cginc):

void fragDeferred (
    VertexOutputDeferred i,
    out half4 outDiffuse : SV_Target0,
    out half4 outSpecSmoothness : SV_Target1,
    out half4 outNormal : SV_Target2,
    out half4 outEmission : SV_Target3
)
{
  // etc.

In the fragment function I found this:

half3 color = UNITY_BRDF_PBS (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, gi.light, gi.indirect).rgb;
    color += UNITY_BRDF_GI (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, occlusion, gi);

// ...

outEmission = half4(color, 1);

So my question is now… Why is the BRDF called in this pass? Shouldn’t that happen later in the lighting pass…?

Sorry if that’s a stupid question and thanks for your help :slight_smile:

I don’t understand BDRF too much so I can’t say much about it, but I do know that the data needed for the reflections is view-dependent, which means you need to know from what direction you are looking at the surface. this view direction needs to be calculated per-pixel, which is why you see it in the fragment shader, but it does not need to be calculated per light, so it would be a waste to calculate it in the lighting pass.

The lighting pass seems to be done in the “Internal-DeferredShading.shader”. World position (which can be used to calculate the eye vector) is calculated here:

    // read depth and reconstruct world position
    float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
    depth = Linear01Depth (depth);
    float4 vpos = float4(i.ray * depth,1);
    float3 wpos = mul (_CameraToWorld, vpos).xyz;

And then the call to the BRDF.

half4 res = UNITY_BRDF_PBS (baseColor, specColor, oneMinusReflectivity, oneMinusRoughness, normalWorld, -eyeVec, light, ind);

The BRDF gets called in both passes…?

Sorry, that’s the extent of my knowledge on the subject :frowning:

Hehe, thanks for your help :slight_smile:

Ok, I didn’t see this first. The call to the BRDF in the G-buffer pass is:

half3 color = UNITY_BRDF_PBS (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, gi.light, gi.indirect).rgb;

It’s about the GI somehow, and not about individual lights.
Have to dig further - inputs are still welcome :slight_smile:

I have the same doubt, do you have any update on this?

Ambient light and material emission are calculated during the g pass, you can see it in the frame debugger if you switch to the last render target