现有PBR流程中与F0有关的公式
F0的定义
- F0,表示平面的基础反射率,它是利用所谓折射指数(Indices of Refraction)或者说IOR计算得出的
- ior的方式计算f0 WebGL 一个PBR Viewer解析 (juejin.cn)
- ior计算两种介质的折射率,用1是因为空气的折射率指定为1
f0 = vec3(pow(( u_Ior - 1.0) / (u_Ior + 1.0), 2.0)); //f0 通过ior计算 - 当光线垂直(以0度角)撞击表面时,该光线被反射(Reflected)为镜面反射光的比率被称为F0,(当然也有F90的说法)
- 一般F0都是0.04了,不直接通过uniform的方式输入,而是以baseColor里面或者通过ior来写
菲涅尔(直接光照)
- F为菲涅尔反射系数(Fresnel reflection coefficient)
- 这里的F0是带有颜色的,高光流是直接取specular贴图颜色,金属流是mix(f0, baseColor, metallic)取得
- 因为示意图近似指数函数,所以函数这么写
- PBR的原理大部分与菲涅尔和F0相关 PBR原理 (juejin.cn)
- 菲涅尔效应表示观察看到的镜面反射光线的"量"(反射和折射)与视角相关的现象,是个百分比来的
- 金属所有可见颜色都来自菲涅尔反射(DFG中,G是一种百分比遮挡,D是镜面波瓣)
- 下面这张图是描述上面这个公式的,
- 当h与v的角度90°的时候(掠射角入射),公式的值是最大的,为1,菲涅尔反射率最大.就最亮
- 当h与v的角度0°的时候,公式的值是F0.反射率不一定最小.
- F0即0度角入射的菲涅尔反射率
- 影响公式的有v和h(即l),两个向量
- 对于0°和45°之间的入射角,反射率几乎是恒定的。
- 在45°和75°之间,反射率变化更为显着(通常但不总是有所增加)。
- 在75°和90°之间,反射率总是迅速变为1
- 该光线被反射(Reflected)为镜面反射光的比率被称为F0。
- 折射(refracted)到表面中的光量则为为1-F0。
- 光滑表面在切线入射时有将接近100%的镜面反射。
- f0 进行菲涅尔公式计算
vec3 V = normalize(camPos - WorldPos);
vec3 L = normalize(lightPositions[i] - WorldPos);
vec3 H = normalize(V + L); //半程向量
vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0);
vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
- 当然一般不用pow5,用下面这个
half Pow5(half v)
{
return v * v * v * v * v;
}
- 当IOR接近1的时候 可能有较大误差,直接使用精确的菲涅尔
金属与非金属与F0
- 金属与非金属
- 非金属 大部分不会高于0.17,
- 金属 大部分0.5和1.0之间变化
- 金属与非金属跟粗糙度无关
- f0与表面混合 以(osg.js框架的pbr为准 IBL)
- 金属的metallic为1,非金属的metallic为0,只取整数
- 金属和非金属都有菲尼尔效应
vec3 f0 = vec3(0.04);
vec3 diffuseColor = mix(baseColor.rgb, vec3(0., 0., 0.), metallic);
vec3 specularColor = mix(f0, baseColor, metallic);
- 非金属
- 非金属有spcular
- 非金属 0.04作为基础反射率已经足够好了,4%的反射
vec3 f0 = vec3(0.04);
vec3 diffuseColor = baseColor.rgb;
vec3 specularColor = f0;
- 金属
- 金属没有漫反射
- 金属的可见颜色都来自菲涅尔反射
- 金属表面而言基础反射率一般是带有色彩的
- 金属会立即吸收任何折射光线,不会出现任何次表面散射或透明感
vec3 f0 = vec3(0.04);
vec3 diffuseColor = 0
vec3 specularColor = baseColor
能量守恒(直接光照)
uniform float metallic;
vec3 kS = F;
kd = (vec3(1.0) - F)(1.0 - metallic)
BRDF积分贴图(间接光照)
- 2D查找纹理存储是菲涅耳响应的系数(R 通道)和偏差值(G 通道)
float lod = getMipLevelFromRoughness(roughness);
vec3 prefilteredColor = textureCubeLod(PrefilteredEnvMap, refVec, lod); //roughnesss
vec2 envBRDF = texture2D(BRDFIntegrationMap, vec2(NdotV, roughness)).xy; //brdf
vec3 indirectSpecular = prefilteredColor * (F * envBRDF.x + envBRDF.y) //fr