Rendering something parsed from a pbrt file
This commit is contained in:
parent
c8ff77a0a9
commit
6d363aecd0
7 changed files with 316 additions and 127 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -2345,6 +2345,7 @@ dependencies = [
|
|||
"indicatif",
|
||||
"rand",
|
||||
"ray-tracing-core",
|
||||
"ray-tracing-pbrt-scene",
|
||||
"ray-tracing-renderer",
|
||||
"ray-tracing-scene",
|
||||
"rayon",
|
||||
|
|
|
|||
|
|
@ -174,6 +174,14 @@ impl AffineTransform {
|
|||
self.inv[2][0] * pos.x() + self.inv[2][1] * pos.y() + self.inv[2][2] * pos.z(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn transform_ray(&self, ray: Ray) -> Ray {
|
||||
Ray::new(
|
||||
self.transform_pos(ray.start()),
|
||||
self.transform_dir(ray.dir()),
|
||||
ray.time(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<AffineTransform> for AffineTransform {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
use crate::{texture::Pbrt_2d_float_texture, tokenizer::Tokenizer};
|
||||
use crate::{
|
||||
scene::PbrtScene,
|
||||
shape::{Shape, ShapeAlpha, ShapeType},
|
||||
texture::Pbrt_2d_float_texture,
|
||||
tokenizer::Tokenizer,
|
||||
};
|
||||
use error::SourceFile;
|
||||
use material::PbrtMaterial;
|
||||
use miette::{Diagnostic, IntoDiagnostic, Result, SourceSpan, bail, miette};
|
||||
|
|
@ -21,6 +26,8 @@ mod tokenizer;
|
|||
mod either;
|
||||
mod error;
|
||||
mod material;
|
||||
pub mod scene;
|
||||
mod shape;
|
||||
mod texture;
|
||||
|
||||
struct Lexer {
|
||||
|
|
@ -595,64 +602,10 @@ impl Parser {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ShapeType {
|
||||
Sphere {
|
||||
radius: Float,
|
||||
zmin: Float,
|
||||
zmax: Float,
|
||||
phimax: Float,
|
||||
},
|
||||
TriangleMesh {
|
||||
indices: Vec<usize>,
|
||||
p: Vec<Pos3>,
|
||||
n: Vec<Dir3>,
|
||||
s: Vec<Dir3>,
|
||||
uv: Vec<[Float; 2]>,
|
||||
},
|
||||
BilinearMesh {
|
||||
indices: Vec<usize>,
|
||||
p: Vec<Pos3>,
|
||||
n: Vec<Dir3>,
|
||||
uv: Vec<[Float; 2]>,
|
||||
},
|
||||
LoopSubDiv {
|
||||
levels: u32,
|
||||
indices: Vec<usize>,
|
||||
p: Vec<Pos3>,
|
||||
},
|
||||
Disk {
|
||||
height: Float,
|
||||
radius: Float,
|
||||
innerradius: Float,
|
||||
phimax: Float,
|
||||
},
|
||||
PlyMesh {
|
||||
filename: String,
|
||||
displacement: Option<String>,
|
||||
edgelength: Float,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ShapeAlpha {
|
||||
None,
|
||||
Value(Float),
|
||||
Texture(String),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Shape {
|
||||
ctm: AffineTransform,
|
||||
material: Arc<dyn PbrtMaterial>,
|
||||
obj: ShapeType,
|
||||
alpha: ShapeAlpha,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Pbrt {
|
||||
settings: PbrtWorldSettings,
|
||||
scene: PbrtScene,
|
||||
pub settings: PbrtWorldSettings,
|
||||
pub scene: PbrtScene,
|
||||
}
|
||||
|
||||
impl Pbrt {
|
||||
|
|
@ -670,11 +623,6 @@ struct PbrtWorldSettings {
|
|||
camera_ctm: AffineTransform,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PbrtScene {
|
||||
shapes: Vec<Shape>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PbrtContext {
|
||||
ctm: Vec<AffineTransform>,
|
||||
|
|
@ -861,7 +809,7 @@ fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
|
|||
}
|
||||
}
|
||||
|
||||
dbg!(context);
|
||||
// dbg!(context);
|
||||
|
||||
Ok(pbrt)
|
||||
}
|
||||
|
|
|
|||
40
ray-tracing-pbrt-scene/src/scene.rs
Normal file
40
ray-tracing-pbrt-scene/src/scene.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use ray_tracing_core::{prelude::Rng, scene::Scene};
|
||||
|
||||
use crate::shape::Shape;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PbrtScene {
|
||||
pub(crate) shapes: Vec<Shape>,
|
||||
}
|
||||
|
||||
impl<R: Rng> Scene<R> for PbrtScene {
|
||||
fn intersect(
|
||||
&self,
|
||||
ray: ray_tracing_core::prelude::Ray,
|
||||
min: ray_tracing_core::prelude::Float,
|
||||
max: ray_tracing_core::prelude::Float,
|
||||
) -> Option<ray_tracing_core::scene::Intersection<'_, R>> {
|
||||
let mut i = None;
|
||||
for s in &self.shapes {
|
||||
if let Some(new_i) = s.intersect::<R>(ray, min, max)
|
||||
&& i.as_ref()
|
||||
.is_none_or(|i: &ray_tracing_core::scene::Intersection<'_, R>| {
|
||||
i.t() > new_i.t()
|
||||
})
|
||||
{
|
||||
i = Some(new_i);
|
||||
}
|
||||
}
|
||||
|
||||
i
|
||||
}
|
||||
|
||||
fn sample_light(
|
||||
&self,
|
||||
w_in: ray_tracing_core::prelude::Dir3,
|
||||
intersection: &ray_tracing_core::scene::Intersection<'_, R>,
|
||||
rng: &mut R,
|
||||
) -> Option<ray_tracing_core::scene::LightSample<'_, R>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
154
ray-tracing-pbrt-scene/src/shape.rs
Normal file
154
ray-tracing-pbrt-scene/src/shape.rs
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use ray_tracing_core::{affine_transform::AffineTransform, prelude::*, scene::Intersection};
|
||||
|
||||
use crate::material::PbrtMaterial;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Shape {
|
||||
pub(crate) ctm: AffineTransform,
|
||||
pub(crate) material: Arc<dyn PbrtMaterial>,
|
||||
pub(crate) obj: ShapeType,
|
||||
pub(crate) alpha: ShapeAlpha,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ShapeAlpha {
|
||||
None,
|
||||
Value(Float),
|
||||
Texture(String),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ShapeType {
|
||||
Sphere {
|
||||
radius: Float,
|
||||
zmin: Float,
|
||||
zmax: Float,
|
||||
phimax: Float,
|
||||
},
|
||||
TriangleMesh {
|
||||
indices: Vec<usize>,
|
||||
p: Vec<Pos3>,
|
||||
n: Vec<Dir3>,
|
||||
s: Vec<Dir3>,
|
||||
uv: Vec<[Float; 2]>,
|
||||
},
|
||||
BilinearMesh {
|
||||
indices: Vec<usize>,
|
||||
p: Vec<Pos3>,
|
||||
n: Vec<Dir3>,
|
||||
uv: Vec<[Float; 2]>,
|
||||
},
|
||||
LoopSubDiv {
|
||||
levels: u32,
|
||||
indices: Vec<usize>,
|
||||
p: Vec<Pos3>,
|
||||
},
|
||||
Disk {
|
||||
height: Float,
|
||||
radius: Float,
|
||||
innerradius: Float,
|
||||
phimax: Float,
|
||||
},
|
||||
PlyMesh {
|
||||
filename: String,
|
||||
displacement: Option<String>,
|
||||
edgelength: Float,
|
||||
},
|
||||
}
|
||||
|
||||
impl Shape {
|
||||
pub(crate) fn intersect<R: Rng>(
|
||||
&self,
|
||||
ray: Ray,
|
||||
min: Float,
|
||||
max: Float,
|
||||
) -> Option<Intersection<R>> {
|
||||
let ray = self.ctm.transform_ray(ray);
|
||||
|
||||
match &self.obj {
|
||||
&ShapeType::Sphere {
|
||||
radius,
|
||||
zmin,
|
||||
zmax,
|
||||
phimax,
|
||||
} => {
|
||||
let a = ray.dir().length_squared();
|
||||
let b = 2.0 * Dir3::dot(ray.dir(), ray.start() - Pos3::zero());
|
||||
let c = Dir3::dot(ray.start() - Pos3::zero(), ray.start() - Pos3::zero())
|
||||
- radius * radius;
|
||||
|
||||
let dir = ray.dir().normalize();
|
||||
let v = ray.start() - (b / (2.0 * a) * dir);
|
||||
let length = (v - Pos3::zero()).length();
|
||||
let discrim = 4.0 * a * (radius + length) * (radius - length);
|
||||
|
||||
if discrim > 0.0 {
|
||||
let root_discrim = Float::sqrt(discrim);
|
||||
|
||||
let q = if b < 0.0 {
|
||||
-0.5 * (b - root_discrim)
|
||||
} else {
|
||||
-0.5 * (b + root_discrim)
|
||||
};
|
||||
|
||||
let mut t0 = q / a;
|
||||
let mut t1 = c / q;
|
||||
|
||||
if t1 < t0 {
|
||||
std::mem::swap(&mut t1, &mut t0);
|
||||
}
|
||||
|
||||
if let Some(t) = [t0, t1]
|
||||
.into_iter()
|
||||
.filter(|&t| {
|
||||
if min <= t && t <= max {
|
||||
let p = ray.at(t0);
|
||||
let mut phi = Float::atan2(p.y(), p.x());
|
||||
if phi < 0.0 {
|
||||
phi += 2.0 * FloatConsts::PI;
|
||||
}
|
||||
if zmin <= p.z() && p.z() <= zmax && phi <= phimax {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
})
|
||||
.next()
|
||||
{
|
||||
return Some(Intersection::new(
|
||||
t,
|
||||
(ray.at(t) - Pos3::zero()).normalize(),
|
||||
None,
|
||||
None,
|
||||
0.0,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
ShapeType::TriangleMesh {
|
||||
indices,
|
||||
p,
|
||||
n,
|
||||
s,
|
||||
uv,
|
||||
} => (),
|
||||
ShapeType::BilinearMesh { indices, p, n, uv } => (),
|
||||
ShapeType::LoopSubDiv { levels, indices, p } => todo!(),
|
||||
ShapeType::Disk {
|
||||
height,
|
||||
radius,
|
||||
innerradius,
|
||||
phimax,
|
||||
} => (),
|
||||
ShapeType::PlyMesh {
|
||||
filename,
|
||||
displacement,
|
||||
edgelength,
|
||||
} => (),
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ tev_client = "0.5.2"
|
|||
ray-tracing-core = { path = "../ray-tracing-core" }
|
||||
ray-tracing-scene = { path = "../ray-tracing-scene" }
|
||||
ray-tracing-renderer = { path = "../ray-tracing-renderer" }
|
||||
ray-tracing-pbrt-scene = { path = "../ray-tracing-pbrt-scene" }
|
||||
rayon = "1.10.0"
|
||||
rand = { version = "0.8.5", features = ["small_rng"] }
|
||||
clap = { version = "4.5.19", features = ["derive"] }
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use ray_tracing_core::{
|
|||
renderer::ClassicalRenderer,
|
||||
scene::Scene,
|
||||
};
|
||||
use ray_tracing_pbrt_scene::parse_pbrt_v4;
|
||||
use ray_tracing_renderer::{
|
||||
depth_renderer::DepthRenderer, mis::MIS, next_event_estimation::NextEventEstimation,
|
||||
path_tracer::PathTracer, path_tracer_importance::PathTracerImportance,
|
||||
|
|
@ -30,6 +31,8 @@ struct Args {
|
|||
height: u32,
|
||||
#[arg(long, default_value_t = 1024)]
|
||||
samples_per_pixel: usize,
|
||||
#[arg(long)]
|
||||
pbrt_filename: Option<std::path::PathBuf>,
|
||||
}
|
||||
|
||||
fn render_image<
|
||||
|
|
@ -105,17 +108,91 @@ fn render_image<
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn choose_renderer<S, C>(args: &Args, scene: &str, s: &S, c: &C, tev: &mut TevClient)
|
||||
where
|
||||
S: Scene<SmallRng> + Sync,
|
||||
C: Camera<SmallRng> + Sync,
|
||||
{
|
||||
if args.renderers.is_empty() || args.renderers.contains(&String::from("depth")) {
|
||||
let r = DepthRenderer::new(args.width, args.height);
|
||||
render_image(
|
||||
format!("{scene} - depth renderer"),
|
||||
&r,
|
||||
s,
|
||||
c,
|
||||
args.samples_per_pixel,
|
||||
tev,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if args.renderers.is_empty() || args.renderers.contains(&String::from("path")) {
|
||||
let r = PathTracer::new(args.width, args.height);
|
||||
render_image(
|
||||
format!("{scene} - path tracer"),
|
||||
&r,
|
||||
s,
|
||||
c,
|
||||
args.samples_per_pixel,
|
||||
tev,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if args.renderers.is_empty() || args.renderers.contains(&String::from("importance")) {
|
||||
let r = PathTracerImportance::new(args.width, args.height);
|
||||
render_image(
|
||||
format!("{scene} - path tracer importance"),
|
||||
&r,
|
||||
s,
|
||||
c,
|
||||
args.samples_per_pixel,
|
||||
tev,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if args.renderers.is_empty() || args.renderers.contains(&String::from("nee")) {
|
||||
let r = NextEventEstimation::new(args.width, args.height);
|
||||
render_image(
|
||||
format!("{scene} - next event estimation"),
|
||||
&r,
|
||||
s,
|
||||
c,
|
||||
args.samples_per_pixel,
|
||||
tev,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if args.renderers.is_empty() || args.renderers.contains(&String::from("mis")) {
|
||||
let r = MIS::new(args.width, args.height);
|
||||
render_image(
|
||||
format!("{scene} - mis"),
|
||||
&r,
|
||||
s,
|
||||
c,
|
||||
args.samples_per_pixel,
|
||||
tev,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
|
||||
let mut client = TevClient::wrap(TcpStream::connect(args.tev).unwrap());
|
||||
let mut client = TevClient::wrap(TcpStream::connect(&args.tev).unwrap());
|
||||
|
||||
let map = example_scenes();
|
||||
|
||||
let scenes: Vec<&str> = if args.scenes.is_empty() {
|
||||
map.keys().copied().collect()
|
||||
let scenes: Vec<&str> = if args.pbrt_filename.is_none() {
|
||||
if args.scenes.is_empty() {
|
||||
map.keys().copied().collect()
|
||||
} else {
|
||||
args.scenes.iter().map(|s| s.as_str()).collect()
|
||||
}
|
||||
} else {
|
||||
args.scenes.iter().map(|s| s.as_str()).collect()
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
for scene in scenes {
|
||||
|
|
@ -132,69 +209,29 @@ fn main() {
|
|||
f.get_horizontal_fov(),
|
||||
);
|
||||
|
||||
if args.renderers.is_empty() || args.renderers.contains(&String::from("depth")) {
|
||||
let r = DepthRenderer::new(args.width, args.height);
|
||||
render_image(
|
||||
format!("{scene} - depth renderer"),
|
||||
&r,
|
||||
&s,
|
||||
&c,
|
||||
args.samples_per_pixel,
|
||||
&mut client,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
choose_renderer(&args, scene, &s, &c, &mut client);
|
||||
}
|
||||
|
||||
if args.renderers.is_empty() || args.renderers.contains(&String::from("path")) {
|
||||
let r = PathTracer::new(args.width, args.height);
|
||||
render_image(
|
||||
format!("{scene} - path tracer"),
|
||||
&r,
|
||||
&s,
|
||||
&c,
|
||||
args.samples_per_pixel,
|
||||
&mut client,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
if let Some(pbrt_filename) = &args.pbrt_filename {
|
||||
let pbrt = parse_pbrt_v4(pbrt_filename).unwrap();
|
||||
|
||||
if args.renderers.is_empty() || args.renderers.contains(&String::from("importance")) {
|
||||
let r = PathTracerImportance::new(args.width, args.height);
|
||||
render_image(
|
||||
format!("{scene} - path tracer importance"),
|
||||
&r,
|
||||
&s,
|
||||
&c,
|
||||
args.samples_per_pixel,
|
||||
&mut client,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
let c = BasicCamera::from_look_at(
|
||||
args.width,
|
||||
args.height,
|
||||
Pos3::new(3.0, 4.0, 1.5),
|
||||
Pos3::new(0.5, 0.5, 0.0),
|
||||
Dir3::new(0.0, 0.0, 1.0),
|
||||
Float::to_radians(45.0),
|
||||
);
|
||||
|
||||
if args.renderers.is_empty() || args.renderers.contains(&String::from("nee")) {
|
||||
let r = NextEventEstimation::new(args.width, args.height);
|
||||
render_image(
|
||||
format!("{scene} - next event estimation"),
|
||||
&r,
|
||||
&s,
|
||||
&c,
|
||||
args.samples_per_pixel,
|
||||
&mut client,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
let s = &pbrt.scene;
|
||||
|
||||
if args.renderers.is_empty() || args.renderers.contains(&String::from("mis")) {
|
||||
let r = MIS::new(args.width, args.height);
|
||||
render_image(
|
||||
format!("{scene} - mis"),
|
||||
&r,
|
||||
&s,
|
||||
&c,
|
||||
args.samples_per_pixel,
|
||||
&mut client,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
choose_renderer(
|
||||
&args,
|
||||
&format!("pbrt \"{pbrt_filename:?}\""),
|
||||
s,
|
||||
&c,
|
||||
&mut client,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue