rtiow: break project into multiple workspaces.
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2019-11-09 11:56:33 -08:00
parent 2541b76ae6
commit d9d183b1e5
62 changed files with 941 additions and 957 deletions

View File

@@ -0,0 +1,33 @@
use crate::texture::Texture;
use crate::vec3::Vec3;
pub struct CheckerTexture<T>
where
T: Texture,
{
odd: T,
even: T,
}
impl<T> CheckerTexture<T>
where
T: Texture,
{
pub fn new(odd: T, even: T) -> CheckerTexture<T> {
CheckerTexture { odd, even }
}
}
impl<T> Texture for CheckerTexture<T>
where
T: Texture,
{
fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3 {
let sines = (10. * p.x).sin() * (10. * p.y).sin() * (10. * p.z).sin();
if sines < 0. {
self.odd.value(u, v, p)
} else {
self.even.value(u, v, p)
}
}
}

View File

@@ -0,0 +1,24 @@
use crate::texture::Texture;
use crate::vec3::Vec3;
#[derive(Debug, PartialEq)]
pub struct ConstantTexture {
color: Vec3,
}
impl ConstantTexture {
pub fn new<V>(color: V) -> ConstantTexture
where
V: Into<Vec3>,
{
ConstantTexture {
color: color.into(),
}
}
}
impl Texture for ConstantTexture {
fn value(&self, _u: f32, _v: f32, _p: Vec3) -> Vec3 {
self.color
}
}

View File

@@ -0,0 +1,26 @@
use std::f32;
use image::RgbImage;
use crate::texture::ImageTexture;
use crate::texture::Texture;
use crate::vec3::Vec3;
#[derive(Debug)]
pub struct EnvMap {
img_tex: ImageTexture,
}
impl EnvMap {
pub fn new(img: RgbImage) -> EnvMap {
EnvMap {
img_tex: ImageTexture::new(img),
}
}
pub fn color(&self, ray: Vec3) -> Vec3 {
let zero = Vec3::new(0., 0., 0.);
let u = ray.x.atan2(ray.z) / f32::consts::PI /2.0 + 0.5;
let v = ray.y / 2.0 + 0.5;
self.img_tex.value(u, v, zero)
}
}

View File

@@ -0,0 +1,48 @@
use image::RgbImage;
use crate::texture::Texture;
use crate::vec3::Vec3;
#[derive(Debug)]
pub struct ImageTexture {
img: RgbImage,
width: f32,
height: f32,
}
impl ImageTexture {
pub fn new(img: RgbImage) -> ImageTexture {
let (w, h) = img.dimensions();
ImageTexture {
img,
width: f32::from(w.min(64000) as u16),
height: f32::from(h.min(64000) as u16),
}
}
}
impl Texture for ImageTexture {
fn value(&self, u: f32, v: f32, _p: Vec3) -> Vec3 {
// Wrap texcoords by default.
let x = (u % 1. * (self.width - 1.)) as u32;
let y = ((1. - v % 1.) * (self.height - 1.)) as u32;
if x >= self.width as u32 {
panic!(format!(
"u {} v {} x {} y {} w {} h {}",
u, v, x, y, self.width, self.height
));
}
if y >= self.height as u32 {
panic!(format!(
"u {} v {} x {} y {} w {} h {}",
u, v, x, y, self.width, self.height
));
}
let pixel = self.img.get_pixel(x, y);
Vec3::new(
f32::from(pixel[0]) / 255.,
f32::from(pixel[1]) / 255.,
f32::from(pixel[2]) / 255.,
)
}
}

View File

