Where is the lighting code of the deferred shader?

I read the deferred pass of standard shader.As we know,there are two parts of a deferred rendering,one is calculating GBuffer,which can be found in standard shader:
#pragma vertex vertDeferred
#pragma fragment fragDeferred
another is lighting,behaving like the postprocessing.But I don’t know where is the lighting code to finish the rendering of the standard shader.Does anybody know that?And if possible,please tell me which C# file calls that shader to calculating lighting.

I doubt lighting code is in *Internal-DeferredShading.shader.*However,first,I have no proof.Second,it’s strange that there is no emissive calculation in it.But standard shader output 4 GBuffer include emissive.

It’s scattered in some .cginc files, you probably need to look in UnityPBSLighting.cginc.

Thanks,but it seems not right.The lighting code which I mention above should be called after getting GBuffer,so the 4 GBuffer which outputted by fragDeferred in build-in standard shader should be the input value of the lighting code.I’ve seen the function LightingStandardSpecular_Deferred in UnityPBSLighting.cginc,it is to create the 4 GBuffer,which is not I want.

Internal-DeferredShading.shader has a function CalculateLight, which decompresses the GBuffer and passes it on to UNITY_BRDF_PBS, which is then expanded into a specific BRDF using a macro. This expansion happens in UnityPBSLighting.cginc. The actual BRDF functions are in UnityStandardBRDF.cginc

One question is the about emissive.This is the fs of standard shader:
void fragDeferred (
VertexOutputDeferred i,
out half4 outGBuffer0 : SV_Target0,
out half4 outGBuffer1 : SV_Target1,
out half4 outGBuffer2 : SV_Target2,
out half4 outEmission : SV_Target3 // RT3: emission (rgb), --unused-- (a)
#if defined(SHADOWS_SHADOWMASK) && (UNITY_ALLOWED_MRT_COUNT > 4)
,out half4 outShadowMask : SV_Target4 // RT4: shadowmask (rgba)
#endif
)
{
}

This is CalculateLight in Internal-DeferredShading.shader:
half4 CalculateLight (unity_v2f_deferred i)
{
float3 wpos;
float2 uv;
float atten, fadeDist;
UnityLight light;
UNITY_INITIALIZE_OUTPUT(UnityLight, light);
UnityDeferredCalculateLightParams (i, wpos, uv, light.dir, atten, fadeDist);

light.color = _LightColor.rgb * atten;

// unpack Gbuffer
half4 gbuffer0 = tex2D (_CameraGBufferTexture0, uv);
half4 gbuffer1 = tex2D (_CameraGBufferTexture1, uv);
half4 gbuffer2 = tex2D (_CameraGBufferTexture2, uv);
UnityStandardData data = UnityStandardDataFromGbuffer(gbuffer0, gbuffer1, gbuffer2);

float3 eyeVec = normalize(wpos-_WorldSpaceCameraPos);
half oneMinusReflectivity = 1 - SpecularStrength(data.specularColor.rgb);

UnityIndirect ind;
UNITY_INITIALIZE_OUTPUT(UnityIndirect, ind);
ind.diffuse = 0;
ind.specular = 0;

half4 res = UNITY_BRDF_PBS (data.diffuseColor, data.specularColor, oneMinusReflectivity, data.smoothness, data.normalWorld, -eyeVec, light, ind);

return res;
}

We can find there is no _CameraGBufferTexture3 in CalculateLight,which stores emissive information outputted by “out half4 outEmission : SV_Target3”.
So where is the code to decompresses the emissive GBuffer?

First, please use code tags .

The “emission” render target is also what ambient and baked lighting is rendered to during the gbuffer rendering. After that it continues to be the render target for deferred reflections, deferred lighting, and eventually the skybox and everything else. It’s never “decoded” in the sense that it’s bound as a gbuffer for something else to sample from as it simply becomes the target everything else renders to.

If you want to access it directly, you’d need to copy it to another render texture with a command buffer. But if you need just the emissive with out any ambient lighting, you’d need to render that out separately with a replacement shader pass or similar.

Thank you very much!That’s what I want to know.By the way thanks also for letting me know the code tag function.

One more question,the GI result in emissive GBuffer which is outputted by fragDeferred of standard shader in UnityStandardCore.cginc has already multiplied ambient occlusion(AO).And in the following lighting code,AO is useless any more.However,when standard shader output GBuffers,it use a alpha channel of the first GBuffer to store AO,the code can be found in UnityGBuffer.cginc as below:

void UnityStandardDataToGbuffer(UnityStandardData data, out half4 outGBuffer0, out half4 outGBuffer1, out half4 outGBuffer2)
{
    // RT0: diffuse color (rgb), occlusion (a) - sRGB rendertarget
    outGBuffer0 = half4(data.diffuseColor, data.occlusion);

    // RT1: spec color (rgb), smoothness (a) - sRGB rendertarget
    outGBuffer1 = half4(data.specularColor, data.smoothness);

    // RT2: normal (rgb), --unused, very low precision-- (a)
    outGBuffer2 = half4(data.normalWorld * 0.5f + 0.5f, 1.0f);
}

But I search the lighting code and find no code use AO in Internal-DeferredShading.shader.
So my question is why fragDeferred of standard shader still output AO information to GBuffer?

It’s not useless. It’s used for deferred reflections. Original the diffuse alpha gbuffer was unused. They used to do reflections as part of the gbuffer pass, which did reflections the same as forward (which uses a single pre-blended reflection probe, or blends between two reflection probes uniformly across the entire object), so it could apply the per object AO then and didn’t need to keep it around. However it’s nice to have it because it means you can do custom “faux ambient” lights that are affected by AO.

One unfortunate side effect of putting all of these into the same buffer is screen space AO applies to ambient lighting, baked lighting, and emissive alike as it runs after the initial gbuffer and deferred reflections are rendered, but before real time lights. Unity uses another trick when you’re using the shadowmask baked shadows mode in that “baked” lights are really just baked shadows, and are otherwise rendered as real time deferred lights. This has a number of benefits, one of the smallest of which is that SSAO doesn’t affect those lights like it does when using other baked shadow modes.

1 Like

I have encountered a problem I am not sure how to solve which I think is related to this discussion,
we are using deferred decals with the default render and have decals that write to GBuffer0 and GBuffer2 at CommandBuffer.BeforeReflections but since our scene is mostly lit by indirect lighting the decals become invisible when the lightning in the scene gets too low, I have tracked the issue to RenderDeferred.ReflectionsToEmissive where I see that the “TempBuffer 55” does not contain the decals only the terrain color, but I don’t know what to do with this information.

I don’t know how to solve this, help would be very appreciated.