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…
Reference in new issue