added antialiasing
This commit is contained in:
@@ -5,4 +5,5 @@ edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
[dependencies]
|
||||
rand = "*"
|
||||
32
src/camera.rs
Normal file
32
src/camera.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
use crate::ray::Ray;
|
||||
use crate::vec3::*;
|
||||
|
||||
pub struct Camera {
|
||||
origin: Point3,
|
||||
lower_left_corner: Point3,
|
||||
horizontal: Vec3,
|
||||
vertical: Vec3,
|
||||
}
|
||||
|
||||
impl Camera {
|
||||
pub fn new() -> Self {
|
||||
let aspect_ratio = 1.0 / 1.0;
|
||||
let viewport_height = 2.0;
|
||||
let viewport_width = aspect_ratio * viewport_height;
|
||||
let focal_length = 1.0;
|
||||
|
||||
let origin = Point3::new(0.0, 0.0, 0.0);
|
||||
let horizontal = Vec3::new(viewport_width, 0.0, 0.0);
|
||||
let vertical = Vec3::new(0.0, viewport_width, 0.0);
|
||||
let lower_left_corner = origin - horizontal / 2.0 - vertical / 2.0 - Vec3::new(0.0, 0.0, focal_length);
|
||||
|
||||
Camera { origin, lower_left_corner, horizontal, vertical}
|
||||
}
|
||||
|
||||
pub fn get_ray(&self, u: f64, v: f64) -> Ray {
|
||||
Ray {
|
||||
origin: self.origin,
|
||||
direction: self.lower_left_corner + u * self.horizontal + v * self.vertical - self.origin
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/color.rs
20
src/color.rs
@@ -1,11 +1,21 @@
|
||||
use std::io::{Write};
|
||||
|
||||
use crate::vec3::*;
|
||||
use crate::{vec3::*, rtweekend::clamp};
|
||||
|
||||
pub fn write_color<T: Write>(buffer: &mut T, pixel_color: Color, samples_per_pixel: i32) {
|
||||
let mut r = pixel_color.x();
|
||||
let mut g = pixel_color.y();
|
||||
let mut b = pixel_color.z();
|
||||
|
||||
// Divide the color by the number of samples
|
||||
let scale = 1.0 / samples_per_pixel as f64;
|
||||
r *= scale;
|
||||
g *= scale;
|
||||
b *= scale;
|
||||
|
||||
pub fn write_color<T: Write>(buffer: &mut T, pixel_color: Color) {
|
||||
write!(buffer, "{} {} {} ",
|
||||
(255.999 * pixel_color.x()).round(),
|
||||
(255.999 * pixel_color.y()).round(),
|
||||
(255.999 * pixel_color.z()).round())
|
||||
(256.0 * clamp(r, 0.0, 0.999)) as i32,
|
||||
(256.0 * clamp(g, 0.0, 0.999)) as i32,
|
||||
(256.0 * clamp(b, 0.0, 0.999)) as i32,)
|
||||
.expect("Error writing Pixel");
|
||||
}
|
||||
@@ -25,5 +25,5 @@ impl HitRecord {
|
||||
}
|
||||
|
||||
pub trait Hittable {
|
||||
fn hit(&self, r: &Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool;
|
||||
fn hit(&mut self, r: &Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool;
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
use crate::hittable::*;
|
||||
|
||||
struct HittableList {
|
||||
pub struct HittableList {
|
||||
pub objects: Vec<Box<dyn Hittable>>
|
||||
}
|
||||
|
||||
impl HittableList {
|
||||
pub fn new_empty() -> Self {
|
||||
HittableList { objects: vec!() }
|
||||
}
|
||||
|
||||
pub fn add(&mut self, object: Box<dyn Hittable>) {
|
||||
self.objects.push(object);
|
||||
}
|
||||
@@ -15,13 +19,17 @@ impl HittableList {
|
||||
}
|
||||
|
||||
impl Hittable for HittableList {
|
||||
fn hit(&self, r: &crate::ray::Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool {
|
||||
fn hit(&mut self, r: &crate::ray::Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool {
|
||||
let mut temp_rec = HitRecord::new_empty();
|
||||
let mut hit_anything = false;
|
||||
let mut closest_so_far = t_max;
|
||||
|
||||
for object in &self.objects {
|
||||
|
||||
for object in &mut self.objects {
|
||||
if object.hit(r, t_min, closest_so_far, &mut temp_rec) {
|
||||
hit_anything = true;
|
||||
closest_so_far = temp_rec.t;
|
||||
*rec = temp_rec.clone();
|
||||
}
|
||||
}
|
||||
|
||||
hit_anything
|
||||
|
||||
76
src/main.rs
76
src/main.rs
@@ -4,34 +4,26 @@ pub mod ray;
|
||||
pub mod sphere;
|
||||
pub mod hittable;
|
||||
pub mod hittable_list;
|
||||
pub mod rtweekend;
|
||||
pub mod camera;
|
||||
|
||||
use std::{io::{BufWriter, Write}, fs::File};
|
||||
use camera::Camera;
|
||||
|
||||
use crate::{
|
||||
vec3::*,
|
||||
color::*,
|
||||
sphere::*,
|
||||
rtweekend::*,
|
||||
hittable_list::*,
|
||||
vec3::*,
|
||||
ray::*,
|
||||
hittable::*,
|
||||
};
|
||||
|
||||
fn hit_sphere(center: &Point3, radius: f64, r: &Ray) -> f64 {
|
||||
let oc = r.origin() - *center;
|
||||
let a = r.direction().length_squared();
|
||||
let half_b = oc.dot(&r.direction());
|
||||
let c = oc.length_squared() - radius*radius;
|
||||
let discriminant = half_b*half_b - a*c;
|
||||
|
||||
if discriminant < 0.0 {
|
||||
-1.0
|
||||
} else {
|
||||
(-half_b - discriminant.sqrt()) / a
|
||||
}
|
||||
}
|
||||
|
||||
fn ray_color(r: &Ray) -> Color {
|
||||
let t = hit_sphere(&Point3::new(0.0, 0.0, -1.0), 0.5, r);
|
||||
|
||||
if t > 0.0 {
|
||||
let n = (r.at(t) - Vec3::new(0.0, 0.0, -1.0)).unit_vector();
|
||||
return 0.5 * Color::new(n.x() + 1.0, n.y() + 1.0, n.z() + 1.0);
|
||||
fn ray_color(r: &Ray, world: &mut dyn Hittable) -> Color {
|
||||
let mut rec = HitRecord::new_empty();
|
||||
if world.hit(r, 0.0, INFINITY, &mut rec) {
|
||||
return 0.5 * (rec.normal + Color::new(1.0, 1.0, 1.0))
|
||||
}
|
||||
|
||||
let unit_direction: Vec3 = r.direction().unit_vector();
|
||||
@@ -43,37 +35,39 @@ fn ray_color(r: &Ray) -> Color {
|
||||
fn main() {
|
||||
// Image
|
||||
let aspect_ratio: f64 = 1.0 / 1.0;
|
||||
let image_width: i32 = 400;
|
||||
let image_width: i32 = 512;
|
||||
let image_height: i32 = (image_width as f64 / aspect_ratio as f64) as i32;
|
||||
let samples_per_pixel = 100;
|
||||
|
||||
// World
|
||||
let mut world = HittableList::new_empty();
|
||||
world.add(Box::new(Sphere::new(Point3::new(0.0, 0.0, -1.0), 0.5)));
|
||||
world.add(Box::new(Sphere::new(Point3::new(0.0, -100.5, -1.0), 100.0)));
|
||||
|
||||
// Camera
|
||||
|
||||
let viewport_height: f64 = 2.0;
|
||||
let viewport_width: f64 = aspect_ratio * viewport_height;
|
||||
let focal_length: f64 = 1.0;
|
||||
|
||||
let origin = Point3::new(0.0,0.0,0.0);
|
||||
let horizontal = Vec3::new(viewport_width, 0.0, 0.0);
|
||||
let vertical = Vec3::new(0.0, viewport_height, 0.0);
|
||||
let lower_left_corner = origin - horizontal/2.0 - vertical/2.0 - Vec3::new(0.0,0.0, focal_length);
|
||||
let mut cam = Camera::new();
|
||||
|
||||
// Render
|
||||
|
||||
let mut file = BufWriter::new(File::create("img.ppm").expect("File creation failed"));
|
||||
|
||||
writeln!(file, "P3\n{image_width} {image_height}\n255").expect("Error while writing Magic Byte");
|
||||
write!(file, "P3\n{image_width} {image_height}\n255").expect("Error while writing Magic Byte");
|
||||
|
||||
for j in 0..image_width {
|
||||
println!("Rows remaining: {}", image_width - j);
|
||||
for j in (0..image_width).rev() {
|
||||
write!(file, "\n").expect("grr");
|
||||
|
||||
for i in 0..image_height {
|
||||
let u: f64 = i as f64 / image_width as f64;
|
||||
let v: f64 = j as f64 / image_height as f64;
|
||||
let r = Ray::new(origin, lower_left_corner + u * horizontal + v * vertical - origin);
|
||||
|
||||
let pixel_color = ray_color(&r);
|
||||
|
||||
write_color(&mut file, pixel_color);
|
||||
let mut pixel_color = Color::new(0.0, 0.0, 0.0);
|
||||
|
||||
for s in 0..samples_per_pixel {
|
||||
let u = (i as f64 + random_f64()) / (image_width - 1) as f64;
|
||||
let v = (j as f64 + random_f64()) / (image_height - 1) as f64;
|
||||
let r: Ray = cam.get_ray(u, v);
|
||||
pixel_color += ray_color(&r, &mut world)
|
||||
}
|
||||
write_color(&mut file, pixel_color, samples_per_pixel);
|
||||
}
|
||||
|
||||
println!("[ {:.2} % ]", (1.0 - ((j + 1) as f64 / image_width as f64)) * 100.0);
|
||||
}
|
||||
}
|
||||
26
src/rtweekend.rs
Normal file
26
src/rtweekend.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use rand::prelude::*;
|
||||
|
||||
// Constants
|
||||
pub const INFINITY: f64 = std::f64::INFINITY;
|
||||
pub const PI: f64 = std::f64::consts::PI;
|
||||
|
||||
// Utility Functions
|
||||
pub fn degrees_to_radians(degrees: f64) -> f64 {
|
||||
degrees * std::f64::consts::PI / 180.0
|
||||
}
|
||||
|
||||
// PLEASE CHANGE
|
||||
pub fn random_f64() -> f64 {
|
||||
rand::thread_rng().gen()
|
||||
}
|
||||
|
||||
// PLEASE CHANGE
|
||||
pub fn random_range_f64(min: f64, max: f64) -> f64 {
|
||||
rand::thread_rng().gen_range(min..=max)
|
||||
}
|
||||
|
||||
pub fn clamp(x: f64, min: f64, max: f64) -> f64 {
|
||||
if x < min { return min; }
|
||||
if x > max { return max; }
|
||||
x
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::hittable::*;
|
||||
use crate::vec3::*;
|
||||
|
||||
struct Sphere {
|
||||
pub struct Sphere {
|
||||
center: Point3,
|
||||
radius: f64
|
||||
}
|
||||
@@ -13,7 +13,7 @@ impl Sphere {
|
||||
}
|
||||
|
||||
impl Hittable for Sphere {
|
||||
fn hit(&self, r: &crate::ray::Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool {
|
||||
fn hit(&mut self, r: &crate::ray::Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool {
|
||||
let oc = r.origin() - self.center;
|
||||
let a = r.direction().length_squared();
|
||||
let half_b = oc.dot(&r.direction());
|
||||
|
||||
Reference in New Issue
Block a user