mmp / pbrt-v4

Source code to pbrt, the ray tracer described in the forthcoming 4th edition of the "Physically Based Rendering: From Theory to Implementation" book.
https://pbrt.org
Apache License 2.0
2.9k stars 461 forks source link

Medium differences between integrators #221

Open shadeops opened 2 years ago

shadeops commented 2 years ago

Summary

I noticed some differences with the homogeneous mediums on some box slabs between the different integrators. (I admittedly can't remember if this is a known issue, but some quick searching didn't turn up anything so opted to create a new issue.)

example

I used a high max depth, 50, to account for the fact that the wavefront integrator counts the interface intersections.

Example Scene

pbrt --cropwindow 0.35,0.45,0,1 ---gpu --spp 8192 --outfile wavefront.exr tmp.pbrt 
pbrt --cropwindow 0.45,0.55,0,1 --spp 8192  --outfile volpath.exr tmp.pbrt 
pbrt --cropwindow 0.55,0.65,0,1 --spp 8192  --outfile bdpt.exr tmp.pbrt
Film "rgb"
    "integer yresolution" [ 720 ]
    "integer xresolution" [ 1280 ]
    "string filename" [ "wavefront.exr" ]
PixelFilter "gaussian"
    "float yradius" [ 2 ]
    "float xradius" [ 2 ]
Sampler "zsobol"
    "integer pixelsamples" [ 1024 ]
Integrator "volpath"
#Integrator "bdpt"
    "integer maxdepth" [ 50 ]
Accelerator "bvh"
Translate 0 0 0.75
Camera "perspective"
    "float screenwindow" [ -1 1 -0.5625 0.5625 ]
    "float fov" [ 53.130104 ]

WorldBegin

AttributeBegin
    Rotate 90 1 0 0
    LightSource "distant"
        "float scale" [ 4 ]
AttributeEnd

MakeNamedMaterial "/mat/pbrt_material_interface1"
    "string type" [ "interface" ]

AttributeBegin
    MakeNamedMedium "/mat/pbrt_medium_homogeneous1"
        "rgb sigma_s" [ 0.9 0.9 0.9 ]
        "rgb sigma_a" [ 0.1 0.1 0.1 ]
        "float scale" [ 100 ]
        "string type" [ "homogeneous" ]

AttributeEnd

NamedMaterial "/mat/pbrt_material_interface1"
MediumInterface "/mat/pbrt_medium_homogeneous1" ""
ReverseOrientation

#  --------------------------------------------------
#  /obj/top_box
AttributeBegin
    Translate 0 0.025 0
    Shape "trianglemesh"
        "integer indices" [ 0 1 3 4 5 7 6 7 2 5 4 1 5 0 2 1 4 6 6 3 1 2 7 5 1 0 5 
                            2 3 6 7 6 4 3 2 0 ]
        "point3 P" [ 0.25 -0.01 0.25 -0.25 -0.01 0.25 0.25 0.01 0.25 -0.25 0.01 0.25 
                     -0.25 -0.01 -0.25 0.25 -0.01 -0.25 -0.25 0.01 -0.25 0.25 0.01 
                     -0.25 ]
AttributeEnd

#  --------------------------------------------------
#  /obj/mid_box
AttributeBegin
    Translate 0 0 0
    Shape "trianglemesh"
        "integer indices" [ 0 1 3 4 5 7 6 7 2 5 4 1 5 0 2 1 4 6 6 3 1 2 7 5 1 0 5 
                            2 3 6 7 6 4 3 2 0 ]
        "point3 P" [ 0.25 -0.01 0.25 -0.25 -0.01 0.25 0.25 0.01 0.25 -0.25 0.01 0.25 
                     -0.25 -0.01 -0.25 0.25 -0.01 -0.25 -0.25 0.01 -0.25 0.25 0.01 
                     -0.25 ]
AttributeEnd

