euv_engine/lighting/
fn.rs1use super::*;
2
3pub fn compute_lambert(light: &Light, normal: Vector3D, material: &Material) -> Vector3D {
29 let light_dir: Vector3D = light.get_direction();
30 let cos: f64 = normal.dot(light_dir).max(0.0);
31 let intensity: f64 = light.get_intensity();
32 let color: Vector3D = light.get_color();
33 let albedo: Vector3D = material.get_albedo();
34 let k: f64 = intensity * cos;
35 Vector3D::new(
36 color.get_x() * albedo.get_x() * k,
37 color.get_y() * albedo.get_y() * k,
38 color.get_z() * albedo.get_z() * k,
39 )
40}
41
42pub fn compute_phong(
65 light: &Light,
66 normal: Vector3D,
67 view_dir: Vector3D,
68 material: &Material,
69) -> Vector3D {
70 let light_dir: Vector3D = light.get_direction();
71 let reflect: Vector3D = (light_dir - normal.scaled(2.0 * light_dir.dot(normal))).normalized();
72 let spec_factor: f64 = reflect
73 .dot(view_dir)
74 .max(0.0)
75 .powf(material.get_shininess());
76 let specular: f64 = material.get_specular();
77 let intensity: f64 = light.get_intensity();
78 let color: Vector3D = light.get_color();
79 let k: f64 = intensity * spec_factor * specular;
80 Vector3D::new(color.get_x() * k, color.get_y() * k, color.get_z() * k)
81}
82
83pub fn apply_falloff(distance: f64, falloff: f64) -> f64 {
96 let d: f64 = distance.abs();
97 let denom: f64 = 1.0 + falloff * d * d;
98 (1.0 / denom).max(0.0)
99}
100
101pub fn ray_sphere_intersect(
120 origin: Vector3D,
121 dir: Vector3D,
122 center: Vector3D,
123 radius: f64,
124) -> Option<(f64, Vector3D)> {
125 let oc: Vector3D = origin - center;
126 let b: f64 = oc.dot(dir);
127 let c: f64 = oc.dot(oc) - radius * radius;
128 let disc: f64 = b * b - c;
129 if disc < 0.0 {
130 return None;
131 }
132 let sq: f64 = disc.sqrt();
133 let t1: f64 = -b - sq;
134 let t2: f64 = -b + sq;
135 let t: f64 = if t1 >= 0.0 {
136 t1
137 } else if t2 >= 0.0 {
138 t2
139 } else {
140 return None;
141 };
142 let hit: Vector3D = origin + dir.scaled(t);
143 let normal: Vector3D = (hit - center).normalized();
144 Some((t, normal))
145}
146
147pub fn ray_aabb_intersect(
161 origin: Vector3D,
162 dir: Vector3D,
163 aabb_min: Vector3D,
164 aabb_max: Vector3D,
165) -> Option<(f64, f64, Vector3D)> {
166 let inv_dir: Vector3D = Vector3D::new(1.0 / dir.get_x(), 1.0 / dir.get_y(), 1.0 / dir.get_z());
167 let t1x: f64 = (aabb_min.get_x() - origin.get_x()) * inv_dir.get_x();
168 let t2x: f64 = (aabb_max.get_x() - origin.get_x()) * inv_dir.get_x();
169 let t1y: f64 = (aabb_min.get_y() - origin.get_y()) * inv_dir.get_y();
170 let t2y: f64 = (aabb_max.get_y() - origin.get_y()) * inv_dir.get_y();
171 let t1z: f64 = (aabb_min.get_z() - origin.get_z()) * inv_dir.get_z();
172 let t2z: f64 = (aabb_max.get_z() - origin.get_z()) * inv_dir.get_z();
173 let tmin_x: f64 = t1x.min(t2x);
174 let tmax_x: f64 = t1x.max(t2x);
175 let tmin_y: f64 = t1y.min(t2y);
176 let tmax_y: f64 = t1y.max(t2y);
177 let tmin_z: f64 = t1z.min(t2z);
178 let tmax_z: f64 = t1z.max(t2z);
179 let t_near: f64 = tmin_x.max(tmin_y).max(tmin_z);
180 let t_far: f64 = tmax_x.min(tmax_y).min(tmax_z);
181 if t_near > t_far || t_far < 0.0 {
182 return None;
183 }
184 let hit: Vector3D = origin + dir.scaled(t_near);
185 let cx: f64 = (aabb_min.get_x() + aabb_max.get_x()) * 0.5;
186 let cy: f64 = (aabb_min.get_y() + aabb_max.get_y()) * 0.5;
187 let cz: f64 = (aabb_min.get_z() + aabb_max.get_z()) * 0.5;
188 let dx: f64 = hit.get_x() - cx;
189 let dy: f64 = hit.get_y() - cy;
190 let dz: f64 = hit.get_z() - cz;
191 let ex: f64 = (aabb_max.get_x() - aabb_min.get_x()) * 0.5;
192 let ey: f64 = (aabb_max.get_y() - aabb_min.get_y()) * 0.5;
193 let ez: f64 = (aabb_max.get_z() - aabb_min.get_z()) * 0.5;
194 let ax: f64 = dx.abs() / ex.max(EPSILON);
195 let ay: f64 = dy.abs() / ey.max(EPSILON);
196 let az: f64 = dz.abs() / ez.max(EPSILON);
197 let normal: Vector3D = if ax >= ay && ax >= az {
198 Vector3D::new(dx.signum(), 0.0, 0.0)
199 } else if ay >= az {
200 Vector3D::new(0.0, dy.signum(), 0.0)
201 } else {
202 Vector3D::new(0.0, 0.0, dz.signum())
203 };
204 Some((t_near, t_far, normal))
205}
206
207pub fn soft_shadow_factor(
224 origin: Vector3D,
225 light_pos: Vector3D,
226 occluders: &[(Vector3D, f64)],
227) -> f64 {
228 let to_light: Vector3D = light_pos - origin;
229 let dist: f64 = to_light.magnitude();
230 if dist < EPSILON {
231 return 1.0;
232 }
233 let dir: Vector3D = to_light.scaled(1.0 / dist);
234 for &(center, radius) in occluders.iter() {
235 if let Some((t, _)) = ray_sphere_intersect(origin, dir, center, radius)
236 && t > EPSILON
237 && t < dist - EPSILON
238 {
239 return 0.0;
240 }
241 }
242 1.0
243}