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
//! Data types and functions related to materials.
use std::sync::Arc;
use nanorand::tls::TlsWyRand;
pub use pbr_material::PbrMaterial;
use crate::color::{Color, Texture};
use crate::math::{Hit, Point2, Ray, Vec3};
mod pbr_material;
/// Characterize optical properties of a surface.
pub trait Material: Send + Sync {
/// Generate the next ray to be traced.
///
/// If the path is to be terminated, [`None`] is returned.
fn next_ray(&self, ray: Ray, hit: Hit, rng: &mut TlsWyRand) -> Option<Ray>;
/// Return the color at the given UV coordinates.
///
/// The first item is the reflected color, the second item is the emitted color.
fn get_color(&self, uv: Point2) -> (Color, Color);
}
/// Compute the combination of a [`Color`], an optional [`Texture`] and a given `strength`
/// for the given UV coordinates.
pub fn compute_color(
color: Color,
texture: &Option<Arc<dyn Texture>>,
strength: f64,
uv: Point2,
) -> Color {
strength as f32
* color
* match texture {
None => Color::WHITE,
Some(t) => t.get_pixel(uv.x, uv.y),
}
}
/// Compute the normal at the given UV coordinates using the `normal_texture`.
///
/// If `normal_texture` is [`None`], `normal` is returned.
pub fn compute_normal(
normal: Vec3,
tangent: Vec3,
bitangent: Vec3,
normal_texture: &Option<Arc<dyn Texture>>,
uv: Point2,
) -> Vec3 {
match normal_texture {
None => normal,
Some(texture) => {
let texture_normal = Vec3::from(texture.get_pixel(uv.x, uv.y)) * 2.0 - Vec3::splat(1.0);
(texture_normal.x * tangent + texture_normal.y * bitangent + texture_normal.z * normal)
.normalize()
}
}
}