Compare commits
1 commit
main
...
pixel-canv
Author | SHA1 | Date | |
---|---|---|---|
|
1cb4defeba |
7 changed files with 1182 additions and 129 deletions
1145
Cargo.lock
generated
1145
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -8,6 +8,7 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
image = { version = "0.24.2", default-features = false, features = ["jpeg", "png", "pnm"] }
|
image = { version = "0.24.2", default-features = false, features = ["jpeg", "png", "pnm"] }
|
||||||
indicatif = "0.17.0"
|
indicatif = "0.17.0"
|
||||||
|
pixel-canvas = "0.2.3"
|
||||||
rand = { version = "0.8.5", features = ["small_rng"] }
|
rand = { version = "0.8.5", features = ["small_rng"] }
|
||||||
rayon = "1.5.3"
|
rayon = "1.5.3"
|
||||||
tobj = "3.2.3"
|
tobj = "3.2.3"
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
# Blender v2.82 (sub 7) OBJ File: ''
|
||||||
|
# www.blender.org
|
||||||
|
mtllib viking_room.mtl
|
||||||
|
o mesh_all1_Texture1_0
|
||||||
v -0.573651 0.001530 0.713748
|
v -0.573651 0.001530 0.713748
|
||||||
v -0.573651 0.151382 -0.000154
|
v -0.573651 0.151382 -0.000154
|
||||||
v -0.573651 0.164474 0.619081
|
v -0.573651 0.164474 0.619081
|
||||||
|
|
|
@ -5,10 +5,10 @@ pub fn put_color(img: &mut RgbImage, pixel_color: &Color, x: u32, y: u32, sample
|
||||||
let mut g = pixel_color.y();
|
let mut g = pixel_color.y();
|
||||||
let mut b = pixel_color.z();
|
let mut b = pixel_color.z();
|
||||||
|
|
||||||
let scale = 1.0;// / samples_per_pixel as f64;
|
//let scale = 1.0 / samples_per_pixel as f64;
|
||||||
r = (scale * r).sqrt();
|
//r = r/samples_per_pixel as f64; //(scale * r).sqrt();
|
||||||
g = (scale * g).sqrt();
|
//g = g/samples_per_pixel as f64; //(scale * g).sqrt();
|
||||||
b = (scale * b).sqrt();
|
//b = b/samples_per_pixel as f64; //(scale * b).sqrt();
|
||||||
|
|
||||||
img.put_pixel(
|
img.put_pixel(
|
||||||
x,
|
x,
|
||||||
|
|
|
@ -29,8 +29,7 @@ impl HittableList {
|
||||||
|
|
||||||
for obj in &self.objects {
|
for obj in &self.objects {
|
||||||
let mut temp_rec = HitRecord::empty();
|
let mut temp_rec = HitRecord::empty();
|
||||||
if obj.hit(&r, t_min, closest_so_far, &mut temp_rec)
|
if obj.hit(&r, t_min, closest_so_far, &mut temp_rec) {
|
||||||
&& closest_so_far > temp_rec.t {
|
|
||||||
hit_anything = true;
|
hit_anything = true;
|
||||||
closest_so_far = temp_rec.t;
|
closest_so_far = temp_rec.t;
|
||||||
*rec = temp_rec;
|
*rec = temp_rec;
|
||||||
|
|
139
src/main.rs
139
src/main.rs
|
@ -15,6 +15,7 @@ use hittable_list::HittableList;
|
||||||
use image::{Rgb, RgbImage};
|
use image::{Rgb, RgbImage};
|
||||||
use indicatif::ProgressBar;
|
use indicatif::ProgressBar;
|
||||||
use material::{Dielectric, Lambertian, Material, Metal, Rainbow};
|
use material::{Dielectric, Lambertian, Material, Metal, Rainbow};
|
||||||
|
use pixel_canvas::{Canvas, Color as canvColor, RC};
|
||||||
use ray::Ray;
|
use ray::Ray;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
@ -39,7 +40,7 @@ fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color {
|
||||||
{
|
{
|
||||||
return attenuation * ray_color(&scattered, world, depth - 1);
|
return attenuation * ray_color(&scattered, world, depth - 1);
|
||||||
}
|
}
|
||||||
return Color::new(255.0, 0.0, 0.0);//Color::null();
|
return Color::null();
|
||||||
}
|
}
|
||||||
|
|
||||||
let unit_direction = r.direction();
|
let unit_direction = r.direction();
|
||||||
|
@ -67,17 +68,17 @@ fn main() {
|
||||||
|
|
||||||
// Image
|
// Image
|
||||||
let aspect_ratio = 10.0 / 7.5; //16.0 / 9.0;
|
let aspect_ratio = 10.0 / 7.5; //16.0 / 9.0;
|
||||||
let image_width = 1200;
|
let image_width = 400;
|
||||||
let image_height = (image_width as f64 / aspect_ratio) as u32;
|
let image_height = (image_width as f64 / aspect_ratio) as u32;
|
||||||
let samples_per_pixel = 1_u32;
|
let samples_per_pixel = 100_u32;
|
||||||
let max_depth = 50;
|
let max_depth = 50;
|
||||||
let antialiasing_threshold = 0.2; // at what diff between two colors will a pixel be antialiased
|
let antialiasing_threshold = 0.2; // at what diff between two colors will a pixel be antialiased
|
||||||
|
|
||||||
let vfov = 43.0;
|
let vfov = 40.0;
|
||||||
let lookfrom = Point3::new(2.0, 1.0, 1.0);
|
let lookfrom = Point3::new(2.0, 0.8, 3.0);
|
||||||
let lookat = Point3::new(0.0, 0.2, 0.0);
|
let lookat = Point3::new(0.0, 0.0, 0.0);
|
||||||
let vup = Vec3::new(0.0, 1.0, 0.0);
|
let vup = Vec3::new(0.0, 1.0, 0.0);
|
||||||
let dist_to_focus = 1.0;
|
let dist_to_focus = 3.0;
|
||||||
let aperture = 0.0; // disable depth of field
|
let aperture = 0.0; // disable depth of field
|
||||||
|
|
||||||
// limit rayon multithreading thread count
|
// limit rayon multithreading thread count
|
||||||
|
@ -88,7 +89,7 @@ fn main() {
|
||||||
|
|
||||||
// World
|
// World
|
||||||
eprintln!("[1/4] Loading meshes from file...");
|
eprintln!("[1/4] Loading meshes from file...");
|
||||||
let world = from_obj("obj/viking_room.obj");
|
let world = from_obj("obj/suzanne.obj");
|
||||||
// let world = random_world();
|
// let world = random_world();
|
||||||
|
|
||||||
// Camera
|
// Camera
|
||||||
|
@ -102,6 +103,11 @@ fn main() {
|
||||||
dist_to_focus,
|
dist_to_focus,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Canvas
|
||||||
|
let canvas = Canvas::new(image_width as usize, image_height as usize)
|
||||||
|
.title("Raytracer");
|
||||||
|
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
if args.len() > 1 && args[1] != "" {
|
if args.len() > 1 && args[1] != "" {
|
||||||
|
@ -131,32 +137,22 @@ fn main() {
|
||||||
max_depth,
|
max_depth,
|
||||||
);
|
);
|
||||||
colors.push(pixel_color);
|
colors.push(pixel_color);
|
||||||
|
canvas.render(
|
||||||
|
|mouse, image| {
|
||||||
|
let addr = RC{0: j as usize, 1: i as usize};
|
||||||
|
image[addr] = canvColor {
|
||||||
|
r: pixel_color.x() as u8,
|
||||||
|
g: pixel_color.y() as u8,
|
||||||
|
b: pixel_color.z() as u8,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return colors;
|
return colors;
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
bar.finish_and_clear();
|
bar.finish_and_clear();
|
||||||
|
|
||||||
// no antialiasing
|
|
||||||
if samples_per_pixel == 1_u32 {
|
|
||||||
eprintln!("[4/4] Exporting image to disk...");
|
|
||||||
(0..image_height).into_iter().rev().for_each(|j| {
|
|
||||||
(0..image_width).into_iter().for_each(|i| {
|
|
||||||
color::put_color(
|
|
||||||
&mut image,
|
|
||||||
&color_lines[(image_height - j - 1) as usize][i as usize],
|
|
||||||
i,
|
|
||||||
image_height - j - 1,
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
image.save(default_file).unwrap();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
eprintln!("[3/4] Antialiasing image...");
|
eprintln!("[3/4] Antialiasing image...");
|
||||||
let mut antialiasing: Vec<Vec<bool>> = Vec::new();
|
let mut antialiasing: Vec<Vec<bool>> = Vec::new();
|
||||||
let mut antialiasing_counter = 0;
|
let mut antialiasing_counter = 0;
|
||||||
|
@ -257,7 +253,8 @@ fn main() {
|
||||||
|
|
||||||
/********************
|
/********************
|
||||||
* WORLD GENERATION *
|
* WORLD GENERATION *
|
||||||
********************/
|
*********************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -281,47 +278,33 @@ fn from_obj(path: &str) -> HittableList {
|
||||||
)));
|
)));
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//let material = Arc::new(Lambertian::new(&Color::new(
|
let material = Arc::new(Lambertian::new(&Color::new(
|
||||||
// 77.0 / 255.0,
|
77.0 / 255.0,
|
||||||
// 77.0 / 255.0,
|
77.0 / 255.0,
|
||||||
// 118.0 / 255.0,
|
118.0 / 255.0,
|
||||||
//)));
|
)));
|
||||||
//let material = Arc::new(Dielectric::new(2.0));
|
//let material = Arc::new(Dielectric::new(2.0));
|
||||||
let material = Arc::new(Metal::new(&Color::new(0.5, 0.55, 0.7), 0.0));
|
//let material = Arc::new(Metal::new(&Color::new(0.9, 0.9, 0.7), 1.0));
|
||||||
//let material = Arc::new(Rainbow::new());
|
//let material = Arc::new(Rainbow::new());
|
||||||
|
|
||||||
let rotate_obj = 1; // rotate clockwise, 0: 0, 1: 90, 2: 180, 3: 270
|
|
||||||
|
|
||||||
let cornell_box = tobj::load_obj(path, &tobj::OFFLINE_RENDERING_LOAD_OPTIONS);
|
let cornell_box = tobj::load_obj(path, &tobj::OFFLINE_RENDERING_LOAD_OPTIONS);
|
||||||
let (models, materials) = cornell_box.expect("Failed to load OBJ file");
|
let (models, materials) = cornell_box.expect("Failed to load OBJ file");
|
||||||
let materials = materials.expect("Failed to load MTL file");
|
let materials = materials.expect("Failed to load MTL file");
|
||||||
|
|
||||||
let mut new_x = 0;
|
|
||||||
let mut new_y = 1;
|
|
||||||
let mut new_z = 2;
|
|
||||||
|
|
||||||
match rotate_obj {
|
|
||||||
1 => {
|
|
||||||
new_x = 0;
|
|
||||||
new_y = 2;
|
|
||||||
new_z = 1;
|
|
||||||
},
|
|
||||||
2 => {
|
|
||||||
new_x = 0;
|
|
||||||
new_y = 2;
|
|
||||||
new_z = 1;
|
|
||||||
},
|
|
||||||
3 => {
|
|
||||||
new_x = 0;
|
|
||||||
new_y = 2;
|
|
||||||
new_z = 1;
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i, m) in models.iter().enumerate() {
|
for (i, m) in models.iter().enumerate() {
|
||||||
let mesh = &m.mesh;
|
let mesh = &m.mesh;
|
||||||
|
|
||||||
|
/* Mesh vector lengths
|
||||||
|
println!("positions: {}", mesh.positions.len());
|
||||||
|
println!("vertex_color: {}", mesh.vertex_color.len());
|
||||||
|
println!("normals: {}", mesh.normals.len());
|
||||||
|
println!("texcoords: {}", mesh.texcoords.len());
|
||||||
|
println!("indices: {}", mesh.indices.len());
|
||||||
|
println!("face_arities: {}", mesh.face_arities.len());
|
||||||
|
println!("texcoord_indices: {}", mesh.texcoord_indices.len());
|
||||||
|
println!("normal_indices: {}", mesh.normal_indices.len());
|
||||||
|
*/
|
||||||
|
|
||||||
let mut next_face = 0;
|
let mut next_face = 0;
|
||||||
for f in 0..mesh.face_arities.len() {
|
for f in 0..mesh.face_arities.len() {
|
||||||
let end = next_face + mesh.face_arities[f] as usize;
|
let end = next_face + mesh.face_arities[f] as usize;
|
||||||
|
@ -340,17 +323,17 @@ fn from_obj(path: &str) -> HittableList {
|
||||||
|
|
||||||
let normal_avg = Vec3::unit_vector(
|
let normal_avg = Vec3::unit_vector(
|
||||||
Vec3::new(
|
Vec3::new(
|
||||||
mesh.positions[3 * index_normal_a + new_x] as f64,
|
mesh.positions[3 * index_normal_a] as f64,
|
||||||
mesh.positions[3 * index_normal_a + new_y] as f64,
|
mesh.positions[3 * index_normal_a + 1] as f64,
|
||||||
mesh.positions[3 * index_normal_a + new_z] as f64,
|
mesh.positions[3 * index_normal_a + 2] as f64,
|
||||||
) + Vec3::new(
|
) + Vec3::new(
|
||||||
mesh.positions[3 * index_normal_b + new_x] as f64,
|
mesh.positions[3 * index_normal_b] as f64,
|
||||||
mesh.positions[3 * index_normal_b + new_y] as f64,
|
mesh.positions[3 * index_normal_b + 1] as f64,
|
||||||
mesh.positions[3 * index_normal_b + new_z] as f64,
|
mesh.positions[3 * index_normal_b + 2] as f64,
|
||||||
) + Vec3::new(
|
) + Vec3::new(
|
||||||
mesh.positions[3 * index_normal_c + new_x] as f64,
|
mesh.positions[3 * index_normal_c] as f64,
|
||||||
mesh.positions[3 * index_normal_c + new_y] as f64,
|
mesh.positions[3 * index_normal_c + 1] as f64,
|
||||||
mesh.positions[3 * index_normal_c + new_z] as f64,
|
mesh.positions[3 * index_normal_c + 2] as f64,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -369,19 +352,19 @@ fn from_obj(path: &str) -> HittableList {
|
||||||
|
|
||||||
world.add(Box::<Triangle>::new(Triangle::new(
|
world.add(Box::<Triangle>::new(Triangle::new(
|
||||||
Point3::new(
|
Point3::new(
|
||||||
mesh.positions[3 * index_a + new_x] as f64,
|
mesh.positions[3 * index_a] as f64,
|
||||||
mesh.positions[3 * index_a + new_y] as f64,
|
mesh.positions[3 * index_a + 1] as f64,
|
||||||
mesh.positions[3 * index_a + new_z] as f64,
|
mesh.positions[3 * index_a + 2] as f64,
|
||||||
),
|
),
|
||||||
Point3::new(
|
Point3::new(
|
||||||
mesh.positions[3 * index_b + new_x] as f64,
|
mesh.positions[3 * index_b] as f64,
|
||||||
mesh.positions[3 * index_b + new_y] as f64,
|
mesh.positions[3 * index_b + 1] as f64,
|
||||||
mesh.positions[3 * index_b + new_z] as f64,
|
mesh.positions[3 * index_b + 2] as f64,
|
||||||
),
|
),
|
||||||
Point3::new(
|
Point3::new(
|
||||||
mesh.positions[3 * index_c + new_x] as f64,
|
mesh.positions[3 * index_c] as f64,
|
||||||
mesh.positions[3 * index_c + new_y] as f64,
|
mesh.positions[3 * index_c + 1] as f64,
|
||||||
mesh.positions[3 * index_c + new_z] as f64,
|
mesh.positions[3 * index_c + 2] as f64,
|
||||||
),
|
),
|
||||||
normal_avg,
|
normal_avg,
|
||||||
material.clone(),
|
material.clone(),
|
||||||
|
|
|
@ -77,13 +77,7 @@ impl Material for Metal {
|
||||||
*scattered = Ray::new(rec.p, reflected + self.fuzz * Vec3::random_in_unit_sphere());
|
*scattered = Ray::new(rec.p, reflected + self.fuzz * Vec3::random_in_unit_sphere());
|
||||||
*attenuation = self.albedo.clone();
|
*attenuation = self.albedo.clone();
|
||||||
|
|
||||||
let reflect = Vec3::dot(r_in.direction(), rec.normal);
|
return Vec3::dot(scattered.direction(), rec.normal) > 0.0;
|
||||||
//dbg!(reflect);
|
|
||||||
|
|
||||||
/*if reflect > 0.0 {
|
|
||||||
*attenuation = Color::new(100.0, 0.0, 0.0);
|
|
||||||
}*/
|
|
||||||
return true;//reflect > 0.0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +97,7 @@ impl Material for Mirror {
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if utility::random_f64() > 0.8 {
|
if utility::random_f64() > 0.8 {
|
||||||
// Reflektiert
|
// Reflektiert
|
||||||
let reflected = Vec3::reflect(&r_in.direction(), &rec.normal);
|
let reflected = Vec3::reflect(&Vec3::unit_vector(r_in.direction()), &rec.normal);
|
||||||
*scattered = Ray::new(rec.p, reflected);
|
*scattered = Ray::new(rec.p, reflected);
|
||||||
*attenuation = self.albedo.clone();
|
*attenuation = self.albedo.clone();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue