Environment light shader
@@ -96,29 +96,45 @@ impl Light for EnvironmentLight {
fn shader_source(&self, i: u32) -> String {
format!(
"
-
- uniform samplerCube irradianceMap{}; // prefiltered env cubemap
- //uniform sampler2D iblbrdf; // IBL BRDF normalization precalculated tex
+ uniform samplerCube irradianceMap;
+ uniform samplerCube prefilterMap;
+ uniform sampler2D brdfLUT;
vec3 calculate_lighting{}(vec3 surface_color, vec3 position, vec3 normal, float metallic, float roughness, float occlusion)
{{
+ vec3 N = normal;
vec3 V = normalize(eyePosition - position);
- float NdV = max(0.001, dot(normal, V));
+ vec3 R = reflect(-V, N);
+ // calculate reflectance at normal incidence; if dia-electric (like plastic) use F0
+ // of 0.04 and if it's a metal, use the albedo color as F0 (metallic workflow)
vec3 F0 = vec3(0.04);
F0 = mix(F0, surface_color, metallic);
- vec3 kS = fresnelSchlickRoughness(NdV, F0, roughness);
+
+ // ambient lighting (we now use IBL as the ambient term)
+ vec3 F = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness);
+
+ vec3 kS = F;
vec3 kD = 1.0 - kS;
- vec3 irradiance = texture(irradianceMap{}, normal).rgb;
+ kD *= 1.0 - metallic;
+
+ vec3 irradiance = texture(irradianceMap, N).rgb;
vec3 diffuse = irradiance * surface_color;
- vec3 ambient = (kD * diffuse) * occlusion;
- return ambient;
+
+ // sample both the pre-filter map and the BRDF lut and combine them together as per the Split-Sum approximation to get the IBL specular part.
+ const float MAX_REFLECTION_LOD = 4.0;
+ vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb;
+ vec2 brdf = texture(brdfLUT, vec2(max(dot(N, V), 0.0), roughness)).rg;
+ vec3 specular = prefilteredColor * (F * brdf.x + brdf.y);
+
+ return (kD * diffuse + specular) * occlusion;
}}
- ", i, i, i)
+ ", i)
}
fn use_uniforms(&self, program: &Program, _camera: &Camera, i: u32) -> ThreeDResult<()> {
- program.use_texture_cube(&format!("irradianceMap{}", i), &self.irradiance_map)?;
+ program.use_texture_cube("irradianceMap", &self.irradiance_map)?;
+ program.use_texture_cube("prefilterMap", &self.prefilter_map)?;
Ok(())
}
}
