feat(scene): make render loop parallelized

This commit is contained in:
Jonas Röger 2024-11-20 00:27:55 +01:00
parent 587471f36a
commit aab1fa0a5e
Signed by: jonas
GPG Key ID: 4000EB35E1AE0F07
6 changed files with 34 additions and 24 deletions

1
Cargo.lock generated
View File

@ -513,6 +513,7 @@ dependencies = [
"image", "image",
"nalgebra", "nalgebra",
"nix", "nix",
"rayon",
] ]
[[package]] [[package]]

View File

@ -24,3 +24,4 @@ futures = "0.3.30"
image = "0.25.5" image = "0.25.5"
nalgebra = "0.33.2" nalgebra = "0.33.2"
nix = "0.29.0" nix = "0.29.0"
rayon = "1.10.0"

View File

@ -1,3 +1,3 @@
[toolchain] [toolchain]
channel = "nightly" channel = "1.80.1"
components = [ "rustfmt", "rustc-dev", "rust-analyzer", "rust-src"] components = [ "rustfmt", "rustc-dev", "rust-analyzer", "rust-src"]

View File

@ -6,6 +6,7 @@ use lispers::raytracer::{
types::{Color, Light, Material, Point3, Vector3}, types::{Color, Light, Material, Point3, Vector3},
}; };
extern crate nalgebra as na; extern crate nalgebra as na;
use std::sync::Arc;
fn main() { fn main() {
let mut scene = Scene::new(); let mut scene = Scene::new();
@ -21,7 +22,7 @@ fn main() {
color: Color::new(1.0, 1.0, 1.0), color: Color::new(1.0, 1.0, 1.0),
}); });
scene.add_object(Box::new(Plane::new( scene.add_object(Arc::new(Plane::new(
Point3::new(0.0, -1.0, 0.0), Point3::new(0.0, -1.0, 0.0),
Vector3::new(0.0, 1.0, 0.0), Vector3::new(0.0, 1.0, 0.0),
Material::new( Material::new(
@ -33,7 +34,7 @@ fn main() {
), ),
))); )));
scene.add_object(Box::new(Sphere::new( scene.add_object(Arc::new(Sphere::new(
Point3::new(-2.0, 0.0, 1.0), Point3::new(-2.0, 0.0, 1.0),
1.0, 1.0,
Material::new( Material::new(
@ -45,7 +46,7 @@ fn main() {
), ),
))); )));
scene.add_object(Box::new(Sphere::new( scene.add_object(Arc::new(Sphere::new(
Point3::new(0.2, -0.5, -0.2), Point3::new(0.2, -0.5, -0.2),
0.5, 0.5,
Material::new( Material::new(
@ -57,7 +58,7 @@ fn main() {
), ),
))); )));
scene.add_object(Box::new(Sphere::new( scene.add_object(Arc::new(Sphere::new(
Point3::new(-0.5, 0.5, -2.0), Point3::new(-0.5, 0.5, -2.0),
1.5, 1.5,
Material::new( Material::new(

View File

@ -3,6 +3,7 @@ use super::{
types::{Color, Point3, Ray, Scalar, Vector3}, types::{Color, Point3, Ray, Scalar, Vector3},
}; };
use image::RgbImage; use image::RgbImage;
use rayon::prelude::*;
/// A camera that can render a scene. /// A camera that can render a scene.
pub struct Camera { pub struct Camera {
@ -77,26 +78,31 @@ impl Camera {
/// - `subp` is the number of subpixels to use for antialiasing. /// - `subp` is the number of subpixels to use for antialiasing.
pub fn render(&self, scene: &Scene, depth: u32, subp: u32) -> RgbImage { pub fn render(&self, scene: &Scene, depth: u32, subp: u32) -> RgbImage {
let dx = 1.0 / self.width as Scalar; let dx = 1.0 / self.width as Scalar;
let dy = 1.0 / self.width as Scalar; let dy = 1.0 / self.height as Scalar;
let dsx = dx / subp as Scalar; let dsx = dx / subp as Scalar;
let dsy = dy / subp as Scalar; let dsy = dy / subp as Scalar;
RgbImage::from_fn(self.width as u32, self.height as u32, |x, y| { let mut img = RgbImage::new(self.width as u32, self.height as u32);
let x = x as Scalar * dx;
let y = y as Scalar * dy; img.enumerate_rows_mut().par_bridge().for_each(|(_, row)| {
let mut color = Color::new(0.0, 0.0, 0.0); for (x, y, pixel) in row {
for sx in 0..subp { let y = y as Scalar * dy;
for sy in 0..subp { let x = x as Scalar * dx;
color += scene.trace( let mut color = Color::new(0.0, 0.0, 0.0);
&self.ray_at_relative( for sx in 0..subp {
x + sx as Scalar * dsx, for sy in 0..subp {
1.0 - (y + sy as Scalar * dsy), color += scene.trace(
), &self.ray_at_relative(
depth, x + sx as Scalar * dsx,
); 1.0 - (y + sy as Scalar * dsy),
),
depth,
);
}
} }
color *= 255.0 / (subp * subp) as Scalar;
*pixel = [color.x as u8, color.y as u8, color.z as u8].into();
} }
color *= 255.0 / (subp * subp) as Scalar; });
[color.x as u8, color.y as u8, color.z as u8].into() img
})
} }
} }

View File

@ -7,6 +7,7 @@ use super::types::Ray;
use super::types::Vector3; use super::types::Vector3;
use super::vec::mirror; use super::vec::mirror;
use super::vec::reflect; use super::vec::reflect;
use std::sync::Arc;
extern crate nalgebra as na; extern crate nalgebra as na;
/// A scene is a collection of objects and lights, and provides a method to trace a ray through the scene. /// A scene is a collection of objects and lights, and provides a method to trace a ray through the scene.
@ -14,7 +15,7 @@ pub struct Scene {
/// The ambient light of the scene /// The ambient light of the scene
ambient: Color, ambient: Color,
/// The objects in the scene /// The objects in the scene
objects: Vec<Box<dyn Intersect>>, objects: Vec<Arc<dyn Intersect + Send + Sync>>,
/// The lights in the scene /// The lights in the scene
lights: Vec<Light>, lights: Vec<Light>,
} }
@ -35,7 +36,7 @@ impl Scene {
} }
/// Add an object to the scene /// Add an object to the scene
pub fn add_object(&mut self, obj: Box<dyn Intersect>) { pub fn add_object(&mut self, obj: Arc<dyn Intersect + Send + Sync>) {
self.objects.push(obj); self.objects.push(obj);
} }