Replies: 2 comments 2 replies
-
Hi @Dream4Leo, ![]() |
Beta Was this translation helpful? Give feedback.
-
Hi, Consider the following figure: If If instead, This convention allows for nearly symmetric implementations for both path and light tracing. Script for verificationYou can check that Mitsuba 3's BSDF implementation follows the above conventions by running the following script. import numpy as np
import matplotlib.pyplot as plt
import drjit as dr
import mitsuba as mi
mi.set_variant('scalar_rgb')
print(f"{dr.__version__ = }") # dr.__version__ = '0.4.6'
print(f"{mi.__version__ = }") # mi.__version__ = '3.5.2'
bsdf_diffuse = mi.load_dict({'type': 'diffuse',
'reflectance': {'type': 'rgb', 'value': [1, 1, 1]}})
bsdf_rd = mi.load_dict({'type': 'roughdielectric', 'alpha': 1.0})
bsdf_list = [bsdf_diffuse, bsdf_rd]
ang_list = [0, 60, -120]
w_list = [mi.Vector3f([dr.sin(dr.deg2rad(deg)), 0, dr.cos(dr.deg2rad(deg))]) for deg in ang_list]
mode_list = [mi.TransportMode.Radiance, mi.TransportMode.Importance]
for bsdf in bsdf_list:
print("\n---------- BSDF ----------\n", bsdf)
for i_m, mode in enumerate(mode_list):
print(f"\n# mi.{mode}")
ctx = mi.BSDFContext(mode)
for i_wi, (wi, wi_label) in enumerate(zip(w_list, ang_list)):
for i_wo, (wo, wo_label) in enumerate(zip(w_list, ang_list)):
si = mi.SurfaceInteraction3f()
si.wi = wi
val = bsdf.eval(ctx, si, wo)
print(f"[wi:{wi_label:4d}, wo:{wo_label:4d}] bsdf.eval(si.wi, wo) == {val}")
# ---------- Test `bsdf.eval()` for diffuse ----------
if bsdf is bsdf_diffuse:
bsdf_GT = 1 / dr.pi # Relationship between albedo and BRDF
if wo.z >= 0 and wi.z >= 0: # BRDF only
assert dr.allclose(val / dr.abs(wo.z), bsdf_GT)
# ---------- Test `mi.TransportMode` ----------
ctx_rev = mi.BSDFContext(mode_list[1-i_m])
si_rev = mi.SurfaceInteraction3f()
si_rev.wi = wo
assert dr.allclose(val * dr.abs(wi.z), bsdf.eval(ctx_rev, si_rev, wi) * dr.abs(wo.z)) Running this should pass all assertions. Instead of reporting all the printed message, I would like to highlight several parts which help our understanding about Mitsuba 3's implementation.
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
In mitsuba, particle tracer samples an emitter ray, intersects the scene at a point
SurfaceInteraction3f si
and connects it to the sensor. The contribution of this light path is evaluated byconnect_sensor()
and splat to the sensor.Inside
connect_sensor()
, the surface interaction is computed inbsdf->eval()
, wheresi.wi
would indicate direction to emitter, andwo
to sensor, which is the opposite way to a path tracer.This is where I start to get confused:
bsdf->eval()
multiplies the cosine forshortening term, and in particle tracer it means to multiply dot(n,wo), the cosine angle between emitter direction and normal. At first glance it seems to be incorrect.I do know that for reciprocal BSDFs, light transport is reversible, so we can treat as if light emits from the sensor. And a simple test on cornell box indeed shows matching renderings between path tracer and particle tracer. But it is difficult to convince myself on the following example:
Consider a perspective camera at [0,0,1] above a diffuse surface z=0, and a directional emitter at grazing angle (say, dir=[0,-1,-0.01]), one-bounce. Path tracer will produce near-zero contributions (roughly 0.01/pi) for each sample, while particle tracer will have 1/pi. Therefore, I would expect particle tracer to render a much brighter image. But again both renderings match (not strictly but close mean disregarding the variance).
Did I miss something?
Beta Was this translation helpful? Give feedback.
All reactions