Render off of world vec
This commit is contained in:
parent
67fc7ea21d
commit
00a1fb16bd
5 changed files with 177 additions and 9 deletions
|
|
@ -18,12 +18,12 @@ impl Pixel {
|
|||
|
||||
pub struct Image {
|
||||
data: Vec<Pixel>,
|
||||
pub width: u16,
|
||||
pub height: u16,
|
||||
pub width: i32,
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
impl Image {
|
||||
pub fn new(width: u16, height: u16) -> Self {
|
||||
pub fn new(width: i32, height: i32) -> Self {
|
||||
let total_pixels = (width as usize) * (height as usize);
|
||||
let data = vec![
|
||||
Pixel {
|
||||
|
|
@ -56,7 +56,7 @@ impl Image {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_pixel(&mut self, x: u16, y: u16) -> Option<&mut Pixel> {
|
||||
pub fn get_pixel(&mut self, x: i32, y: i32) -> Option<&mut Pixel> {
|
||||
if x >= self.width || y >= self.height {
|
||||
return None;
|
||||
}
|
||||
|
|
|
|||
30
src/main.rs
30
src/main.rs
|
|
@ -1,8 +1,15 @@
|
|||
mod image;
|
||||
mod object;
|
||||
mod render;
|
||||
mod vec3;
|
||||
|
||||
use image::Image;
|
||||
use object::Sphere;
|
||||
use render::World;
|
||||
use vec3::{Point3, Ray, Vec3};
|
||||
|
||||
use crate::vec3::Interval;
|
||||
|
||||
fn main() {
|
||||
let aspect_ratio = 16.0 / 9.0;
|
||||
let image_width = 800;
|
||||
|
|
@ -10,7 +17,7 @@ fn main() {
|
|||
|
||||
let focal_length = 1.0;
|
||||
let viewport_height = 2.0;
|
||||
let viewport_width = (viewport_height * (image_width / image_height) as f64) as i32;
|
||||
let viewport_width = viewport_height * (image_width as f64 / image_height as f64);
|
||||
let camera_center = Point3::new(0.0, 0.0, 0.0);
|
||||
|
||||
let viewport_u = Vec3::new(viewport_width as f64, 0.0, 0.0);
|
||||
|
|
@ -19,11 +26,20 @@ fn main() {
|
|||
let pixel_delta_u = viewport_u / image_width as f64;
|
||||
let pixel_delta_v = viewport_v / image_height as f64;
|
||||
|
||||
let viewport_upper_left = camera_center
|
||||
- (Vec3::new(0.0, 0.0, focal_length) - viewport_u / 2.0 - viewport_v / 2.0).to_point();
|
||||
let viewport_upper_left = (camera_center.to_vec()
|
||||
- Vec3::new(0.0, 0.0, focal_length)
|
||||
- viewport_u / 2.0
|
||||
- viewport_v / 2.0)
|
||||
.to_point();
|
||||
|
||||
let pixel00_loc = viewport_upper_left + ((pixel_delta_u + pixel_delta_v) * 0.5).to_point();
|
||||
|
||||
let mut img = Image::new(800, 600);
|
||||
let mut img = Image::new(image_width, image_height);
|
||||
|
||||
let mut world = World::new();
|
||||
world.add(Sphere::new(0.5, Point3::new(0.0, 0.0, -1.0)));
|
||||
world.add(Sphere::new(100.0, Point3::new(0.0, -100.5, -1.0)));
|
||||
|
||||
for y in 0..img.height {
|
||||
for x in 0..img.width {
|
||||
if let Some(px) = img.get_pixel(x, y) {
|
||||
|
|
@ -32,7 +48,13 @@ fn main() {
|
|||
let ray_direction = (pixel_center - camera_center).to_vec();
|
||||
let ray = Ray::new(camera_center, ray_direction);
|
||||
let (r, g, b) = color_ray(ray);
|
||||
let i = Interval::new(0.001,f64::INFINITY);
|
||||
if let Some(hit) = world.hit(ray, i) {
|
||||
let (r,g,b) = hit.color();
|
||||
px.set_color(r,g,b);
|
||||
} else {
|
||||
px.set_color(r, g, b);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
82
src/object.rs
Normal file
82
src/object.rs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
use crate::vec3::{Point3, Ray, Vec3, Interval};
|
||||
|
||||
pub trait Hittable {
|
||||
fn hit(&self, ray: Ray, interval:Interval) -> Option<HitRecord>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct HitRecord {
|
||||
point: Point3,
|
||||
normal: Vec3,
|
||||
root: f64,
|
||||
front_face: bool,
|
||||
color: (f64,f64,f64)
|
||||
}
|
||||
|
||||
impl HitRecord {
|
||||
pub fn normal(self) -> Vec3 {
|
||||
self.normal
|
||||
}
|
||||
|
||||
pub fn point(self) -> Point3 {
|
||||
self.point
|
||||
}
|
||||
|
||||
pub fn root(self) -> f64 {
|
||||
self.root
|
||||
}
|
||||
|
||||
pub fn color(self) -> (f64,f64,f64) {
|
||||
self.color
|
||||
}
|
||||
|
||||
pub fn set_face_normal(&mut self, ray: Ray, norm: Vec3) {
|
||||
self.front_face = ray.direction().dot(norm) < 0.0;
|
||||
self.normal = if self.front_face { norm } else { norm * -1.0 };
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Sphere {
|
||||
radius: f64,
|
||||
center: Point3,
|
||||
}
|
||||
|
||||
impl Sphere {
|
||||
pub fn new(radius: f64, center: Point3) -> Self {
|
||||
Sphere { radius, center }
|
||||
}
|
||||
}
|
||||
|
||||
impl Hittable for Sphere {
|
||||
fn hit(&self, ray: Ray, interval:Interval) -> Option<HitRecord> {
|
||||
let oc = self.center - ray.origin();
|
||||
let a = ray.direction().length_squared();
|
||||
let h = Vec3::dot(ray.direction(), oc.to_vec());
|
||||
let c = oc.to_vec().length_squared() - self.radius * self.radius;
|
||||
let discriminant = h * h - a * c;
|
||||
if discriminant < 0.0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let sqrtd = discriminant.sqrt();
|
||||
let mut root = (h - sqrtd) / a;
|
||||
if !interval.surounds(root) {
|
||||
root = (h + sqrtd) / a;
|
||||
if !interval.surounds(root) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let point: Point3 = ray.at(root);
|
||||
let normal = ((point - self.center) / self.radius).to_vec();
|
||||
let mut tmp = HitRecord {
|
||||
root,
|
||||
point,
|
||||
normal,
|
||||
front_face: false,
|
||||
color: (normal.x(),normal.y(),normal.z())
|
||||
};
|
||||
tmp.set_face_normal(ray, normal);
|
||||
Some(tmp)
|
||||
}
|
||||
}
|
||||
32
src/render.rs
Normal file
32
src/render.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
use crate::object::{HitRecord, Hittable};
|
||||
use crate::vec3::{Interval, Ray};
|
||||
|
||||
pub struct World {
|
||||
pub objects: Vec<Box<dyn Hittable>>,
|
||||
}
|
||||
|
||||
impl World {
|
||||
pub fn new() -> Self {
|
||||
World {
|
||||
objects: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, object: impl Hittable + 'static) {
|
||||
self.objects.push(Box::new(object));
|
||||
}
|
||||
|
||||
pub fn hit(&self, ray: Ray, interval:Interval) -> Option<HitRecord> {
|
||||
let mut hit_anything = None;
|
||||
let mut closest_so_far = interval.max();
|
||||
|
||||
for object in &self.objects {
|
||||
let i = Interval::new(interval.min(),closest_so_far);
|
||||
if let Some(record) = object.hit(ray, i) {
|
||||
closest_so_far = record.root();
|
||||
hit_anything = Some(record);
|
||||
}
|
||||
}
|
||||
hit_anything
|
||||
}
|
||||
}
|
||||
32
src/vec3.rs
32
src/vec3.rs
|
|
@ -14,6 +14,38 @@ pub struct Point3 {
|
|||
z: f64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Interval {
|
||||
min: f64,
|
||||
max: f64
|
||||
}
|
||||
|
||||
impl Interval {
|
||||
pub fn new(min:f64,max:f64) ->Self{
|
||||
Self{min,max}
|
||||
}
|
||||
|
||||
pub fn min(self) -> f64{
|
||||
self.min
|
||||
}
|
||||
|
||||
pub fn max(self) -> f64{
|
||||
self.max
|
||||
}
|
||||
|
||||
pub fn size(self) -> f64{
|
||||
self.max - self.min
|
||||
}
|
||||
|
||||
pub fn contains(self, x:f64) -> bool {
|
||||
self.min <= x && x <= self.max
|
||||
}
|
||||
|
||||
pub fn surounds(self, x:f64) -> bool {
|
||||
self.min < x && x < self.max
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Ray {
|
||||
direction: Vec3,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue