def test02_intersection_partials(variant_scalar_rgb): from mitsuba.core import Frame3f, Ray3f, RayDifferential3f from mitsuba.render import SurfaceInteraction3f # Test the texture partial computation with some random data o = [0.44650541, 0.16336525, 0.74225088] d = [0.2956123, 0.67325977, 0.67774232] time = 0.5 w = [] r = RayDifferential3f(o, d, time, w) r.o_x = r.o + [0.1, 0, 0] r.o_y = r.o + [0, 0.1, 0] r.d_x = r.d r.d_y = r.d r.has_differentials = True si = SurfaceInteraction3f() si.p = r(10) si.dp_du = [0.5514372, 0.84608955, 0.41559092] si.dp_dv = [0.14551054, 0.54917541, 0.39286475] si.n = ek.cross(si.dp_du, si.dp_dv) si.n /= ek.norm(si.n) si.t = 0 si.compute_partials(r) # Positions reached via computed partials px1 = si.dp_du * si.duv_dx[0] + si.dp_dv * si.duv_dx[1] py1 = si.dp_du * si.duv_dy[0] + si.dp_dv * si.duv_dy[1] # Manually px2 = r.o_x + r.d_x * \ ((ek.dot(si.n, si.p) - ek.dot(si.n, r.o_x)) / ek.dot(si.n, r.d_x)) py2 = r.o_y + r.d_y * \ ((ek.dot(si.n, si.p) - ek.dot(si.n, r.o_y)) / ek.dot(si.n, r.d_y)) px2 -= si.p py2 -= si.p assert (ek.allclose(px1, px2)) assert (ek.allclose(py1, py2)) si.dp_du = [0, 0, 0] si.compute_partials(r) assert (ek.allclose(px1, px2)) assert (ek.allclose(py1, py2)) si.compute_partials(r) assert (ek.allclose(si.duv_dx, [0, 0])) assert (ek.allclose(si.duv_dy, [0, 0]))
def det(m): if not _ek.is_matrix_v(m): raise Exception("Unsupported target type!") if m.Size == 1: return m[0, 0] elif m.Size == 2: return _ek.fmsub(m[0, 0], m[1, 1], m[0, 1] * m[1, 0]) elif m.Size == 3: return _ek.dot(m[0], _ek.cross(m[1], m[2])) elif m.Size == 4: col0, col1, col2, col3 = m col1 = _ek.shuffle((2, 3, 0, 1), col1) col3 = _ek.shuffle((2, 3, 0, 1), col3) temp = _ek.shuffle((1, 0, 3, 2), col2 * col3) row0 = col1 * temp temp = _ek.shuffle((2, 3, 0, 1), temp) row0 = _ek.fmsub(col1, temp, row0) temp = _ek.shuffle((1, 0, 3, 2), col1 * col2) row0 = _ek.fmadd(col3, temp, row0) temp = _ek.shuffle((2, 3, 0, 1), temp) row0 = _ek.fnmadd(col3, temp, row0) col1 = _ek.shuffle((2, 3, 0, 1), col1) col2 = _ek.shuffle((2, 3, 0, 1), col2) temp = _ek.shuffle((1, 0, 3, 2), col1 * col3) row0 = _ek.fmadd(col2, temp, row0) temp = _ek.shuffle((2, 3, 0, 1), temp) row0 = _ek.fnmadd(col2, temp, row0) return _ek.dot(col0, row0) else: raise Exception('Unsupported array size!')
def test02_sample_pol_local(variant_scalar_mono_polarized): from mitsuba.core import Frame3f, Transform4f, Spectrum, UnpolarizedSpectrum, Vector3f from mitsuba.core.xml import load_string from mitsuba.render import BSDFContext, TransportMode, SurfaceInteraction3f, fresnel_conductor from mitsuba.render.mueller import stokes_basis, rotate_mueller_basis def spectrum_from_stokes(v): res = Spectrum(0.0) for i in range(4): res[i, 0] = v[i] return res # Create a Silver conductor BSDF and reflect different polarization states # at a 45˚ angle. # All tests take place directly in local BSDF coordinates. Here we only # want to make sure that the output of this looks like what you would # expect from a Mueller matrix describing specular reflection on a mirror. eta = 0.136125 + 4.010625j # IoR values of Ag at 635.816284nm bsdf = load_string("""<bsdf version='2.0.0' type='conductor'> <spectrum name="eta" value="{}"/> <spectrum name="k" value="{}"/> </bsdf>""".format(eta.real, eta.imag)) theta_i = 45 * ek.pi / 180 wi = Vector3f([-ek.sin(theta_i), 0, ek.cos(theta_i)]) ctx = BSDFContext() ctx.mode = TransportMode.Importance si = SurfaceInteraction3f() si.p = [0, 0, 0] si.wi = wi n = [0, 0, 1] si.sh_frame = Frame3f(n) bs, M_local = bsdf.sample(ctx, si, 0.0, [0.0, 0.0]) wo = bs.wo # Rotate into standard coordinates for specular reflection bi_s = ek.normalize(ek.cross(n, -wi)) bi_p = ek.normalize(ek.cross(-wi, bi_s)) bo_s = ek.normalize(ek.cross(n, wo)) bo_p = ek.normalize(ek.cross(wo, bi_s)) M_local = rotate_mueller_basis(M_local, -wi, stokes_basis(-wi), bi_p, wo, stokes_basis(wo), bo_p) # Apply to unpolarized light and verify that it is equivalent to normal Fresnel a0 = M_local @ spectrum_from_stokes([1, 0, 0, 0]) F = fresnel_conductor(ek.cos(theta_i), ek.scalar.Complex2f(eta.real, eta.imag)) a0 = a0[0, 0] assert ek.allclose(a0[0], F, atol=1e-3) # Apply to horizontally polarized light (linear at 0˚) # Test that it is.. # 1) still fully polarized (though with reduced intensity) # 2) still horizontally polarized a1 = M_local @ spectrum_from_stokes([1, +1, 0, 0]) assert ek.allclose(a1[0, 0], ek.abs(a1[1, 0]), atol=1e-3) # 1) a1 /= a1[0, 0] assert ek.allclose(a1, spectrum_from_stokes([1, 1, 0, 0]), atol=1e-3) # 2) # Apply to vertically polarized light (linear at 90˚) # Test that it is.. # 1) still fully polarized (though with reduced intensity) # 2) still vertically polarized a2 = M_local @ spectrum_from_stokes([1, -1, 0, 0]) assert ek.allclose(a2[0, 0], ek.abs(a2[1, 0]), atol=1e-3) # 1) a2 /= a2[0, 0] assert ek.allclose(a2, spectrum_from_stokes([1, -1, 0, 0]), atol=1e-3) # 2) # Apply to (positive) diagonally polarized light (linear at +45˚) # Test that.. # 1) The polarization is flipped to -45˚ # 2) There is now also some (left) circular polarization a3 = M_local @ spectrum_from_stokes([1, 0, +1, 0]) assert ek.all(a3[2, 0] < UnpolarizedSpectrum(0.0)) assert ek.all(a3[3, 0] < UnpolarizedSpectrum(0.0)) # Apply to (negative) diagonally polarized light (linear at -45˚) # Test that.. # 1) The polarization is flipped to +45˚ # 2) There is now also some (right) circular polarization a4 = M_local @ spectrum_from_stokes([1, 0, -1, 0]) assert ek.all(a4[2, 0] > UnpolarizedSpectrum(0.0)) assert ek.all(a4[3, 0] > UnpolarizedSpectrum(0.0)) # Apply to right circularly polarized light # Test that the polarization is flipped to left circular a5 = M_local @ spectrum_from_stokes([1, 0, 0, +1]) assert ek.all(a5[3, 0] < UnpolarizedSpectrum(0.0)) # Apply to left circularly polarized light # Test that the polarization is flipped to right circular a6 = M_local @ spectrum_from_stokes([1, 0, 0, -1]) assert ek.all(a6[3, 0] > UnpolarizedSpectrum(0.0))
def inverse_transpose(m): if not _ek.is_matrix_v(m): raise Exception("Unsupported target type!") t = type(m) if m.Size == 1: return t(_ek.rcp(m[0, 0])) elif m.Size == 2: inv_det = _ek.rcp(_ek.fmsub(m[0, 0], m[1, 1], m[0, 1] * m[1, 0])) return t(m[1, 1] * inv_det, -m[1, 0] * inv_det, -m[0, 1] * inv_det, m[0, 0] * inv_det) elif m.Size == 3: col0, col1, col2 = m row0 = _ek.cross(col1, col2) row1 = _ek.cross(col2, col0) row2 = _ek.cross(col0, col1) inv_det = _ek.rcp(_ek.dot(col0, row0)) return t(row0 * inv_det, row1 * inv_det, row2 * inv_det) elif m.Size == 4: col0, col1, col2, col3 = m col1 = _ek.shuffle((2, 3, 0, 1), col1) col3 = _ek.shuffle((2, 3, 0, 1), col3) temp = _ek.shuffle((1, 0, 3, 2), col2 * col3) row0 = col1 * temp row1 = col0 * temp temp = _ek.shuffle((2, 3, 0, 1), temp) row0 = _ek.fmsub(col1, temp, row0) row1 = _ek.shuffle((2, 3, 0, 1), _ek.fmsub(col0, temp, row1)) temp = _ek.shuffle((1, 0, 3, 2), col1 * col2) row0 = _ek.fmadd(col3, temp, row0) row3 = col0 * temp temp = _ek.shuffle((2, 3, 0, 1), temp) row0 = _ek.fnmadd(col3, temp, row0) row3 = _ek.shuffle((2, 3, 0, 1), _ek.fmsub(col0, temp, row3)) temp = _ek.shuffle((1, 0, 3, 2), _ek.shuffle((2, 3, 0, 1), col1) * col3) col2 = _ek.shuffle((2, 3, 0, 1), col2) row0 = _ek.fmadd(col2, temp, row0) row2 = col0 * temp temp = _ek.shuffle((2, 3, 0, 1), temp) row0 = _ek.fnmadd(col2, temp, row0) row2 = _ek.shuffle((2, 3, 0, 1), _ek.fmsub(col0, temp, row2)) temp = _ek.shuffle((1, 0, 3, 2), col0 * col1) row2 = _ek.fmadd(col3, temp, row2) row3 = _ek.fmsub(col2, temp, row3) temp = _ek.shuffle((2, 3, 0, 1), temp) row2 = _ek.fmsub(col3, temp, row2) row3 = _ek.fnmadd(col2, temp, row3) temp = _ek.shuffle((1, 0, 3, 2), col0 * col3) row1 = _ek.fnmadd(col2, temp, row1) row2 = _ek.fmadd(col1, temp, row2) temp = _ek.shuffle((2, 3, 0, 1), temp) row1 = _ek.fmadd(col2, temp, row1) row2 = _ek.fnmadd(col1, temp, row2) temp = _ek.shuffle((1, 0, 3, 2), col0 * col2) row1 = _ek.fmadd(col3, temp, row1) row3 = _ek.fnmadd(col1, temp, row3) temp = _ek.shuffle((2, 3, 0, 1), temp) row1 = _ek.fnmadd(col3, temp, row1) row3 = _ek.fmadd(col1, temp, row3) inv_det = _ek.rcp(_ek.dot(col0, row0)) return t(row0 * inv_det, row1 * inv_det, row2 * inv_det, row3 * inv_det) else: raise Exception('Unsupported array size!')