aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJulian T <julian@jtle.dk>2021-02-03 17:29:27 +0100
committerJulian T <julian@jtle.dk>2021-02-03 17:29:27 +0100
commit977b0e4152433b2a68e2b97fe5fe2c0ff6fb20d8 (patch)
tree9c1eccef2ede2507e7d29a0daf44d56c76036415 /src
parent8296be848319eecd43f94900d4d12414ec189166 (diff)
Can render a simple sphere, without shading
Diffstat (limited to 'src')
-rw-r--r--src/camera/camera.rs9
-rw-r--r--src/camera/film.rs40
-rw-r--r--src/camera/mod.rs1
-rw-r--r--src/core/spectrum.rs6
-rw-r--r--src/core/vector2.rs7
-rw-r--r--src/lib.rs3
-rw-r--r--src/main.rs38
-rw-r--r--src/render.rs51
8 files changed, 132 insertions, 23 deletions
diff --git a/src/camera/camera.rs b/src/camera/camera.rs
index 69fd4e0..7822e92 100644
--- a/src/camera/camera.rs
+++ b/src/camera/camera.rs
@@ -7,13 +7,13 @@
//!
//! ```
//! use pathtrace::camera::Camera;
-//! use pathtrace::core::{Vector3f, Vector2f};
+//! use pathtrace::core::{Vector3f, Vector2f, Vector2i};
//!
//! let cam = Camera::new(
//! Vector3f::new(10.0),
//! Vector3f::new(0.0),
//! Vector3f::new_xyz(0.0, 1.0, 0.0),
-//! 90.0, Vector2f::new(10.0),
+//! 90.0, Vector2i::new(10.0),
//! );
//!
//! let (r, _) = cam.generate_ray(&Vector2f::new(5.0));
@@ -27,7 +27,7 @@
//!
//! ```
use crate::Float;
-use crate::core::{Vector3f, Vector2f, Ray};
+use crate::core::{Vector3f, Vector2f, Vector2i, Ray};
/// A simple perspective camera
pub struct Camera {
@@ -45,7 +45,8 @@ impl Camera {
///
/// The field of view specifies how wide the image should be.
/// Currently must be between [0; 180[.
- pub fn new(origin: Vector3f, target: Vector3f, up: Vector3f, fov: Float, screensize: Vector2f) -> Camera {
+ pub fn new(origin: Vector3f, target: Vector3f, up: Vector3f, fov: Float, screensize: Vector2i) -> Camera {
+ let screensize = Vector2f::from(screensize);
// Calculate translation vectors
let forward = (target - origin).norm();
let right = up.cross(&origin).norm();
diff --git a/src/camera/film.rs b/src/camera/film.rs
index 30fd2fe..3586374 100644
--- a/src/camera/film.rs
+++ b/src/camera/film.rs
@@ -1,5 +1,6 @@
use crate::core::*;
use crate::Float;
+use image::{RgbImage, Rgb};
/// Contains the necesary values when doing calculations
///
@@ -14,7 +15,7 @@ pub struct Pixel {
pub struct Film {
size: Vector2i,
- drawing_bound: Bound2i,
+ pub frame: Bound2i,
pixels: Vec<Pixel>,
}
@@ -24,14 +25,12 @@ pub struct Film {
/// This means that multiple threads can work on the same area and commit their changed when they
/// are done.
pub struct FilmTile {
- bounds: Bound2i,
- size: Vector2i,
+ pub bounds: Bound2i,
+ pub size: Vector2i,
pixels: Vec<Pixel>,
}
-//const HalfPixel = Vector2f::new(0.5);
-
impl Pixel {
fn new() -> Pixel {
Pixel {
@@ -44,6 +43,15 @@ impl Pixel {
self.rgb += &(c * weight);
self.samples += 1;
}
+
+ fn finalize_rgb(&self) -> [u8; 3] {
+ let (r, g, b) = self.rgb.to_rgb(255.0);
+ [
+ r as u8,
+ g as u8,
+ b as u8,
+ ]
+ }
}
impl std::ops::AddAssign<&Self> for Pixel {
@@ -58,7 +66,7 @@ impl Film {
let area = size.x * size.y;
Film {
size,
- drawing_bound: Bound2i::new(&Vector2i::new(0), &size),
+ frame: Bound2i::new(&Vector2i::new(0), &size),
pixels: vec![Pixel::new(); area as usize],
}
}
@@ -79,18 +87,34 @@ impl Film {
pub fn commit_tile(&mut self, tile: &FilmTile) {
let offset = tile.bounds.min;
- for y in 0 ..= tile.size.y {
+ for y in 0 .. tile.size.y {
let rowindex = (offset.y + y) * self.size.x;
let prowindex = y * tile.size.x;
- for x in 0 ..= tile.size.x {
+ for x in 0 .. tile.size.x {
let index = offset.x + x + rowindex;
let pindex: i32 = x + prowindex;
self.pixels[index as usize] += &tile.pixels[pindex as usize];
}
}
+ }
+
+ pub fn finalize_image(&self) -> RgbImage {
+ let mut img = RgbImage::new(self.size.x as u32, self.size.y as u32);
+
+ for y in 0..self.size.y {
+ let index = y * self.size.x;
+ for x in 0..self.size.x {
+ img.put_pixel(
+ x as u32,
+ y as u32,
+ Rgb(self.pixels[(index + x) as usize].finalize_rgb()),
+ );
+ }
+ }
+ img
}
}
diff --git a/src/camera/mod.rs b/src/camera/mod.rs
index b7c982b..1391cea 100644
--- a/src/camera/mod.rs
+++ b/src/camera/mod.rs
@@ -10,3 +10,4 @@ pub mod film;
pub mod camera;
pub use camera::Camera;
+pub use film::Film;
diff --git a/src/core/spectrum.rs b/src/core/spectrum.rs
index c72a251..fb82a9e 100644
--- a/src/core/spectrum.rs
+++ b/src/core/spectrum.rs
@@ -12,9 +12,13 @@ pub struct Spectrum {
}
impl Spectrum {
- fn new_rgb(r: Float, g: Float, b: Float) -> Spectrum {
+ pub fn new_rgb(r: Float, g: Float, b: Float) -> Spectrum {
Spectrum { c: [r, g, b] }
}
+
+ pub fn to_rgb(&self, scale: Float) -> (Float, Float, Float) {
+ (self.c[0] * scale, self.c[1] * scale, self.c[2] * scale)
+ }
}
impl std::ops::Mul<Float> for &Spectrum {
diff --git a/src/core/vector2.rs b/src/core/vector2.rs
index 5afa0f2..3aadb46 100644
--- a/src/core/vector2.rs
+++ b/src/core/vector2.rs
@@ -3,6 +3,7 @@
//! This is implemented generictly with types that fit in the Number trait
use crate::{Float, Number};
use std::ops::{Sub, Add};
+use std::fmt;
#[derive(Clone, Copy)]
pub struct Vector2<T: Number> {
@@ -43,6 +44,12 @@ impl<T: Number> Add for Vector2<T> {
}
}
+impl<T: Number> fmt::Display for Vector2<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_fmt(format_args!("[{}, {}]", self.x, self.y))
+ }
+}
+
impl Vector2f {
pub fn ceil(&self) -> Self {
Self::new_xy(
diff --git a/src/lib.rs b/src/lib.rs
index c3025b3..50d0435 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,7 @@
pub mod core;
pub mod camera;
-mod scene;
+pub mod render;
+pub mod scene;
use std::ops::{Add, Sub, Mul, DivAssign};
use std::cmp;
diff --git a/src/main.rs b/src/main.rs
index 22998dd..05d6617 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,17 +1,37 @@
-use pathtrace::camera::Camera;
-use pathtrace::core::{Vector3f, Vector2f};
-
+use pathtrace::camera::{Camera, Film};
+use pathtrace::scene::Scene;
+use pathtrace::scene::shapes::Sphere;
+use pathtrace::core::{Vector2i, Vector3f};
+use pathtrace::render::{RenderContext, RenderTask};
fn main() {
+ let res = Vector2i::new_xy(500, 500);
let cam = Camera::new(
- Vector3f::new(10.0),
- Vector3f::new(0.0),
- Vector3f::new_xyz(0.0, 1.0, 0.0),
- 90.0, Vector2f::new(10.0),
+ Vector3f::new_xyz(10.0, 0.0, 0.0),
+ Vector3f::new(0.0),
+ Vector3f::new_xyz(0.0, 0.1, 0.0),
+ 90.0, res,
+ );
+
+ let mut scn = Scene::new();
+ scn.add_shape(
+ Box::new(Sphere::new(4.0, Vector3f::new(0.0))),
);
- let (r, _) = cam.generate_ray(Vector2f::new(5.0));
+ let ctx = RenderContext { cam: &cam, scn: &scn };
+
+ let mut film = Film::new(res);
+ let tile = film.get_tile(&film.frame);
+
+ let mut task = RenderTask::new(Box::new(tile), 1);
+ task.render(&ctx);
+
+ film.commit_tile(&task.tile);
+
+ let image = film.finalize_image();
+ if let Err(e) = image.save("test.png") {
+ println!("Failed to save {}", e);
+ }
- println!("r: {}, norm: {}", r.direction, r.direction.norm());
}
diff --git a/src/render.rs b/src/render.rs
new file mode 100644
index 0000000..dcda672
--- /dev/null
+++ b/src/render.rs
@@ -0,0 +1,51 @@
+//! Implements the main render loop
+//!
+//! This is not a final design
+use crate::camera::film::FilmTile;
+use crate::camera::Camera;
+use crate::scene::Scene;
+
+use crate::core::{Vector2f, Spectrum};
+use crate::Float;
+
+const HALF_PIXEL: Vector2f = Vector2f {x: 0.5, y: 0.5 };
+
+pub struct RenderTask {
+ pub tile: Box<FilmTile>,
+ samples: u32,
+}
+
+pub struct RenderContext<'a> {
+ pub scn: &'a Scene,
+ pub cam: &'a Camera,
+}
+
+impl RenderTask {
+ pub fn new(tile: Box<FilmTile>, samples: u32) -> Self {
+ Self { tile, samples }
+ }
+
+ fn render_at(&self, ctx: &RenderContext, x: i32, y: i32) -> Spectrum {
+ // Create a ray
+ let (r, _) = ctx.cam.generate_ray(&Vector2f::new_xy(x as Float, y as Float));
+
+ // Trace ray
+ if let Some(_) = ctx.scn.intersect(r) {
+ return Spectrum::new_rgb(0.5, 0.5, 0.0);
+ }
+
+ Spectrum::new_rgb(0.0, 0.0, 0.0)
+
+ }
+
+ pub fn render(&mut self, ctx: &RenderContext) {
+ let b = self.tile.bounds.clone();
+ for x in b.min.x .. b.max.x {
+ for y in b.min.y .. b.max.y {
+ let p = Vector2f::new_xy(x as Float, y as Float);
+
+ self.tile.add_sample(&p, self.render_at(ctx, x, y))
+ }
+ }
+ }
+}