three_d/renderer/light/
ambient_light.rs1use crate::core::*;
2use crate::renderer::*;
3
4pub struct AmbientLight {
9    pub intensity: f32,
11    pub color: Srgba,
13    pub environment: Option<Environment>,
15}
16
17impl AmbientLight {
18    pub fn new(_context: &Context, intensity: f32, color: Srgba) -> Self {
20        Self {
21            intensity,
22            color,
23            environment: None,
24        }
25    }
26
27    pub fn new_with_environment(
29        context: &Context,
30        intensity: f32,
31        color: Srgba,
32        environment_map: &TextureCubeMap,
33    ) -> Self {
34        Self {
35            intensity,
36            color,
37            environment: Some(Environment::new(context, environment_map)),
38        }
39    }
40}
41
42impl Light for AmbientLight {
43    fn shader_source(&self, i: u32) -> String {
44        if self.environment.is_some() {
45            format!(
46            "
47                uniform samplerCube irradianceMap;
48                uniform samplerCube prefilterMap;
49                uniform sampler2D brdfLUT;
50                uniform vec3 ambientColor;
51    
52                vec3 calculate_lighting{}(vec3 surface_color, vec3 position, vec3 normal, vec3 view_direction, float metallic, float roughness, float occlusion)
53                {{
54                    vec3 N = normal;
55                    vec3 V = view_direction;
56                    vec3 R = reflect(-V, N); 
57                    float NdV = max(0.001, dot(N, V));
58                    
59                    // calculate reflectance at normal incidence; if dia-electric (like plastic) use F0 
60                    // of 0.04 and if it's a metal, use the albedo color as F0 (metallic workflow)    
61                    vec3 F0 = mix(vec3(0.04), surface_color, metallic);
62                    vec3 specular_fresnel = fresnel_schlick_roughness(F0, NdV, roughness);
63                    vec3 diffuse_fresnel = 1.0 - specular_fresnel;
64
65                    // Diffuse
66                    vec3 irradiance = texture(irradianceMap, N).rgb;
67                    vec3 diffuse = diffuse_fresnel * mix(surface_color, vec3(0.0), metallic) * irradiance;
68                    
69                    // 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.
70                    const float MAX_REFLECTION_LOD = 4.0;
71                    vec3 prefilteredColor = textureLod(prefilterMap, R,  roughness * MAX_REFLECTION_LOD).rgb;    
72                    vec2 brdf  = texture(brdfLUT, vec2(NdV, roughness)).rg;
73                    vec3 specular = prefilteredColor * (specular_fresnel * brdf.x + brdf.y);
74    
75                    return (diffuse + specular) * occlusion * ambientColor;
76                }}
77            
78            ", i)
79        } else {
80            format!(
81                "
82                    uniform vec3 ambientColor;
83                    vec3 calculate_lighting{}(vec3 surface_color, vec3 position, vec3 normal, vec3 view_direction, float metallic, float roughness, float occlusion)
84                    {{
85                        return occlusion * ambientColor * mix(surface_color, vec3(0.0), metallic);
86                    }}
87                
88                ", i)
89        }
90    }
91    fn use_uniforms(&self, program: &Program, _i: u32) {
92        if let Some(ref environment) = self.environment {
93            program.use_texture_cube("irradianceMap", &environment.irradiance_map);
94            program.use_texture_cube("prefilterMap", &environment.prefilter_map);
95            program.use_texture("brdfLUT", &environment.brdf_map);
96        }
97        program.use_uniform(
98            "ambientColor",
99            self.color.to_linear_srgb().truncate() * self.intensity,
100        );
101    }
102
103    fn id(&self) -> LightId {
104        LightId::AmbientLight(self.environment.is_some())
105    }
106}
107
108impl Default for AmbientLight {
109    fn default() -> Self {
110        Self {
111            color: Srgba::WHITE,
112            intensity: 1.0,
113            environment: None,
114        }
115    }
116}