master
mitchellhansen 4 years ago
commit 1e042c6691

@ -0,0 +1,11 @@
[package]
name = "rust-scratchpad"
version = "0.1.0"
authors = ["mitchellhansen <mitchellhansen0@gmail.com>"]
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"

@ -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<f32> {
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<f32>
{
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::<f32>() * view_res.x as f32) as i32,
y: (rng.gen::<f32>() * 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<u8> = *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();
}

@ -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<float>(ray.z * sin(1.57) + ray.x * cos(1.57)),
static_cast<float>(ray.y),
static_cast<float>(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;
}
Loading…
Cancel
Save