|
| 1 | +import pytest |
| 2 | +import drjit as dr |
| 3 | +import mitsuba as mi |
| 4 | + |
| 5 | +from mitsuba.scalar_rgb.test.util import fresolver_append_path |
| 6 | + |
| 7 | + |
| 8 | +spectrum_dicts = { |
| 9 | + 'd65': { |
| 10 | + "type": "d65", |
| 11 | + }, |
| 12 | + 'regular': { |
| 13 | + "type": "regular", |
| 14 | + "wavelength_min": 500, |
| 15 | + "wavelength_max": 600, |
| 16 | + "values": "1, 2" |
| 17 | + } |
| 18 | +} |
| 19 | + |
| 20 | + |
| 21 | +@fresolver_append_path |
| 22 | +def create_emitter_and_spectrum(s_key='d65'): |
| 23 | + emitter = mi.load_dict({ |
| 24 | + "type": "obj", |
| 25 | + "filename": "resources/data/tests/obj/cbox_smallbox.obj", |
| 26 | + "emitter" : { "type": "volumelight", "radiance" : spectrum_dicts[s_key] } |
| 27 | + }) |
| 28 | + spectrum = mi.load_dict(spectrum_dicts[s_key]) |
| 29 | + expanded = spectrum.expand() |
| 30 | + if len(expanded) == 1: |
| 31 | + spectrum = expanded[0] |
| 32 | + |
| 33 | + return emitter, spectrum |
| 34 | + |
| 35 | + |
| 36 | +def test01_constructor(variant_scalar_rgb): |
| 37 | + # Check that the shape is properly bound to the emitter |
| 38 | + shape, spectrum = create_emitter_and_spectrum() |
| 39 | + assert shape.emitter().bbox() == shape.bbox() |
| 40 | + |
| 41 | + # Check that we are not allowed to specify a to_world transform directly in the emitter. |
| 42 | + with pytest.raises(RuntimeError): |
| 43 | + e = mi.load_dict({ |
| 44 | + "type" : "volumelight", |
| 45 | + "to_world" : mi.ScalarTransform4f.translate([5, 0, 0]) |
| 46 | + }) |
| 47 | + |
| 48 | + |
| 49 | +@pytest.mark.parametrize("spectrum_key", spectrum_dicts.keys()) |
| 50 | +def test02_eval(variants_vec_spectral, spectrum_key): |
| 51 | + # Check that eval() return the same values as the 'radiance' spectrum |
| 52 | + |
| 53 | + shape, spectrum = create_emitter_and_spectrum(spectrum_key) |
| 54 | + emitter = shape.emitter() |
| 55 | + |
| 56 | + it = dr.zeros(mi.SurfaceInteraction3f, 3) |
| 57 | + assert dr.allclose(emitter.eval(it), spectrum.eval(it)) |
| 58 | + |
| 59 | + # Check that eval returns 0.0 when the sample point is outside the shape |
| 60 | + it.p = mi.ScalarPoint3f([0.0, 0.0, 0.0]) |
| 61 | + assert dr.allclose(emitter.eval(it), 0.0) |
| 62 | + |
| 63 | + |
| 64 | +@pytest.mark.parametrize("spectrum_key", spectrum_dicts.keys()) |
| 65 | +def test03_sample_ray(variants_vec_spectral, spectrum_key): |
| 66 | + # Check the correctness of the sample_ray() method |
| 67 | + |
| 68 | + shape, spectrum = create_emitter_and_spectrum(spectrum_key) |
| 69 | + emitter = shape.emitter() |
| 70 | + |
| 71 | + time = 0.5 |
| 72 | + wavelength_sample = [0.5, 0.33, 0.1] |
| 73 | + pos_sample = [[0.2, 0.1, 0.2], [0.6, 0.9, 0.2], [0.5]*3] |
| 74 | + dir_sample = [[0.4, 0.5, 0.3], [0.1, 0.4, 0.9]] |
| 75 | + |
| 76 | + # Sample a ray (position, direction, wavelengths) on the emitter |
| 77 | + ray, res = emitter.sample_ray(time, wavelength_sample, pos_sample, dir_sample) |
| 78 | + |
| 79 | + # Sample wavelengths on the spectrum |
| 80 | + it = dr.zeros(mi.SurfaceInteraction3f, 3) |
| 81 | + |
| 82 | + # Sample a position in the shape |
| 83 | + ps = shape.sample_position_3d(time, pos_sample) |
| 84 | + pdf = mi.warp.square_to_uniform_sphere_pdf(mi.warp.square_to_uniform_sphere(dir_sample)) |
| 85 | + it.p = ps.p |
| 86 | + it.n = ps.n |
| 87 | + it.time = time |
| 88 | + it.wavelengths = mi.Float(wavelength_sample) * (mi.MI_CIE_MAX - mi.MI_CIE_MIN) + mi.MI_CIE_MIN |
| 89 | + |
| 90 | + spec = dr.select(ps.pdf > 0.0, emitter.eval(it) * (mi.MI_CIE_MAX - mi.MI_CIE_MIN) / (ps.pdf * pdf), 0.0) |
| 91 | + assert dr.allclose(res, spec) |
| 92 | + assert dr.allclose(ray.time, time) |
| 93 | + assert dr.allclose(ray.o, ps.p, atol=2e-2) |
| 94 | + assert dr.allclose(ray.d, mi.Frame3f(ps.n).to_world(mi.warp.square_to_uniform_sphere(dir_sample))) |
| 95 | + |
| 96 | + |
| 97 | +@pytest.mark.parametrize("spectrum_key", spectrum_dicts.keys()) |
| 98 | +def test04_sample_direction(variants_vec_spectral, spectrum_key): |
| 99 | + # Check the correctness of the sample_direction(), pdf_direction(), and eval_direction() methods |
| 100 | + |
| 101 | + shape, spectrum = create_emitter_and_spectrum(spectrum_key) |
| 102 | + emitter = shape.emitter() |
| 103 | + |
| 104 | + # Direction sampling is conditioned on a sampled position |
| 105 | + it = dr.zeros(mi.SurfaceInteraction3f, 3) |
| 106 | + it.p = [[0.2, 0.1, 0.2], [0.6, -0.9, 0.2], |
| 107 | + [0.4, 0.9, -0.2]] # Some positions |
| 108 | + it.time = 1.0 |
| 109 | + |
| 110 | + # Sample direction on the emitter |
| 111 | + samples = [[0.4, 0.5, 0.3], [0.1, 0.4, 0.9], [0.5]*3] |
| 112 | + ds, res = emitter.sample_direction(it, samples) |
| 113 | + |
| 114 | + # Sample direction on the shape |
| 115 | + sphere_ds = dr.zeros(mi.DirectionSample3f) |
| 116 | + sphere_ds.p = it.p |
| 117 | + ps = shape.sample_position_3d(it.time, samples) |
| 118 | + sphere_ds.d = ps.p - it.p |
| 119 | + dist2 = dr.squared_norm(sphere_ds.d) |
| 120 | + sphere_ds.d = sphere_ds.d / dr.sqrt(dist2) |
| 121 | + sphere_ds.pdf = ps.pdf * dist2 |
| 122 | + |
| 123 | + assert dr.allclose(ds.pdf, sphere_ds.pdf) |
| 124 | + assert dr.allclose(ds.pdf, emitter.pdf_direction(it, ds)) |
| 125 | + assert dr.allclose(ds.d, sphere_ds.d, atol=1e-3) |
| 126 | + assert dr.allclose(ds.time, it.time) |
| 127 | + |
| 128 | + # Evaluate the spectrum (divide by the pdf) |
| 129 | + spec = dr.select(ds.pdf > 0.0, emitter.eval(it) / ds.pdf, 0.0) |
| 130 | + assert dr.allclose(res, spec) |
| 131 | + |
| 132 | + assert dr.allclose(emitter.eval_direction(it, ds), spec) |
0 commit comments