#  --------------------------------------------------
#  /obj/bottom_box
AttributeBegin
    Translate 0 -0.025 0
    Shape "trianglemesh"
        "integer indices" [ 0 1 3 4 5 7 6 7 2 5 4 1 5 0 2 1 4 6 6 3 1 2 7 5 1 0 5 
                            2 3 6 7 6 4 3 2 0 ]
        "point3 P" [ 0.25 -0.01 0.25 -0.25 -0.01 0.25 0.25 0.01 0.25 -0.25 0.01 0.25 
                     -0.25 -0.01 -0.25 0.25 -0.01 -0.25 -0.25 0.01 -0.25 0.25 0.01 
                     -0.25 ]
AttributeEnd
shadeops commented 2 years ago

Another example between VolPath and Wavefront. In this scene there is a unit cube with a homogeneous interior medium, then another cube inside that has the same homogeneous medium set for both the interior and exterior. Rendering I get the following -

VolPath

volpath

Wavefront

gpu

The VolPath matches my mental model, where the inner cube just eats up some depth hits but the Wavefront integrator isn't able to handle this case.

Scene

Film "rgb"
    "integer yresolution" [ 256 ]
    "integer xresolution" [ 256 ]
    "string filename" [ "example_2.exr" ]
PixelFilter "gaussian"
    "float yradius" [ 2 ]
    "float xradius" [ 2 ]
Sampler "zsobol"
    "integer pixelsamples" [ 1024 ]
Integrator "volpath"
    "integer maxdepth" [ 50 ]
Accelerator "bvh"
Translate 0 0 2
Camera "orthographic"
    "float screenwindow" [ -1 1 -1 1 ]

WorldBegin

AttributeBegin
    Rotate 90 1 0 0
    LightSource "distant"
        "float scale" [ 1 ]
AttributeEnd

MakeNamedMaterial "/mat/pbrt_material_interface1"
    "string type" [ "interface" ]

AttributeBegin
    MakeNamedMedium "/mat/pbrt_medium_homogeneous1"
        "rgb sigma_s" [ 0.9 0.9 0.9 ]
        "rgb sigma_a" [ 0.1 0.1 0.1 ]
        "float scale" [ 1 ]
        "string type" [ "homogeneous" ]

AttributeEnd

NamedMaterial "/mat/pbrt_material_interface1"

ReverseOrientation

#  --------------------------------------------------
#  outer_box
AttributeBegin
    MediumInterface "/mat/pbrt_medium_homogeneous1" ""
    Shape "trianglemesh"
        "integer indices" [ 0 1 3 4 5 7 6 7 2 5 4 1 5 0 2 1 4 6 6 3 1 2 7 5 1 0 5 
                            2 3 6 7 6 4 3 2 0 ]
        "point3 P" [ 1 -1 1 -1 -1 1 1 1 1 -1 1 1 -1 -1 -1 1 -1 -1 -1 1 -1 1 1 -1 ]
AttributeEnd

#  --------------------------------------------------
#  inner_box
AttributeBegin
    MediumInterface "/mat/pbrt_medium_homogeneous1" "/mat/pbrt_medium_homogeneous1"
    Scale 0.5 0.5 0.5
    Shape "trianglemesh"
        "integer indices" [ 0 1 3 4 5 7 6 7 2 5 4 1 5 0 2 1 4 6 6 3 1 2 7 5 1 0 5 
                            2 3 6 7 6 4 3 2 0 ]
        "point3 P" [ 1 -1 1 -1 -1 1 1 1 1 -1 1 1 -1 -1 -1 1 -1 -1 -1 1 -1 1 1 -1 ]
AttributeEnd
mmp commented 2 years ago

I finally got a chance to look at this; apologies for not digging in sooner. It was quite an "interesting" one; it took a while to figure out what the issue was.

While trying to figure out what was going on, I tried the test case below where the outer box is (basically) only absorptive and where the inner box is an emissive volume (and there is no other light source.) We find:

Volpath

volpath

Wavefront

wavefront

Film "rgb"
    "integer yresolution" [ 256 ]
    "integer xresolution" [ 256 ]
    "string filename" [ "example_2.exr" ]
PixelFilter "gaussian"
    "float yradius" [ 2 ]
    "float xradius" [ 2 ]
Sampler "zsobol"
    "integer pixelsamples" [ 32 ]
Integrator "volpath"
    "integer maxdepth" [ 50 ]
Accelerator "bvh"
Translate 0 0 2
Camera "orthographic"
    "float screenwindow" [ -1 1 -1 1 ]

WorldBegin

AttributeBegin
    Rotate 90 1 0 0
#    LightSource "distant"
#        "float scale" [ 1 ]
AttributeEnd

MakeNamedMaterial "/mat/pbrt_material_interface1"
    "string type" [ "interface" ]

AttributeBegin
    MakeNamedMedium "/mat/pbrt_medium_homogeneous1"
        "rgb sigma_s" [ 0.000001 0.000001 0.000001 ]
        "rgb sigma_a" [ 1 1 1 ]
        "float scale" [ 1 ]
        "string type" [ "homogeneous" ]
    MakeNamedMedium "/mat/pbrt_medium_homogeneous1-emit"
        "rgb sigma_s" [ 0.0 0.0 0.0 ]
        "rgb sigma_a" [ .1 .1 .1 ]
        "rgb Le" [10 10 10]
        "float scale" [ 1 ]
        "string type" [ "homogeneous" ]

#        "string type" [ "uniformgrid" ]
#"integer nx" 4 "integer ny" 4 "integer nz" 4
#"float density" [ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
#1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
#1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
#1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ]
#"point3 p0" [ -2 -2 -2 ] 
#"point3 p1" [ 2 2 2 ] 

AttributeEnd

NamedMaterial "/mat/pbrt_material_interface1"

ReverseOrientation

#  --------------------------------------------------
#  outer_box
AttributeBegin
    MediumInterface "/mat/pbrt_medium_homogeneous1" ""
    Shape "trianglemesh"
        "integer indices" [ 0 1 3 4 5 7 6 7 2 5 4 1 5 0 2 1 4 6 6 3 1 2 7 5 1 0 5 
                            2 3 6 7 6 4 3 2 0 ]
        "point3 P" [ 1 -1 1 -1 -1 1 1 1 1 -1 1 1 -1 -1 -1 1 -1 -1 -1 1 -1 1 1 -1 ]
AttributeEnd

#  --------------------------------------------------
#  inner_box
AttributeBegin
    MediumInterface "/mat/pbrt_medium_homogeneous1-emit" "/mat/pbrt_medium_homogeneous1"
#Translate 0 0 0.495
    Scale 0.5 0.5 0.5
    Shape "trianglemesh"
        "integer indices" [ 0 1 3 4 5 7 6 7 2 5 4 1 5 0 2 1 4 6 6 3 1 2 7 5 1 0 5 
                            2 3 6 7 6 4 3 2 0 ]
        "point3 P" [ 1 -1 1 -1 -1 1 1 1 1 -1 1 1 -1 -1 -1 1 -1 -1 -1 1 -1 1 1 -1 ]
AttributeEnd

With the wavefront integrator, we don't see the emissive volume at all. Surely this is a bug related to tracking which medium the ray is in? Turns out, it is not. Perhaps a bug related to homogeneous media? Not that either. Nor a number of other theories.

It turns out that with the wavefront integrator the same random sample was being used to sample depth in the medium along the ray for both the outside box and the inside box. So, for this latest test case, if the sample's value was relatively low, a volume interaction would be sampled in the outer box which would be an absorption event and the ray would terminate. If it was higher so that the sampled point was past the boundary of the inner box, there would be no scattering event in the outer box and sampling would begin in the inner box. But... with a large sample value, then it would always sample a point along the ray that was beyond the extent of the inner box and bam, the emissive volume is never sampled. (And so, the same was happening with the other test cases.)

I haven't yet had a chance to look at the BDPT discrepancy, so leaving this open for now...

shadeops commented 2 years ago

Thanks @mmp, and I really appreciate you taking the time to explain what the issue was.