@@ -0,0 +1,79 @@
#![allow(clippy::many_single_char_names)]
use rand;
use rand::Rng;
use crate::texture::Texture;
use crate::vec3::Vec3;
#[derive(Debug)]
pub struct Mandelbrot {
scale: f32,
palette: Vec<Vec3>,
}
// HSV values in [0..1]
// returns [r, g, b] values from 0 to 255
//From https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
fn hsv_to_rgb(h: f32, s: f32, v: f32) -> Vec3 {
let h_i = (h * 6.) as i32;
let f = h * 6. - h_i as f32;
let p = v * (1. - s);
let q = v * (1. - f * s);
let t = v * (1. - (1. - f) * s);
match h_i {
0 => Vec3::new(v, t, p),
1 => Vec3::new(q, v, p),
2 => Vec3::new(p, v, t),
3 => Vec3::new(p, q, v),
4 => Vec3::new(t, p, v),
5 => Vec3::new(v, p, q),
_ => panic!(format!("Unknown H value {}", h_i)),
}
}
fn generate_palette(num: usize) -> Vec<Vec3> {
let mut rng = rand::thread_rng();
let mut random = || rng.gen_range(0.0, 0.1);
// use golden ratio
let golden_ratio_conjugate = 0.618_034;
let mut h = random();
(0..num)
.map(|_| {
h += golden_ratio_conjugate;
h %= 1.0;
hsv_to_rgb(h, 0.99, 0.99)
})
.collect()
}
impl Default for Mandelbrot {
fn default() -> Self {
Mandelbrot {
scale: 2.0,
palette: generate_palette(10),
}
}
}
impl Texture for Mandelbrot {
fn value(&self, u: f32, v: f32, _p: Vec3) -> Vec3 {
// scaled x coordinate of pixel (scaled to lie in the Mandelbrot X scale (-2.5, 1))
let x0 = u * 3.5 - 2.5;
// scaled y coordinate of pixel (scaled to lie in the Mandelbrot Y scale (-1, 1))
let y0 = v * 2.0 - 1.0;
let mut x = 0.0;
let mut y = 0.0;
let mut iteration = 0;
let max_iteration = 1000;
while (x * x + y * y) <= 2. * 2. && iteration < max_iteration {
let xtemp = x * x - y * y + x0;
y = 2. * x * y + y0;
x = xtemp;
iteration += 1;
}
if iteration == max_iteration {
return Vec3::default();
}
self.palette[iteration % self.palette.len()]
}
}

View File

@@ -0,0 +1,45 @@
mod checker;
mod constant;
mod envmap;
mod image;
mod mandelbrot;
mod noise;
pub use crate::texture::checker::CheckerTexture;
pub use crate::texture::constant::ConstantTexture;
pub use crate::texture::envmap::EnvMap;
pub use crate::texture::image::ImageTexture;
pub use crate::texture::mandelbrot::Mandelbrot;
pub use crate::texture::noise::NoiseTexture;
use std::sync::Arc;
use crate::vec3::Vec3;
pub trait Texture: Send + Sync {
fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3;
}
impl Texture for Arc<dyn Texture> {
fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3 {
(**self).value(u, v, p)
}
}
impl Texture for Box<dyn Texture> {
fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3 {
(**self).value(u, v, p)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn constant_texture_from_array() {
assert_eq!(
ConstantTexture::new(Vec3::new(1., 2., 3.)),
ConstantTexture::new([1., 2., 3.])
);
}
}

View File

@@ -0,0 +1,46 @@
use crate::noise::NoiseSource;
use crate::noise::NoiseType;
use crate::texture::Texture;
use crate::vec3::Vec3;
pub struct NoiseTexture<N>
where
N: NoiseSource,
{
noise_source: N,
noise_type: NoiseType,
}
impl<N> NoiseTexture<N>
where
N: NoiseSource,
{
pub fn new(noise_source: N, noise_type: NoiseType) -> NoiseTexture<N> {
NoiseTexture {
noise_source,
noise_type,
}
}
}
impl<N> Texture for NoiseTexture<N>
where
N: NoiseSource,
{
fn value(&self, _u: f32, _v: f32, p: Vec3) -> Vec3 {
let v = match self.noise_type {
NoiseType::Scale(scale) => self.noise_source.scaled(p, scale),
NoiseType::Turbulence(turbulence) => self.noise_source.turbulence(p, turbulence),
NoiseType::Marble {
period,
power,
size,
scale,
} => self.noise_source.marble(p, period, power, size, scale),
};
debug_assert!(v >= 0., "Cold pixel @ {}: {}", p, v);
debug_assert!(v <= 1., "Hot pixel @ {}: {}", p, v);
Vec3::new(1., 1., 1.) * v
}
}