Add basic color to spheres
This commit is contained in:
parent
9d188ed692
commit
cb87c1e70c
107 changed files with 77 additions and 28 deletions
25
src/main.rs
25
src/main.rs
|
|
@ -11,19 +11,20 @@ mod camera; use camera::*;
|
|||
mod types; use types::*;
|
||||
mod object; use object::*;
|
||||
|
||||
fn trace(ray: Ray, scene: &Scene) -> Option<(&Object, f32)> {
|
||||
scene.iter()
|
||||
.filter_map(|obj| obj.intersect(ray)
|
||||
.map(|x| (obj, x)))
|
||||
.min_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Equal))
|
||||
}
|
||||
|
||||
fn cast_ray(ray: Ray, scene: &Scene) -> Color {
|
||||
//Color::new(0.0, -ray.direction.x, ray.direction.y)
|
||||
if let Some((obj, dist)) = trace(ray, scene) {
|
||||
let point = ray.project(dist);
|
||||
|
||||
let closest = scene.iter()
|
||||
.filter_map(|obj| obj.intersect(ray)
|
||||
.map(|x| (obj, x)))
|
||||
.min_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Equal));
|
||||
|
||||
if closest.is_some() {
|
||||
Color::new(1.0, 1.0, 1.0)
|
||||
} else {
|
||||
Color::new(0.0, 0.0, 0.0)
|
||||
obj.getcolor(point)
|
||||
}
|
||||
else { Color::black() }
|
||||
}
|
||||
|
||||
fn render(camera: &Camera, scene: &Scene, filename: &str) -> std::io::Result<()> {
|
||||
|
|
@ -54,8 +55,8 @@ fn main() -> std::io::Result<()> {
|
|||
let camera = Camera::new(Point3::new(0.0,0.0,0.0), Vector3::new(0.0,0.0,-1.0), 1.0, 2.0, 2.0, 400, 400);
|
||||
|
||||
let scene = vec![
|
||||
Object::Sphere(Sphere::new(0.0,0.0,-5.0,2.0)),
|
||||
Object::Sphere(Sphere::new(-3.0,0.0,-8.0,2.5))
|
||||
Object::Sphere(Sphere::new(0.0,0.0,-5.0,2.0, |_, _| Color::white())),
|
||||
Object::Sphere(Sphere::new(-3.0,0.0,-8.0,2.5, |_, _| Color::white()))
|
||||
];
|
||||
|
||||
render(&camera, &scene, "out.ppm")
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ mod triangle; pub use triangle::*;
|
|||
|
||||
use na::*;
|
||||
|
||||
use crate::types::Ray;
|
||||
use crate::types::*;
|
||||
|
||||
pub enum Object {
|
||||
Sphere(Sphere)
|
||||
|
|
@ -17,9 +17,15 @@ impl Object {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn normal(&self, ray: Ray) -> Unit<Vector3<f32>> {
|
||||
pub fn getcolor(&self, point: Point3<f32>) -> Color {
|
||||
match *self {
|
||||
Object::Sphere(ref sphere) => sphere.normal(ray)
|
||||
Object::Sphere(ref sphere) => sphere.getcolor(point)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn normal(&self, point: Point3<f32>) -> Unit<Vector3<f32>> {
|
||||
match *self {
|
||||
Object::Sphere(ref sphere) => sphere.normal(point)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
extern crate nalgebra as na;
|
||||
|
||||
use std::f32::consts::PI;
|
||||
|
||||
use na::*;
|
||||
use na::geometry::Point3;
|
||||
|
||||
|
|
@ -7,17 +9,26 @@ use crate::types::*;
|
|||
|
||||
pub struct Sphere {
|
||||
pub center: Point3<f32>,
|
||||
pub radius: f32
|
||||
pub radius: f32,
|
||||
|
||||
pub texture: Box<dyn Fn(f32, f32) -> Color>
|
||||
}
|
||||
|
||||
impl Sphere {
|
||||
pub fn new(x: f32, y: f32, z: f32, radius: f32) -> Self {
|
||||
pub fn new<F: 'static>(x: f32, y: f32, z: f32, radius: f32, texture: F) -> Self
|
||||
where F: Fn(f32, f32) -> Color
|
||||
{
|
||||
Sphere {
|
||||
center: Point3::new(x, y, z),
|
||||
radius: radius
|
||||
radius: radius,
|
||||
texture: Box::new(texture)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_solid(x: f32, y: f32, z: f32, radius: f32, color: Color) -> Self { Sphere::new(x, y, z, radius, Box::new(move |_, _| color)) }
|
||||
|
||||
// Determines if a ray intersects the circle.
|
||||
// If so, returns the distance to the intersection point.
|
||||
pub fn intersect(&self, ray: Ray) -> Option<f32> {
|
||||
fn solve_quadratic(a: f32, b: f32, c: f32) -> Option<(f32, f32)> {
|
||||
let discr = b * b - 4.0 * a * c;
|
||||
|
|
@ -46,7 +57,21 @@ impl Sphere {
|
|||
else { None }
|
||||
}
|
||||
|
||||
pub fn normal(&self, ray: Ray) -> Unit<Vector3<f32>> {
|
||||
unimplemented!()
|
||||
pub fn getcolor(&self, point: Point3<f32>) -> Color {
|
||||
let normal = self.normal(point);
|
||||
|
||||
// In this particular case, the normal is simular to a point on a unit sphere
|
||||
// centred around the origin. We can thus use the normal coordinates to compute
|
||||
// the spherical coordinates of the point.
|
||||
// atan2 returns a value in the range [-pi, pi] and we need to remap it to range [0, 1]
|
||||
// acosf returns a value in the range [0, pi] and we also need to remap it to the range [0, 1]
|
||||
let x = 0.5 + normal.z.atan2(normal.x) / (2.0 * PI);
|
||||
let y = normal.y.acos() / PI;
|
||||
|
||||
(*self.texture)(x, y)
|
||||
}
|
||||
|
||||
pub fn normal(&self, point: Point3<f32>) -> Unit<Vector3<f32>> {
|
||||
Unit::new_normalize(point - self.center)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
19
src/types.rs
19
src/types.rs
|
|
@ -47,4 +47,23 @@ impl Color {
|
|||
let blue = (255.0 * self.blue) as u8;
|
||||
[red, green, blue]
|
||||
}
|
||||
|
||||
pub fn black() -> Self {
|
||||
Color {
|
||||
red: 0.0,
|
||||
green: 0.0,
|
||||
blue: 0.0,
|
||||
|
||||
_private: ()
|
||||
}
|
||||
}
|
||||
pub fn white() -> Self {
|
||||
Color {
|
||||
red: 1.0,
|
||||
green: 1.0,
|
||||
blue: 1.0,
|
||||
|
||||
_private: ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue