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}