def test05_specular_reflection(variant_scalar_rgb): from mitsuba.core import Matrix4f from mitsuba.render.mueller import specular_reflection import numpy as np # Identity matrix (and no phase shift) at perpendicular incidence assert ek.allclose(specular_reflection(1, 1.5), Matrix4f.identity()*0.04) assert ek.allclose(specular_reflection(1, 1/1.5), Matrix4f.identity()*0.04) # 180 deg phase shift at grazing incidence assert ek.allclose(specular_reflection(0, 1.5), [[1,0,0,0],[0,1,0,0],[0,0,-1,0],[0,0,0,-1]], atol=1e-6) assert ek.allclose(specular_reflection(0, 1/1.5), [[1,0,0,0],[0,1,0,0],[0,0,-1,0],[0,0,0,-1]], atol=1e-6) # Perfect linear polarization at Brewster's angle M = np.zeros((4, 4)) M[0:2, 0:2] = 0.0739645 assert ek.allclose(specular_reflection(ek.cos(ek.atan(1/1.5)), 1/1.5), M, atol=1e-6) assert ek.allclose(specular_reflection(ek.cos(ek.atan(1.5)), 1.5), M, atol=1e-6) # 180 deg phase shift just below Brewster's angle (air -> glass) M = specular_reflection(ek.cos(ek.atan(1.5)+1e-4), 1.5) assert M[0, 0] > 0 and M[1, 1] > 0 and M[2, 2] < 0 and M[3, 3] < 0 M = specular_reflection(ek.cos(ek.atan(1/1.5)+1e-4), 1/1.5) assert M[0, 0] > 0 and M[1, 1] > 0 and M[2, 2] < 0 and M[3, 3] < 0 # Complex phase shift in the total internal reflection case eta = 1/1.5 cos_theta_min = ek.sqrt((1 - eta**2) / (1 + eta**2)) M = specular_reflection(cos_theta_min, eta).numpy() assert np.all(M[0:2, 2:4] == 0) and np.all(M[2:4, 0:2] == 0) and ek.allclose(M[0:2, 0:2], np.eye(2), atol=1e-6) phi_delta = 4*ek.atan(eta) assert ek.allclose(M[2:4, 2:4], [[ek.cos(phi_delta), ek.sin(phi_delta)], [-ek.sin(phi_delta), ek.cos(phi_delta)]])
def test16_sin(m): x = ek.linspace(m.Float, 0, 10, 10) ek.enable_grad(x) y = ek.sin(x) ek.backward(y) assert ek.allclose(ek.detach(y), ek.sin(ek.detach(x))) assert ek.allclose(ek.grad(x), ek.cos(ek.detach(x)))
def test02_unit_frame(variant_scalar_rgb): from mitsuba.core import Frame3f, Vector2f, Vector3f for theta in [30 * mitsuba.core.math.Pi / 180, 95 * mitsuba.core.math.Pi / 180]: phi = 73 * mitsuba.core.math.Pi / 180 sin_theta, cos_theta = ek.sin(theta), ek.cos(theta) sin_phi, cos_phi = ek.sin(phi), ek.cos(phi) v = Vector3f( cos_phi * sin_theta, sin_phi * sin_theta, cos_theta ) f = Frame3f(Vector3f(1.0, 2.0, 3.0) / ek.sqrt(14)) v2 = f.to_local(v) v3 = f.to_world(v2) assert ek.allclose(v3, v) assert ek.allclose(Frame3f.cos_theta(v), cos_theta) assert ek.allclose(Frame3f.sin_theta(v), sin_theta) assert ek.allclose(Frame3f.cos_phi(v), cos_phi) assert ek.allclose(Frame3f.sin_phi(v), sin_phi) assert ek.allclose(Frame3f.cos_theta_2(v), cos_theta * cos_theta) assert ek.allclose(Frame3f.sin_theta_2(v), sin_theta * sin_theta) assert ek.allclose(Frame3f.cos_phi_2(v), cos_phi * cos_phi) assert ek.allclose(Frame3f.sin_phi_2(v), sin_phi * sin_phi) assert ek.allclose(Vector2f(Frame3f.sincos_phi(v)), [sin_phi, cos_phi]) assert ek.allclose(Vector2f(Frame3f.sincos_phi_2(v)), [sin_phi * sin_phi, cos_phi * cos_phi])
def test04_snell(variant_packet_rgb): from mitsuba.render import fresnel # Snell's law theta_i = ek.linspace(Float, 0, ek.pi / 2, 20) F, cos_theta_t, _, _ = fresnel(ek.cos(theta_i), 1.5) theta_t = ek.acos(cos_theta_t) assert ek.allclose(ek.sin(theta_i) - 1.5 * ek.sin(theta_t), Float.zero(20), atol=1e-5)
def test03_smith_g1_beckmann(variant_packet_rgb): from mitsuba.core import Vector3f from mitsuba.render import MicrofacetDistribution, MicrofacetType # Compare against data obtained from previous Mitsuba v0.6 implementation mdf = MicrofacetDistribution(MicrofacetType.Beckmann, 0.1, 0.3, False) mdf_i = MicrofacetDistribution(MicrofacetType.Beckmann, 0.1, False) steps = 20 theta = ek.linspace(Float, ek.pi / 3, ek.pi / 2, steps) phi = Float.full(ek.pi / 2, steps) cos_theta, sin_theta = ek.cos(theta), ek.sin(theta) cos_phi, sin_phi = ek.cos(phi), ek.sin(phi) v = [cos_phi * sin_theta, sin_phi * sin_theta, cos_theta] wi = Vector3f(0, 0, 1) ek.set_slices(wi, steps) assert np.allclose(mdf.smith_g1(v, wi), [ 1.0000000e+00, 1.0000000e+00, 1.0000000e+00, 1.0000523e+00, 9.9941480e-01, 9.9757767e-01, 9.9420297e-01, 9.8884594e-01, 9.8091525e-01, 9.6961778e-01, 9.5387781e-01, 9.3222123e-01, 9.0260512e-01, 8.6216795e-01, 8.0686140e-01, 7.3091686e-01, 6.2609726e-01, 4.8074335e-01, 2.7883825e-01, 1.9197471e-06 ]) assert ek.allclose(mdf_i.smith_g1(v, wi), [ 1.0000000e+00, 1.0000000e+00, 1.0000000e+00, 1.0000000e+00, 1.0000000e+00, 1.0000000e+00, 1.0000000e+00, 1.0000000e+00, 1.0000000e+00, 1.0000000e+00, 1.0000000e+00, 1.0000000e+00, 1.0000000e+00, 1.0000000e+00, 9.9828446e-01, 9.8627287e-01, 9.5088160e-01, 8.5989666e-01, 6.2535185e-01, 5.7592310e-06 ]) steps = 20 theta = Float.full(ek.pi / 2 * 0.98, steps) phi = ek.linspace(Float, 0, 2 * ek.pi, steps) cos_theta, sin_theta = ek.cos(theta), ek.sin(theta) cos_phi, sin_phi = ek.cos(phi), ek.sin(phi) v = [cos_phi * sin_theta, sin_phi * sin_theta, cos_theta] assert ek.allclose(mdf.smith_g1(v, wi), [ 0.67333597, 0.56164336, 0.42798978, 0.35298213, 0.31838724, 0.31201753, 0.33166203, 0.38421196, 0.48717275, 0.63746351, 0.63746351, 0.48717275, 0.38421196, 0.33166203, 0.31201753, 0.31838724, 0.35298213, 0.42798978, 0.56164336, 0.67333597 ]) assert ek.allclose(mdf_i.smith_g1(v, wi), Float.full(0.67333597, steps))
def test09_trig(): for i in range(-5, 5): for j in range(-5, 5): a = ek.sin(C(i, j)) b = C(cmath.sin(complex(i, j))) assert ek.allclose(a, b) a = ek.cos(C(i, j)) b = C(cmath.cos(complex(i, j))) assert ek.allclose(a, b) sa, ca = ek.sincos(C(i, j)) sb = C(cmath.sin(complex(i, j))) cb = C(cmath.cos(complex(i, j))) assert ek.allclose(sa, sb) assert ek.allclose(ca, cb) # Python appears to handle the branch cuts # differently from Enoki, C, and Mathematica.. a = ek.asin(C(i, j + 0.1)) b = C(cmath.asin(complex(i, j + 0.1))) assert ek.allclose(a, b) a = ek.acos(C(i, j + 0.1)) b = C(cmath.acos(complex(i, j + 0.1))) assert ek.allclose(a, b) if abs(j) != 1 or i != 0: a = ek.atan(C(i, j)) b = C(cmath.atan(complex(i, j))) assert ek.allclose(a, b, atol=1e-7)
def test03_smith_g1_ggx(variant_packet_rgb): from mitsuba.render import MicrofacetDistribution, MicrofacetType # Compare against data obtained from previous Mitsuba v0.6 implementation mdf = MicrofacetDistribution(MicrofacetType.GGX, 0.1, 0.3, False) mdf_i = MicrofacetDistribution(MicrofacetType.GGX, 0.1, False) steps = 20 theta = ek.linspace(Float, ek.pi / 3, ek.pi / 2, steps) phi = Float.full(ek.pi / 2, steps) cos_theta, sin_theta = ek.cos(theta), ek.sin(theta) cos_phi, sin_phi = ek.cos(phi), ek.sin(phi) v = [cos_phi * sin_theta, sin_phi * sin_theta, cos_theta] wi = np.tile([0, 0, 1], (steps, 1)) assert ek.allclose(mdf.smith_g1(v, wi), [ 9.4031686e-01, 9.3310797e-01, 9.2485082e-01, 9.1534841e-01, 9.0435863e-01, 8.9158219e-01, 8.7664890e-01, 8.5909742e-01, 8.3835226e-01, 8.1369340e-01, 7.8421932e-01, 7.4880326e-01, 7.0604056e-01, 6.5419233e-01, 5.9112519e-01, 5.1425743e-01, 4.2051861e-01, 3.0633566e-01, 1.6765384e-01, 1.0861372e-06 ]) assert ek.allclose(mdf_i.smith_g1(v, wi), [ 9.9261039e-01, 9.9160647e-01, 9.9042398e-01, 9.8901933e-01, 9.8733366e-01, 9.8528832e-01, 9.8277503e-01, 9.7964239e-01, 9.7567332e-01, 9.7054905e-01, 9.6378750e-01, 9.5463598e-01, 9.4187391e-01, 9.2344058e-01, 8.9569420e-01, 8.5189372e-01, 7.7902949e-01, 6.5144652e-01, 4.1989169e-01, 3.2584082e-06 ]) theta = Float.full(ek.pi / 2 * 0.98, steps) phi = ek.linspace(Float, 0, 2 * ek.pi, steps) cos_theta, sin_theta = ek.cos(theta), ek.sin(theta) cos_phi, sin_phi = ek.cos(phi), ek.sin(phi) v = [cos_phi * sin_theta, sin_phi * sin_theta, cos_theta] assert ek.allclose(mdf.smith_g1(v, wi), [ 0.46130955, 0.36801264, 0.26822716, 0.21645154, 0.19341162, 0.18922243, 0.20219423, 0.23769052, 0.31108665, 0.43013984, 0.43013984, 0.31108665, 0.23769052, 0.20219423, 0.18922243, 0.19341162, 0.21645154, 0.26822716, 0.36801264, 0.46130955 ]) assert ek.allclose(mdf_i.smith_g1(v, wi), Float.full(0.46130955, steps))
def csc_(a0): if not a0.IsFloat: raise Exception("csc(): requires floating point operands!") if not a0.IsSpecial: ar, sr = _check1(a0) for i in range(sr): ar[i] = _ek.csc(a0[i]) else: return 1 / _ek.sin(a0) return ar
def sin_(a0): if not a0.IsFloat: raise Exception("sin(): requires floating point operands!") ar, sr = _check1(a0) if not a0.IsSpecial: for i in range(sr): ar[i] = _ek.sin(a0[i]) elif a0.IsComplex: s, c = _ek.sincos(a0.real) sh, ch = _ek.sincosh(a0.imag) ar.real = s * ch ar.imag = c * sh else: raise Exception("sin(): unsupported array type!") return ar
def test04_linear_polarizer_rotated(variant_scalar_rgb): from mitsuba.render.mueller import rotated_element, linear_polarizer, rotator # The closed-form expression for a rotated linear polarizer is available # in many textbooks and should match the behavior of manually rotating the # optical element. angle = 33 * ek.pi/180 s, c = ek.sin(2*angle), ek.cos(2*angle) M_ref = ek.scalar.Matrix4f([[1, c, s, 0], [c, c*c, s*c, 0], [s, s*c, s*s, 0], [0, 0, 0, 0]]) * 0.5 R = rotator(angle) L = linear_polarizer() M = rotated_element(angle, L) assert ek.allclose(M, M_ref)
def test02_eval_pdf(variant_scalar_rgb): from mitsuba.core import Frame3f from mitsuba.render import BSDFContext, BSDFFlags, SurfaceInteraction3f from mitsuba.core.xml import load_string bsdf = load_string("<bsdf version='2.0.0' type='diffuse'></bsdf>") si = SurfaceInteraction3f() si.p = [0, 0, 0] si.n = [0, 0, 1] si.wi = [0, 0, 1] si.sh_frame = Frame3f(si.n) ctx = BSDFContext() for i in range(20): theta = i / 19.0 * (ek.pi / 2) wo = [ek.sin(theta), 0, ek.cos(theta)] v_pdf = bsdf.pdf(ctx, si, wo=wo) v_eval = bsdf.eval(ctx, si, wo=wo)[0] assert ek.allclose(v_pdf, wo[2] / ek.pi) assert ek.allclose(v_eval, 0.5 * wo[2] / ek.pi)
def sample_cone(sample, cos_theta_max): cos_theta = (1 - sample[1]) + sample[1] * cos_theta_max sin_theta = ek.sqrt(1 - cos_theta * cos_theta) phi = 2 * ek.pi * sample[0] s, c = ek.sin(phi), ek.cos(phi) return [c * sin_theta, s * sin_theta, cos_theta]
def K(self, x, m_): return ek.rsqrt(1 - m_ * ek.sqr(ek.sin(x)))
def y_1_n1(colors, theta, phi): K = ek.sqrt(3.0 / (4 * ek.pi)) return K * ek.sin(phi) * -ek.sin(theta) * colors
def test15_differentiable_surface_interaction_params_forward( variant_gpu_autodiff_rgb): from mitsuba.core import xml, Float, Ray3f, Vector3f, UInt32, Transform4f # Convert flat array into a vector of arrays (will be included in next enoki release) def ravel(buf, dim=3): idx = dim * UInt32.arange(ek.slices(buf) // dim) if dim == 2: return Vector2f(ek.gather(buf, idx), ek.gather(buf, idx + 1)) elif dim == 3: return Vector3f(ek.gather(buf, idx), ek.gather(buf, idx + 1), ek.gather(buf, idx + 2)) # Return contiguous flattened array (will be included in next enoki release) def unravel(source, target, dim=3): idx = UInt32.arange(ek.slices(source)) for i in range(dim): ek.scatter(target, source[i], dim * idx + i) scene = xml.load_string(''' <scene version="2.0.0"> <shape type="obj" id="rect"> <string name="filename" value="resources/data/common/meshes/rectangle.obj"/> </shape> </scene> ''') params = traverse(scene) shape_param_key = 'rect.vertex_positions_buf' positions_buf = params[shape_param_key] positions_initial = ravel(positions_buf) # Create differential parameter to be optimized diff_vector = Vector3f(0.0) ek.set_requires_gradient(diff_vector) # Apply the transformation to mesh vertex position and update scene def apply_transformation(trasfo): trasfo = trasfo(diff_vector) new_positions = trasfo.transform_point(positions_initial) unravel(new_positions, params[shape_param_key]) params.set_dirty(shape_param_key) params.update() # --------------------------------------- # Test translation ray = Ray3f(Vector3f(-0.2, -0.3, -10.0), Vector3f(0.0, 0.0, 1.0), 0, []) pi = scene.ray_intersect_preliminary(ray) # # If the vertices are shifted along z-axis, so does si.t apply_transformation(lambda v: Transform4f.translate(v)) si = pi.compute_surface_interaction(ray) ek.forward(diff_vector.z) assert ek.allclose(ek.gradient(si.t), 1) # If the vertices are shifted along z-axis, so does si.p apply_transformation(lambda v: Transform4f.translate(v)) si = pi.compute_surface_interaction(ray) ek.forward(diff_vector.z) assert ek.allclose(ek.gradient(si.p), [0.0, 0.0, 1.0]) # If the vertices are shifted along x-axis, so does si.uv (times 0.5) apply_transformation(lambda v: Transform4f.translate(v)) si = pi.compute_surface_interaction(ray) ek.forward(diff_vector.x) assert ek.allclose(ek.gradient(si.uv), [-0.5, 0.0]) # If the vertices are shifted along y-axis, so does si.uv (times 0.5) apply_transformation(lambda v: Transform4f.translate(v)) si = pi.compute_surface_interaction(ray) ek.forward(diff_vector.y) assert ek.allclose(ek.gradient(si.uv), [0.0, -0.5]) # --------------------------------------- # Test rotation ray = Ray3f(Vector3f(-0.99999, -0.99999, -10.0), Vector3f(0.0, 0.0, 1.0), 0, []) pi = scene.ray_intersect_preliminary(ray) # If the vertices are rotated around the center, so does si.uv (times 0.5) apply_transformation(lambda v: Transform4f.rotate([0, 0, 1], v.x)) si = pi.compute_surface_interaction(ray) ek.forward(diff_vector.x) du = 0.5 * ek.sin(2 * ek.pi / 360.0) assert ek.allclose(ek.gradient(si.uv), [-du, du], atol=1e-6)
def y_2_n2(colors, theta, phi): K = ek.sqrt(15.0 / (4 * ek.pi)) return K * ek.sin(phi) * ek.cos(phi) * ek.pow(ek.sin(theta), 2) * colors
def y_2_p1(colors, theta, phi): K = ek.sqrt(15.0 / (4 * ek.pi)) return K * ek.cos(phi) * ek.sin(theta) * -ek.cos(theta) * colors
def instantiate(args): wi = [0, 0, 1] if len(args) == 1: angle = args[0] * ek.pi / 180 wi = [ek.sin(angle), 0, ek.cos(angle)] return MicrofacetDistribution(md_type, alpha, sample_visible), wi
def test02_eval_pdf_beckmann(variant_packet_rgb): from mitsuba.core import Vector3f from mitsuba.render import MicrofacetDistribution, MicrofacetType # Compare against data obtained from previous Mitsuba v0.6 implementation mdf = MicrofacetDistribution(MicrofacetType.Beckmann, 0.1, 0.3, False) mdf_i = MicrofacetDistribution(MicrofacetType.Beckmann, 0.1, False) assert not mdf.is_isotropic() assert mdf.is_anisotropic() assert mdf_i.is_isotropic() assert not mdf_i.is_anisotropic() steps = 20 theta = ek.linspace(Float, 0, ek.pi, steps) phi = Float.full(ek.pi / 2, steps) cos_theta, sin_theta = ek.cos(theta), ek.sin(theta) cos_phi, sin_phi = ek.cos(phi), ek.sin(phi) v = [cos_phi * sin_theta, sin_phi * sin_theta, cos_theta] wi = Vector3f(0, 0, 1) ek.set_slices(wi, steps) assert ek.allclose(mdf.eval(v), [ 1.06103287e+01, 8.22650051e+00, 3.57923722e+00, 6.84863329e-01, 3.26460004e-02, 1.01964230e-04, 5.87322635e-10, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00 ]) assert ek.allclose(mdf.pdf(wi, v), [ 1.06103287e+01, 8.11430168e+00, 3.38530421e+00, 6.02319300e-01, 2.57622823e-02, 6.90584930e-05, 3.21235011e-10, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00 ]) assert ek.allclose(mdf_i.eval(v), [ 3.18309879e+01, 2.07673073e+00, 3.02855828e-04, 1.01591990e-11, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00 ]) assert ek.allclose(mdf_i.pdf(wi, v), [ 3.18309879e+01, 2.04840684e+00, 2.86446273e-04, 8.93474877e-12, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00, -0.00000000e+00 ]) theta = Float.full(0.1, steps) phi = ek.linspace(Float, 0, 2 * ek.pi, steps) cos_theta, sin_theta = ek.cos(theta), ek.sin(theta) cos_phi, sin_phi = ek.cos(phi), ek.sin(phi) v = [cos_phi * sin_theta, sin_phi * sin_theta, cos_theta] assert ek.allclose(mdf.eval(v), [ 3.95569706, 4.34706259, 5.54415846, 7.4061389, 9.17129803, 9.62056446, 8.37803268, 6.42071199, 4.84459257, 4.05276537, 4.05276537, 4.84459257, 6.42071199, 8.37803268, 9.62056446, 9.17129803, 7.4061389, 5.54415846, 4.34706259, 3.95569706 ]) assert ek.allclose( mdf.pdf(wi, v), Float([ 3.95569706, 4.34706259, 5.54415846, 7.4061389, 9.17129803, 9.62056446, 8.37803268, 6.42071199, 4.84459257, 4.05276537, 4.05276537, 4.84459257, 6.42071199, 8.37803268, 9.62056446, 9.17129803, 7.4061389, 5.54415846, 4.34706259, 3.95569706 ]) * ek.cos(0.1)) assert ek.allclose(mdf_i.eval(v), Float.full(11.86709118, steps)) assert ek.allclose(mdf_i.pdf(wi, v), Float.full(11.86709118 * ek.cos(0.1), steps))
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 y_2_p2(colors, theta, phi): K = ek.sqrt(15.0 / (16 * ek.pi)) return K * (ek.pow(ek.cos(phi), 2) - ek.pow(ek.sin(phi), 2)) * ek.pow( ek.sin(theta), 2) * colors