Add basic color to spheres

This commit is contained in:
bijan2005 2020-11-27 12:36:38 -05:00
parent 9d188ed692
commit cb87c1e70c
107 changed files with 77 additions and 28 deletions

View file

@ -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")

View file

@ -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)
}
}
}

View file

@ -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)
}
}

View file

@ -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: ()
}
}
}