-
Notifications
You must be signed in to change notification settings - Fork 59
Release Notes
The release notes are published here from now on.
There are mainly two new shapes being supported to be read from
.pbrt
files:
- NURBS (Non-Uniform Rational B-Splines) - see shapes/nurbs
- Subdivision Surfaces - see shapes/loopsubdiv
The related issues are:
- CreateNURBS (see issue #65)
- Implement 'Shape "loopsubdiv"' (see issue #67)
- Fix motion blur (see issue #66)
I started to implement some Python scripts for
Blender to export to rs_pbrt
. This is basically a simple
way to create basic scene files for certain features of the renderer
I'm working on. The repository also contains 4 new test scenes related
to those topics.
I added a new test scene to the GitLab repository, which caused a lot of issues and TODOs:
- The first task (see issue #56) I opened, was about rendering the (new) VW scene. Which surely would create new issues.
- The parser had to be changed to allow spaces in identifiers
(e.g. for materials). The related issue #57 can be
re-opened in the future for any parser related problems for
reading/parsing
.pbrt
scene files. - While working on the parser I saw that the test scene contains
ObjectBegin
,ObjectEnd
, andObjectInstance
keywords and I opened a separate enhancement issue (see issue #58) for that. - There was one material in particular which specified two filenames
for
Spectrum
parameters. We had to deal with those filenames viaParamSet::add_sampled_spectrum_files()
. See issue #59 but also read the content of those files viaread_float_file()
(see issue #60). - The test scene contained a new
FourierMaterial
, which also had a parameter which reads BSDF information from a file. So we needed two more structs:FourierBSDFTable
andFourierBSDF
. See issue #61. - After implementing all the
Bxdf
trait methods forFourierBSDF
I triggered a panic during rendering of the test scene. While debugging the problem I figured out that I had to go back to theObjectInstance
lines, which do influence the scene bound, which is used e.g. byInfiniteAreaLight
. Issue #63 deals with that aspect, but it didn't fix the panic. - I created issue #64 in the hope that I had identified the cause, but in the end I had to fix a couple of things which I identified during debugging and comparing the original C++ version with the current Rust code.
The two sampled spectrum files are now part of this repository and there is a new executable to test the function to read those kind of files (see floatfile documentation):
$ ./target/release/examples/core_read_float_file
read_float_file("/home/jan/git/self_hosted/Rust/pbrt/assets/spds/Al.k.spd", ...) returns true.
[298.75705, 3.59375, 302.40042, 3.64, 306.13376, 3.689375, 309.96045, 3.74, 313.884, 3.789375, 317.90814, 3.84, 322.03683, 3.894375, 326.27414, 3.95, 330.62448, 4.005, 335.09238, 4.06, 339.68268, 4.11375, 344.40048, 4.17, 349.25122, 4.23375, 354.2405, 4.3, 359.37442, 4.365, 364.65933, 4.43, 370.10202, 4.49375, 375.70963, 4.56, 381.48978, 4.63375, 387.45056, 4.71, 393.60056, 4.784375, 399.94897, 4.86, 406.5055, 4.938125, 413.28058, 5.02, 420.28534, 5.10875, 427.53165, 5.2, 435.0322, 5.29, 442.80063, 5.38, 450.85156, 5.48, 459.20065, 5.58, 467.86484, 5.69, 476.8622, 5.8, 486.21246, 5.915, 495.9367, 6.03, 506.05786, 6.15, 516.60077, 6.28, 527.5922, 6.42, 539.06165, 6.55, 551.0408, 6.7, 563.56445, 6.85, 576.6706, 7.0, 590.4008, 7.15, 604.80084, 7.31, 619.9209, 7.48, 635.8163, 7.65, 652.5483, 7.82, 670.18475, 8.01, 688.80096, 8.21, 708.481, 8.39, 729.31866, 8.57, 751.41925, 8.62, 774.9011, 8.6, 799.89795, 8.45, 826.56116, 8.31, 855.0633, 8.21, 885.60126, 8.21]
read_float_file("/home/jan/git/self_hosted/Rust/pbrt/assets/spds/Al.eta.spd", ...) returns true.
[298.75705, 0.273375, 302.40042, 0.28, 306.13376, 0.286813, 309.96045, 0.294, 313.884, 0.301875, 317.90814, 0.31, 322.03683, 0.317875, 326.27414, 0.326, 330.62448, 0.33475, 335.09238, 0.344, 339.68268, 0.353813, 344.40048, 0.364, 349.25122, 0.374375, 354.2405, 0.385, 359.37442, 0.39575, 364.65933, 0.407, 370.10202, 0.419125, 375.70963, 0.432, 381.48978, 0.445688, 387.45056, 0.46, 393.60056, 0.474688, 399.94897, 0.49, 406.5055, 0.506188, 413.28058, 0.523, 420.28534, 0.540063, 427.53165, 0.558, 435.0322, 0.577313, 442.80063, 0.598, 450.85156, 0.620313, 459.20065, 0.644, 467.86484, 0.668625, 476.8622, 0.695, 486.21246, 0.72375, 495.9367, 0.755, 506.05786, 0.789, 516.60077, 0.826, 527.5922, 0.867, 539.06165, 0.912, 551.0408, 0.963, 563.56445, 1.02, 576.6706, 1.08, 590.4008, 1.15, 604.80084, 1.22, 619.9209, 1.3, 635.8163, 1.39, 652.5483, 1.49, 670.18475, 1.6, 688.80096, 1.74, 708.481, 1.91, 729.31866, 2.14, 751.41925, 2.41, 774.9011, 2.63, 799.89795, 2.8, 826.56116, 2.74, 855.0633, 2.58, 885.60126, 2.24]
I also had to implement several spline-based interpolation functions
(see interpolation for documentation). The biggest
changes were made in fourier (FourierMaterial
) and
reflection (FourierBSDF
, FourierBSDFTable
).
Version 0.4.3 consists of 120 public structs, 9 enums, 23 traits, and 188 public functions:
> pwd
/home/jan/git/github/rs_pbrt/src
> rg -trust "^pub struct" | wc
120 483 5430
> rg -trust "^pub enum" | wc
9 36 371
> rg -trust "^pub trait" | wc
23 96 972
> rg -trust "^pub fn" | wc
188 1428 13712
I started working on a parser, which can use another renderers scene description (in this case Arnold’s .ass files). It's in a very early stage of implementation but it can be used on a couple of test scenes already:
> ./target/release/examples/parse_ass_file -h
Usage: ./target/release/examples/parse_ass_file [options]
Options:
-h, --help print this help menu
-i FILE parse an input file
-s, --samples NUM samples per pixel
-v, --version print version number
Currently we allow to specify the number of samples per pixel on
the command line, but limit the numbers to 8 bit (u8
). In the future
it will likely be raised to 16 bit unsigned integer numbers:
> ./target/release/examples/parse_ass_file -i assets/ass/cornell_box.ass -s 128
The three test scenes provided are:
> ls -1 assets/ass/c*.ass
assets/ass/cafe_scene1.ass
assets/ass/cafe_scene2.ass
assets/ass/cornell_box.ass
I also worked on the parser a bit to be able to render a test scene from the Blender to PBRTv3 exporter. Look at the resulting image at the GitLab repository gathering test scenes for this Rust based implementation of PBRT. The .ass files for Arnold (mentioned above) can be found there as well.
Since the last release where the main executable (rs_pbrt) was ported to the latest pest crate version, a couple of problems were introduced and were unnoticed until you try to render some test scenes.
Otherwise I worked mainly on three issues:
- Basically I wanted to be able to use
Float
image textures (see issue #52), as well asSpectrum
textures (which I had implemented already). - While working on that I found a bug (see issue #53),
in case the scene description was missing the
Integrator
line (which was really easy to fix - the default string was wrong). - I also needed a better test scene to see that those
Float
textures are read and handled correctly. Therefore I added a scene for bump mapping which had one imagemap texture to control where the bump mapping is supposed to happen, and one ScaleTexture to scale the effect (by a constant value). See issue #54
Version 0.4.1 consists of 116 public structs, 9 enums, 23 traits, and 179 public functions:
> pwd
/home/jan/git/github/rs_pbrt/src
> rg -trust "^pub struct" | wc
116 467 5252
> rg -trust "^pub enum" | wc
9 36 371
> rg -trust "^pub trait" | wc
23 96 972
> rg -trust "^pub fn" | wc
179 1366 13070
Here are the traits:
> rg -trust "^pub trait"
core/reflection.rs
253:pub trait Bxdf {
307:pub trait Fresnel {
core/mipmap.rs
392:pub trait Clampable {
core/primitive.rs
16:pub trait Primitive {
core/filter.rs
11:pub trait Filter {
core/camera.rs
16:pub trait Camera {
core/microfacet.rs
12:pub trait MicrofacetDistribution {
core/medium.rs
266:pub trait PhaseFunction {
271:pub trait Medium {
core/light.rs
26:pub trait Light {
126:pub trait AreaLight: Light {
textures/imagemap.rs
103:pub trait ImageTextureConvert<T> {
core/interaction.rs
28:pub trait Interaction {
core/texture.rs
17:pub trait TextureMapping2D {
77:pub trait Texture<T> {
core/shape.rs
16:pub trait Shape {
core/integrator.rs
23:pub trait SamplerIntegrator {
core/lightdistrib.rs
22:pub trait LightDistribution {
core/material.rs
26:pub trait Material {
core/sampler.rs
12:pub trait Sampler: SamplerClone {
36:pub trait PixelSampler: Sampler {}
38:pub trait GlobalSampler: Sampler {}
40:pub trait SamplerClone {
The current version should compile with all three Rust versions (stable, beta, nightly).
The main executable to render test scenes is called rs_pbrt
:
> ./target/release/examples/rs_pbrt -v
./target/release/examples/rs_pbrt 0.4.0
Issue #39 was resolved and the latest version of the
pest
crate is being used.
The atomic
crate was upgraded to version 0.4.
Most of the functionality which is independent of the parser, moved into the API.
All global variables within the parser are gone. They are
all collected within ApiState
(see link) and there is
no need for unsafe code blocks to deal with them.
All test scenes are collected on GitLab.
Version 0.4.0 consists of 115 public structs, 9 enums, 21 traits, and 176 public functions:
> pwd
/home/jan/git/github/rs_pbrt/src
> rg -trust "^pub struct" | wc
115 463 5659
> rg -trust "^pub enum" | wc
9 36 407
> rg -trust "^pub trait" | wc
21 88 963
> rg -trust "^pub fn" | wc
176 1349 13591
Here are the traits:
> rg -trust "^pub trait"
src/core/microfacet.rs
12:pub trait MicrofacetDistribution {
src/core/texture.rs
17:pub trait TextureMapping2D {
77:pub trait Texture<T> {
src/core/lightdistrib.rs
22:pub trait LightDistribution {
src/core/interaction.rs
28:pub trait Interaction {
src/core/shape.rs
16:pub trait Shape {
src/core/integrator.rs
23:pub trait SamplerIntegrator {
src/core/primitive.rs
16:pub trait Primitive {
src/core/light.rs
26:pub trait Light {
126:pub trait AreaLight: Light {
src/core/camera.rs
16:pub trait Camera {
src/core/material.rs
20:pub trait Material {
src/core/sampler.rs
12:pub trait Sampler: SamplerClone {
36:pub trait PixelSampler: Sampler {}
38:pub trait GlobalSampler: Sampler {}
40:pub trait SamplerClone {
src/core/medium.rs
266:pub trait PhaseFunction {
271:pub trait Medium {
src/core/reflection.rs
253:pub trait Bxdf {
307:pub trait Fresnel {
src/core/filter.rs
11:pub trait Filter {
Version 0.3.2 can render with Metropolis Light Transport now. See blog post to see some images.
The openexr crate got upgraded to version 0.6. The
MLT main render loop does use the rayon crate (a
data-parallelism library) to run several Markov chains in parallel
(using par_iter()
).
There are two progress bars for the two stages of rendering. The first
one isn't very clever and should probably be changed in the
future. Basically a large vector of float values (bootstrap samples)
is split into num_cores
chunks and each processor is dealing with
one chunk. After that the main render loop indicates with a progress
bar the number of Markov chains which were already dealt with, and an
estimate about the remaining render time.
All three render functions use Arc
now for the camera pointer
(instead of a Box
).
There is a new linear interpolation function (lerp) for Bounds2
.
The signatures of VisibilityTester::tr(...)
and Medium::tr(...)
changed.
New constant SQRT_2
in core/pbrt.rs
and new function
erf_inv(...)
.
Four issues were closed:
- bootstrap samples differ (see issue #48)
- Implement MLTIntegrator (see issue #43)
- Show status of MLT render loop via progress bars (see issue #49)
- Fix "black windows" for bi-directional path tracing (see issue #50)
Version 0.3.1 can render volumetric caustics now:
A glass sphere in participating media, showing off a volumetric caustic.
Test scene for image above (see also issue #46).
During debugging I figured out that I got slightly different values
between the C++ version and Rust. This file is a reminder and
multiplying the two Float values first, before multiplying the result
with a Vector3f
, makes a difference:
- *x * sin_theta * phi.cos() + *y * sin_theta * phi.sin() + *z * cos_theta
+ *x * (sin_theta * phi.cos()) + *y * (sin_theta * phi.sin()) + *z * cos_theta
Contains three new structs:
$ grep "^pub struct" src/core/medium.rs
pub struct MeasuredSS {
pub struct HenyeyGreenstein {
pub struct MediumInterface {
One new constant:
$ grep "^pub const" src/core/medium.rs
pub const SUBSURFACE_PARAMETER_TABLE: [MeasuredSS; 47] = [
Two new traits:
$ grep "^pub trait" src/core/medium.rs
pub trait PhaseFunction {
pub trait Medium {
And two new functions:
$ grep "^pub fn" src/core/medium.rs
pub fn get_medium_scattering_properties(
pub fn phase_hg(cos_theta: Float, g: Float) -> Float {
I started to implement the MLTIntegrator
(see issue
#43), but for now we only got some skeleton code:
Contains two new structs:
jan@purism:~/git/self_hosted/Rust/pbrt$ grep "^pub struct" src/integrators/mlt.rs
pub struct MLTSampler {
pub struct MLTIntegrator {
Two new constants:
jan@purism:~/git/self_hosted/Rust/pbrt$ grep "^pub const" src/integrators/mlt.rs
pub const CAMERA_STREAM_INDEX: u8 = 0;
pub const N_SAMPLE_STREAMS: u8 = 3;
For the test scene with volumetric caustics we needed a SpotLight (see issue #21).
Contains:
pub struct HomogeneousMedium {
pub sigma_a: Spectrum,
pub sigma_s: Spectrum,
pub sigma_t: Spectrum,
pub g: Float,
}
Which implements the Medium trait.
See media in the documentation.
Version 0.3.0 can render with bi-directional path tracing (BDPT) now:
On the left the same scene was rendered with uni-directional path tracing and the resulting image contains much more noise, on the right bi-directional path tracing was used (with otherwise identical settings). Rays leaving the scene without hitting geometry render black right now (see windows). This should be fixed for future releases.
Here is another scene which profits from using BDPT:
Version 0.3.0 consists of 105 public structs, 9 enums, 19 traits, and 138 public functions:
> pwd
/home/jan/git/github/rs_pbrt/src
> rg -trust "^pub struct" | wc
105 423 4739
> rg -trust "^pub enum" | wc
9 36 371
> rg -trust "^pub trait" | wc
19 80 802
> rg -trust "^pub fn" | wc
138 1061 10024
Here are the traits:
> rg -trust "^pub trait"
core/microfacet.rs
12:pub trait MicrofacetDistribution {
core/texture.rs
17:pub trait TextureMapping2D {
77:pub trait Texture<T> {
core/lightdistrib.rs
21:pub trait LightDistribution {
core/interaction.rs
27:pub trait Interaction {
core/shape.rs
16:pub trait Shape {
core/integrator.rs
20:pub trait SamplerIntegrator {
core/primitive.rs
15:pub trait Primitive {
core/light.rs
23:pub trait Light {
113:pub trait AreaLight: Light {
core/sampler.rs
12:pub trait Sampler: SamplerClone {
36:pub trait PixelSampler: Sampler {
39:pub trait GlobalSampler: Sampler {
42:pub trait SamplerClone {
core/material.rs
20:pub trait Material {
core/reflection.rs
253:pub trait Bxdf {
307:pub trait Fresnel {
core/filter.rs
11:pub trait Filter {
core/camera.rs
16:pub trait Camera {
- Implemented
SubstrateMaterial
issue #34. - Taking
ReverseOrientation
in a .pbrt scene into account. - Fix a problem for
InfiniteAreaLight
and HDR images. - Fix a problem with world-space normals and uv-coords.
- Implemented
TriangleFilter
(this resolves issue #18). - Implemented
UberMaterial
issue #35. - Deal with
TransformBegin
andTransformEnd
(see issue #36). - Fixed two bugs, one for mipmaps, the other for Bsdfs.
- Implemented the curve shape (see issue #37).
- Implemented
HairMaterial
issue #38. - Have a default matte material for the
GraphicsState
.
Very detailed scan of a small statue with over 4.3 million triangles, illuminated by a few area light sources.
The ground object consists of two triangles using the default matte material, the ganesha statue is using a substrate material with a texture.
The Japanese Classroom scene comes from Benedikt Bitterli’s Rendering Resources.
While debugging this scene (see issue #36) I noticed that
the parser didn't deal with TransformBegin
and TransformEnd
(yet)
and fixed that.
There are other scenes which I was able to render with the Rust version of PBRT and the resulting images can be seen here. The PBRT scene files were slightly modified and can be downloaded from my web site (at the bottom of the download page).
The hair scattering model in action:
- Created and solved issue #27 for using PLY files.
- Fix a bug in
ParamSet::copy_from(...)
to deal with boolean parameters (see issue #28). - New test scene for bi-directional path-tracing (see issue #29).
- Implemented and tested the
RandomSampler
(see issue #26). - New test scene for depth of field.
- New material
MetalMaterial
(see issue #30). - Implemented depth of field (see issue #31).
- Building without OpenEXR on Travis CI.
- Add images and more text to the documentation.
- Allow blackbody param type (see issue #32).
- Implement
MixMaterial
with the help of ScaledBxDF (see issue #33).
- We can build with or without OpenEXR now.
- Via the
image::hdr
crate/module we can use HDR images. - The single lib.rs file was split into many files and folders.
- Implemented two new samplers:
HaltonSampler
andSobolSampler
.
To compile without OpenEXR you can use this command line:
cargo test --release --no-default-features
The test scene for motion blur uses a Radiance HDR file now:
-LightSource "infinite" "string mapname" ["textures/skylight-day.exr"]
+LightSource "infinite" "string mapname" ["textures/skylight-day.hdr"]
The conversion from OpenEXR to HDR can be done within Blender.
The documentation is now more structured (using modules, and splitting the core into sub-modules).
+Sampler "lowdiscrepancy" "integer pixelsamples" [8]
+Sampler "halton" "integer pixelsamples" [8]
+Sampler "sobol" "integer pixelsamples" [8]
Version 0.2.5 consists of 88 public structs, 6 enums, 17 traits, and 117 public functions:
> pwd
/home/jan/git/github/rs_pbrt/src
> rg -trust "^pub struct" | wc
88 353 3927
> rg -trust "^pub enum" | wc
6 24 251
> rg -trust "^pub trait" | wc
17 70 701
> rg -trust "^pub fn" | wc
117 955 8752
Here are the traits:
> rg -trust "^pub trait"
textures/mod.rs
15:pub trait TextureMapping2D {
75:pub trait Texture<T> {
materials/mod.rs
14:pub trait Material {
shapes/mod.rs
241:pub trait Shape {
filters/mod.rs
90:pub trait Filter {
core/microfacet.rs
12:pub trait MicrofacetDistribution {
core/interaction.rs
29:pub trait Interaction {
core/lightdistrib.rs
17:pub trait LightDistribution {
core/primitive.rs
16:pub trait Primitive {
core/light.rs
17:pub trait Light {
67:pub trait AreaLight: Light {
core/camera.rs
10:pub trait Camera {
core/sampler.rs
8:pub trait Sampler: SamplerClone {
22:pub trait SamplerClone {
core/reflection.rs
240:pub trait Bxdf {
262:pub trait Fresnel {
core/integrator.rs
20:pub trait SamplerIntegrator {
The rg
(or ripgrep
executable) comes from the ripgrep
GitHub repository, but can be installed via cargo
:
> cargo install ripgrep
The main features are:
- We have an InfiniteAreaLight now. See issue #20.
- We had to be able to read a HDR image for image based lighting.
- We do support basic motion blur. See issue #24.
- We allow to specify the number of threads on the command line.
> ./target/release/examples/pest_test -h
Usage: ./target/release/examples/pest_test [options]
Options:
-h, --help print this help menu
-i FILE parse an input file
-t, --nthreads NUM use specified number of threads for rendering
-v, --version print version number
As a consequence we rely on the openexr crate now. This complicates cross platform development and continuous integration via Travis CI. Therefore I would like to replace it by using Radiance HDR image supported by the image crate.
Added new structs:
pub struct Interval
pub struct TransformedPrimitive
pub struct ResampleWeight
pub struct InfiniteAreaLight
pub struct Distribution2D
New functions:
pub fn spherical_theta(v: &Vector3f) -> Float
pub fn spherical_phi(v: &Vector3f) -> Float
pub fn interval_sin(i: Interval) -> Interval
pub fn interval_cos(i: Interval) -> Interval
pub fn interval_find_zeros(c1: Float, ... , depth: usize)
pub fn quat_slerp(t: Float, q1: Quaternion, q2: Quaternion) -> Quaternion
pub fn lanczos(x: Float, tau: Float) -> Float
Renamed functions or changed signatures:
pub fn clamp_t<T>(val: T, low: T, high: T) -> T
pub fn round_up_pow2_32(v: i32) -> i32
pub fn round_up_pow2_64(v: i64) -> i64
pub fn quat_dot_quat(q1: Quaternion, q2: Quaternion) -> Float
New operators:
< impl PartialEq for Matrix4x4 {
< impl PartialEq for Transform {
< impl Add for Interval {
< impl Mul for Interval {
< impl Add for Quaternion {
New implementors (of a trait):
< impl Primitive for TransformedPrimitive {
< impl Primitive for BVHAccel {
< impl Light for InfiniteAreaLight {
New member functions (of an already existing struct):
> rg -B 19 -trust "fn corner"
src/lib.rs
2406-impl<T> Bounds3<T> {
...
2425: pub fn corner(&self, corner: u8) -> Point3<T>
> rg -B 59 -trust "fn is_identity"
src/lib.rs
2873-impl Transform {
...
2932: pub fn is_identity(&self) -> bool {
> rg -B 1 -trust "fn eval\("
src/lib.rs
3526-impl DerivativeTerm {
3527: pub fn eval(&self, p: Point3f) -> Float {
> rg -B 833 -trust "fn interpolate"
src/lib.rs
3550-impl AnimatedTransform {
...
4383: pub fn interpolate(&self, time: Float, t: &mut Transform) {
> rg -B 883 -trust "fn motion_bounds"
3550-impl AnimatedTransform {
...
4433: pub fn motion_bounds(&self, b: Bounds3f) -> Bounds3f {
> rg -B 50 -trust "fn to_transform"
src/lib.rs
4628-impl Quaternion {
...
4678: pub fn to_transform(&self) -> Transform {
> rg -trust "impl MipMap"
src/lib.rs
9931:impl MipMap {
...
10058: pub fn width(&self) -> i32 {
...
10061: pub fn height(&self) -> i32 {
...
10088: pub fn lookup_pnt_flt(&self, st: &Point2f, width: Float) -> Spectrum {
...
10104: pub fn lookup_pnt_vec_vec(&self, st: &Point2f, dst0: &mut Vector2f, dst1: &mut Vector2f) -> Spectrum {
> rg -trust "impl Distribution1D"
src/lib.rs
11137:impl Distribution1D {
...
11164: pub fn count(&self) -> usize {
11167: pub fn sample_continuous(&self, u: Float, pdf: Option<&mut Float>, off: Option<&mut usize>) -> Float {
> rg -trust "impl Distribution2D"
src/lib.rs
11251:impl Distribution2D {
...
11270: pub fn sample_continuous(&self, u: &Point2f, pdf: &mut Float) -> Point2f {
...
11281: pub fn pdf(&self, p: &Point2f) -> Float {
> rg -A 1 -trust "impl TransformSet"
src/lib.rs
12781:impl TransformSet {
12782- pub fn is_animated(&self) -> bool {
Version 0.2.4 keeps the library in a single file with 13280 lines of code:
> wc lib.rs
13280 58238 504946 lib.rs
The first 857 lines are mainly used to create parts of the documentation and example code mentioned there. More examples are kept in a subdirectory (called examples) and the one file used to render the image above is called pest_test.rs. Version 0.2.4 consists of 86 public structs, 6 enums, 16 traits, and 110 public ""functions"":
> grep "^pub struct" lib.rs | wc
86 345 2333
> grep "^pub enum" lib.rs | wc
6 24 136
> grep "^pub trait" lib.rs | wc
16 65 374
> grep "^pub fn" lib.rs | wc
110 880 6228
As mentioned in the last release I ran into a major bottleneck regarding building the BVH recursively. This releases fixes the problem. The art gallery scene builds it's BVH now in approx. 2 seconds (as opposed to 17 minutes before). All the details can be found here.
While trying to render the following new scene ...
... I ran into problems with the parser. The scene seemed to big and
created a stack overflow. On the chat on gitter
about pest I was told to update to pest = "^1.0.0-beta"
(and
pest_derive = "^1.0.0-beta"
) and it might go away. So, this is
basically the main change of this release. The parser (in
pest_test
) had to be rewritten.
As you can see in the following image (which was rendered by the C++ version of PBRT), we still miss two textures (on the floor and the picture on the left wall):
I also ran into serious delays after parsing the scene (and before rendering starts), where an acceleration structure is build. So I will focus on solving those problems in the next release. I assume that I need to implement the counterpart to the folowing C++ class, which deals with memory allocation:
> rg -tcpp "MemoryArena \{" ~/git/github/pbrt-v3/src -B 4 -A 3
/usr/people/jan/git/github/pbrt-v3/src/core/memory.h
58-class
59-#ifdef PBRT_HAVE_ALIGNAS
60-alignas(PBRT_L1_CACHE_LINE_SIZE)
61-#endif // PBRT_HAVE_ALIGNAS
62: MemoryArena {
63- public:
64- // MemoryArena Public Methods
65- MemoryArena(size_t blockSize = 262144) : blockSize(blockSize) {}
I was so focused on getting path tracing working, that I didn't realize that the PBRT scene was actually flipped in x-direction. Version 0.2.1 can handle scale transformations, which I use to compensate for that:
Scale -1 1 1 # swap x-axis direction
I created also a new test scene, called simple room, which was originally a Radiance scene:
What's missing in this release is to handle OpenEXR input textures, which could be used in conjunction with infinte light sources to simulate the effect of a sun&sky shader (which PBRT does not implement):
LightSource "infinite"
"integer samples" [ 4 ]
"spectrum L" [ 2.0 2.0 ]
"string mapname" "textures/baked_sky.exr"
The original scene uses such an outdoor lighting, which would be visible in the reflections of the crystal sphere.
The next new scene includes a cafe scene lit by two different set of lights:
Version 0.2.0 can parse and render the Cornell Box scene correctly (with path tracing):
> ./target/release/examples/pest_test -i assets/scenes/cornell_box.pbrt
...
Writing image "pbrt.png" ...
done.
Low settings render in below 5 seconds:
Using higher settings creates a less noisy picture:
The changed settings can be seen in the diff output:
diff --git a/pbrt/assets/scenes/cornell_box.pbrt b/pbrt/assets/scenes/cornell_box.pbrt
index fcd79a6..4159b54 100644
--- a/pbrt/assets/scenes/cornell_box.pbrt
+++ b/pbrt/assets/scenes/cornell_box.pbrt
@@ -9,8 +9,9 @@ Film "image"
"integer yresolution" [ 500 ]
## "integer outlierrejection_k" [ 10 ]
##Sampler "sobol"
-Sampler "lowdiscrepancy" "integer pixelsamples" [8]
+Sampler "lowdiscrepancy" "integer pixelsamples" [512]
##PixelFilter "blackmanharris"
+PixelFilter "gaussian" "float xwidth" [2.000000 ] "float ywidth" [2.000000 ]
##SurfaceIntegrator "bidirectional"
##Integrator "directlighting" "integer maxdepth" [10]
##Integrator "ambientocclusion"
It also supports rendering ambient occlusion (AO):
You have to change the following line to use the AOIntegrator
:
Integrator "ambientocclusion"
Version 0.1.13 can parse and render the Cornell Box scene correctly (with direct lighting):
> ./target/release/examples/pest_test -i assets/scenes/cornell_box.pbrt
...
Writing image "pbrt.png" ...
done.
The scene will later be used for global illumination.
The resulting image matches the C++ counterpart a hundred percent:
> imf_diff -d -f pbrt.png pbrt_cpp.png
pbrt.png pbrt_cpp.png: no differences.
== "pbrt.png" and "pbrt_cpp.png" are identical
The teapot scene matches, after fixing a bug in the
ZeroTwoSequenceSampler
, as well, beside a couple of pixels, probably
due to the usage of HDR (OpenEXR) on the C++ side:
> imf_diff -d -f pbrt.png teapot-area-light.png diff.jpg
differing pixels: 0.008% (5 of 65536)
average difference: 0.907%
maximum difference: 0.907%
Summary: 5 pixels differ slightly.
== "pbrt.png" and "teapot-area-light.png" are similar
Version 0.1.12 can parse and render the teapot scene correctly:
> ./target/release/examples/pest_test -i assets/scenes/teapot-area-light.pbrt
...
Writing image "pbrt.png" ...
done.
If you compare that with the result rendered by the C++ version of PBRT:
You will notice only minor differences. The problem is that we still use slightly different setting on the C++ side. I updated the scene description file so we use the same settings on the C++ side and the Rust side:
> diff teapot-area-light.pbrt teapot-area-light.pbrt.~90ae05b4d49cbbd900b8ef5f55be46f25de0557d~
8,11c8,9
< Integrator "directlighting" "integer maxdepth" [10]
< #Integrator "directlighting"
< Sampler "lowdiscrepancy" "integer pixelsamples" [1]
< #Sampler "halton" "integer pixelsamples" [8]
---
> Integrator "directlighting"
> Sampler "halton" "integer pixelsamples" [8]
13c11
< #Accelerator "kdtree"
---
> Accelerator "kdtree"
Now the resulting differences are only visible with false colors:
> imf_diff -d -f pbrt.png teapot-area-light.png diff.jpg
differing pixels: 0.273% (179 of 65536)
average difference: 4.640%
maximum difference: 53.807%
Summary: Some pixels differ strongly.
== "pbrt.png" and "teapot-area-light.png" are different
Version 0.1.11 can parse and render another provided test scenes now:
> ./target/release/examples/pest_test -i assets/scenes/teapot-area-light.pbrt
...
Writing image "pbrt.png" ...
done.
If you compare that with the result rendered by the C++ version of PBRT:
You will notice that only the point light does illuminate the scene, but not the area light source emitted by the disk shape:
...
AttributeBegin
...
AreaLightSource "area" "integer nsamples" [16 ] "color L" [8 8 8]
...
Shape "disk" "float height" 0.000000 "float radius" 2.000000
AttributeEnd
...
AttributeBegin
CoordSysTransform "camera"
LightSource "point" "color I" [ 50 50 50 ]
AttributeEnd
...
We also ignore the Sampler "halton" ...
and Accelerator "kdtree"1
lines for now.
An interesting fact of this release is that we do avoid a fatal runtime error, a stack overflow, by spawning a thread with a bigger stack:
use std::thread;
...
fn main() {
let child = thread::Builder::new().stack_size(32 * 1024 * 1024).spawn(move || {
...
}).unwrap();
let _res = child.join().unwrap();
}
The next release should illuminate this scene as well with the area light source.
Version 0.1.10 can parse and render the first provided test scenes now:
> ./target/release/examples/pest_test -i assets/scenes/spheres-differentials-texfilt.pbrt
...
Writing image "pbrt.png" ...
done.
The second provided scene can be parsed but does not render (yet):
> ./target/release/examples/pest_test -i assets/scenes/example.pbrt
...
do something with created tokens ...
...
TODO: UVMapping2D
...
TODO: CreateDiskShape
...
WorldEnd
done.
The next release should either render that second test scene or provide another scene which renders.
Version 0.1.9 can parse both provided test scenes now:
> ./target/release/examples/pest_test -i assets/scenes/example.pbrt
FILE = assets/scenes/example.pbrt
[Token { rule: statement, start: 0, end: 30 }, ...
... Token { rule: last_statement, start: 732, end: 741 }]
do something with created tokens ...
LookAt 0 10 100 0 -1 0 0 1 0
Camera "perspective"
"float fov" [30]
PixelFilter "mitchell"
"float xwidth" [2]
"float ywidth" [2]
Sampler "halton"
Film "image"
"integer xresolution" [200]
"integer yresolution" [200]
"string filename" ["simple.png"]
WorldBegin
AttributeBegin
CoordSysTransform "camera"
LightSource "distant"
"point from" [0 0 0]
"point to" [0 0 1]
"rgb L" [3 3 3]
AttributeEnd
AttributeBegin
Rotate 135 1 0 0
Texture "checks" "spectrum" "checkerboard"
"float uscale" [4]
"float vscale" [4]
"rgb tex1" [1 0 0]
"rgb tex2" [0 0 1]
Material "matte"
"texture Kd" "checks"
Shape "disk"
"float radius" [20]
"float height" [-1]
AttributeEnd
WorldEnd
done.
The second scene should render in the next release after parsing the scene description:
> ./target/release/examples/pest_test -i assets/scenes/spheres-differentials-texfilt.pbrt
FILE = assets/scenes/spheres-differentials-texfilt.pbrt
[Token { rule: statement, start: 1, end: 29 }, ...
... Token { rule: last_statement, start: 1070, end: 1079 }]
do something with created tokens ...
LookAt 2 2 5 0 -0.4 0 0 1 0
Camera "perspective"
"float fov" [30]
Film "image"
"integer xresolution" [1000]
"integer yresolution" [500]
"string filename" ["spheres-differentials-texfilt.exr"]
Integrator "directlighting"
"integer maxdepth" [10]
Sampler "lowdiscrepancy"
"integer pixelsamples" [1]
PixelFilter "box"
WorldBegin
LightSource "distant"
"point from" [0 10 0]
"point to" [0 0 0]
"rgb L" [3.141593 3.141593 3.141593]
AttributeBegin
Translate 0.25 0 0
Texture "checker" "color" "checkerboard"
"vector v1" [1 0 0]
"vector v2" [0 0 1]
"string mapping" ["planar"]
"string aamode" ["none"]
Texture "lines-tex" "color" "imagemap"
"float uscale" [100]
"float vscale" [100]
"string filename" ["textures/lines.png"]
Material "matte"
"texture Kd" "lines-tex"
Shape "trianglemesh"
"integer indices" [ 0 2 1 0 3 2 ]
"float st" [ 0 0 1 0 0 1 1 1 ]
"point P" [
-100 -1 -100
400 -1 -100
400 -1 400
-100 -1 400
]
AttributeEnd
Translate -1.3 0 0
Material "mirror"
Shape "sphere"
Translate 2.6 0 0
Material "glass"
Shape "sphere"
WorldEnd
done.
Version 0.1.8 still keeps the library in a single file with 9725 lines of code:
> wc lib.rs
9725 42500 362833 lib.rs
The first 613 lines are mainly used to create parts of the documentation and example code mentioned there. More examples are kept in a subdirectory (called examples).
Version 0.1.8 consists of 73 public structs, 6 enums, 12 traits, and 86 public ""functions"":
> grep "^pub struct" lib.rs | wc
73 293 1943
> grep "^pub enum" lib.rs | wc
6 24 136
> grep "^pub trait" lib.rs | wc
12 49 281
> grep "^pub fn" lib.rs | wc
86 709 4934
This version still renders the images shown below, via an example, which generates a scene and gives you a couple of options how to render the scene:
> cargo test --release
> ./target/release/examples/pbrt_spheres_differentials_texfilt -h
Usage: ./target/release/examples/pbrt_spheres_differentials_texfilt [options]
Options:
-h, --help print this help menu
-c, --checker use procedural texture
-i, --image use image texture
-n, --none use no texture
-m, --matte use only matte materials
-v, --version print version number
There is another example program which can render a teapot scene with 2328 triangles:
But I removed the Rust code which generates most of the triangles and checked in only a version with the ground plane triangles. The reason is that the resulting 120k lines of Rust code take several minutes to compile.
Therefore I started to work on issue #3 and invested some time to investigate, if I could use a crate called pest to write a parser for the scene description. The current example code has a help message, which tells you how to parse an input file:
> ./target/release/examples/pest_test -h
Usage: ./target/release/examples/pest_test [options]
Options:
-h, --help print this help menu
-i FILE parse an input file
-v, --version print version number
Warning: If you want to compile the pest_test executable you need to download and compile with Rust nightly:
rustup install nightly
rustup default nightly
If you run the example executable with one of the provided examples (currently only one works), you will see that tokens get generated:
> ./target/release/examples/pest_test -i assets/scenes/pest_test.pbrt
FILE = assets/scenes/pest_test.pbrt
[Token { rule: statement, start: 0, end: 30 }, Token { rule: look_at, start: 0, end: 30 }, ...
Token { rule: last_statement, start: 732, end: 740 }]
do something with created tokens ...
LookAt 0 10 100 0 -1 0 0 1 0
Camera "perspective"
"float fov" [30]
PixelFilter "mitchell"
"float xwidth" [2]
"float ywidth" [2]
Sampler "halton"
Film "image"
"integer xresolution" [200]
"integer yresolution" [200]
"string filename" ["simple.png"]
WorldBegin
AttributeBegin
CoordSysTransform "camera"
LightSource "distant"
"point from" [0 0 0]
"point to" [0 0 1]
"rgb L" [3 3 3]
AttributeEnd
AttributeBegin
Rotate 135 1 0 0
Texture "checks" "spectrum" "checkerboard"
"float uscale" [4]
"float vscale" [4]
"rgb tex1" [1 0 0]
"rgb tex2" [0 0 1]
Material "matte"
"texture Kd" "checks"
Shape "disk"
"float radius" [20]
"float height" [-1]
AttributeEnd
WorldEnd
done.
The tokens are then used to print the read information in a slightly different formating to prove that all read information is ready to be used in API calls to actually generate geometry and render a parsed scene description. I have to work on that API next and the parser has to be changed to parse more scene description files. I would say if it can parse the scene file used for the previous images I call it another release.
Version v0.1.7 renders the same image as v0.1.6 using all available CPUs.
Scene with a glass material on the first sphere and a mirror material on the second sphere. The ground triangles use a texture on a matte material. Rendered via the Rust version of PBRT:
Scene with a glass material on the first sphere and a mirror material on the second sphere. The ground triangles use a procedural checker texture on a matte material. Rendered via the Rust version of PBRT:
Scene with a glass material on the first sphere and a mirror material on the second sphere, rendered via Rust version of PBRT:
The scene should render correctly now (using matte, mirror, and glass materials).
- New structs:
SpecularTransmission
(implementingBxdf
trait),TrowbridgeReitzDistribution
- New functions:
nrm_faceforward_vec3()
,refract()
,fr_dielectric()
,GlassMaterial::bsdf()
,DirectLightingIntegrator::specular_transmit()
- New operators:
RGBSpectrum::operator-
- New parameters:
GlassMaterial::remap_roughness
- Changed signature of trait function
Fresnel::evaluate()
impl Fresnel for FresnelDielectric
- New
fresnel
parameter in constructor ofSpecularReflection
-
#[derive(PartialEq)]
forTransportMode
Scene with a mirror material on the second sphere, rendered via Rust version of PBRT:
The scene should render correctly now (using matte and mirror materials).
- Implemented
MirrorMaterial::compute_scattering_functions()
MirrorMaterial::bsdf()
- New
struct SpecularReflection
(implementingf()
,sample_f()
, andget_type()
forBxdf
trait) - New
trait Fresnel
withFresnel::evaluate()
- New struct
FresnelNoOp
implementingFresnel::evaluate()
Bxdf::sample_f()
-
LambertianReflection::sample_f()
andOrenNayar::sample_f()
-
Bsdf::components()
,Bsdf::local_to_world()
, andBsdf::sample_f()
SurfaceInteraction::spawn_ray()
- New functions
cosine_sample_hemisphere()
andconcentric_sample_disk()
-
operator+
andoperator*
onNormal3<T>
-
operator[]
onPoint2<T>
- New constants:
PI_OVER_2
andPI_OVER_4
- New utility function
cos_theta()
Correct picture for matte material rendered via Rust version of PBRT:
The scene should render correctly now (using only matte materials).
- Sphere::phi_max in radians
- implemented Transform::transform_surface_interaction()
- implemented Transform::transform_normal()
- implemented Transform::transform_point_with_abs_error()
- changed 'struct Shading' to use some normals instead of vectors
- added vec3_abs_dot_nrm()
- renamed vec3_cross() to vec3_cross_vec3()
- impl Neg for Normal3
- impl Div for Normal3
- added nrm_cross_vec3()
- added nrm_normalize()
- added nrm_dot_nrm()
- added nrm_faceforward_nrm()
Improved picture rendered via Rust version of PBRT:
Basically the black spots on the ground of the test scene are gone now.
- fixed bug in DistantLight::sample_li()
- switched to f32 for Float
- fixed get_1d()
- calculate ray.time via lerp()
- fixed some precision issues
- corrected absolute error for transformed point
- use double precision in vec3_cross()
- implement division by multiplying with inverse
- normalizing vectors
First picture rendered via Rust version of PBRT:
The original scene, rendered by the C++ version of PBRT, can be seen here.
Version 0.1.0 keeps the library in a single file with 7173 lines of code:
> wc lib.rs
7173 31925 268293 lib.rs
The first 613 lines are mainly used to create parts of the documentation and example code mentioned there. More examples are kept in a subdirectory (called examples) and the one file used to render the image above is called pbrt_spheres_differentials_texfilt.rs. Version 0.1.0 consists of 51 public structs, 5 enums, 5 traits, and 61 public functions:
> grep "^pub struct" lib.rs | wc
51 204 1302
> grep "^pub enum" lib.rs | wc
5 20 115
> grep "^pub trait" lib.rs | wc
5 20 108
> grep "^pub fn" lib.rs | wc
61 500 3549