Break texture module into multiple files.

This commit is contained in:
Bill Thiede 2018-10-11 20:00:44 -07:00
parent 66d599b50d
commit f483f2905b
6 changed files with 178 additions and 160 deletions

View File

@ -1,160 +0,0 @@
use std::sync::Arc;
use image::RgbImage;
use rand;
use perlin::Perlin;
use vec3::Vec3;
pub trait Texture: Send + Sync {
fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3;
}
impl Texture for Arc<Texture> {
fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3 {
(**self).value(u, v, p)
}
}
#[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
}
}
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)
}
}
}
pub struct NoiseTexture {
scale: f32,
perlin: Perlin,
}
impl NoiseTexture {
pub fn new<R>(rng: &mut R) -> NoiseTexture
where
R: rand::Rng,
{
NoiseTexture::with_scale(rng, 1.)
}
pub fn with_scale<R>(rng: &mut R, scale: f32) -> NoiseTexture
where
R: rand::Rng,
{
NoiseTexture {
scale,
perlin: Perlin::new(rng),
}
}
}
impl Texture for NoiseTexture {
fn value(&self, _u: f32, _v: f32, p: Vec3) -> Vec3 {
Vec3::new(1., 1., 1.) * 0.5 * (1. + self.perlin.noise(self.scale * p))
//Vec3::new(1., 1., 1.) * turb(self.scale * p, 7)
//Vec3::new(1., 1., 1.) * 0.5 * (1. + turb(self.scale * p, 7))
//Vec3::new(1., 1., 1.) * 0.5 * (1. + (self.scale * p.z + 10. * self.perlin.turb(p, 7)).sin())
//Vec3::new(1., 1., 1.) * 0.5 * (1. + GENERATOR.noise(self.scale * p))
}
}
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.,
)
}
}
#[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,33 @@
use texture::Texture;
use 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 texture::Texture;
use 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,47 @@
use image::RgbImage;
use texture::Texture;
use vec3::Vec3;
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.,
)
}
}

35
rtiow/src/texture/mod.rs Normal file
View File

@ -0,0 +1,35 @@
mod checker;
mod constant;
mod image;
mod noise;
pub use texture::checker::CheckerTexture;
pub use texture::constant::ConstantTexture;
pub use texture::image::ImageTexture;
pub use texture::noise::NoiseTexture;
use std::sync::Arc;
use vec3::Vec3;
pub trait Texture: Send + Sync {
fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3;
}
impl Texture for Arc<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,39 @@
use rand;
use perlin::Perlin;
use texture::Texture;
use vec3::Vec3;
pub struct NoiseTexture {
scale: f32,
perlin: Perlin,
}
impl NoiseTexture {
pub fn new<R>(rng: &mut R) -> NoiseTexture
where
R: rand::Rng,
{
NoiseTexture::with_scale(rng, 1.)
}
pub fn with_scale<R>(rng: &mut R, scale: f32) -> NoiseTexture
where
R: rand::Rng,
{
NoiseTexture {
scale,
perlin: Perlin::new(rng),
}
}
}
impl Texture for NoiseTexture {
fn value(&self, _u: f32, _v: f32, p: Vec3) -> Vec3 {
Vec3::new(1., 1., 1.) * 0.5 * (1. + self.perlin.noise(self.scale * p))
//Vec3::new(1., 1., 1.) * turb(self.scale * p, 7)
//Vec3::new(1., 1., 1.) * 0.5 * (1. + turb(self.scale * p, 7))
//Vec3::new(1., 1., 1.) * 0.5 * (1. + (self.scale * p.z + 10. * self.perlin.turb(p, 7)).sin())
//Vec3::new(1., 1., 1.) * 0.5 * (1. + GENERATOR.noise(self.scale * p))
}
}