materials: add StripePattern as a Material color option.
This commit is contained in:
parent
3e383c4dbd
commit
bfa3282a37
@ -22,7 +22,7 @@ fn main() -> Result<()> {
|
||||
let half = wall_size / 2.;
|
||||
let mut shape = Shape::sphere();
|
||||
shape.material = Material {
|
||||
color: Color::new(1., 0.2, 1.),
|
||||
color: Color::new(1., 0.2, 1.).into(),
|
||||
specular: 0.5,
|
||||
diffuse: 0.7,
|
||||
shininess: 30.,
|
||||
|
||||
@ -42,7 +42,7 @@ fn main() -> Result<()> {
|
||||
let mut floor = Shape::sphere();
|
||||
floor.set_transform(Matrix4x4::scaling(10., 0.01, 10.));
|
||||
floor.material = Material {
|
||||
color: Color::new(1., 0.9, 0.9),
|
||||
color: Color::new(1., 0.9, 0.9).into(),
|
||||
specular: 0.,
|
||||
..Material::default()
|
||||
};
|
||||
@ -68,7 +68,7 @@ fn main() -> Result<()> {
|
||||
let mut middle = Shape::sphere();
|
||||
middle.set_transform(Matrix4x4::translation(-0.5, 1., 0.5));
|
||||
middle.material = Material {
|
||||
color: Color::new(0.1, 1., 0.5),
|
||||
color: Color::new(0.1, 1., 0.5).into(),
|
||||
diffuse: 0.7,
|
||||
specular: 0.3,
|
||||
..Material::default()
|
||||
@ -77,7 +77,7 @@ fn main() -> Result<()> {
|
||||
let mut right = Shape::sphere();
|
||||
right.set_transform(Matrix4x4::translation(1.5, 0.5, -0.5) * Matrix4x4::scaling(0.5, 0.5, 0.5));
|
||||
right.material = Material {
|
||||
color: Color::new(0.5, 1., 0.1),
|
||||
color: Color::new(0.5, 1., 0.1).into(),
|
||||
diffuse: 0.7,
|
||||
specular: 0.3,
|
||||
..Material::default()
|
||||
@ -88,7 +88,7 @@ fn main() -> Result<()> {
|
||||
Matrix4x4::translation(-1.5, 0.33, -0.75) * Matrix4x4::scaling(0.33, 0.33, 0.33),
|
||||
);
|
||||
left.material = Material {
|
||||
color: Color::new(1., 0.8, 0.1),
|
||||
color: Color::new(1., 0.8, 0.1).into(),
|
||||
diffuse: 0.7,
|
||||
specular: 0.3,
|
||||
..Material::default()
|
||||
|
||||
@ -54,7 +54,7 @@ fn main() -> Result<()> {
|
||||
let mut floor = Shape::sphere();
|
||||
floor.set_transform(Matrix4x4::scaling(10., 0.01, 10.));
|
||||
floor.material = Material {
|
||||
color: Color::new(1., 0.9, 0.9),
|
||||
color: Color::new(1., 0.9, 0.9).into(),
|
||||
specular: 0.,
|
||||
..Material::default()
|
||||
};
|
||||
@ -80,7 +80,7 @@ fn main() -> Result<()> {
|
||||
let mut middle = Shape::sphere();
|
||||
middle.set_transform(Matrix4x4::translation(-0.5, 1., 0.5));
|
||||
middle.material = Material {
|
||||
color: Color::new(0.1, 1., 0.5),
|
||||
color: Color::new(0.1, 1., 0.5).into(),
|
||||
diffuse: 0.7,
|
||||
specular: 0.3,
|
||||
..Material::default()
|
||||
@ -89,7 +89,7 @@ fn main() -> Result<()> {
|
||||
let mut right = Shape::sphere();
|
||||
right.set_transform(Matrix4x4::translation(1.5, 0.5, -0.5) * Matrix4x4::scaling(0.5, 0.5, 0.5));
|
||||
right.material = Material {
|
||||
color: Color::new(1., 1., 1.),
|
||||
color: Color::new(1., 1., 1.).into(),
|
||||
diffuse: 0.7,
|
||||
specular: 0.0,
|
||||
..Material::default()
|
||||
@ -100,7 +100,7 @@ fn main() -> Result<()> {
|
||||
Matrix4x4::translation(-1.5, 0.33, -0.75) * Matrix4x4::scaling(0.33, 0.33, 0.33),
|
||||
);
|
||||
left.material = Material {
|
||||
color: Color::new(1., 0.8, 0.1),
|
||||
color: Color::new(1., 0.8, 0.1).into(),
|
||||
diffuse: 0.7,
|
||||
specular: 0.3,
|
||||
..Material::default()
|
||||
|
||||
@ -59,14 +59,14 @@ fn main() -> Result<()> {
|
||||
|
||||
let mut floor = Shape::plane();
|
||||
floor.material = Material {
|
||||
color: Color::new(1., 0.2, 0.2),
|
||||
color: Color::new(1., 0.2, 0.2).into(),
|
||||
specular: 0.,
|
||||
..Material::default()
|
||||
};
|
||||
let mut ceiling = Shape::plane();
|
||||
ceiling.set_transform(Matrix4x4::translation(0., 6., 0.) * Matrix4x4::rotation_x(PI));
|
||||
ceiling.material = Material {
|
||||
color: Color::new(0.6, 0.6, 0.8),
|
||||
color: Color::new(0.6, 0.6, 0.8).into(),
|
||||
specular: 0.2,
|
||||
..Material::default()
|
||||
};
|
||||
@ -74,7 +74,7 @@ fn main() -> Result<()> {
|
||||
let mut middle = Shape::sphere();
|
||||
middle.set_transform(Matrix4x4::translation(-0.5, 0.5, 0.5));
|
||||
middle.material = Material {
|
||||
color: Color::new(0.1, 1., 0.5),
|
||||
color: Color::new(0.1, 1., 0.5).into(),
|
||||
diffuse: 0.7,
|
||||
specular: 0.3,
|
||||
..Material::default()
|
||||
@ -83,7 +83,7 @@ fn main() -> Result<()> {
|
||||
let mut right = Shape::sphere();
|
||||
right.set_transform(Matrix4x4::translation(1.5, 0.5, -0.5) * Matrix4x4::scaling(0.5, 0.5, 0.5));
|
||||
right.material = Material {
|
||||
color: Color::new(1., 1., 1.),
|
||||
color: Color::new(1., 1., 1.).into(),
|
||||
diffuse: 0.7,
|
||||
specular: 0.0,
|
||||
..Material::default()
|
||||
@ -94,7 +94,7 @@ fn main() -> Result<()> {
|
||||
Matrix4x4::translation(-1.5, 0.33, -0.75) * Matrix4x4::scaling(0.33, 0.33, 0.33),
|
||||
);
|
||||
left.material = Material {
|
||||
color: Color::new(1., 0.8, 0.1),
|
||||
color: Color::new(1., 0.8, 0.1).into(),
|
||||
diffuse: 0.7,
|
||||
specular: 0.3,
|
||||
..Material::default()
|
||||
|
||||
@ -45,6 +45,7 @@ pub mod prelude {
|
||||
lights::{PointLight, PointLightBuilder},
|
||||
materials::{Material, MaterialBuilder},
|
||||
matrices::{identity, rotation_x, rotation_y, rotation_z, scaling, shearing, translation},
|
||||
patterns::stripe_pattern,
|
||||
shapes::{plane, sphere, test_shape},
|
||||
transformations::view_transform,
|
||||
tuples::{point, vector, Color},
|
||||
|
||||
@ -2,16 +2,43 @@ use derive_builder::Builder;
|
||||
|
||||
use crate::{
|
||||
lights::PointLight,
|
||||
tuples::Color,
|
||||
tuples::{dot, reflect, Tuple},
|
||||
patterns::StripePattern,
|
||||
tuples::{dot, reflect, Color, Tuple},
|
||||
Float, BLACK, WHITE,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum ColorMapper {
|
||||
Constant(Color),
|
||||
StripePattern(StripePattern),
|
||||
}
|
||||
|
||||
/// Creates a [ColorMapper::Constant] from the given [Color]
|
||||
impl From<Color> for ColorMapper {
|
||||
fn from(c: Color) -> Self {
|
||||
ColorMapper::Constant(c)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a [ColorMapper::Constant] from the given array.
|
||||
impl From<[Float; 3]> for ColorMapper {
|
||||
fn from(rgb: [Float; 3]) -> Self {
|
||||
ColorMapper::Constant(rgb.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a [ColorMapper::StripePattern] from the given [Color]
|
||||
impl From<StripePattern> for ColorMapper {
|
||||
fn from(sp: StripePattern) -> Self {
|
||||
ColorMapper::StripePattern(sp)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Builder, Debug, PartialEq, Clone)]
|
||||
#[builder(default)]
|
||||
pub struct Material {
|
||||
#[builder(setter(into))]
|
||||
pub color: Color,
|
||||
pub color: ColorMapper,
|
||||
pub ambient: Float,
|
||||
pub diffuse: Float,
|
||||
pub specular: Float,
|
||||
@ -29,7 +56,7 @@ impl Default for Material {
|
||||
/// assert_eq!(
|
||||
/// m,
|
||||
/// Material {
|
||||
/// color: WHITE,
|
||||
/// color: WHITE.into(),
|
||||
/// ambient: 0.1,
|
||||
/// diffuse: 0.9,
|
||||
/// specular: 0.9,
|
||||
@ -39,7 +66,7 @@ impl Default for Material {
|
||||
/// ```
|
||||
fn default() -> Material {
|
||||
Material {
|
||||
color: WHITE,
|
||||
color: WHITE.into(),
|
||||
ambient: 0.1,
|
||||
diffuse: 0.9,
|
||||
specular: 0.9,
|
||||
@ -55,56 +82,74 @@ impl Default for Material {
|
||||
/// use rtchallenge::{
|
||||
/// lights::PointLight,
|
||||
/// materials::{lighting, Material},
|
||||
/// tuples::{Color, Tuple},
|
||||
/// Float, WHITE,
|
||||
/// patterns::stripe_pattern,
|
||||
/// tuples::{point, vector, Color},
|
||||
/// Float, BLACK, WHITE,
|
||||
/// };
|
||||
///
|
||||
/// let in_shadow = false;
|
||||
/// let m = Material::default();
|
||||
/// let position = Tuple::point(0., 0., 0.);
|
||||
/// let position = point(0., 0., 0.);
|
||||
///
|
||||
/// // Lighting with the eye between the light and the surface.
|
||||
/// let eyev = Tuple::vector(0., 0., -1.);
|
||||
/// let normalv = Tuple::vector(0., 0., -1.);
|
||||
/// let light = PointLight::new(Tuple::point(0., 0., -10.), WHITE);
|
||||
/// let eyev = vector(0., 0., -1.);
|
||||
/// let normalv = vector(0., 0., -1.);
|
||||
/// let light = PointLight::new(point(0., 0., -10.), WHITE);
|
||||
/// let result = lighting(&m, &light, position, eyev, normalv, in_shadow);
|
||||
/// assert_eq!(result, Color::new(1.9, 1.9, 1.9));
|
||||
///
|
||||
/// // Lighting with the eye between the light and the surface, eye offset 45°.
|
||||
/// let eyev = Tuple::vector(0., (2. as Float).sqrt() / 2., -(2. as Float).sqrt() / 2.);
|
||||
/// let normalv = Tuple::vector(0., 0., -1.);
|
||||
/// let light = PointLight::new(Tuple::point(0., 0., -10.), WHITE);
|
||||
/// let eyev = vector(0., (2. as Float).sqrt() / 2., -(2. as Float).sqrt() / 2.);
|
||||
/// let normalv = vector(0., 0., -1.);
|
||||
/// let light = PointLight::new(point(0., 0., -10.), WHITE);
|
||||
/// let result = lighting(&m, &light, position, eyev, normalv, in_shadow);
|
||||
/// assert_eq!(result, WHITE);
|
||||
///
|
||||
/// // Lighting with the eye opposite surface, light offset 45°.
|
||||
/// let eyev = Tuple::vector(0., 0., -1.);
|
||||
/// let normalv = Tuple::vector(0., 0., -1.);
|
||||
/// let light = PointLight::new(Tuple::point(0., 10., -10.), WHITE);
|
||||
/// let eyev = vector(0., 0., -1.);
|
||||
/// let normalv = vector(0., 0., -1.);
|
||||
/// let light = PointLight::new(point(0., 10., -10.), WHITE);
|
||||
/// let result = lighting(&m, &light, position, eyev, normalv, in_shadow);
|
||||
/// assert_eq!(result, Color::new(0.7364, 0.7364, 0.7364));
|
||||
///
|
||||
/// // Lighting with the eye in the path of the reflection vector.
|
||||
/// let eyev = Tuple::vector(0., -(2.0 as Float).sqrt() / 2., -(2.0 as Float).sqrt() / 2.);
|
||||
/// let normalv = Tuple::vector(0., 0., -1.);
|
||||
/// let light = PointLight::new(Tuple::point(0., 10., -10.), WHITE);
|
||||
/// let eyev = vector(0., -(2.0 as Float).sqrt() / 2., -(2.0 as Float).sqrt() / 2.);
|
||||
/// let normalv = vector(0., 0., -1.);
|
||||
/// let light = PointLight::new(point(0., 10., -10.), WHITE);
|
||||
/// let result = lighting(&m, &light, position, eyev, normalv, in_shadow);
|
||||
/// assert_eq!(result, Color::new(1.63639, 1.63639, 1.63639));
|
||||
///
|
||||
/// // Lighting with the light behind the surface.
|
||||
/// let eyev = Tuple::vector(0., 0., -1.);
|
||||
/// let normalv = Tuple::vector(0., 0., -1.);
|
||||
/// let light = PointLight::new(Tuple::point(0., 0., 10.), WHITE);
|
||||
/// let eyev = vector(0., 0., -1.);
|
||||
/// let normalv = vector(0., 0., -1.);
|
||||
/// let light = PointLight::new(point(0., 0., 10.), WHITE);
|
||||
/// let result = lighting(&m, &light, position, eyev, normalv, in_shadow);
|
||||
/// assert_eq!(result, Color::new(0.1, 0.1, 0.1));
|
||||
///
|
||||
/// // Lighting with the surface in shadow.
|
||||
/// let in_shadow = true;
|
||||
/// let eyev = Tuple::vector(0., 0., -1.);
|
||||
/// let normalv = Tuple::vector(0., 0., -1.);
|
||||
/// let light = PointLight::new(Tuple::point(0., 0., -10.), WHITE);
|
||||
/// let eyev = vector(0., 0., -1.);
|
||||
/// let normalv = vector(0., 0., -1.);
|
||||
/// let light = PointLight::new(point(0., 0., -10.), WHITE);
|
||||
/// let result = lighting(&m, &light, position, eyev, normalv, in_shadow);
|
||||
/// assert_eq!(result, Color::new(0.1, 0.1, 0.1));
|
||||
///
|
||||
/// // Lighting with a pattern applied.
|
||||
///
|
||||
/// let m = Material {
|
||||
/// color: stripe_pattern(WHITE, BLACK).into(),
|
||||
/// ambient: 1.,
|
||||
/// diffuse: 0.,
|
||||
/// specular: 0.,
|
||||
/// ..Material::default()
|
||||
/// };
|
||||
/// let eyev = vector(0., 0., -1.);
|
||||
/// let normalv = vector(0., 0., -1.);
|
||||
/// let light = PointLight::new(point(0., 0., -10.), WHITE);
|
||||
/// let c1 = lighting(&m, &light, point(0.9, 0., 0.), eyev, normalv, false);
|
||||
/// let c2 = lighting(&m, &light, point(1.1, 0., 0.), eyev, normalv, false);
|
||||
/// assert_eq!(c1, WHITE);
|
||||
/// assert_eq!(c2, BLACK);
|
||||
/// ```
|
||||
pub fn lighting(
|
||||
material: &Material,
|
||||
@ -115,7 +160,11 @@ pub fn lighting(
|
||||
in_shadow: bool,
|
||||
) -> Color {
|
||||
// Combine the surface color with the light's color.
|
||||
let effective_color = material.color * light.intensity;
|
||||
let color = match &material.color {
|
||||
ColorMapper::Constant(color) => *color,
|
||||
ColorMapper::StripePattern(pat) => pat.stripe_at(point),
|
||||
};
|
||||
let effective_color = color * light.intensity;
|
||||
// Find the direciton of the light source.
|
||||
let lightv = (light.position - point).normalize();
|
||||
// Compute the ambient distribution.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::tuples::{Color, Tuple};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct StripePattern {
|
||||
pub a: Color,
|
||||
pub b: Color,
|
||||
|
||||
@ -44,7 +44,7 @@ impl World {
|
||||
let light = PointLight::new(Tuple::point(-10., 10., -10.), WHITE);
|
||||
let mut s1 = Shape::sphere();
|
||||
s1.material = Material {
|
||||
color: Color::new(0.8, 1., 0.6),
|
||||
color: [0.8, 1., 0.6].into(),
|
||||
diffuse: 0.7,
|
||||
specular: 0.2,
|
||||
..Material::default()
|
||||
@ -161,7 +161,7 @@ impl World {
|
||||
/// shapes::Shape,
|
||||
/// tuples::{Color, Tuple},
|
||||
/// world::World,
|
||||
/// BLACK,
|
||||
/// BLACK, WHITE,
|
||||
/// };
|
||||
///
|
||||
/// // The color when a ray misses.
|
||||
@ -188,7 +188,8 @@ impl World {
|
||||
/// let inner = &w.objects[1];
|
||||
/// let r = Ray::new(Tuple::point(0., 0., 0.75), Tuple::vector(0., 0., -1.));
|
||||
/// let c = w.color_at(&r);
|
||||
/// assert_eq!(c, inner.material.color);
|
||||
/// // inner.material.color is WHITE
|
||||
/// assert_eq!(c, WHITE);
|
||||
/// ```
|
||||
pub fn color_at(&self, r: &Ray) -> Color {
|
||||
match self.intersect(r).hit() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user