Added Diffuse material image and bug fixes.
1. Added Diffuse Materials image. 2. Using f32 everywhere was causing slight artifacts in images so replaced all use of f32 with f64 3. Fixed a implementation bug in DivAssign on Vec3
This commit is contained in:
parent
30c8b6054f
commit
d903b4a57c
|
@ -22,7 +22,7 @@ impl Camera {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_ray(&self, u: f32, v: f32) -> Ray {
|
||||
pub fn get_ray(&self, u: f64, v: f64) -> Ray {
|
||||
Ray::new(
|
||||
self.origin,
|
||||
self.lower_left_corner + self.horizontal * u + self.vertical * v - self.origin,
|
||||
|
|
70
ria-weekend/src/demos/diffuse_materials.rs
Normal file
70
ria-weekend/src/demos/diffuse_materials.rs
Normal file
|
@ -0,0 +1,70 @@
|
|||
use {
|
||||
crate::{
|
||||
demos::Demo,
|
||||
types::{Hitable, HitableList, Ray, Sphere, Vec3},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
};
|
||||
|
||||
pub struct DiffuseMaterials;
|
||||
|
||||
impl Demo for DiffuseMaterials {
|
||||
fn name(&self) -> &'static str {
|
||||
"Diffuse Materials"
|
||||
}
|
||||
|
||||
fn render(&self, buf: &mut [u8], width: usize, height: usize, samples: u8) {
|
||||
let world = HitableList {
|
||||
list: vec![
|
||||
Box::new(Sphere::new(Vec3::new(0.0, 0.0, -1.0), 0.5)),
|
||||
Box::new(Sphere::new(Vec3::new(0.0, -100.5, -1.0), 100.0)),
|
||||
],
|
||||
};
|
||||
|
||||
let camera: Camera = Default::default();
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut offset = 0;
|
||||
|
||||
for j in (0..height).rev() {
|
||||
for i in 0..width {
|
||||
let mut color = Vec3::new(0.0, 0.0, 0.0);
|
||||
|
||||
for _s in 0..samples {
|
||||
let u = (i as f64 + rng.gen::<f64>()) / width as f64;
|
||||
let v = (j as f64 + rng.gen::<f64>()) / height as f64;
|
||||
|
||||
let r = camera.get_ray(u, v);
|
||||
color += calc_color(r, &world, &mut rng);
|
||||
}
|
||||
|
||||
color /= samples as f64;
|
||||
buf[offset] = (255.99 * color.r()) as u8;
|
||||
buf[offset + 1] = (255.99 * color.g()) as u8;
|
||||
buf[offset + 2] = (255.99 * color.b()) as u8;
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList, rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.0, std::f64::MAX) {
|
||||
let target = hit_rec.p + hit_rec.normal + random_point_in_unit_sphere(rng);
|
||||
calc_color(Ray::new(hit_rec.p, target - hit_rec.p), &world, rng) * 0.5
|
||||
} else {
|
||||
let unit_direction = ray.direction().unit_vector();
|
||||
let t = 0.5 * (unit_direction.y() + 1.0);
|
||||
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||
}
|
||||
}
|
||||
|
||||
fn random_point_in_unit_sphere(rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
||||
let mut point = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>()) * 2.0
|
||||
- Vec3::new(1.0, 1.0, 1.0);
|
||||
while point.sq_len() >= 1.0 {
|
||||
point = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>()) * 2.0
|
||||
- Vec3::new(1.0, 1.0, 1.0);
|
||||
}
|
||||
point
|
||||
}
|
|
@ -25,8 +25,8 @@ impl Demo for HitableSphere {
|
|||
let mut offset = 0;
|
||||
for j in (0..height).rev() {
|
||||
for i in 0..width {
|
||||
let u = i as f32 / width as f32;
|
||||
let v = j as f32 / height as f32;
|
||||
let u = i as f64 / width as f64;
|
||||
let v = j as f64 / height as f64;
|
||||
let ray = Ray::new(origin, lower_left_corner + horizontal * u + vertical * v);
|
||||
|
||||
let color = calc_color(ray, &world);
|
||||
|
@ -40,7 +40,7 @@ impl Demo for HitableSphere {
|
|||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.0, std::f32::MAX) {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.0, std::f64::MAX) {
|
||||
// It's easier to visualise normals as unit vectors
|
||||
// So, This trick of adding 1 to each dimension and then halving
|
||||
// the resulting value shifts the normals from -1<->1 range to
|
||||
|
|
|
@ -22,8 +22,8 @@ impl Demo for LinearGradientRectangle {
|
|||
|
||||
for j in (0..height).rev() {
|
||||
for i in 0..width {
|
||||
let u = i as f32 / width as f32;
|
||||
let v = j as f32 / height as f32;
|
||||
let u = i as f64 / width as f64;
|
||||
let v = j as f64 / height as f64;
|
||||
let ray = Ray::new(origin, lower_left_corner + horizontal * u + vertical * v);
|
||||
|
||||
let c = color(ray);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
mod diffuse_materials;
|
||||
mod hitable_sphere;
|
||||
mod linear_gradient_rectangle;
|
||||
mod simple_antialiasing;
|
||||
|
@ -5,6 +6,7 @@ mod simple_rectangle;
|
|||
mod simple_sphere;
|
||||
mod surface_normal_sphere;
|
||||
|
||||
pub use diffuse_materials::DiffuseMaterials;
|
||||
pub use hitable_sphere::HitableSphere;
|
||||
pub use linear_gradient_rectangle::LinearGradientRectangle;
|
||||
pub use simple_antialiasing::SimpleAntialiasing;
|
||||
|
|
|
@ -28,13 +28,13 @@ impl Demo for SimpleAntialiasing {
|
|||
for i in 0..width {
|
||||
let mut color = Vec3::new(0.0, 0.0, 0.0);
|
||||
for _s in 0..samples {
|
||||
let u = (i as f32 + rng.gen::<f32>()) / width as f32;
|
||||
let v = (j as f32 + rng.gen::<f32>()) / height as f32;
|
||||
let u = (i as f64 + rng.gen::<f64>()) / width as f64;
|
||||
let v = (j as f64 + rng.gen::<f64>()) / height as f64;
|
||||
|
||||
let r = camera.get_ray(u, v);
|
||||
color += calc_color(r, &world);
|
||||
}
|
||||
color /= samples as f32;
|
||||
color /= samples as f64;
|
||||
buf[offset] = (255.99 * color.r()) as u8;
|
||||
buf[offset + 1] = (255.99 * color.g()) as u8;
|
||||
buf[offset + 2] = (255.99 * color.b()) as u8;
|
||||
|
@ -45,7 +45,7 @@ impl Demo for SimpleAntialiasing {
|
|||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.0, std::f32::MAX) {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.0, std::f64::MAX) {
|
||||
// It's easier to visualise normals as unit vectors
|
||||
// So, This trick of adding 1 to each dimension and then halving
|
||||
// the resulting value shifts the normals from -1<->1 range to
|
||||
|
|
|
@ -11,7 +11,7 @@ impl Demo for SimpleRectangle {
|
|||
let mut offset = 0;
|
||||
for j in (0..height).rev() {
|
||||
for i in 0..width {
|
||||
let color = Vec3::new(i as f32 / width as f32, j as f32 / width as f32, 0.2);
|
||||
let color = Vec3::new(i as f64 / width as f64, j as f64 / width as f64, 0.2);
|
||||
|
||||
buf[offset] = (255.99 * color.r()) as u8;
|
||||
buf[offset + 1] = (255.99 * color.g()) as u8;
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
|||
Demo,
|
||||
};
|
||||
|
||||
const RADIUS: f32 = 0.5;
|
||||
const RADIUS: f64 = 0.5;
|
||||
|
||||
pub struct SimpleSphere;
|
||||
|
||||
|
@ -35,8 +35,8 @@ impl Demo for SimpleSphere {
|
|||
for i in 0..w {
|
||||
// relative offsets
|
||||
// current position to total width/length
|
||||
let u = i as f32 / w as f32;
|
||||
let v = j as f32 / h as f32;
|
||||
let u = i as f64 / w as f64;
|
||||
let v = j as f64 / h as f64;
|
||||
|
||||
let ray = Ray::new(origin, lower_left_corner + horizontal * u + vertical * v);
|
||||
let color = calc_color(ray);
|
||||
|
@ -49,7 +49,7 @@ impl Demo for SimpleSphere {
|
|||
}
|
||||
}
|
||||
|
||||
fn ray_hit_sphere(center: Vec3, radius: f32, ray: &Ray) -> bool {
|
||||
fn ray_hit_sphere(center: Vec3, radius: f64, ray: &Ray) -> bool {
|
||||
// For a point to lie on a circle,
|
||||
// (x-cx)^2 + (y-cy)^2 + (z-cz)^2 = R * R
|
||||
// should hold true. This equation can be rewritten as,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::types::{Ray, Vec3};
|
||||
|
||||
const RADIUS: f32 = 0.5;
|
||||
const RADIUS: f64 = 0.5;
|
||||
pub struct SurfaceNormalSphere;
|
||||
|
||||
impl crate::Demo for SurfaceNormalSphere {
|
||||
|
@ -28,8 +28,8 @@ impl crate::Demo for SurfaceNormalSphere {
|
|||
let mut offset = 0;
|
||||
for j in (0..h).rev() {
|
||||
for i in 0..w {
|
||||
let u = i as f32 / w as f32;
|
||||
let v = j as f32 / h as f32;
|
||||
let u = i as f64 / w as f64;
|
||||
let v = j as f64 / h as f64;
|
||||
|
||||
let ray = Ray::new(origin, lower_left_corner + horizontal * u + vertical * v);
|
||||
let color = calculate_color(ray);
|
||||
|
@ -61,7 +61,7 @@ fn calculate_color(ray: Ray) -> Vec3 {
|
|||
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||
}
|
||||
|
||||
fn ray_hit_sphere(center: Vec3, radius: f32, ray: &Ray) -> f32 {
|
||||
fn ray_hit_sphere(center: Vec3, radius: f64, ray: &Ray) -> f64 {
|
||||
let pc = ray.origin() - center;
|
||||
let a = ray.direction().dot(&ray.direction());
|
||||
let b = 2.0 * pc.dot(&ray.direction());
|
||||
|
|
|
@ -15,7 +15,7 @@ use {
|
|||
},
|
||||
};
|
||||
|
||||
const NUM_SAMPLES: u8 = 100;
|
||||
const NUM_SAMPLES: u8 = 20;
|
||||
|
||||
fn main() -> Result<(), String> {
|
||||
let sdl_ctx = sdl2::init()?;
|
||||
|
@ -72,6 +72,7 @@ fn main() -> Result<(), String> {
|
|||
Some(Keycode::Num4) => active_demo = Box::new(demos::SurfaceNormalSphere),
|
||||
Some(Keycode::Num5) => active_demo = Box::new(demos::HitableSphere),
|
||||
Some(Keycode::Num6) => active_demo = Box::new(demos::SimpleAntialiasing),
|
||||
Some(Keycode::Num7) => active_demo = Box::new(demos::DiffuseMaterials),
|
||||
None => unreachable!(),
|
||||
_ => (),
|
||||
};
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use crate::types::{Ray, Vec3};
|
||||
|
||||
pub struct HitRecord {
|
||||
pub t: f32,
|
||||
pub t: f64,
|
||||
pub p: Vec3,
|
||||
pub normal: Vec3,
|
||||
}
|
||||
|
||||
pub trait Hitable {
|
||||
fn hit(&self, _ray: &Ray, _t_min: f32, _t_max: f32) -> Option<HitRecord> {
|
||||
fn hit(&self, _ray: &Ray, _t_min: f64, _t_max: f64) -> Option<HitRecord> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ pub struct HitableList {
|
|||
}
|
||||
|
||||
impl Hitable for HitableList {
|
||||
fn hit(&self, ray: &Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
||||
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
|
||||
let mut closest_so_far = t_max;
|
||||
let mut hit_rec: Option<HitRecord> = None;
|
||||
for obj in &self.list {
|
||||
|
|
|
@ -18,7 +18,7 @@ impl Ray {
|
|||
self.b
|
||||
}
|
||||
#[inline]
|
||||
pub fn point_at_parameter(&self, t: f32) -> Vec3 {
|
||||
pub fn point_at_parameter(&self, t: f64) -> Vec3 {
|
||||
self.a + self.b * t
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,17 @@
|
|||
use crate::types::{HitRecord, Hitable, Ray, Vec3};
|
||||
pub struct Sphere {
|
||||
center: Vec3,
|
||||
radius: f32,
|
||||
radius: f64,
|
||||
}
|
||||
|
||||
impl Sphere {
|
||||
pub fn new(center: Vec3, radius: f32) -> Self {
|
||||
pub fn new(center: Vec3, radius: f64) -> Self {
|
||||
Self { center, radius }
|
||||
}
|
||||
const fn radius(&self) -> f32 {
|
||||
self.radius
|
||||
}
|
||||
const fn center(&self) -> Vec3 {
|
||||
self.center
|
||||
}
|
||||
}
|
||||
|
||||
impl Hitable for Sphere {
|
||||
fn hit(&self, ray: &Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
||||
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
|
||||
let oc = ray.origin() - self.center;
|
||||
let a = ray.direction().dot(&ray.direction());
|
||||
let b = oc.dot(&ray.direction());
|
||||
|
|
|
@ -4,50 +4,50 @@ use std::{
|
|||
};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Vec3([f32; 3]);
|
||||
pub struct Vec3([f64; 3]);
|
||||
|
||||
impl Vec3 {
|
||||
#[inline]
|
||||
pub const fn new(a: f32, b: f32, c: f32) -> Vec3 {
|
||||
pub const fn new(a: f64, b: f64, c: f64) -> Vec3 {
|
||||
Vec3([a, b, c])
|
||||
}
|
||||
#[inline]
|
||||
pub fn x(&self) -> f32 {
|
||||
pub fn x(&self) -> f64 {
|
||||
self[0]
|
||||
}
|
||||
#[inline]
|
||||
pub fn y(&self) -> f32 {
|
||||
pub fn y(&self) -> f64 {
|
||||
self[1]
|
||||
}
|
||||
#[inline]
|
||||
pub fn z(&self) -> f32 {
|
||||
pub fn z(&self) -> f64 {
|
||||
self[2]
|
||||
}
|
||||
#[inline]
|
||||
pub fn r(&self) -> f32 {
|
||||
pub fn r(&self) -> f64 {
|
||||
self[0]
|
||||
}
|
||||
#[inline]
|
||||
pub fn g(&self) -> f32 {
|
||||
pub fn g(&self) -> f64 {
|
||||
self[1]
|
||||
}
|
||||
#[inline]
|
||||
pub fn b(&self) -> f32 {
|
||||
pub fn b(&self) -> f64 {
|
||||
self[2]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn length(&self) -> f32 {
|
||||
pub fn length(&self) -> f64 {
|
||||
self.sq_len().sqrt()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sq_len(&self) -> f32 {
|
||||
pub fn sq_len(&self) -> f64 {
|
||||
self[0] * self[0] + self[1] * self[1] + self[2] * self[2]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn dot(&self, v: &Vec3) -> f32 {
|
||||
pub fn dot(&self, v: &Vec3) -> f64 {
|
||||
self[0] * v[0] + self[1] * v[1] + self[2] * v[2]
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ impl Vec3 {
|
|||
|
||||
#[inline]
|
||||
pub fn make_unit_vector(&mut self) {
|
||||
let k = 1.0f32 / (self[0] * self[0] + self[1] * self[1] + self[2] * self[2]);
|
||||
let k = 1.0f64 / (self[0] * self[0] + self[1] * self[1] + self[2] * self[2]);
|
||||
self[0] *= k;
|
||||
self[1] *= k;
|
||||
self[2] *= k;
|
||||
|
@ -115,17 +115,17 @@ impl MulAssign<Vec3> for Vec3 {
|
|||
}
|
||||
}
|
||||
|
||||
impl MulAssign<f32> for Vec3 {
|
||||
fn mul_assign(&mut self, o: f32) {
|
||||
impl MulAssign<f64> for Vec3 {
|
||||
fn mul_assign(&mut self, o: f64) {
|
||||
self[0] *= o;
|
||||
self[1] *= o;
|
||||
self[2] *= o;
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<f32> for Vec3 {
|
||||
impl Mul<f64> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn mul(self, o: f32) -> Vec3 {
|
||||
fn mul(self, o: f64) -> Vec3 {
|
||||
Vec3([self[0] * o, self[1] * o, self[2] * o])
|
||||
}
|
||||
}
|
||||
|
@ -138,34 +138,34 @@ impl Div<Vec3> for Vec3 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Div<f32> for Vec3 {
|
||||
impl Div<f64> for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn div(self, o: f32) -> Vec3 {
|
||||
fn div(self, o: f64) -> Vec3 {
|
||||
let o = 1.0 / o;
|
||||
Vec3([self[0] * o, self[1] * o, self[2] * o])
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign<f32> for Vec3 {
|
||||
fn div_assign(&mut self, o: f32) {
|
||||
impl DivAssign<f64> for Vec3 {
|
||||
fn div_assign(&mut self, o: f64) {
|
||||
let o = 1.0 / o;
|
||||
self.0[0] /= o;
|
||||
self.0[1] /= o;
|
||||
self.0[2] /= o;
|
||||
self.0[0] *= o;
|
||||
self.0[1] *= o;
|
||||
self.0[2] *= o;
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for Vec3 {
|
||||
type Output = f32;
|
||||
type Output = f64;
|
||||
|
||||
fn index(&self, q: usize) -> &f32 {
|
||||
fn index(&self, q: usize) -> &f64 {
|
||||
&self.0[q]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for Vec3 {
|
||||
fn index_mut(&mut self, q: usize) -> &mut f32 {
|
||||
fn index_mut(&mut self, q: usize) -> &mut f64 {
|
||||
&mut self.0[q]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user