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 {
|
pub struct Image {
|
||||||
data: Vec<Pixel>,
|
data: Vec<Pixel>,
|
||||||
pub width: u16,
|
pub width: i32,
|
||||||
pub height: u16,
|
pub height: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Image {
|
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 total_pixels = (width as usize) * (height as usize);
|
||||||
let data = vec![
|
let data = vec![
|
||||||
Pixel {
|
Pixel {
|
||||||
|
|
@ -56,7 +56,7 @@ impl Image {
|
||||||
Ok(())
|
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 {
|
if x >= self.width || y >= self.height {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
32
src/main.rs
32
src/main.rs
|
|
@ -1,8 +1,15 @@
|
||||||
mod image;
|
mod image;
|
||||||
|
mod object;
|
||||||
|
mod render;
|
||||||
mod vec3;
|
mod vec3;
|
||||||
|
|
||||||
use image::Image;
|
use image::Image;
|
||||||
|
use object::Sphere;
|
||||||
|
use render::World;
|
||||||
use vec3::{Point3, Ray, Vec3};
|
use vec3::{Point3, Ray, Vec3};
|
||||||
|
|
||||||
|
use crate::vec3::Interval;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let aspect_ratio = 16.0 / 9.0;
|
let aspect_ratio = 16.0 / 9.0;
|
||||||
let image_width = 800;
|
let image_width = 800;
|
||||||
|
|
@ -10,7 +17,7 @@ fn main() {
|
||||||
|
|
||||||
let focal_length = 1.0;
|
let focal_length = 1.0;
|
||||||
let viewport_height = 2.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 camera_center = Point3::new(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
let viewport_u = Vec3::new(viewport_width as f64, 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_u = viewport_u / image_width as f64;
|
||||||
let pixel_delta_v = viewport_v / image_height as f64;
|
let pixel_delta_v = viewport_v / image_height as f64;
|
||||||
|
|
||||||
let viewport_upper_left = camera_center
|
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();
|
- 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 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 y in 0..img.height {
|
||||||
for x in 0..img.width {
|
for x in 0..img.width {
|
||||||
if let Some(px) = img.get_pixel(x, y) {
|
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_direction = (pixel_center - camera_center).to_vec();
|
||||||
let ray = Ray::new(camera_center, ray_direction);
|
let ray = Ray::new(camera_center, ray_direction);
|
||||||
let (r, g, b) = color_ray(ray);
|
let (r, g, b) = color_ray(ray);
|
||||||
px.set_color(r, g, b);
|
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 {
|
} 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,
|
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)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Ray {
|
pub struct Ray {
|
||||||
direction: Vec3,
|
direction: Vec3,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue