Created
April 17, 2014 01:12
-
-
Save axelmagn/10946425 to your computer and use it in GitHub Desktop.
This file contains 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
extern crate rand; | |
use std::f64; | |
use std::iter::range_step_inclusive; | |
use std::io; | |
use std::num; | |
use rand::{task_rng,Rng}; | |
static G : [int, ..9] = [247570,280596,280600,249748,18578,18577,231184,16,16]; | |
struct Vector3 { | |
x: f64, | |
y: f64, | |
z: f64 | |
} | |
impl Vector3 { | |
fn scale(&self, other: &f64) -> Vector3 { | |
Vector3 {x: self.x * *other, y: self.y * *other, z: self.z * *other} | |
} | |
fn dot(&self, o: &Vector3) -> f64 { | |
self.x * o.x + self.y * o.y + self.z * o.z | |
} | |
fn cross(&self, o: &Vector3) -> Vector3 { | |
Vector3 { | |
x: self.y * o.z - self.z * o.y, | |
y: self.z * o.x - self.x * o.z, | |
z: self.x * o.y - self.y * o.x | |
} | |
} | |
fn norm(&self) -> Vector3 { | |
self.scale(&(1.0 / num::sqrt(self.dot(self)))) | |
} | |
} | |
impl Add<Vector3, Vector3> for Vector3 { | |
fn add(&self, other: &Vector3) -> Vector3 { | |
Vector3 {x: self.x + other.x, y: self.y + other.y, z: self.z + other.z} | |
} | |
} | |
impl Sub<Vector3, Vector3> for Vector3 { | |
fn sub(&self, other: &Vector3) -> Vector3 { | |
Vector3 {x: self.x - other.x, y: self.y - other.y, z: self.z - other.z} | |
} | |
} | |
// Vector scaling | |
impl Mul<f64, Vector3> for Vector3 { | |
fn mul(&self, o: &f64) -> Vector3 { | |
self.scale(o) | |
} | |
} | |
// Vector dot product | |
impl Rem<Vector3, f64> for Vector3 { | |
fn rem(&self, o: &Vector3) -> f64 { | |
self.dot(o) | |
} | |
} | |
// Cross product for ^ | |
impl BitXor<Vector3, Vector3> for Vector3 { | |
fn bitxor(&self, o: &Vector3) -> Vector3 { | |
self.cross(o) | |
} | |
} | |
// Normalize vector | |
impl Not<Vector3> for Vector3 { | |
fn not(&self) -> Vector3 { | |
self.norm() | |
} | |
} | |
fn randNorm() -> f64 { | |
let mut rng = task_rng(); | |
let n: f64 = rng.gen_range(0.0, 1.0); | |
return n; | |
} | |
// sample the world and return the pixel color for a ray | |
fn sample(origin: &Vector3, dir: &Vector3) -> Vector3 { | |
let(m, t, n) = trace(origin, dir); | |
if m == 0 { | |
// no sphere found and ray goes upward: generate sky color | |
return Vector3{ x: 0.7, y: 0.6, z: 1.0} * num::pow(1.0-dir.z, 4); | |
} | |
// A sphere was maybe hit | |
let mut intersectCoord = origin + dir * t; | |
let lightDir = !(Vector3{x: 9.0 + randNorm(), y: 9.0 + randNorm(), z: 16.0} + intersectCoord * -1.0); | |
let halfVect = dir + n * (n % *dir * -2.0); | |
// calculate lambertian factor | |
let mut lambertFactor = lightDir % n; | |
// calculate the illumination factor | |
let illumFlag = | |
match (lambertFactor, trace(&intersectCoord, &lightDir)) { | |
(b, (a, _, _)) if b < 0.0 || a != 0 => { lambertFactor = 0.0; 0 } | |
_ => { 1 } | |
}; | |
let p = num::pow(lightDir % halfVect * illumFlag as f64, 99); | |
if(m == 1) { | |
intersectCoord = intersectCoord * 0.2; | |
let patch = ((f64::ceil(intersectCoord.x) + f64::ceil(intersectCoord.y)) as int) & 1; | |
return match patch { | |
1 => Vector3{x: 3.0, y: 1.0, z: 1.0}, | |
_ => Vector3{x: 3.0, y: 3.0, z: 3.0} * (lambertFactor * 0.2 + 0.1) | |
}; | |
} | |
return Vector3{x: p, y: p, z: p} + sample(&intersectCoord, &halfVect) * 0.5; | |
} | |
// The intersection test for line [o,v] | |
// Return 2 if a hit was found | |
// Return 0 if no hit was found but ray goes upward | |
// Return 1 if no hit was found but ray goes downward | |
fn trace(origin: &Vector3, dir: &Vector3) -> (int, f64, Vector3) { | |
let mut t = 1e9; | |
let mut m = 0; | |
let p = -origin.z / dir.z; | |
let mut n = Vector3{x: 0.0, y: 0.0, z: 0.0}; | |
if 0.01 < p { | |
t = p; | |
n = Vector3{x: 0.0, y: 0.0, z: 1.0}; | |
m = 1; | |
} | |
// the world is encoded in G, with 9 lines and 19 columns | |
for k in range_step_inclusive(18, 0, -1) { | |
for j in range_step_inclusive(8, 0, -1) { | |
// for this line j, is there a sphere at column i? | |
if G[j] & 1 << k != 0 { | |
let v = origin + Vector3{x: -k as f64,y: 0.0,z: (-j as f64) - 4.0}; | |
let b = v % *dir; | |
let c = v % v - 1.0; | |
let q = b * b - c; | |
// does the ray hit the sphere | |
if q > 0.0 { | |
let s = -b - num::sqrt(q); | |
if s < t && s > 0.1 { | |
t = s; | |
n = !(v + dir * t); | |
m = 2; | |
} | |
} | |
} | |
} | |
} | |
(m, t, n) | |
} | |
fn main() { | |
// PPM header | |
print!("P6 512 512 255 "); | |
// Camera direction | |
let cameraDir = !Vector3{x: -6.0, y: -16.0, z: 0.0}; | |
// Camera up vector | |
let cameraUp = !(Vector3{x: 0.0, y: 0.0, z: 1.0} ^ cameraDir) * 0.002; | |
// The right vector | |
let cameraRight = !(cameraDir ^ cameraUp) * 0.002; | |
let c=(cameraUp+cameraRight)* -256.0 + cameraDir; | |
let mut out = io::stdout(); | |
for y in range_step_inclusive(511, 0, -1) { | |
for x in range_step_inclusive(511, 0, -1) { | |
// reuse the vector class to store RGB pixels | |
// default pixel is almost pitch black | |
let mut p = Vector3{x: 13.0, y: 13.0, z: 13.0}; | |
for r in range_step_inclusive(63, 0, -1) { | |
// delta applied to the origin for depth of field blur | |
let cameraDelta = cameraDir * (randNorm() - 0.5) * 99.0 + cameraRight * (randNorm() - 0.5) * 99.0; | |
// set the camera focal point to v(17,16,8) and Cast the ray | |
let focalPoint = Vector3{x: 17.0, y: 16.0, z: 8.0}; | |
let rayDirection = !(cameraDelta * -1.0 + | |
(cameraUp * (randNorm() + (x as f64)) + | |
cameraRight * ((y as f64) + randNorm()) + c) * 16.0); | |
// Accumulate the color returned in the p variable | |
p = sample( &(focalPoint + cameraDelta), &rayDirection) * 3.5 + p; | |
} | |
// print!("{:s}{:s}{:s}", (p.x as u8).to_ascii().to_str(), (p.y as u8).to_ascii().to_str(), (p.z as u8).to_ascii().to_str()); | |
// print!("{:t}{:t}{:t}", (p.x as u8), (p.y as u8), (p.z as u8)); | |
out.write(&[(p.x as u16),(p.x as u16),(p.x as u16)]); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment