Working renderer.
This commit is contained in:
parent
5a549957c4
commit
f69704b7b1
190
Cargo.lock
generated
190
Cargo.lock
generated
@ -1,11 +1,36 @@
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aobench"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stderrlog 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"structopt 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.4"
|
||||
@ -21,6 +46,42 @@ dependencies = [
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.0.2"
|
||||
@ -52,11 +113,52 @@ name = "num-traits"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "redox_termios"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stderrlog"
|
||||
version = "0.4.1"
|
||||
@ -68,6 +170,40 @@ dependencies = [
|
||||
"thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "structopt"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"structopt-derive 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "structopt-derive"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "0.3.6"
|
||||
@ -76,6 +212,24 @@ dependencies = [
|
||||
"wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termion"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.3.5"
|
||||
@ -95,6 +249,16 @@ dependencies = [
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "1.0.0"
|
||||
@ -103,6 +267,11 @@ dependencies = [
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
@ -136,19 +305,40 @@ dependencies = [
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1"
|
||||
"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789"
|
||||
"checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e"
|
||||
"checksum chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6962c635d530328acc53ac6a955e83093fedc91c5809dfac1fa60fa470830a37"
|
||||
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fb497c35d362b6a331cfd94956a07fc2c78a4604cdbee844a81170386b996dd3"
|
||||
"checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1"
|
||||
"checksum log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "61bd98ae7f7b754bc53dca7d44b604f733c6bba044ea6f41bc8d89272d8161d2"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe"
|
||||
"checksum proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "cccdc7557a98fe98453030f077df7f3a042052fae465bb61d2c2c41435cfd9b6"
|
||||
"checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035"
|
||||
"checksum rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "12397506224b2f93e6664ffc4f664b29be8208e5157d3d90b44f09b5fae470ea"
|
||||
"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2"
|
||||
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum stderrlog 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "61dc66b7ae72b65636dbf36326f9638fb3ba27871bb737a62e2c309b87d91b70"
|
||||
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||
"checksum structopt 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8e9ad6a11096cbecdcca0cc6aa403fdfdbaeda2fb3323a39c98e6a166a1e45a"
|
||||
"checksum structopt-derive 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4cbce8ccdc62166bd594c14396a3242bf94c337a51dbfa9be1076dd74b3db2af"
|
||||
"checksum syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2beff8ebc3658f07512a413866875adddd20f4fd47b2a4e6c9da65cd281baaea"
|
||||
"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83"
|
||||
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
||||
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
||||
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
|
||||
"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
|
||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
@ -6,3 +6,5 @@ authors = ["Bill Thiede <rust@xinu.tv>"]
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
stderrlog = "0.4.1"
|
||||
structopt = "0.2.10"
|
||||
rand = "0.5"
|
||||
|
||||
402
src/main.rs
402
src/main.rs
@ -1,16 +1,119 @@
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate rand;
|
||||
extern crate stderrlog;
|
||||
#[macro_use]
|
||||
extern crate structopt;
|
||||
|
||||
use rand::Rng;
|
||||
use std::clone::Clone;
|
||||
use std::f64;
|
||||
use std::fmt;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::ops::Add;
|
||||
use std::ops::Mul;
|
||||
use std::ops::Sub;
|
||||
use structopt::StructOpt;
|
||||
|
||||
fn vdot(v0: &Vector, v1: &Vector) -> f64 {
|
||||
v0.x * v1.x + v0.y * v1.y + v0.z * v1.z
|
||||
}
|
||||
|
||||
fn vcross(v0: &Vector, v1: &Vector) -> Vector {
|
||||
Vector {
|
||||
x: v0.y * v1.z - v0.z * v1.y,
|
||||
y: v0.z * v1.x - v0.x * v1.z,
|
||||
z: v0.x * v1.y - v0.y * v1.x,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct Vector {
|
||||
x: f64,
|
||||
y: f64,
|
||||
z: f64,
|
||||
}
|
||||
|
||||
impl Vector {
|
||||
fn zero() -> Vector {
|
||||
Vector {
|
||||
x: 0.,
|
||||
y: 0.,
|
||||
z: 0.,
|
||||
}
|
||||
}
|
||||
fn new(x: f64, y: f64, z: f64) -> Vector {
|
||||
Vector { x, y, z }
|
||||
}
|
||||
|
||||
fn normalize(&mut self) {
|
||||
let length = vdot(self, self).sqrt();
|
||||
if length.abs() < 1.0e-17 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.x = self.x / length;
|
||||
self.y = self.y / length;
|
||||
self.z = self.z / length;
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Vector {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "({:.4}, {:.4}, {:.4})", self.x, self.y, self.z)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Vector {
|
||||
type Output = Vector;
|
||||
|
||||
fn add(self, other: Vector) -> Vector {
|
||||
Vector {
|
||||
x: self.x + other.x,
|
||||
y: self.y + other.y,
|
||||
z: self.z + other.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Vector {
|
||||
type Output = Vector;
|
||||
|
||||
fn mul(self, other: Vector) -> Vector {
|
||||
Vector {
|
||||
x: self.x * other.x,
|
||||
y: self.y * other.y,
|
||||
z: self.z * other.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<f64> for Vector {
|
||||
type Output = Vector;
|
||||
|
||||
fn mul(self, other: f64) -> Vector {
|
||||
Vector {
|
||||
x: self.x * other,
|
||||
y: self.y * other,
|
||||
z: self.z * other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Vector {
|
||||
type Output = Vector;
|
||||
|
||||
fn sub(self, other: Vector) -> Vector {
|
||||
Vector {
|
||||
x: self.x - other.x,
|
||||
y: self.y - other.y,
|
||||
z: self.z - other.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct ISect {
|
||||
t: f64,
|
||||
p: Vector,
|
||||
@ -28,102 +131,281 @@ struct Plane {
|
||||
n: Vector,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Ray {
|
||||
org: Vector,
|
||||
dir: Vector,
|
||||
}
|
||||
|
||||
impl fmt::Display for Ray {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "o: {} d: {}", self.org, self.dir)
|
||||
}
|
||||
}
|
||||
|
||||
fn ray_sphere_intersect(mut isect: ISect, ray: &Ray, sphere: &Sphere) -> ISect {
|
||||
let rs = ray.org - sphere.center;
|
||||
|
||||
let b = vdot(&rs, &ray.dir);
|
||||
let c = vdot(&rs, &rs) - sphere.radius * sphere.radius;
|
||||
let d = b * b - c;
|
||||
if d > 0.0 {
|
||||
let t = -b - d.sqrt();
|
||||
if t > 0.0 && t < isect.t {
|
||||
isect.t = t;
|
||||
isect.hit = true;
|
||||
|
||||
isect.p = ray.org + ray.dir * t;
|
||||
|
||||
isect.n = isect.p - sphere.center;
|
||||
isect.n.normalize();
|
||||
}
|
||||
}
|
||||
|
||||
isect
|
||||
}
|
||||
|
||||
fn ray_plane_intersect(mut isect: ISect, ray: &Ray, plane: &Plane) -> ISect {
|
||||
let d = -vdot(&plane.p, &plane.n);
|
||||
let v = vdot(&ray.dir, &plane.n);
|
||||
|
||||
if v.abs() < 1.0e-17 {
|
||||
return isect;
|
||||
}
|
||||
|
||||
let t = -(vdot(&ray.org, &plane.n) + d) / v;
|
||||
|
||||
if (t > 0.0) && (t < isect.t) {
|
||||
isect.t = t;
|
||||
isect.hit = true;
|
||||
|
||||
isect.p = ray.org + ray.dir * t;
|
||||
isect.n = plane.n;
|
||||
}
|
||||
isect
|
||||
}
|
||||
|
||||
struct World {
|
||||
spheres: Vec<Sphere>,
|
||||
plane: Plane,
|
||||
|
||||
width: usize,
|
||||
height: usize,
|
||||
n_subsamples: u32,
|
||||
n_aosamples: u32,
|
||||
n_subsamples: usize,
|
||||
n_aosamples: usize,
|
||||
}
|
||||
|
||||
img: Vec<u8>,
|
||||
fn ortho_basis(n: &Vector) -> [Vector; 3] {
|
||||
let mut basis: [Vector; 3] = [Vector::zero(), Vector::zero(), n.clone()];
|
||||
|
||||
if (n.x < 0.6) && (n.x > -0.6) {
|
||||
basis[1].x = 1.0;
|
||||
} else if (n.y < 0.6) && (n.y > -0.6) {
|
||||
basis[1].y = 1.0;
|
||||
} else if (n.z < 0.6) && (n.z > -0.6) {
|
||||
basis[1].z = 1.0;
|
||||
} else {
|
||||
basis[1].x = 1.0;
|
||||
}
|
||||
|
||||
basis[0] = vcross(&basis[1], &basis[2]);
|
||||
basis[0].normalize();
|
||||
|
||||
basis[1] = vcross(&basis[2], &basis[0]);
|
||||
basis[1].normalize();
|
||||
|
||||
basis
|
||||
}
|
||||
|
||||
impl World {
|
||||
fn render(&mut self) {
|
||||
info!(
|
||||
"Rendering world {}x{} w/ {} subsampling and {} ambient occlusion sampling",
|
||||
self.width, self.height, self.n_subsamples, self.n_aosamples
|
||||
);
|
||||
for y in 0..self.height {
|
||||
for x in 0..self.width {
|
||||
self.img[(x + y * self.width) * 3 + 0] = (x % 256) as u8;
|
||||
self.img[(x + y * self.width) * 3 + 1] = (y % 256) as u8;
|
||||
self.img[(x + y * self.width) * 3 + 2] = ((x * y) % 256) as u8;
|
||||
fn ambient_occlusion(&self, isect: ISect) -> Vector {
|
||||
let n_theta: usize = self.n_aosamples;
|
||||
let n_phi: usize = self.n_aosamples;
|
||||
let eps: f64 = 0.0001;
|
||||
|
||||
let p = isect.p + isect.n * eps;
|
||||
let basis = ortho_basis(&isect.n);
|
||||
let mut occlusion: f64 = 0.0;
|
||||
let mut rng = rand::thread_rng();
|
||||
for _ in 0..n_theta {
|
||||
for _ in 0..n_phi {
|
||||
let theta: f64 = rng.gen::<f64>().sqrt();
|
||||
let phi: f64 = rng.gen::<f64>() * 2.0 * f64::consts::PI;
|
||||
|
||||
let x = phi.cos() * theta;
|
||||
let y = phi.sin() * theta;
|
||||
let z = (1.0 - theta * theta).sqrt();
|
||||
|
||||
let rx = x * basis[0].x + y * basis[1].x + z * basis[2].x;
|
||||
let ry = x * basis[0].y + y * basis[1].y + z * basis[2].y;
|
||||
let rz = x * basis[0].z + y * basis[1].z + z * basis[2].z;
|
||||
|
||||
let ray = Ray {
|
||||
org: p.clone(),
|
||||
dir: Vector::new(rx, ry, rz),
|
||||
};
|
||||
|
||||
let mut occ_isect = ISect {
|
||||
t: 1.0e+17,
|
||||
hit: false,
|
||||
p: Vector::zero(),
|
||||
n: Vector::zero(),
|
||||
};
|
||||
|
||||
occ_isect = ray_sphere_intersect(occ_isect, &ray, &self.spheres[0]);
|
||||
occ_isect = ray_sphere_intersect(occ_isect, &ray, &self.spheres[1]);
|
||||
occ_isect = ray_sphere_intersect(occ_isect, &ray, &self.spheres[2]);
|
||||
occ_isect = ray_plane_intersect(occ_isect, &ray, &self.plane);
|
||||
|
||||
if occ_isect.hit {
|
||||
occlusion += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn save(&self, path: &str) -> std::io::Result<()> {
|
||||
info!("Saving scene to {}", path);
|
||||
let mut buf = File::create(path)?;
|
||||
writeln!(&buf, "P6\n{} {}\n255", self.width, self.height)?;
|
||||
buf.write_all(&self.img)
|
||||
let n_theta = n_theta as f64;
|
||||
let n_phi = n_phi as f64;
|
||||
occlusion = (n_theta * n_phi - occlusion) / (n_theta * n_phi);
|
||||
Vector::new(occlusion, occlusion, occlusion)
|
||||
}
|
||||
}
|
||||
|
||||
fn init_scene() -> World {
|
||||
let w: usize = 512;
|
||||
let h: usize = 512;
|
||||
fn clamp(f: f64) -> u8 {
|
||||
let i = (f * 255.5) as i32;
|
||||
|
||||
if i < 0 {
|
||||
return 0;
|
||||
}
|
||||
if i > 255 {
|
||||
return 255;
|
||||
}
|
||||
i as u8
|
||||
}
|
||||
|
||||
impl World {
|
||||
fn render(&mut self) -> Vec<u8> {
|
||||
let w = self.width;
|
||||
let h = self.height;
|
||||
info!(
|
||||
"Rendering world {}x{} w/ {} subsampling and {} ambient occlusion sampling",
|
||||
w, h, self.n_subsamples, self.n_aosamples
|
||||
);
|
||||
let mut img = vec![0; w * h * 3];
|
||||
let mut fimg = vec![0.0; w * h * 3];
|
||||
for y in 0..h as usize {
|
||||
for x in 0..w as usize {
|
||||
for v in 0..self.n_subsamples {
|
||||
for u in 0..self.n_subsamples {
|
||||
let fx = x as f64;
|
||||
let fy = y as f64;
|
||||
let fw = w as f64;
|
||||
let fh = h as f64;
|
||||
let fu = u as f64;
|
||||
let fv = v as f64;
|
||||
let n_subsamples = self.n_subsamples as f64;
|
||||
let px = (fx + (fu / n_subsamples) - (fw / 2.0)) / (fw / 2.);
|
||||
let py = -(fy + (fv / n_subsamples) - (fh / 2.0)) / (fh / 2.);
|
||||
|
||||
let mut dir = Vector::new(px, py, -1.0);
|
||||
dir.normalize();
|
||||
|
||||
let ray = Ray {
|
||||
org: Vector::zero(),
|
||||
dir,
|
||||
};
|
||||
let mut isect = ISect {
|
||||
t: 1.0e+17,
|
||||
hit: false,
|
||||
p: Vector::zero(),
|
||||
n: Vector::zero(),
|
||||
};
|
||||
|
||||
isect = ray_sphere_intersect(isect, &ray, &self.spheres[0]);
|
||||
|
||||
isect = ray_sphere_intersect(isect, &ray, &self.spheres[1]);
|
||||
isect = ray_sphere_intersect(isect, &ray, &self.spheres[2]);
|
||||
isect = ray_plane_intersect(isect, &ray, &self.plane);
|
||||
|
||||
if isect.hit {
|
||||
let col = self.ambient_occlusion(isect);
|
||||
fimg[(x + y * w) * 3 + 0] += col.x;
|
||||
fimg[(x + y * w) * 3 + 1] += col.y;
|
||||
fimg[(x + y * w) * 3 + 2] += col.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
let n2 = (self.n_subsamples * self.n_subsamples) as f64;
|
||||
fimg[3 * (y * w + x) + 0] /= n2;
|
||||
fimg[3 * (y * w + x) + 1] /= n2;
|
||||
fimg[3 * (y * w + x) + 2] /= n2;
|
||||
|
||||
img[3 * (y * w + x) + 0] = clamp(fimg[3 * (y * w + x) + 0]);
|
||||
img[3 * (y * w + x) + 1] = clamp(fimg[3 * (y * w + x) + 1]);
|
||||
img[3 * (y * w + x) + 2] = clamp(fimg[3 * (y * w + x) + 2]);
|
||||
}
|
||||
}
|
||||
img
|
||||
}
|
||||
}
|
||||
|
||||
fn save(width: usize, height: usize, img: &[u8], path: &str) -> std::io::Result<()> {
|
||||
info!("Saving scene to {}", path);
|
||||
let mut buf = File::create(path)?;
|
||||
writeln!(&buf, "P6\n{} {}\n255", width, height)?;
|
||||
buf.write_all(img)
|
||||
}
|
||||
|
||||
fn init_scene(width: usize, height: usize, n_subsamples: usize, n_aosamples: usize) -> World {
|
||||
World {
|
||||
spheres: vec![
|
||||
Sphere {
|
||||
center: Vector {
|
||||
x: -2.0,
|
||||
y: 0.0,
|
||||
z: -3.5,
|
||||
},
|
||||
center: Vector::new(-2.0, 0.0, -3.5),
|
||||
radius: 0.5,
|
||||
},
|
||||
Sphere {
|
||||
center: Vector {
|
||||
x: -0.5,
|
||||
y: 0.0,
|
||||
z: -3.0,
|
||||
},
|
||||
center: Vector::new(-0.5, 0.0, -3.0),
|
||||
radius: 0.5,
|
||||
},
|
||||
Sphere {
|
||||
center: Vector {
|
||||
x: 1.0,
|
||||
y: 0.0,
|
||||
z: -2.2,
|
||||
},
|
||||
center: Vector::new(1.0, 0.0, -2.2),
|
||||
radius: 0.5,
|
||||
},
|
||||
],
|
||||
plane: Plane {
|
||||
p: Vector {
|
||||
x: 0.0,
|
||||
y: -0.5,
|
||||
z: 0.0,
|
||||
},
|
||||
n: Vector {
|
||||
x: 0.0,
|
||||
y: 1.0,
|
||||
z: 0.0,
|
||||
},
|
||||
p: Vector::new(0.0, -0.5, 0.0),
|
||||
n: Vector::new(0.0, 1.0, 0.0),
|
||||
},
|
||||
width: w,
|
||||
height: h,
|
||||
n_subsamples: 2,
|
||||
n_aosamples: 8,
|
||||
|
||||
img: vec![0; w * h * 3],
|
||||
width,
|
||||
height,
|
||||
n_subsamples,
|
||||
n_aosamples,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
stderrlog::new().verbosity(3).init().unwrap();
|
||||
|
||||
let mut w = init_scene();
|
||||
w.render();
|
||||
w.save("ao.ppm")
|
||||
#[derive(StructOpt, Debug)]
|
||||
#[structopt()]
|
||||
struct Opt {
|
||||
/// Verbose mode (-v, -vv, -vvv, etc)
|
||||
#[structopt(short = "v", long = "verbose", parse(from_occurrences), default_value = "vvv")]
|
||||
verbose: usize,
|
||||
#[structopt(short = "w", long = "width", default_value = "512")]
|
||||
width: usize,
|
||||
#[structopt(short = "h", long = "height", default_value = "512")]
|
||||
height: usize,
|
||||
#[structopt(short = "s", long = "subsamples", default_value = "2")]
|
||||
n_subsamples: usize,
|
||||
#[structopt(short = "a", long = "aosamples", default_value = "8")]
|
||||
n_aosamples: usize,
|
||||
}
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let opt = Opt::from_args();
|
||||
stderrlog::new()
|
||||
.verbosity(opt.verbose)
|
||||
.timestamp(stderrlog::Timestamp::Millisecond)
|
||||
.init()
|
||||
.unwrap();
|
||||
|
||||
let mut w = init_scene(opt.width, opt.height, opt.n_subsamples, opt.n_aosamples);
|
||||
let img = w.render();
|
||||
save(opt.width, opt.height, &img, "ao.ppm")
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user