A valid, if incorrect PPM raytracer
This commit is contained in:
commit
9a2d3405a1
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "raytracer"
|
||||
version = "0.1.0"
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "raytracer"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
89
src/main.rs
Normal file
89
src/main.rs
Normal file
|
@ -0,0 +1,89 @@
|
|||
use crate::{
|
||||
ray::Ray,
|
||||
utils::{Color3D, Header, Position3D, PpmFormat, Vec3},
|
||||
};
|
||||
|
||||
pub mod ray;
|
||||
pub mod utils;
|
||||
|
||||
pub const WIDTH: u32 = 640;
|
||||
pub const HEIGHT: u32 = 480;
|
||||
|
||||
pub const ASPECT_RATIO: f32 = WIDTH as f32 / HEIGHT as f32;
|
||||
|
||||
fn main() {
|
||||
let viewport_height = 2.0;
|
||||
let viewport_width = viewport_height * ASPECT_RATIO;
|
||||
let focal_length = 1.0;
|
||||
|
||||
let origin = Position3D {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
};
|
||||
|
||||
let horizontal = Position3D {
|
||||
x: viewport_width,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
};
|
||||
|
||||
let vertical = Position3D {
|
||||
x: 0.0,
|
||||
y: viewport_height,
|
||||
z: 0.0,
|
||||
};
|
||||
|
||||
let lower_left_corner = origin - horizontal / 2.0 - vertical / 2.0 - focal_length;
|
||||
|
||||
let header = Header {
|
||||
format: PpmFormat::P3,
|
||||
width: WIDTH,
|
||||
height: HEIGHT,
|
||||
max_color: 255,
|
||||
};
|
||||
println!("# {}", ASPECT_RATIO);
|
||||
println!("{}", header);
|
||||
|
||||
// Code block to measure.
|
||||
{
|
||||
for y in 0..HEIGHT {
|
||||
for x in 0..WIDTH {
|
||||
let u = (x / WIDTH) as f32 - 1.0;
|
||||
let v = (y / HEIGHT) as f32 - 1.0;
|
||||
|
||||
let bcr = lower_left_corner + u * horizontal + v * vertical - origin;
|
||||
|
||||
let ray = Ray {
|
||||
origin,
|
||||
direction: bcr,
|
||||
};
|
||||
|
||||
let rgb_color = ray_color(&ray);
|
||||
println!("{}", rgb_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unit_vector(v: &Vec3) -> Vec3 {
|
||||
*v / v.length()
|
||||
}
|
||||
|
||||
fn ray_color(ray: &ray::Ray) -> Color3D {
|
||||
let unit_dir = unit_vector(&ray.direction);
|
||||
let t = 0.5 * (unit_dir.y + 1.0);
|
||||
|
||||
let color1 = Color3D {
|
||||
x: 1.0,
|
||||
y: 1.0,
|
||||
z: 1.0,
|
||||
};
|
||||
let color2 = Color3D {
|
||||
x: 0.5,
|
||||
y: 0.7,
|
||||
z: 1.0,
|
||||
};
|
||||
|
||||
return (1.0 - t) * color1 + t * color2;
|
||||
}
|
6
src/ray.rs
Normal file
6
src/ray.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
use crate::utils::Position3D;
|
||||
|
||||
pub struct Ray {
|
||||
pub origin: Position3D,
|
||||
pub direction: Position3D,
|
||||
}
|
133
src/utils.rs
Normal file
133
src/utils.rs
Normal file
|
@ -0,0 +1,133 @@
|
|||
use std::{
|
||||
fmt::Display,
|
||||
ops::{Add, Div, Mul, Sub},
|
||||
};
|
||||
|
||||
pub type Position3D = Vec3;
|
||||
pub type Color3D = Vec3;
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
|
||||
pub struct Vec3 {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32,
|
||||
}
|
||||
impl Vec3 {
|
||||
pub fn new(x: f32, y: f32, z: f32) -> Self {
|
||||
Self { x, y, z }
|
||||
}
|
||||
pub fn zero() -> Self {
|
||||
Self::new(0.0, 0.0, 0.0)
|
||||
}
|
||||
pub fn length(&self) -> f32 {
|
||||
self.length_squared().sqrt()
|
||||
}
|
||||
pub fn length_squared(&self) -> f32 {
|
||||
self.x * self.x + self.y * self.y + self.z * self.z
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<f32> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn mul(self, rhs: f32) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self.x * rhs,
|
||||
y: self.y * rhs,
|
||||
z: self.z * rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<f32> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn add(self, rhs: f32) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self.x + rhs,
|
||||
y: self.y + rhs,
|
||||
z: self.z + rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Vec3> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn add(self, rhs: Vec3) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self.x + rhs.x,
|
||||
y: self.y + rhs.y,
|
||||
z: self.z + rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<f32> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn sub(self, rhs: f32) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self.x - rhs,
|
||||
y: self.y - rhs,
|
||||
z: self.z - rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Vec3> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn sub(self, rhs: Vec3) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self.x - rhs.x,
|
||||
y: self.y - rhs.y,
|
||||
z: self.z - rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<f32> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn div(self, rhs: f32) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self.x / rhs,
|
||||
y: self.y / rhs,
|
||||
z: self.z / rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Vec3> for f32 {
|
||||
type Output = Vec3;
|
||||
fn mul(self, rhs: Vec3) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self * rhs.x,
|
||||
y: self * rhs.y,
|
||||
z: self * rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Vec3 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{} {} {}", self.x as u8, self.y as u8, self.z as u8)
|
||||
}
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub enum PpmFormat {
|
||||
P3,
|
||||
}
|
||||
|
||||
pub struct Header {
|
||||
pub format: PpmFormat,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub max_color: u8,
|
||||
}
|
||||
|
||||
impl Display for Header {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"# HEADER BEGIN
|
||||
{:?}\n{} {}\n{}
|
||||
# HEADER END",
|
||||
self.format, self.width, self.height, self.max_color
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue