Created
January 30, 2019 15:04
-
-
Save MaikKlein/6e36b579d1a14cb52a49b1df6ddb52ab to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use rlsl_math::prelude::*; | |
use rlsl_math::Array; | |
#[derive(Copy, Clone)] | |
pub struct Ray { | |
pub origin: Vec3<f32>, | |
pub dir: Unit<Vec3<f32>>, | |
} | |
impl Ray { | |
pub fn position(self, t: f32) -> Vec3<f32> { | |
self.origin + *self.dir * t | |
} | |
} | |
#[derive(Copy, Clone)] | |
pub struct Sphere { | |
pub origin: Vec3<f32>, | |
pub radius: f32, | |
pub color: Vec3<f32>, | |
} | |
impl Sphere { | |
pub fn intersect(self, ray: Ray) -> Option<RayHit> { | |
use rlsl_math::polynomial::quadratic; | |
let oc = ray.origin - self.origin; | |
//a is always one if the direction is a unit vector | |
let a = 1.0f32; | |
let b = 2.0 * ray.dir.dot(oc); | |
let c = Vec3::dot(oc, oc) - self.radius * self.radius; | |
let t = quadratic(a, b, c)?.min(); | |
if t < 0.0 { | |
return None; | |
} | |
let position = ray.position(t); | |
let normal = position - self.origin; | |
let hit = RayHit { | |
position, | |
normal: normal.to_unit(), | |
color: self.color, | |
}; | |
Some(hit) | |
} | |
} | |
pub struct RayHit { | |
pub position: Vec3<f32>, | |
pub normal: Unit<Vec3<f32>>, | |
pub color: Vec3<f32>, | |
} | |
fn color( | |
rng: &mut Rng, | |
mut ray: Ray, | |
spheres: &impl Array<Sphere>, | |
depth: usize, | |
) -> Option<Vec3<f32>> { | |
let mut color = intersect_spheres(ray, spheres).map(|hit| hit.color)?; | |
let mut i = 0usize; | |
while let Some(hit) = intersect_spheres(ray, spheres) { | |
//let dir =ray.dir.reflect(*hit.normal).to_unit(); | |
let dir = hit.normal; | |
let random = Vec3::new(rng.random(), rng.random(), rng.random()).normalize(); | |
let dir = (*dir + random).to_unit(); | |
ray = Ray { | |
origin: hit.position, | |
dir, | |
}; | |
color = color * hit.color; | |
i += 1; | |
if i > depth { | |
break; | |
} | |
} | |
Some(color) | |
} | |
fn intersect_spheres(ray: Ray, spheres: &impl Array<Sphere>) -> Option<RayHit> { | |
let mut hit = None; | |
let mut i = 0usize; | |
while i < spheres.length() { | |
if let Some(h) = spheres.get(i).intersect(ray) { | |
hit = Some(h); | |
} | |
i += 1; | |
} | |
hit | |
} | |
pub fn render(uv: Vec2<f32>, time: f32) -> Vec4<f32> { | |
let mut rng = Rng::from_seed(0.0); | |
let look = Vec3::new(0.0, 0.0, 1.0); | |
let coord = (uv * 2.0 - 1.0).extend(0.0) * Vec3::new(1.0, -1.0, 1.0); | |
let origin = Vec3::single(0.0f32); | |
let dir = look + coord; | |
let ray = Ray { | |
origin, | |
dir: dir.to_unit(), | |
}; | |
let floor = Sphere { | |
origin: Vec3::new(0.0, -100.5, -1.0), | |
radius: 100.0, | |
color: Vec3::new(0.4, 0.4, 0.4), | |
}; | |
let sphere2 = Sphere { | |
origin: Vec3::new(0.0, 0.0, 1.0), | |
radius: 0.5, | |
color: Vec3::new(1.0, 0.2, 0.1), | |
}; | |
let spheres = [floor, sphere2]; | |
let color = color(&mut rng, ray, &spheres, 5000).unwrap_or_else(move || { | |
let blue = Vec3::new(0.2, 0.5, 1.0); | |
let white = Vec3::single(1.0f32); | |
blue.lerp(white, uv.y) | |
}); | |
color.extend(1.0) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment