• Create Account

We're offering banner ads on our site from just \$5!

# UE4 IBL / shading confusion

Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

5 replies to this topic

### #1lipsryme  Members   -  Reputation: 1042

Like
2Likes
Like

Posted 27 June 2014 - 07:55 AM

Few months back I had a thread here on trying to implement their approach of IBL using this so called split-sum-approximation and I thought I understood what it was trying to do (same with other aspects of their paper)...I guess I was wrong and I'm even more confused now.

1. Metallic shading parameter: I'm still unsure if I get what this parameter actually does. What I thought it does is have some value [0-1] that just attenuates the diffuse term like so:

Diffuse *= 1.0f - metallic;


Because if we want the material to be more metallic the diffuse term needs to decrease until it's fully gone for an actual metal. Just attenuating the fresnel reflectance does not completely remove that. Looking more closely at the pictures in the paper it looks as if they control the actual FresnelReflectance with it, something like:

FresnelReflectance = lerp(0.04, 1.0f, metallic);


Does anyone know what the parameter actually does ?

2. Cavity Map: They describe this as small-scale shadowing...so is this just an AO map ? But then they talk about this being a replacement for specular (do they mean specular intensity?)

3. Split-sum-approxmation: Now this is the most confusing thing to me. My understanding of this was that they additionally precompute a 2D texture that handles the geometry and fresnel portion of the BRDF and that this is a lookup texture that is used during the realtime lighting pass to attenuate the FresnelReflectance so that it looks more realistic(?) / e.g. removes the glowing edges at high roughness. Am I wrong ?

I've generated this 2d lookup texture and it look almost precisely like the picture in his paper except that it's rotated 45 degrees for some odd reason ? I've tried rotating it so it looks the same as in the paper using photoshop but the result of looking up the values seems completely wrong (did he just artificially rotate the texture just for the paper ??) while the original texture does produce reasonable(?) results in that if applied to a sphere the edges become increasingly stronger the smoother it is.

Let me give you a few screenshots:

This is the texture generated by me:

This is the texture shown in his paper:

And here's a quick video showing how the fresnel reflectance looks like using the formula described in the paper:

FresnelReflectance * EnvBRDF.x + EnvBRDF.y


Also what does he mean by can only afford a single sample for each (why would you have more ?):

Even with importance sampling, many samples still need to be taken. The sample count can be
reduced significantly by using mip maps [3], but counts still need to be greater than 16 for sufficient
quality. Because we blend between many environment maps per pixel for local reflections, we can only
practically afford a single sample for each

In his sample code he uses a sample_count of 1024 which in my tests produces lots of dots on the env map from the random distribution and it only gets better using at least 5k samples. I don't see how he does that. Is this just a case of making the precomputation faster because of hundreds/thousands of probes ?

Edited by lipsryme, 27 June 2014 - 03:46 PM.

### #2Tessellator  Members   -  Reputation: 656

Like
6Likes
Like

Posted 27 June 2014 - 01:13 PM

Hi,

1) As far as I can tell, the metallic parameter controls how the primary colour is used i.e. whether it goes into diffuse (metallic == 0) or into specular (metallic == 1) or a mix somewhere in between. When metallic == 1, the diffuse colour is black (0), when metallic == 0, the specular colour is assumed to be 0.04 (which is typical for the majority of non-metals as they tend to lie between 0.02 and 0.05 for common things). Perhaps something similar to this in shader terms:

vec3 diffuse = mix(colour, vec3(0, 0, 0), metallic);
vec3 specular = mix(vec3(0.04, 0.04, 0.04), colour, metallic);

2) I *think* the cavity map is multiplied by the resulting specular value to help darken it - light from an environment map tends to look a little too bright in small creases without proper occlusion being taken into account, so this is a reasonable work around for it. They no longer need a separate specular input (except for special cases) as it's handled by the single colour input and the metallic parameter.

### #3Tessellator  Members   -  Reputation: 656

Like
0Likes
Like

Posted 27 June 2014 - 01:23 PM

3) Not sure about the precomputed textures - are your inputs mapped differently to his? I've used an empircal EnvironmentBRDF for playing around at home (similar to the one in http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf) and haven't tried that approach yet (it's on my list though). The 1024 samples he takes in the sample code is (I assume) for generating the reference version so he can see how close the split-sum approximation gets.

### #4lipsryme  Members   -  Reputation: 1042

Like
0Likes
Like

Posted 27 June 2014 - 01:42 PM

Hi,

1) As far as I can tell, the metallic parameter controls how the primary colour is used i.e. whether it goes into diffuse (metallic == 0) or into specular (metallic == 1) or a mix somewhere in between. When metallic == 1, the diffuse colour is black (0), when metallic == 0, the specular colour is assumed to be 0.04 (which is typical for the majority of non-metals as they tend to lie between 0.02 and 0.05 for common things). Perhaps something similar to this in shader terms:

vec3 diffuse = mix(colour, vec3(0, 0, 0), metallic);
vec3 specular = mix(vec3(0.04, 0.04, 0.04), colour, metallic);

2) I *think* the cavity map is multiplied by the resulting specular value to help darken it - light from an environment map tends to look a little too bright in small creases without proper occlusion being taken into account, so this is a reasonable work around for it. They no longer need a separate specular input (except for special cases) as it's handled by the single colour input and the metallic parameter.

Thanks for clearing it up for me. That seems to make the most sense...

Is this cavity map just a single channel 8bit texture ? If they use the base color as the specular color I guess this only needs to be greyscale, right ?

Can't think of a reason otherwise...

3) Not sure about the precomputed textures - are your inputs mapped differently to his? I've used an empircal EnvironmentBRDF for playing around at home (similar to the one in http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf) and haven't tried that approach yet (it's on my list though). The 1024 samples he takes in the sample code is (I assume) for generating the reference version so he can see how close the split-sum approximation gets.

But 1024 samples don't come close to being enough to produce an image that has no dots on it (errors from random distribution). As I said it gets better starting at 5k+

The explanation parts in that paper are really confusing as to what he is actually doing. He seems to compare his approximation with a full approximation (N == L) and an importance sampled reference...but...isn't what he is doing here importance sampling ?

I'm using the exact same code to compute the 2d texture with the only exception being G_Smith(Roughness, NdotV, NdotL) which he didn't have code for.

So I looked at his blog and figured it to be this:

float GGX(float NdotV, float a)
{
float k = (a * a) / 2;
return NdotV / (NdotV * (1.0f - k) + k);
}

// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
float G_Smith(float a, float nDotV, float nDotL)
{
return GGX(nDotL, a) * GGX(nDotV, a);
}


Edited by lipsryme, 27 June 2014 - 01:47 PM.

### #5Krzysztof Narkowicz  Members   -  Reputation: 1224

Like
2Likes
Like

Posted 29 June 2014 - 09:11 AM

Metallic works like Tessellator wrote, but it's also has an additional specular parameter (which is equal 0.5 by default). Mentioned specular parameter is driven by a cavity map (single channel).

BaseColor = Cavity * OldBaseColor
Specular = Cavity * 0.5

DiffuseColor = lerp( BaseColor, 0, Metallic )
SpecularColor = lerp( 0.08 * Specular, BaseColor, Metallic )

https://forums.unrealengine.com/archive/index.php/t-3869.html

https://docs.unrealengine.com/latest/INT/Engine/Rendering/Materials/PhysicallyBased/index.html

As for split sum aproximation try comparing with an reference shader, which takes hundreds of samples per pixel in real time.

Edited by Krzysztof Narkowicz, 29 June 2014 - 09:12 AM.

blog | twitter | "Don't have any friends? Still a virgin? Programming is for you!"

### #6lipsryme  Members   -  Reputation: 1042

Like
0Likes
Like

Posted 30 June 2014 - 05:41 AM

I find the FresnelReflectance(they call it Specular) * 0.5 peculiar...

I guess they did it to limit the range of non-metals to something that was foolproof.

Edited by lipsryme, 30 June 2014 - 05:41 AM.

Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

PARTNERS