def test_directional(mode_mono): from mitsuba.core.xml import load_dict # We need a default spectral config ctx = KernelDictContext() # Constructor d = DirectionalIllumination() assert load_dict(onedict_value(d.kernel_dict(ctx))) is not None # Check if a more detailed spec is valid d = DirectionalIllumination(irradiance={"type": "uniform", "value": 1.0}) assert load_dict(onedict_value(d.kernel_dict(ctx))) is not None # Check if solar irradiance spectrum can be used d = DirectionalIllumination(irradiance={"type": "solar_irradiance"}) assert load_dict(onedict_value(d.kernel_dict(ctx))) is not None # Check if specification from a float works d = DirectionalIllumination(irradiance=1.0) assert load_dict(onedict_value(d.kernel_dict(ctx))) is not None # Check if specification from a constant works d = DirectionalIllumination(irradiance=ureg.Quantity(1.0, "W/m^2/nm")) assert load_dict(onedict_value(d.kernel_dict(ctx))) is not None with pytest.raises(pinttr.exceptions.UnitsError): # Wrong units DirectionalIllumination(irradiance=ureg.Quantity(1.0, "W/m^2/sr/nm"))
def test04_surface_area(variant_scalar_rgb): from mitsuba.core import xml, Transform4f # Unifomly-scaled rectangle rect = xml.load_dict({ "type": "rectangle", "to_world": Transform4f([[2, 0, 0, 0], [0, 2, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) }) assert ek.allclose(rect.surface_area(), 2.0 * 2.0 * 2.0 * 2.0) # Rectangle sheared along the Z-axis rect = xml.load_dict({ "type": "rectangle", "to_world": Transform4f([[1, 0, 0, 0], [0, 1, 0, 0], [1, 0, 1, 0], [0, 0, 0, 1]]) }) assert ek.allclose(rect.surface_area(), 2.0 * 2.0 * ek.sqrt(2.0)) # Rectangle sheared along the X-axis (shouldn't affect surface_area) rect = xml.load_dict({ "type": "rectangle", "to_world": Transform4f([[1, 1, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) }) assert ek.allclose(rect.surface_area(), 2.0 * 2.0)
def example_scene(shape, scale=1.0, translate=[0, 0, 0], angle=0.0): from mitsuba.core import xml, ScalarTransform4f as T to_world = T.translate(translate) * T.rotate([0, 1, 0], angle) * T.scale(scale) shape2 = shape.copy() shape2['to_world'] = to_world s = xml.load_dict({'type': 'scene', 'shape': shape2}) s_inst = xml.load_dict({ 'type': 'scene', 'group_0': { 'type': 'shapegroup', 'shape': shape }, 'instance': { 'type': 'instance', "group": { "type": "ref", "id": "group_0" }, 'to_world': to_world } }) return s, s_inst
def test01_create(variant_scalar_rgb): from mitsuba.core import xml, ScalarTransform4f s = xml.load_dict({"type": "sphere"}) assert s is not None assert s.primitive_count() == 1 assert ek.allclose(s.surface_area(), 4 * ek.pi) # Test transforms order in constructor rot = ScalarTransform4f.rotate([1.0, 0.0, 0.0], 35) s1 = xml.load_dict({ "type": "sphere", "radius": 2.0, "center": [1, 0, 0], "to_world": rot }) s2 = xml.load_dict({ "type": "sphere", "to_world": rot * ScalarTransform4f.translate([1, 0, 0]) * ScalarTransform4f.scale(2) }) assert str(s1) == str(s2)
def test8_dict_unreferenced_attribute_error(variants_all_rgb): from mitsuba.core import xml with pytest.raises(Exception) as e: xml.load_dict({ "type" : "point", "foo": 0.44 }) e.match("Unreferenced attribute")
def test2_dict_missing_type(variants_all_rgb): from mitsuba.core import xml with pytest.raises(Exception) as e: xml.load_dict({ "center" : [0, 0, -10], "radius" : 10.0, }) e.match("""Missing key 'type'""")
def test03_ray_intersect(variant_scalar_rgb): from mitsuba.core import xml, Ray3f, Transform4f # Scalar scene = xml.load_dict({ "type": "scene", "foo": { "type": "rectangle", "to_world": Transform4f.scale((2.0, 0.5, 1.0)) } }) n = 15 coords = ek.linspace(Float, -1, 1, n) rays = [ Ray3f(o=[a, a, 5], d=[0, 0, -1], time=0.0, wavelengths=[]) for a in coords ] si_scalar = [] valid_count = 0 for i in range(n): its_found = scene.ray_test(rays[i]) si = scene.ray_intersect(rays[i]) assert its_found == (abs(coords[i]) <= 0.5) assert si.is_valid() == its_found si_scalar.append(si) valid_count += its_found assert valid_count == 7 try: mitsuba.set_variant('packet_rgb') from mitsuba.core import xml, Ray3f as Ray3fX except ImportError: pytest.skip("packet_rgb mode not enabled") # Packet scene_p = xml.load_dict({ "type": "scene", "foo": { "type": "rectangle", "to_world": Transform4f.scale((2.0, 0.5, 1.0)) } }) packet = Ray3fX.zero(n) for i in range(n): packet[i] = rays[i] si_p = scene_p.ray_intersect(packet) its_found_p = scene_p.ray_test(packet) assert ek.all(si_p.is_valid() == its_found_p) for i in range(n): assert ek.allclose(si_p.t[i], si_scalar[i].t)
def test10_xml_rgb(variants_scalar_all): from mitsuba.python.xml import dict_to_xml from mitsuba.core.xml import load_dict, load_file from mitsuba.core import Thread, ScalarColor3f fr = Thread.thread().file_resolver() mts_root = str(fr[len(fr) - 1]) filepath = os.path.join(mts_root, 'resources/data/scenes/dict10/dict.xml') fr.append(os.path.dirname(filepath)) d1 = { 'type': 'scene', 'point': { "type": "point", "intensity": { "type": "rgb", "value": ScalarColor3f(0.5, 0.2, 0.5) } } } d2 = { 'type': 'scene', 'point': { "type": "point", "intensity": { "type": "rgb", "value": [0.5, 0.2, 0.5] # list -> ScalarColor3f } } } dict_to_xml(d1, filepath) s1 = load_file(filepath) dict_to_xml(d2, filepath) s2 = load_file(filepath) s3 = load_dict(d1) assert str(s1) == str(s2) assert str(s1) == str(s3) d1 = { 'type': 'scene', 'point': { "type": "point", "intensity": { "type": "rgb", "value": 0.5 # float -> ScalarColor3f } } } dict_to_xml(d1, filepath) s1 = load_file(filepath) s2 = load_dict(d1) assert str(s1) == str(s2) rmtree(os.path.split(filepath)[0])
def test10_dict_expand_nested_object(variant_scalar_rgb): from mitsuba.core import xml # Nested dictionary objects should be expanded b0 = xml.load_dict({ "type" : "diffuse", "reflectance" : { "type" : "bitmap", "filename" : "resources/data/common/textures/museum.exr" } }) b1 = xml.load_string(""" <bsdf type="diffuse" version="2.0.0"> <texture type="bitmap" name="reflectance"> <string name="filename" value="resources/data/common/textures/museum.exr"/> </texture> </bsdf> """) assert str(b0) == str(b1) # Check that root object isn't expanded texture = xml.load_dict({ "type" : "bitmap", "filename" : "resources/data/common/textures/museum.exr" }) assert len(texture.expand()) == 1 # But we should be able to use this object in another dict, and it will be expanded b3 = xml.load_dict({ "type" : "diffuse", "reflectance" : texture }) assert str(b0) == str(b3) # Object should be expanded when used through a reference scene = xml.load_dict({ "type" : "scene", "mytexture" : { "type" : "bitmap", "filename" : "resources/data/common/textures/museum.exr" }, "shape1" : { "type" : "sphere", "bsdf" : { "type" : "diffuse", "reflectance" : { "type" : "ref", "id" : "mytexture" } } }, }) assert str(b0) == str(scene.shapes()[0].bsdf())
def test_incoming_flux_integrator(variant_scalar_rgb, radiance): """ We test the recorded power density of the irradiance meter, by creating a simple scene: The irradiance meter is attached to a sphere with unit radius at the coordinate origin surrounded by a constant environment emitter. We render the scene with the path tracer integrator and compare the recorded power density with our theoretical expectation. We expect the average value to be \\pi * L with L the radiance of the constant emitter. """ from mitsuba.core import Spectrum, Bitmap, Struct, ScalarVector3f from mitsuba.core.xml import load_dict scene_dict = { "type": "scene", "sensor": sensor_shape_dict(1, ScalarVector3f(0, 0, 0)), "emitter": constant_emitter_dict(radiance), "integrator": {"type": "path"} } scene = load_dict(scene_dict) sensor = scene.sensors()[0] scene.integrator().render(scene, sensor) film = sensor.film() img = film.bitmap(raw=True).convert(Bitmap.PixelFormat.Y, Struct.Type.Float32, srgb_gamma=False) image_np = np.array(img) ek.allclose(image_np, (radiance * ek.pi))
def create_camera(o, d, fov=34, fov_axis="x", s_open=1.5, s_close=5, aperture=0.1, focus_dist=15): from mitsuba.core.xml import load_dict from mitsuba.core import ScalarTransform4f, ScalarVector3f t = [o[0] + d[0], o[1] + d[1], o[2] + d[2]] camera_dict = { "type": "thinlens", "near_clip": 1.0, "far_clip": 35.0, "focus_distance": focus_dist, "aperture_radius": aperture, "fov": fov, "fov_axis": fov_axis, "shutter_open": s_open, "shutter_close": s_close, "to_world": ScalarTransform4f.look_at(origin=o, target=t, up=[0, 1, 0]), "film": { "type": "hdrfilm", "width": 512, "height": 256, } } return load_dict(camera_dict)
def test03_ray_intersect_instance(variants_all_rgb): from mitsuba.core import xml, Ray3f, ScalarVector3f, ScalarTransform4f as T """Check that we can the correct instance pointer when tracing a ray""" scene = xml.load_dict({ 'type': 'scene', 'group_0': { 'type': 'shapegroup', 'shape': { 'type': 'rectangle' } }, 'instance_00': { 'type': 'instance', "group": { "type": "ref", "id": "group_0" }, 'to_world': T.translate([-0.5, -0.5, 0.0]) * T.scale(0.5) }, 'instance_01': { 'type': 'instance', "group": { "type": "ref", "id": "group_0" }, 'to_world': T.translate([-0.5, 0.5, 0.0]) * T.scale(0.5) }, 'instance_10': { 'type': 'instance', "group": { "type": "ref", "id": "group_0" }, 'to_world': T.translate([0.5, -0.5, 0.0]) * T.scale(0.5) }, 'shape': { 'type': 'rectangle', 'to_world': T.translate([0.5, 0.5, 0.0]) * T.scale(0.5) } }) ray = Ray3f([-0.5, -0.5, -12], [0.0, 0.0, 1.0], 0.0, []) pi = scene.ray_intersect_preliminary(ray) assert '[0.5, 0, 0, -0.5]' in str(pi) assert '[0, 0.5, 0, -0.5]' in str(pi) ray = Ray3f([-0.5, 0.5, -12], [0.0, 0.0, 1.0], 0.0, []) pi = scene.ray_intersect_preliminary(ray) assert '[0.5, 0, 0, -0.5]' in str(pi) assert '[0, 0.5, 0, 0.5]' in str(pi) ray = Ray3f([0.5, -0.5, -12], [0.0, 0.0, 1.0], 0.0, []) pi = scene.ray_intersect_preliminary(ray) assert '[0.5, 0, 0, 0.5]' in str(pi) assert '[0, 0.5, 0, -0.5]' in str(pi) ray = Ray3f([0.5, 0.5, -12], [0.0, 0.0, 1.0], 0.0, []) pi = scene.ray_intersect_preliminary(ray) assert 'instance = nullptr' in str(pi) or 'instance = [nullptr]' in str(pi)
def test01_create(variant_scalar_rgb): from mitsuba.core import xml s = xml.load_dict({"type": "rectangle"}) assert s is not None assert s.primitive_count() == 1 assert ek.allclose(s.surface_area(), 4.0)
def test01_xml_save_plugin(variant_scalar_rgb): from mitsuba.core import xml from mitsuba.core import Thread from mitsuba.python.xml import dict_to_xml fr = Thread.thread().file_resolver() # Add the path to the mitsuba root folder, so that files are always saved in mitsuba/resources/... # This way we know where to look for the file in case the unit test fails mts_root = str(fr[len(fr) - 1]) filepath = os.path.join(mts_root, 'resources/data/scenes/dict01/dict.xml') fr.append(os.path.dirname(filepath)) scene_dict = { "type": "sphere", "center": [0, 0, -10], "radius": 10.0, } dict_to_xml(scene_dict, filepath) s1 = xml.load_dict({ 'type': 'scene', 'sphere': { "type": "sphere", "center": [0, 0, -10], "radius": 10.0, } }) s2 = xml.load_file(filepath) assert str(s1) == str(s2) rmtree(os.path.split(filepath)[0])
def create_emitter_and_spectrum(lookat, cutoff_angle, s_key='d65'): from mitsuba.core.xml import load_dict spectrum = load_dict(spectrum_strings[s_key]) expanded = spectrum.expand() if len(expanded) == 1: spectrum = expanded[0] emitter = load_dict({ 'type': 'spot', 'cutoff_angle': cutoff_angle, 'to_world': lookat, 'intensity': spectrum }) return emitter, spectrum
def test04_sample_direct(variant_scalar_rgb): from mitsuba.core import xml, Ray3f from mitsuba.render import Interaction3f sphere = xml.load_dict({"type": "sphere"}) 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] it = Interaction3f.zero() it.p = [0, 0, -3] it.t = 0 sin_cone_angle = 1.0 / it.p[2] cos_cone_angle = ek.sqrt(1 - sin_cone_angle**2) for xi_1 in ek.linspace(Float, 0, 1, 10): for xi_2 in ek.linspace(Float, 1e-3, 1 - 1e-3, 10): sample = sphere.sample_direction(it, [xi_2, 1 - xi_1]) d = sample_cone([xi_1, xi_2], cos_cone_angle) its = sphere.ray_intersect(Ray3f(it.p, d, 0, [])) assert ek.allclose(d, sample.d, atol=1e-5, rtol=1e-5) assert ek.allclose(its.t, sample.dist, atol=1e-5, rtol=1e-5) assert ek.allclose(its.p, sample.p, atol=1e-5, rtol=1e-5)
def test01_create(variant_scalar_rgb): from mitsuba.core import xml, ScalarTransform4f s = xml.load_dict({ 'type': 'shapegroup', 'shape_01': { 'type': 'sphere', 'radius': 1.0, 'to_world': ScalarTransform4f.translate([-2, 0, 0]) }, 'shape_02': { 'type': 'sphere', 'radius': 1.0, 'to_world': ScalarTransform4f.translate([2, 0, 0]) } }) b = s.bbox() assert s is not None assert s.primitive_count() == 2 assert s.effective_primitive_count() == 0 assert s.surface_area() == 0 assert ek.allclose(b.center(), [0, 0, 0]) assert ek.allclose(b.min, [-3, -1, -1]) assert ek.allclose(b.max, [3, 1, 1])
def test09_xml_decompose_transform(variant_scalar_rgb): from mitsuba.python.xml import dict_to_xml from mitsuba.core.xml import load_dict, load_file from mitsuba.core import Transform4f, Vector3f, Thread fr = Thread.thread().file_resolver() mts_root = str(fr[len(fr) - 1]) filepath = os.path.join(mts_root, 'resources/data/scenes/dict09/dict.xml') fr.append(os.path.dirname(filepath)) scene_dict = { 'type': 'scene', 'cam': { 'type': 'perspective', 'fov_axis': 'x', 'fov': 35, 'to_world': Transform4f.look_at(Vector3f(15, 42.3, 25), Vector3f(1.0, 0.0, 0.5), Vector3f(1.0, 0.0, 0.0)) } } dict_to_xml(scene_dict, filepath) s1 = load_file(filepath) s2 = load_dict(scene_dict) vects = [Vector3f(0, 0, 1), Vector3f(0, 1, 0), Vector3f(1, 0, 0)] tr1 = s1.sensors()[0].world_transform().eval(0) tr2 = s2.sensors()[0].world_transform().eval(0) for vec in vects: assert tr1.transform_point(vec) == tr2.transform_point(vec) rmtree(os.path.split(filepath)[0])
def test08_xml_defaults(variant_scalar_rgb): from mitsuba.python.xml import dict_to_xml from mitsuba.core import Thread from mitsuba.core.xml import load_dict, load_file fr = Thread.thread().file_resolver() mts_root = str(fr[len(fr) - 1]) filepath = os.path.join(mts_root, 'resources/data/scenes/dict08/dict.xml') fr.append(os.path.dirname(filepath)) spp = 250 resx = 1920 resy = 1080 scene_dict = { 'type': 'scene', 'cam': { 'type': 'perspective', 'fov_axis': 'x', 'fov': 35, 'sampler': { 'type': 'independent', 'sample_count': spp # --> default }, 'film': { 'type': 'hdrfilm', 'width': resx, # --> default 'height': resy # --> default } } } dict_to_xml(scene_dict, filepath) # Load a file using default values s1 = load_file(filepath) s2 = load_dict(scene_dict) assert str(s1.sensors()[0].film()) == str(s2.sensors()[0].film()) assert str(s1.sensors()[0].sampler()) == str(s2.sensors()[0].sampler()) # Set new parameters spp = 45 resx = 2048 resy = 485 # Load a file with options for the rendering parameters s3 = load_file(filepath, spp=spp, resx=resx, resy=resy) scene_dict['cam']['sampler']['sample_count'] = spp scene_dict['cam']['film']['width'] = resx scene_dict['cam']['film']['height'] = resy s4 = load_dict(scene_dict) assert str(s3.sensors()[0].film()) == str(s4.sensors()[0].film()) assert str(s3.sensors()[0].sampler()) == str(s4.sensors()[0].sampler()) rmtree(os.path.split(filepath)[0])
def test5_dict_nested_object(variants_all_rgb): from mitsuba.core import xml bsdf = xml.load_dict({"type" : "diffuse"}) s1 = xml.load_dict({ "type" : "sphere", "bsdf" : bsdf }) s2 = xml.load_string(""" <shape type="sphere" version="2.0.0"> <bsdf type="diffuse"/> </shape> """) assert str(s1.bsdf()) == str(s2.bsdf())
def test03_ray_intersect(variant_scalar_rgb): from mitsuba.core import xml, Ray3f, Transform4f for r in [1, 2, 4]: for l in [1, 5]: s = xml.load_dict({ "type": "scene", "foo": { "type": "cylinder", "to_world": Transform4f.scale((r, r, l)) } }) # grid size n = 10 for x in ek.linspace(Float, -1, 1, n): for z in ek.linspace(Float, -1, 1, n): x = 1.1 * r * x z = 1.1 * l * z ray = Ray3f(o=[x, -10, z], d=[0, 1, 0], time=0.0, wavelengths=[]) si_found = s.ray_test(ray) si = s.ray_intersect(ray) assert si_found == si.is_valid() assert si_found == ek.allclose(si.p[0]**2 + si.p[1]**2, r**2) if si_found: ray = Ray3f(o=[x, -10, z], d=[0, 1, 0], time=0.0, wavelengths=[]) si = s.ray_intersect(ray) ray_u = Ray3f(ray) ray_v = Ray3f(ray) eps = 1e-4 ray_u.o += si.dp_du * eps ray_v.o += si.dp_dv * eps si_u = s.ray_intersect(ray_u) si_v = s.ray_intersect(ray_v) dn = si.shape.normal_derivative(si, True, True) if si_u.is_valid(): dp_du = (si_u.p - si.p) / eps dn_du = (si_u.n - si.n) / eps assert ek.allclose(dp_du, si.dp_du, atol=2e-2) assert ek.allclose(dn_du, dn[0], atol=2e-2) if si_v.is_valid(): dp_dv = (si_v.p - si.p) / eps dn_dv = (si_v.n - si.n) / eps assert ek.allclose(dp_dv, si.dp_dv, atol=2e-2) assert ek.allclose(dn_dv, dn[1], atol=2e-2)
def test01_ldsampler_scalar(variant_scalar_rgb): from mitsuba.core import xml sampler = xml.load_dict({ "type" : "ldsampler", "sample_count" : 1024, }) check_uniform_scalar_sampler(sampler)
def test01_orthogonal_scalar(variant_scalar_rgb): from mitsuba.core import xml sampler = xml.load_dict({ "type": "orthogonal", "sample_count": 1369, }) check_uniform_scalar_sampler(sampler, res=4, atol=4.0)
def test02_orthogonal_wavefront(variant_gpu_rgb): from mitsuba.core import xml sampler = xml.load_dict({ "type": "orthogonal", "sample_count": 1369, }) check_uniform_wavefront_sampler(sampler, atol=4.0)
def test02_ldsampler_wavefront(variant_gpu_rgb): from mitsuba.core import xml sampler = xml.load_dict({ "type" : "ldsampler", "sample_count" : 1024, }) check_uniform_wavefront_sampler(sampler)
def test3_dict_simple_field(variants_all_rgb): from mitsuba.core import xml, ScalarPoint3f import numpy as np s1 = xml.load_dict({ "type" : "sphere", "center" : ScalarPoint3f(0, 0, -10), "radius" : 10.0, "flip_normals" : False, }) s2 = xml.load_dict({ "type" : "sphere", "center" : [0, 0, -10], # list -> ScalarPoint3f "radius" : 10, # int -> float "flip_normals" : False, }) s3 = xml.load_dict({ "type" : "sphere", "center" : np.array([0, 0, -10]), # numpy array -> ScalarPoint3f "radius" : 10.0, "flip_normals" : False, }) s4 = xml.load_dict({ "type" : "sphere", "center" : (0, 0, -10), # tuple -> ScalarPoint3f "radius" : 10.0, "flip_normals" : False, }) s5 = xml.load_string(""" <shape type="sphere" version="2.0.0"> <point name="center" value="0.0 0.0 -10.0"/> <float name="radius" value="10.0"/> <boolean name="flip_normals" value="false"/> </shape> """) assert str(s1) == str(s2) assert str(s1) == str(s3) assert str(s1) == str(s4) assert str(s1) == str(s5)
def test7_dict_spectrum(variants_scalar_all): from mitsuba.core import xml e1 = xml.load_dict({ "type" : "point", "intensity" : { "type" : "spectrum", "value" : [(400, 0.1), (500, 0.2), (600, 0.4), (700, 0.1)] } }) e2 = xml.load_string(""" <emitter type="point" version="2.0.0"> <spectrum name="intensity" value="400:0.1 500:0.2 600:0.4 700:0.1"/> </emitter> """) assert str(e1) == str(e2) e1 = xml.load_dict({ "type" : "point", "intensity" : { "type" : "spectrum", "value" : 0.44 } }) e2 = xml.load_string(""" <emitter type="point" version="2.0.0"> <spectrum name="intensity" value="0.44"/> </emitter> """) assert str(e1) == str(e2) with pytest.raises(Exception) as e: xml.load_dict({ "type" : "point", "intensity" : { "type" : "spectrum", "value" : [(400, 0.1), (500, 0.2), (300, 0.4)] } }) e.match("Wavelengths must be specified in increasing order")
def test02_error(variant_scalar_rgb): from mitsuba.core import xml error = "Nested instancing is not permitted" with pytest.raises(RuntimeError, match='.*{}.*'.format(error)): xml.load_dict({ 'type': 'shapegroup', 'shape_01': { 'type': 'instance', 'shapegroup': { 'type': 'shapegroup', 'shape_01': { 'type': 'sphere', }, } }, }) error = "Nested ShapeGroup is not permitted" with pytest.raises(RuntimeError, match='.*{}.*'.format(error)): xml.load_dict({ 'type': 'shapegroup', 'shape_01': { 'type': 'shapegroup', 'shape': { 'type': 'sphere' }, }, }) error = "Instancing of emitters is not supported" with pytest.raises(RuntimeError, match='.*{}.*'.format(error)): xml.load_dict({ 'type': 'shapegroup', 'shape_01': { 'type': 'sphere', 'emitter': { 'type': 'area' } }, }) error = "Instancing of sensors is not supported" with pytest.raises(RuntimeError, match='.*{}.*'.format(error)): xml.load_dict({ 'type': 'shapegroup', 'shape_01': { 'type': 'sphere', 'sensor': { 'type': 'perspective' } }, })
def test6_dict_rgb(variants_scalar_all): from mitsuba.core import xml, ScalarColor3f e1 = xml.load_dict({ "type" : "point", "intensity" : { "type": "rgb", "value" : ScalarColor3f(0.5, 0.2, 0.5) } }) e2 = xml.load_dict({ "type" : "point", "intensity" : { "type": "rgb", "value" : [0.5, 0.2, 0.5] # list -> ScalarColor3f } }) e3 = xml.load_string(""" <emitter type="point" version="2.0.0"> <rgb name="intensity" value="0.5, 0.2, 0.5"/> </emitter> """) assert str(e1) == str(e2) assert str(e1) == str(e3) e1 = xml.load_dict({ "type" : "point", "intensity" : { "type": "rgb", "value" : 0.5 # float -> ScalarColor3f } }) e2 = xml.load_string(""" <emitter type="point" version="2.0.0"> <rgb name="intensity" value="0.5"/> </emitter> """) assert str(e1) == str(e2)
def test05_differentiable_surface_interaction_ray_forward( variant_gpu_autodiff_rgb): from mitsuba.core import xml, Ray3f, Vector3f, UInt32 shape = xml.load_dict({'type': 'sphere'}) ray = Ray3f(Vector3f(0.0, -10.0, 0.0), Vector3f(0.0, 1.0, 0.0), 0, []) pi = shape.ray_intersect_preliminary(ray) ek.set_requires_gradient(ray.o) ek.set_requires_gradient(ray.d) # If the ray origin is shifted along the x-axis, so does si.p si = pi.compute_surface_interaction(ray) ek.forward(ray.o.x) assert ek.allclose(ek.gradient(si.p), [1, 0, 0]) # If the ray origin is shifted along the z-axis, so does si.p si = pi.compute_surface_interaction(ray) ek.forward(ray.o.z) assert ek.allclose(ek.gradient(si.p), [0, 0, 1]) # If the ray origin is shifted along the y-axis, so does si.t si = pi.compute_surface_interaction(ray) ek.forward(ray.o.y) assert ek.allclose(ek.gradient(si.t), -1) # If the ray direction is shifted along the x-axis, so does si.p si = pi.compute_surface_interaction(ray) ek.forward(ray.d.x) assert ek.allclose(ek.gradient(si.p), [9, 0, 0]) # If the ray origin is shifted tangent to the sphere (azimuth), so si.uv.x move by 1 / 2pi ek.set_requires_gradient(ray.o) si = shape.ray_intersect(ray) ek.forward(ray.o.x) assert ek.allclose(ek.gradient(si.uv), [1 / (2.0 * ek.pi), 0]) # If the ray origin is shifted tangent to the sphere (inclination), so si.uv.y move by 2 / 2pi ek.set_requires_gradient(ray.o) si = shape.ray_intersect(ray) ek.forward(ray.o.z) assert ek.allclose(ek.gradient(si.uv), [0, -2 / (2.0 * ek.pi)]) # # If the ray origin is shifted along the x-axis, so does si.n ek.set_requires_gradient(ray.o) si = shape.ray_intersect(ray) ek.forward(ray.o.x) assert ek.allclose(ek.gradient(si.n), [1, 0, 0]) # # If the ray origin is shifted along the z-axis, so does si.n ek.set_requires_gradient(ray.o) si = shape.ray_intersect(ray) ek.forward(ray.o.z) assert ek.allclose(ek.gradient(si.n), [0, 0, 1])