1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use crate::core::*;
use crate::renderer::*;
pub struct AmbientLight {
pub color: Color,
pub intensity: f32,
pub environment: Option<Environment>,
}
impl Light for AmbientLight {
fn shader_source(&self, i: u32) -> String {
if self.environment.is_some() {
format!(
"
uniform samplerCube irradianceMap;
uniform samplerCube prefilterMap;
uniform sampler2D brdfLUT;
uniform vec3 ambientColor;
vec3 calculate_lighting{}(vec3 surface_color, vec3 position, vec3 normal, vec3 view_direction, float metallic, float roughness, float occlusion)
{{
vec3 N = normal;
vec3 V = view_direction;
vec3 R = reflect(-V, N);
float NdV = max(0.001, dot(N, V));
// 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 = mix(vec3(0.04), surface_color, metallic);
vec3 specular_fresnel = fresnel_schlick_roughness(F0, NdV, roughness);
vec3 diffuse_fresnel = 1.0 - specular_fresnel;
// Diffuse
vec3 irradiance = texture(irradianceMap, N).rgb;
vec3 diffuse = diffuse_fresnel * mix(surface_color, vec3(0.0), metallic) * irradiance;
// 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(NdV, roughness)).rg;
vec3 specular = prefilteredColor * (specular_fresnel * brdf.x + brdf.y);
return (diffuse + specular) * occlusion * ambientColor;
}}
", i)
} else {
format!(
"
uniform vec3 ambientColor;
vec3 calculate_lighting{}(vec3 surface_color, vec3 position, vec3 normal, vec3 view_direction, float metallic, float roughness, float occlusion)
{{
return occlusion * ambientColor * mix(surface_color, vec3(0.0), metallic);
}}
", i)
}
}
fn use_uniforms(&self, program: &Program, _i: u32) -> ThreeDResult<()> {
if let Some(ref environment) = self.environment {
program.use_texture_cube("irradianceMap", &environment.irradiance_map)?;
program.use_texture_cube("prefilterMap", &environment.prefilter_map)?;
program.use_texture("brdfLUT", &environment.brdf_map)?;
}
program.use_uniform_vec3("ambientColor", &(self.color.to_vec3() * self.intensity))
}
}
impl Default for AmbientLight {
fn default() -> Self {
Self {
color: Color::WHITE,
intensity: 1.0,
environment: None,
}
}
}