Skip to content

Commit

Permalink
Ensure correct rotation of backfacing retarders (#947)
Browse files Browse the repository at this point in the history
  • Loading branch information
dvicini committed Oct 19, 2023
1 parent 14fc606 commit 8033a80
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 6 deletions.
16 changes: 10 additions & 6 deletions src/bsdfs/retarder.cpp
Expand Up @@ -111,13 +111,15 @@ class LinearRetarder final : public BSDF<Float, Spectrum> {
UnpolarizedSpectrum delta = dr::deg_to_rad(m_delta->eval(si, active));

// Approximate angle-of-incidence behaviour with a cosine falloff
delta *= dr::abs(Frame3f::cos_theta(si.wi));
Float cos_theta = Frame3f::cos_theta(si.wi);
delta *= dr::abs(cos_theta);

// Get standard Mueller matrix for a linear polarizer.
Spectrum M = mueller::linear_retarder(delta);

// Rotate optical element by specified angle
M = mueller::rotated_element(theta, M);
/* Rotate optical element by specified angle. The angle is flipped if
the element is intersected from the backside. */
M = mueller::rotated_element(dr::sign(cos_theta) * theta, M);

/* The `forward` direction here is always along the direction that
light travels. This is needed for the coordinate system rotation
Expand Down Expand Up @@ -161,13 +163,15 @@ class LinearRetarder final : public BSDF<Float, Spectrum> {
UnpolarizedSpectrum delta = dr::deg_to_rad(m_delta->eval(si, active));

// Approximate angle-of-incidence behaviour with a cosine falloff
delta *= dr::abs(Frame3f::cos_theta(si.wi));
Float cos_theta = Frame3f::cos_theta(si.wi);
delta *= dr::abs(cos_theta);

// Get standard Mueller matrix for a linear polarizer.
Spectrum M = mueller::linear_retarder(delta);

// Rotate optical element by specified angle
M = mueller::rotated_element(theta, M);
/* Rotate optical element by specified angle. The angle is flipped if
the element is intersected from the backside. */
M = mueller::rotated_element(dr::sign(cos_theta) * theta, M);

/* The `forward` direction here is always along the direction that
light travels. This is needed for the coordinate system rotation
Expand Down
50 changes: 50 additions & 0 deletions src/bsdfs/tests/test_retarder.py
Expand Up @@ -497,3 +497,53 @@ def spectrum_from_stokes(v):
# Make sure observations match expectations
for k in range(len(expected)):
assert dr.allclose(observed[k], expected[k], atol=1e-3)


def test08_rotated_quarter_wave(variant_scalar_mono_polarized):

def spectrum_from_stokes(v):
res = mi.Spectrum(0.0)
for i in range(4):
res[i,0] = v[i]
return res

linear_horizontal = spectrum_from_stokes([1, +1, 0, 0])
linear_vertical = spectrum_from_stokes([1, -1, 0, 0])
circular_right = spectrum_from_stokes([1, 0, 0, +1])
circular_left = spectrum_from_stokes([1, 0, 0, -1])

bsdf = mi.load_dict({
'type': 'retarder',
'theta': 45.0,
'delta': 90.0,
})

ctx = mi.BSDFContext()
ctx.mode = mi.TransportMode.Importance
si = mi.SurfaceInteraction3f()
si.p = [0, 0, 0]
si.wi = [0, 0, 1]
n = [0, 0, 1]
si.n = n
si.sh_frame = mi.Frame3f(si.n)

_, M = bsdf.sample(ctx, si, 0.0, [0.0, 0.0])
M_null = bsdf.eval_null_transmission(si)
assert dr.allclose(M, M_null, atol=1e-3)

assert dr.allclose(M @ linear_horizontal, circular_right, atol=1e-3)
assert dr.allclose(M @ linear_vertical, circular_left, atol=1e-3)
assert dr.allclose(M @ circular_right, linear_vertical, atol=1e-3)
assert dr.allclose(M @ circular_left, linear_horizontal, atol=1e-3)

# Reverse incident direction.
si.wi = [0, 0, -1]

_, M = bsdf.sample(ctx, si, 0.0, [0.0, 0.0])
M_null = bsdf.eval_null_transmission(si)
assert dr.allclose(M, M_null, atol=1e-3)

assert dr.allclose(M @ linear_horizontal, circular_left, atol=1e-3)
assert dr.allclose(M @ linear_vertical, circular_right, atol=1e-3)
assert dr.allclose(M @ circular_right, linear_horizontal, atol=1e-3)
assert dr.allclose(M @ circular_left, linear_vertical, atol=1e-3)

0 comments on commit 8033a80

Please sign in to comment.