In-engine environment map probes questions
1. In a deferred renderer (deferred shading) at what stage and how would I add the environment to use as glossy reflections ?
My first thought was ofc in the lighting/material pass but the problem here is you multiply all your lighting in a later compose pass with the albedo. But what if the albedo was pure black (e.g. metals). Whatever I do in the lighting shader it's going to be completely black in the end.
So how do I do that ? Add the environment reflections to the albedo during gbuffer ? I do need access to the normals for this to work so this won't work anywhere else.
2. I understand that you can use AMD's cubemap gen to generate blurred mip maps for an environment map where you can later fetch the texture mip based on the glossiness of the material. But for this to work with probes that were placed everywhere around the level, do I really have to save those to the hdd and manually create those mips with cubemap gen myself ?
1. You would need an extra specular buffer to composite correctly.
2. I believe the source code is available. You should be able to automate it.
1. You add environment reflections the same way you'd add the specular contribution from a light source. They're both the same exact thing, they're just adding the contribution from different sources of reflections. So you'll want to use the same specular albedo and same roughness/glossiness/specular power that you'd use in your lighting equations.
2. There's a library version included in the download that you can integrate into your own tools.
But whatever the lighting may be if I multiply this with a black diffuse albedo later on it's going to be black. How would I work around this?You shouldn't be multiplying your specular lighting with the diffuse albedo in the first place. This "compose pass" simply sounds incorrect.
To add environment map, multiply the sample by the fresnel term (but calculate the Fresnel term using the view vector and the normal instead of the light direction and the half vector)
More info here (slide 54, Fresnel function some slides before).
I do my lighting (meaning diffuse+specular and + ambient) an later use this to multiply it with the albedo. Is that wrong? I've never seen it done differentlyYes it is. Diffuse albedo of a material should not be multiplied with the specular lighting because the specular highlight color of a light hitting a non-metallic material should be the color of the light.
You could multiply diffuse albedo with specular lighting to fake metallic surfaces, but only to fake.
Sorry for the double post. Only saw your reply after I made the first post.
Now that I think about it it does seem stupidly redundant ...
So it's correct that the brighter the specular gets the less "color" (texture color) it gets ? It looks a little odd to me at first sight.
Here's some code I'm using now
float4 Ls = float4(0, 0, 0, 1);
float4 Lr = float4(0, 0, 0, 1);
// Incident radiance
float3 Li = _LightColor.rgb * _LightIntensity;
// Calculate cos(theta)
float NdotL = saturate(dot(N, L));
// Compute Fresnel Term (F) using Schlick's approximation
float base = 1.0 - dot(V, H_norm);
float exponential = pow(base, 5.0);
float3 F = exponential + 0.028f * (1.0 - exponential);
float FresnelFactor = 1.0f;
F = lerp(1.0f, 0.028f, FresnelFactor);
// Add ambient light
Lr.rgb += ambient;
// Add diffuse light
Lr.rgb += NdotL * Li * shadowFactor;
Lr.rgb *= DiffuseAlbedo;
Lr.rgb *= 1.0f - F;
// Kelemen/Szirmay-Kalos (D) using a precomputed beckmann distribution
float NdotH = saturate(dot(N, H_norm));
float PH = pow(2.0f * BeckmannTarget.SampleLevel(LinearSampler, float2(NdotH, SpecularPower), 0).r, 10.0f);
float ksk = max(PH * F / dot(H, H), 0.0f);
float D = ksk;
// Cook-Torrance approximation (G) by Kelemen and Szirmay-Kalos
float NdotV = saturate(dot(N, V)) + 0.00001f;
float LdotH = saturate(dot(L, H_norm)); + 0.00001f;
float G = 1.0f / (LdotH * LdotH);
float3 nominator = G * D;
float denominator = 4.0f;
Ls.rgb += nominator / denominator;
Ls.rgb *= NdotL * Li * shadowFactor; // multiply by cosine factor and incoming radiance
return Lr + Ls;