feat(plane): add a special checkerboard plane

This commit is contained in:
Jonas Röger 2024-11-20 13:42:25 +01:00
parent c3d6d80fd7
commit 61b5437561
Signed by: jonas
GPG Key ID: 4000EB35E1AE0F07
2 changed files with 85 additions and 11 deletions

View File

@ -1,6 +1,6 @@
use lispers::raytracer::{
camera::Camera,
plane::Plane,
plane::Checkerboard,
scene::Scene,
sphere::Sphere,
types::{Color, Light, Material, Point3, Vector3},
@ -12,10 +12,10 @@ use std::time::Instant;
fn main() {
let mut scene = Scene::new();
scene.set_ambient(Color::new(0.2, 0.2, 0.2));
scene.set_ambient(Color::new(0.1, 0.1, 0.1));
scene.add_light(Light {
position: Point3::new(4.0, 7.0, 10.0),
position: Point3::new(5.0, 7.0, 10.0),
color: Color::new(1.0, 1.0, 1.0),
});
scene.add_light(Light {
@ -23,16 +23,25 @@ fn main() {
color: Color::new(1.0, 1.0, 1.0),
});
scene.add_object(Arc::new(Plane::new(
scene.add_object(Arc::new(Checkerboard::new(
Point3::new(0.0, -1.0, 0.0),
Vector3::new(0.0, 1.0, 0.0),
Material::new(
Color::new(0.5, 0.5, 0.5),
Color::new(0.5, 0.5, 0.5),
Color::new(1.0, 1.0, 1.0),
Color::new(1.0, 1.0, 1.0),
Color::new(0.0, 0.0, 0.0),
0.0,
0.6,
0.5,
),
Material::new(
Color::new(0.0, 0.0, 0.0),
Color::new(0.0, 0.0, 0.0),
Color::new(0.0, 0.0, 0.0),
0.0,
0.5,
),
0.3,
Vector3::new(0.0, 0.0, 1.0),
)));
scene.add_object(Arc::new(Sphere::new(
@ -76,14 +85,14 @@ fn main() {
Point3::new(-1.0, -0.5, 0.0),
Vector3::new(0.0, 1.0, 0.0),
60.0,
4 * 256,
3 * 256,
4 * 512,
3 * 512,
);
let fname = "demo-scene.png";
print!("Rendering demo scene...");
let start = Instant::now();
match camera.render(&scene, 5, 3).save(fname) {
match camera.render(&scene, 10, 4).save(fname) {
Ok(_) => {
println!(" finished ({}s) ", start.elapsed().as_secs_f32());
println!("Image saved to {}", fname)

View File

@ -1,4 +1,4 @@
use super::types::{Intersect, Material, Point3, Vector3};
use super::types::{Intersect, Material, Point3, Scalar, Vector3};
extern crate nalgebra as na;
@ -12,6 +12,18 @@ pub struct Plane {
material: Material,
}
/// A infinite checkerboard plane in 3D space.
pub struct Checkerboard {
/// The base plane containing the "white" material
base: Plane,
/// An alternative "black" material
material_alt: Material,
/// The scale of the checkerboard (side-length of each square)
scale: f64,
/// A projection matrix to map 3D points to the 2D plane space.
projection_matrix: na::Matrix2x3<Scalar>,
}
impl Plane {
/// Create a new plane.
/// - `position` is the position of the plane.
@ -26,6 +38,32 @@ impl Plane {
}
}
impl Checkerboard {
/// Create a new Checkerboard Plane.
/// - `position` is the position of the plane.
/// - `normal` is the normal of the plane.
/// - `material1` is the material of the "white" squares.
/// - `material2` is the material of the "black" squares.
/// - `scale` is the side-length of each square.
/// - `up` is "y" direction on the plane in 3D-Space.
pub fn new(
position: Point3,
normal: Vector3,
material1: Material,
material2: Material,
scale: f64,
up: Vector3,
) -> Checkerboard {
let right = up.cross(&normal).normalize();
Checkerboard {
base: Plane::new(position, normal, material1),
material_alt: material2,
scale,
projection_matrix: na::Matrix3x2::from_columns(&[right, up]).transpose(),
}
}
}
impl Intersect for Plane {
fn intersect<'a>(
&'a self,
@ -49,3 +87,30 @@ impl Intersect for Plane {
None
}
}
impl Intersect for Checkerboard {
fn intersect<'a>(
&'a self,
ray: &super::types::Ray,
) -> Option<(
Point3,
Vector3,
super::types::Scalar,
&'a super::types::Material,
)> {
if let Some((point, normal, t, material)) = self.base.intersect(ray) {
let v3 = point - self.base.position;
let v2 = self.projection_matrix * v3;
if ((v2.x / self.scale).round() % 2.0 == 0.0)
== ((v2.y / self.scale).round() % 2.0 == 0.0)
{
Some((point, normal, t, material))
} else {
Some((point, normal, t, &self.material_alt))
}
} else {
None
}
}
}