began writing spheretracer and realized I'll have to reimplement cgmath
(badly)
This commit is contained in:
parent
c6290f93fd
commit
6c88c8ddfe
8 changed files with 136 additions and 48 deletions
35
raytracer/Cargo.lock
generated
35
raytracer/Cargo.lock
generated
|
|
@ -2,21 +2,6 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "approx"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "autocfg"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit_field"
|
name = "bit_field"
|
||||||
version = "0.10.3"
|
version = "0.10.3"
|
||||||
|
|
@ -35,16 +20,6 @@ version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cgmath"
|
|
||||||
version = "0.18.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317"
|
|
||||||
dependencies = [
|
|
||||||
"approx",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.176"
|
version = "0.2.176"
|
||||||
|
|
@ -57,15 +32,6 @@ version = "0.4.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-traits"
|
|
||||||
version = "0.2.19"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.101"
|
version = "1.0.101"
|
||||||
|
|
@ -108,7 +74,6 @@ dependencies = [
|
||||||
name = "raytracer"
|
name = "raytracer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cgmath",
|
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"uefi",
|
"uefi",
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cgmath = "0.18.0"
|
|
||||||
libc = "0.2.176"
|
libc = "0.2.176"
|
||||||
log = "0.4.28"
|
log = "0.4.28"
|
||||||
uefi = { version = "0.35.0", features = ["logger", "panic_handler"] }
|
uefi = { version = "0.35.0", features = ["logger", "panic_handler"] }
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,15 @@ impl Buffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a single pixel.
|
/// Get a single pixel.
|
||||||
pub fn pixel(&mut self, x: usize, y: usize) -> Option<&mut BltPixel> {
|
pub fn get_pixel(&mut self, x: usize, y: usize) -> Option<&mut BltPixel> {
|
||||||
self.pixels.get_mut(y * self.width + x)
|
self.pixels.get_mut(y * self.width + x)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a single pixel.
|
||||||
|
pub fn set_pixel(&mut self, x: usize, y: usize, pixel: BltPixel) {
|
||||||
|
self.pixels[y * self.width + x] = pixel;
|
||||||
|
}
|
||||||
|
|
||||||
/// Blit the buffer to the framebuffer.
|
/// Blit the buffer to the framebuffer.
|
||||||
pub fn blit(&self, gop: &mut GraphicsOutput) -> Result<(), Error> {
|
pub fn blit(&self, gop: &mut GraphicsOutput) -> Result<(), Error> {
|
||||||
gop.blt(BltOp::BufferToVideo {
|
gop.blt(BltOp::BufferToVideo {
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,14 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
mod buffer;
|
mod buffer;
|
||||||
|
mod math;
|
||||||
mod ray;
|
mod ray;
|
||||||
mod renderer;
|
mod renderer;
|
||||||
|
mod spheretracer;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use crate::buffer::Buffer;
|
use crate::buffer::Buffer;
|
||||||
|
use crate::renderer::render;
|
||||||
use uefi::allocator::Allocator;
|
use uefi::allocator::Allocator;
|
||||||
use uefi::boot::ScopedProtocol;
|
use uefi::boot::ScopedProtocol;
|
||||||
use uefi::prelude::*;
|
use uefi::prelude::*;
|
||||||
|
|
@ -32,7 +35,8 @@ fn init_buffer(gop: &GraphicsOutput) -> Buffer {
|
||||||
fn main() -> Status {
|
fn main() -> Status {
|
||||||
uefi::helpers::init().unwrap();
|
uefi::helpers::init().unwrap();
|
||||||
let mut gop = init_gop().unwrap();
|
let mut gop = init_gop().unwrap();
|
||||||
let buffer = init_buffer(&gop);
|
let mut buffer = init_buffer(&gop);
|
||||||
|
render(&mut buffer);
|
||||||
buffer.blit(&mut gop).unwrap();
|
buffer.blit(&mut gop).unwrap();
|
||||||
Status::SUCCESS
|
Status::SUCCESS
|
||||||
}
|
}
|
||||||
|
|
|
||||||
24
raytracer/src/math.rs
Normal file
24
raytracer/src/math.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
pub struct Matrix4<T> {
|
||||||
|
x: T,
|
||||||
|
}
|
||||||
|
pub struct Vector3<T> {
|
||||||
|
x: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Vector4<T> {
|
||||||
|
x: T,
|
||||||
|
y: T,
|
||||||
|
z: T,
|
||||||
|
w: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Vector4<T> {
|
||||||
|
pub fn new(x: T, y: T, z: T, w: T) -> Vector4<T> {
|
||||||
|
Vector4 {
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
z: z,
|
||||||
|
w: w,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
|
use crate::math::{Matrix4, Vector3, Vector4};
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use cgmath::{Matrix4, Vector3, Vector4, num_traits::Num};
|
|
||||||
|
|
||||||
pub struct Ray<T> {
|
pub struct Ray<T> {
|
||||||
pub(crate) origin: Vector3<T>,
|
pub(crate) origin: Vector3<T>,
|
||||||
pub(crate) direction: Vector3<T>,
|
pub(crate) direction: Vector3<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn construct_primary_rays(
|
pub fn construct_primary_rays_for_pixel(
|
||||||
(width, height): (usize, usize),
|
(width, height): (usize, usize),
|
||||||
(pixel_x_coord, pixel_y_coord): (usize, usize),
|
(pixel_x_coord, pixel_y_coord): (usize, usize),
|
||||||
cam_to_world_matrix: &Matrix4<f32>,
|
cam_to_world_matrix: &Matrix4<f32>,
|
||||||
focal_length: f32,
|
focal_length: f32,
|
||||||
rays_per_pixel: usize,
|
rays_per_pixel: usize,
|
||||||
) -> Vec<Ray> {
|
) -> Vec<Ray<f32>> {
|
||||||
let mut rays: Vec<Ray> = Vec::with_capacity(rays_per_pixel);
|
let mut rays: Vec<Ray<f32>> = Vec::with_capacity(rays_per_pixel);
|
||||||
|
|
||||||
//generate all rays for this pixel and add them to the rays vector
|
//generate all rays for this pixel and add them to the rays vector
|
||||||
for _ in 0..rays_per_pixel {
|
for _ in 0..rays_per_pixel {
|
||||||
|
|
@ -24,8 +24,8 @@ pub fn construct_primary_rays(
|
||||||
pixel_x_coord,
|
pixel_x_coord,
|
||||||
pixel_y_coord,
|
pixel_y_coord,
|
||||||
//no noise
|
//no noise
|
||||||
0.0f,
|
0.0f32,
|
||||||
0.0f,
|
0.0f32,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,7 +40,7 @@ fn generate_single_primary_ray(
|
||||||
v: usize,
|
v: usize,
|
||||||
u_offset: f32,
|
u_offset: f32,
|
||||||
v_offset: f32,
|
v_offset: f32,
|
||||||
) -> Ray {
|
) -> Ray<f32> {
|
||||||
//calculate the ray direction and translate it to world space
|
//calculate the ray direction and translate it to world space
|
||||||
let direction_camera_space: Vector4<f32> = Vector4::new(
|
let direction_camera_space: Vector4<f32> = Vector4::new(
|
||||||
u as f32 - (buffer_width as f32 / 2.0) + u_offset,
|
u as f32 - (buffer_width as f32 / 2.0) + u_offset,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
|
use core::cmp::{max, min};
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use cgmath::{Matrix4, Vector4, Zero};
|
use cgmath::{Matrix4, Vector4, Zero};
|
||||||
|
use uefi::proto::console::gop::BltPixel;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
buffer::Buffer,
|
buffer::Buffer,
|
||||||
ray::{Ray, construct_primary_rays},
|
ray::{Ray, construct_primary_rays_for_pixel},
|
||||||
|
spheretracer::{Radiosity, sdf, spheretrace},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn render(buffer: Buffer) {
|
pub fn render(buffer: &mut Buffer) {
|
||||||
let camera_matrix: Matrix4<f32> = Matrix4 {
|
let camera_matrix: Matrix4<f32> = Matrix4 {
|
||||||
x: Vector4::unit_x(),
|
x: Vector4::unit_x(),
|
||||||
y: Vector4::unit_y(),
|
y: Vector4::unit_y(),
|
||||||
|
|
@ -16,16 +20,53 @@ pub fn render(buffer: Buffer) {
|
||||||
|
|
||||||
let focal_length = 1.0f;
|
let focal_length = 1.0f;
|
||||||
|
|
||||||
|
let mut radiosiy_buffer: Vec<Radiosity> = Vec::with_capacity(buffer.width * buffer.height);
|
||||||
|
|
||||||
//this reeeeally wants to run in parallel…
|
//this reeeeally wants to run in parallel…
|
||||||
(0..buffer.width).for_each(|x| {
|
(0..buffer.width).for_each(|x| {
|
||||||
(0..buffer.height).for_each(|y| {
|
(0..buffer.height).for_each(|y| {
|
||||||
let rays: Vec<Ray<f32>> = construct_primary_rays(
|
//construct rays for each pixel
|
||||||
|
let rays: Vec<Ray<f32>> = construct_primary_rays_for_pixel(
|
||||||
(buffer.width, buffer.height),
|
(buffer.width, buffer.height),
|
||||||
(x, y),
|
(x, y),
|
||||||
camera_matrix,
|
camera_matrix,
|
||||||
focal_length,
|
focal_length,
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//spheretrace the ray and add the determined radiosity to the buffer
|
||||||
|
radiosiy_buffer.push(
|
||||||
|
rays.iter()
|
||||||
|
.for_each(|ray| spheretrace(ray, 100.00f, 0.01, sdf)),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
//remap radiosities to colors
|
||||||
|
radiosiy_buffer = normalize_radiosity(&mut radiosiy_buffer)
|
||||||
|
|
||||||
|
//copy vector over to buffer
|
||||||
|
(0..buffer.width)
|
||||||
|
.for_each(|x| {
|
||||||
|
(0..buffer.height).for_each(|y| {
|
||||||
|
let rad = radiosiy_buffer[y * buffer.width + x];
|
||||||
|
buffer.set_pixel(x, y, BltPixel::new(rad, rad, rad));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn normalize_radiosity(radiosities: &mut Vec<Radiosity>) -> Vec<Radiosity> {
|
||||||
|
//find the minimum and maximum radiosities in he buffer
|
||||||
|
let (min_rad, max_rad) =
|
||||||
|
radiosities
|
||||||
|
.iter()
|
||||||
|
.zip(radiosities)
|
||||||
|
.reduce(|(acc_min, acc_max), (curr_min, curr_max)| {
|
||||||
|
acc_min = min(acc_min, curr_min);
|
||||||
|
acc_max = max(acc_max, curr_max);
|
||||||
|
});
|
||||||
|
//remap radiosities to [0,255] for framebuffer
|
||||||
|
radiosities
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|r| r = (r - min_rad) / (max_rad - min_rad) * 255.0)
|
||||||
|
}
|
||||||
|
|
|
||||||
50
raytracer/src/spheretracer.rs
Normal file
50
raytracer/src/spheretracer.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
use cgmath::{Vector3, num_traits::abs};
|
||||||
|
|
||||||
|
use crate::ray::Ray;
|
||||||
|
|
||||||
|
pub type Radiosity = f32;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Spheretraces a ray in a certain signed distance function up to a maximum ray length
|
||||||
|
/// and with respect to a certain floating point error epsilon
|
||||||
|
///
|
||||||
|
pub fn spheretrace<P>(
|
||||||
|
ray: Ray<P>,
|
||||||
|
max_ray_length: P,
|
||||||
|
epsilon: P,
|
||||||
|
signed_distance_function: Fn(Vector3<P>) -> (P, Vector3<P>),
|
||||||
|
) -> Radiosity {
|
||||||
|
//accumulate the length this ray has already travelled
|
||||||
|
let mut distance_travelled: P = 0.0;
|
||||||
|
|
||||||
|
//accumulate radiosity
|
||||||
|
let mut accumulated_radiosity: P = 0.f;
|
||||||
|
|
||||||
|
//if we still have some distance left to walk
|
||||||
|
while abs(distance_travelled - max_ray_length) < epsilon {
|
||||||
|
//walk a bit
|
||||||
|
let current_point = ray.origin + distance_travelled * ray.direction;
|
||||||
|
let (distance, normal) = signed_distance_function(current_point);
|
||||||
|
|
||||||
|
//we have a collision
|
||||||
|
if abs(distance) < epsilon || distance < 0.f {
|
||||||
|
//TODO: we wanna pathtrace recursively here
|
||||||
|
accumulated_radiosity += 1.f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accumulated_radiosity
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// A signed distance function that for each sample point
|
||||||
|
/// returns the Euclidean distance to the next geometric intersection
|
||||||
|
/// as well as a normal direction (gradient vector). Distance is negative
|
||||||
|
/// iff point is inside geometry.
|
||||||
|
///
|
||||||
|
/// P is the precision
|
||||||
|
///
|
||||||
|
pub fn sdf<P>(sample_point: Vector3<P>) -> (P, Vector3<P>) {
|
||||||
|
(1.0, Vector3::unit_x())
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue