use super::*;
impl Light {
pub fn new_directional(direction: Vector3D, color: Vector3D) -> Light {
Light::new(
LightType::Directional,
Vector3D::zero(),
direction.normalized(),
color,
1.0,
0.0,
0.0,
)
}
pub fn new_point(position: Vector3D, color: Vector3D, intensity: f64) -> Light {
Light::new(
LightType::Point,
position,
Vector3D::zero(),
color,
intensity,
1.0,
0.0,
)
}
pub fn new_spot(
position: Vector3D,
direction: Vector3D,
color: Vector3D,
intensity: f64,
half_angle_rad: f64,
) -> Light {
Light::new(
LightType::Spot,
position,
direction.normalized(),
color,
intensity,
1.0,
half_angle_rad.cos(),
)
}
}
impl Material {
pub fn lambert(albedo: Vector3D) -> Material {
Material::new(
MaterialKind::Lambert,
albedo,
0.0,
LIGHTING_DEFAULT_SHININESS,
Vector3D::zero(),
)
}
pub fn phong(albedo: Vector3D, specular: f64, shininess: f64) -> Material {
Material::new(
MaterialKind::Phong,
albedo,
specular,
shininess,
Vector3D::zero(),
)
}
pub fn emissive(color: Vector3D) -> Material {
Material::new(MaterialKind::Lambert, Vector3D::zero(), 0.0, 0.0, color)
}
}
impl LightingUniforms {
pub fn with_eye(eye: Vector3D) -> LightingUniforms {
LightingUniforms::new(Vec::new(), LIGHTING_DEFAULT_AMBIENT, eye)
}
pub fn add_light(&mut self, light: Light) {
self.get_mut_lights().push(light);
}
pub fn shade(
&self,
position: Vector3D,
normal: Vector3D,
material: &Material,
occluders: &[(Vector3D, f64)],
) -> Vector3D {
let mut color: Vector3D = self.get_ambient();
let eye: Vector3D = self.get_eye();
let to_eye: Vector3D = eye - position;
let view_dist: f64 = to_eye.magnitude();
let view_dir: Vector3D = if view_dist > EPSILON {
to_eye.scaled(1.0 / view_dist)
} else {
Vector3D::zero()
};
for light in self.get_lights().iter() {
let kind: LightType = light.get_kind();
let shadow: f64 = match kind {
LightType::Directional => 1.0,
LightType::Point | LightType::Spot => {
soft_shadow_factor(position, light.get_position(), occluders)
}
};
if shadow <= 0.0 {
continue;
}
let mut lambert_input: Light = light.clone();
match kind {
LightType::Directional => {}
LightType::Point | LightType::Spot => {
let to_light: Vector3D = light.get_position() - position;
let dist: f64 = to_light.magnitude().max(LIGHTING_POINT_LIGHT_MIN_DISTANCE);
let dir: Vector3D = to_light.scaled(1.0 / dist);
lambert_input.set_direction(dir);
}
}
let diffuse: Vector3D = compute_lambert(&lambert_input, normal, material);
let mut spec_input: Light = lambert_input.clone();
spec_input.set_intensity(
light.get_intensity() * apply_falloff(view_dist, light.get_falloff()),
);
let specular: Vector3D = compute_phong(&spec_input, normal, view_dir, material);
let mut contribution: Vector3D = diffuse + specular;
contribution = contribution.scaled(shadow);
color += contribution;
}
let emissive: Vector3D = material.get_emissive();
color += emissive;
color
}
}