From 1e042c66919698f4604bed584438eef7c757707a Mon Sep 17 00:00:00 2001 From: mitchellhansen Date: Mon, 30 Nov 2020 19:44:08 -0800 Subject: [PATCH] init --- Cargo.toml | 11 +++ src/main.rs | 252 ++++++++++++++++++++++++++++++++++++++++++++++++ src/voxel-stuff | 71 ++++++++++++++ 3 files changed, 334 insertions(+) create mode 100644 Cargo.toml create mode 100644 src/main.rs create mode 100644 src/voxel-stuff diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..512186b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rust-scratchpad" +version = "0.1.0" +authors = ["mitchellhansen "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +image = "0.23.11" +rand = "0.7.3" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..7501f36 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,252 @@ +extern crate rand; + +use std::cmp::max; +use std::f32::consts::PI; +use std::io::Cursor; +use std::ops; +use std::ops::Rem; + +use image::ImageFormat; +use image::io::Reader as ImageReader; +use rand::prelude::*; + +struct Circle { + x: i32, + y: i32, + r: i32, +} + +impl Circle {} + +fn createCircle() -> Circle { + Circle { + x: 0, + y: 0, + r: 0, + } +} + +#[derive(Clone, Copy, Debug, Default)] +struct Vector2f { x: f32, y: f32 } + +#[derive(Clone, Copy, Debug, Default)] +struct Vector2i { x: i32, y: i32 } + +#[derive(Clone, Copy, Debug, Default)] +struct Vector3f { x: f32, y: f32, z: f32 } + +#[derive(Clone, Copy, Debug, Default)] +struct Vector4f { x: f32, y: f32, z: f32, w: f32 } + +fn dot(vec_a: Vector3f, vec_b: Vector3f) -> f32 { + vec_a.x * vec_b.x + vec_a.y * vec_b.y + vec_a.z * vec_b.z +} + +fn mult(vec: Vector3f, scalar: f32) -> Vector3f { + Vector3f { + x: vec.x * scalar, + y: vec.y * scalar, + z: vec.z * scalar, + } +} + +fn sub(vec_a: Vector3f, vec_b: Vector3f) -> Vector3f { + Vector3f { + x: vec_a.x - vec_b.x, + y: vec_a.y - vec_b.y, + z: vec_a.z - vec_b.z, + } +} + +fn add(vec_a: Vector3f, vec_b: Vector3f) -> Vector3f { + Vector3f { + x: vec_a.x + vec_b.x, + y: vec_a.y + vec_b.y, + z: vec_a.z + vec_b.z, + } +} + +fn mix(a: Vector3f, b: Vector3f, mixValue: f32) -> Vector3f +{ + add(mult(a, (1.0 - mixValue)), mult(b, mixValue)) +} + +fn normalize(ray: Vector3f) -> Vector3f { + let multiplier = (ray.x * ray.x + ray.y * ray.y + ray.z * ray.z).sqrt(); + Vector3f { + x: ray.x / multiplier, + y: ray.y / multiplier, + z: ray.z / multiplier, + } +} + +fn intersect(ray_orig: Vector3f, ray_dir: Vector3f, sphere_center: Vector3f, sphere_radius: f32) -> Option { + let mut t0 = 0.0; + let mut t1 = 0.0; + + let L = sub(ray_orig, sphere_center); + let a = dot(ray_dir, ray_dir); + let b = 2.0 * dot(L, ray_dir); + let c = dot(L, L) - sphere_radius; + solve_quadratic(a, b, c, t0, t1) +} + +fn solve_quadratic(a: f32, b: f32, c: f32, mut x0: f32, mut x1: f32) -> Option +{ + let discr: f32 = b * b - 4.0 * a * c; + if (discr < 0.0) { + return None; + } else if (discr == 0.0) { + x0 = -0.5 * b / a; + x1 = x0; + } else { + let q = if b > 0.0 { + -0.5 * (b + discr.sqrt()) + } else { + -0.5 * (b - discr.sqrt()) + }; + + x0 = q / a; + x1 = c / q; + } + match f32::max(x0, x1) > 0.0 { + true => { Some(f32::max(x0, x1)) } + false => { None } + } +} + +fn get_surface_data(phit: Vector3f, nhit: Vector3f, sphere_center: Vector3f) -> Vector2f +{ + let nhit = sub(phit, sphere_center); + let nhit = normalize(nhit); +// In this particular case, the normal is simular to a point on a unit sphere +// centred around the origin. We can thus use the normal coordinates to compute +// the spherical coordinates of Phit. +// atan2 returns a value in the range [-pi, pi] and we need to remap it to range [0, 1] +// acosf returns a value in the range [0, pi] and we also need to remap it to the range [0, 1] + Vector2f { + x: (1.0 + (nhit.x).atan2(nhit.z) / PI) * 0.5, + y: (nhit.y).acos() / PI, + } +} + +fn main() { + let mut rng = rand::thread_rng(); + let view_res = Vector2i { x: 800, y: 800 }; + + let mut circles = Vec::new(); + for i in 0..100 { + circles.push(Circle { + x: (rng.gen::() * view_res.x as f32) as i32, + y: (rng.gen::() * view_res.y as f32) as i32, + r: 10, + }); + } + + let mut viewport_matrix = vec![Vector3f { + x: 0.0, + y: 0.0, + z: 0.0, + }; (view_res.x as usize * view_res.y as usize * 4)]; + + for y in (-view_res.y / 2)..(view_res.y / 2) { + for x in (-view_res.x / 2)..(view_res.x / 2) { + let ray = Vector3f { z: -800.0, x: x as f32, y: y as f32 }; + let ray = Vector3f { + x: (ray.z * (1.57 as f32).sin() + ray.x * (1.57 as f32).cos()), + y: (ray.y), + z: (ray.z * (1.57 as f32).cos() - ray.x * (1.57 as f32).sin()), + }; + + let ray = normalize(ray); + let index = ((x + view_res.x / 2) + view_res.x * (y + view_res.y / 2)) as usize; + + viewport_matrix[index] = Vector3f { + x: ray.x, + y: ray.y, + z: ray.z, + }; + } + } + + // Create a new ImgBuf with width: imgx and height: imgy + let mut imgbuf = image::ImageBuffer::new(view_res.x as u32, view_res.y as u32); + + let sphere_center = Vector3f { x: -70.0, y: 20.0, z: -10.0 }; + let sphere_color = Vector3f { + x: 78.0, + y: 22.0, + z: 125.0, + }; + let radius = 10.0; + + // Iterate over the coordinates and pixels of the image + for (x, y, pixel) in imgbuf.enumerate_pixels_mut() { + let index = (x + view_res.x as u32 * y) as usize; + + let orig = Vector3f { + x: 0.0, + y: 0.0, + z: 0.0, + }; + let dir = viewport_matrix[index]; + + match intersect(orig, dir, sphere_center, radius) { + None => {} + Some(t) => { + let phit = add(orig, mult(dir, t)); + let nhit = Vector3f::default(); + + let tex = get_surface_data(phit, nhit, sphere_center); + + let scale = 4.0; + + let pattern = match ((tex.x * scale).rem(1.0) > 0.5) ^ ((tex.y * scale).rem(1.0) > 0.5) { + true => { 1.0 } + false => { 0.0 } + }; + + let ndir = Vector3f { + x: -dir.x, + y: -dir.y, + z: -dir.z, + }; + + let hit_color = mult(mix(sphere_color, mult(sphere_color, 0.8), f32::max(0.0, dot(nhit, ndir))), pattern); + *pixel = image::Rgb([hit_color.x as u8, hit_color.y as u8, hit_color.z as u8]); + } + }; + + } + + // A redundant loop to demonstrate reading image data + // for x in 0..view_res.x { + // for y in 0..view_res.y { + // let pixel = imgbuf.get_pixel_mut(x as u32, y as u32); + // let data: image::Rgb = *pixel; // read the prexisting data if needed + // *pixel = image::Rgb([0, 0, 255]); + // } + // } + + // Save the image as “fractal.png”, the format is deduced from the path + imgbuf.save("fractal.png").unwrap(); +} + + + + + + + + + + + + + + + + + + + diff --git a/src/voxel-stuff b/src/voxel-stuff new file mode 100644 index 0000000..f363737 --- /dev/null +++ b/src/voxel-stuff @@ -0,0 +1,71 @@ +bool CLCaster::create_viewport(int width, int height, float v_fov, float h_fov) { + + + + sf::Vector2i view_res(width, height); + + This creates a buffer to give the kernal a [x,y] coord set + if (!create_buffer("viewport_resolution", sizeof(int) * 2, &view_res)) + return false; + + + // And an array of vectors describing the way the "lens" of our + // camera works + viewport_matrix = new sf::Vector4f[width * height * 4]; + + for (int y = -view_res.y / 2; y < view_res.y / 2; y++) { + + for (int x = -view_res.x / 2; x < view_res.x / 2; x++) { + + // The base ray direction to slew from + sf::Vector3f ray(-800, x, y); + + // correct for the base ray pointing to (1, 0, 0) as (0, 0). Should equal (1.57, 0) + ray = sf::Vector3f( + static_cast(ray.z * sin(1.57) + ray.x * cos(1.57)), + static_cast(ray.y), + static_cast(ray.z * cos(1.57) - ray.x * sin(1.57)) + ); + +// ray.y += (rand() % 1000) / 100000.0; +// ray.x += (rand() % 1000) / 100000.0; +// ray.z += (rand() % 1000) / 100000.0; + + ray = Normalize(ray); + int index = (x + view_res.x / 2) + view_res.x * (y + view_res.y / 2); + + viewport_matrix[index] = sf::Vector4f( + ray.x, + ray.y, + ray.z, + 0 + ); + } + } + + if (!create_buffer("viewport_matrix", sizeof(float) * 4 * view_res.x * view_res.y, viewport_matrix)) + return false; + + // Create the image that opencl's rays write to + viewport_image = new sf::Uint8[width * height * 4]; + + for (int i = 0; i < width * height * 4; i += 4) { + + viewport_image[i] = 255; // R + viewport_image[i + 1] = 255; // G + viewport_image[i + 2] = 255; // B + viewport_image[i + 3] = 100; // A + } + + // Interop lets us keep a reference to it as a texture + viewport_texture.create(width, height); + viewport_texture.update(viewport_image); + viewport_sprite.setTexture(viewport_texture); + + // Pass the buffer to opencl + if (!create_image_buffer("image", sizeof(sf::Uint8) * width * height * 4, &viewport_texture, CL_MEM_WRITE_ONLY)) + return false; + + return true; + +}