• 9
• 11
• 9
• 20
• 12

# PBR Metalness equation

This topic is 901 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I've been messing around with some texturing in some programs that have PBR viewport shaders. From a little reading and messing around, it seems like the only thing that the metalness changes in the lighting equation is whether the specular is multiplied or added. Metal = multiply, non-metal = add.

Is that correct?

##### Share on other sites

I use a value of 0.08 as multiplier of the specular value, 0.03 is more correct ?

SurfaceData.DiffuseColor = Diffuse_Lambert( FinalBaseColor.rgb - ( FinalBaseColor.rgb * Metallic ) );
SurfaceData.SpecularColor = lerp( 0.08f * Specular, FinalBaseColor.rgb, Metallic );
Edited by Alundra

##### Share on other sites

Lot's of things confusing me here. In the Marmoset example, F0 is in range 0 to 1, but your second comment says to use a color for F0. I guess that is fine because is the amount of R,G,B independent reflection. Either way, just a multiplication on the specular computation.

Q1: For a non metal that is glossy, if F0 = vec3(.03,.03,.03), then how will the equation ever reflect full light? I'm definitely missing some equations here.

For a shiny plastic, say a guitar or piece of marble.  roughness = 0, metal= 0, diffuse = dark green:
---->dark green * textureCube(mipLevel 0)   + textureCube(mipLevel0)*vec3(.03, .03, .03)  ?

My current understanding which must be wrong because shiny dark green plastic just comes out to be shiny dark green plastic with a super tiny amount of specular.

Q2: What is used for the incoming light values for diffuse?

IncomingSpecularLightValueAtPixel = textureCube( reflected eye over surface normal,  roughnessValue)

IncomingDiffuseLightValueAtPixel  = same thing?

##### Share on other sites
For a non metal that is glossy, if F0 = vec3(.03,.03,.03), then how will the equation ever reflect full light?

There are two elements to this question,

First, a non metal material will tend to have a dimmer reflection of the surrounding (because some of the light will be absorbed and/or diffused). You can usually still see bright spots because the intensity of point lights is so much higher than the surrounding.

Second, that color F0 is the minimum total reflection. If you are seeing things from a grazing angle, the reflection is closer to one (if you take the Fresnel effect into account).

Here's an illustration : http://media.codermind.com/lighting/dielectric-ggx-rough-0-2.mp4

There's a bright spot from the sun, it is dim when it is facing the camera but becomes much whiter as it is seen from increasingly grazing angles on the edges of the sphere.

##### Share on other sites

I'll have to start implementing this tonight and come back. I'm thinking what I'm missing is that the amount of reflection is not actually additive with non-metals.

Ex. Dark green shiny plastic
reflectiveness = matrialReflectiveProperty + Fresnel

FinalColor = (1.0- reflectiveness)*darkGreen  + reflectiveness*textureCube(envTexture, roughness)

I'm thinking this is more what the equation would have to look like. And in the case of metals something like:

reflectiveness = matrialReflectiveProperty + Fresnel
FinalColor = /*(1.0- reflectiveness)*darkGreen*/  + reflectiveness*textureCube(envTexture, roughness)*metalColor

That seems more correct. If a material is 100% reflective, the diffuse doesn't matter right? I can't find any actual code used for PBR.  That was how I did my car shader, but then what is F0?

##### Share on other sites

If a material is 100% reflective, the diffuse doesn't matter right?

No.  What's stored in the diffuse texture always matters, it just means different things in different cases.  In the setup you're trying to use, if a material is 100% metal, the value in the diffuse texture is re-purposed to be the F0 value.  Otherwise, for non-metal (dielectric) materials you hard-code F0 to ~0.03-~0.04 for most materials (see Hodgman's comment), and the value in the diffuse texture is the diffuse color you're used to.  I haven't used Marmoset, but from seeing what a few other places are doing, the 0 to 1 mapping for F0 will probably do something like change the value from ~0.01 to ~0.08.

I think what you're referring to as reflectiveness is what most people refer to as roughness (or shininess).  This is stored in its own texture and is used alongside the others to control how shiny the surface is - this is what controls the specular highlights for direct lighting, and the mip selection for indirect lighting.  It is used as part of a larger equation to control surface appearance.

Most approaches use the following (or close variations) as the starting point of textures using physically based rendering.

Diffuse (or Base Color):  for dielectrics, exactly what's in the texture.  for metals, the f0 value

Metal:  0 - dielectric.  1 - metal.

Roughness:  how rough the microsurfaces along the geometry are (alternatively, this can be Shininess, which is just 1.0 - roughness)

Normal:  plain old normal map

There are a few variations to the above that different engines use, but that should give you the gist of where values are coming from.

As far as finding actual code used for PBR (btw, you need to read this stuff - start with the Physics of Math and Shading presentation and go from there):

##### Share on other sites

Ok I see F0 is when the angle to the surface is 0.  I already understood this idea, just didn't know what it was. I'll respond if I end up getting with this shader.

##### Share on other sites

I'm close but I don't get how F0 = a color. Fresnel is a scalar I thought? An amount of reflectivness given a direction of the viewer to the surface. So how do I plug a color in to the fresnel equation?

This picture demonstrates why I'm confused. I have Roughness = 0. BaseColor = Red.  Then the top image is pure metal, bottom is pure plastic.

Metal
Since metal has no diffuse, the red must come from the specular portion of the equation, which means my cube map must multiplied by red. However in image 3, we have the fresnel effect, where at high angles, it is not multiplied by red. So the only equation that works for this is.

Output = 0*red  + mix(  cubeMap*red,  cubeMap,  fresnelAmount);

So we are either direct on viewing a tinted cubemap  or at high angles fresnel goes to 1.0, in which case the cubemap takes over completely.  For some reason I feel like this is wrong but based on these images that is the only mathematics that makes sense to what I see.

Plastic
To arrive at this plastic value which is image #2, it seems like:
Output = red*cubeMap  +   cubeMap*fresnelAmount;

Our diffuse material reflects only red values based on light intensity incoming and then we have specular added ontop of this, which appears to be untinted specular.

However, I feel like both of these are wrong.