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 bsdfs(self, ctx: KernelDictContext) -> KernelDict: from mitsuba.core import ScalarTransform4f returndict = KernelDict({ f"bsdf_{self.id}": { "type": "blendbsdf", "inner_bsdf": onedict_value(self.central_patch.bsdfs(ctx=ctx)), "outer_bsdf": onedict_value(self.background_surface.bsdfs(ctx=ctx)), "weight": { "type": "bitmap", "filename": str( eradiate.path_resolver.resolve( "textures/rami4atm_experiment_surface_mask.bmp")), "filter_type": "nearest", "wrap_mode": "clamp", }, } }) scale = self._compute_scale_parameter(ctx=ctx) trafo = ScalarTransform4f.scale(scale) * ScalarTransform4f.translate(( -0.5 + (0.5 / scale), -0.5 + (0.5 / scale), 0, )) returndict[f"bsdf_{self.id}"]["weight"]["to_uv"] = trafo return returndict
def test_ramiatm_experiment_surface_adjustment(mode_mono): """Create a Rami4ATM experiment and assert the central patch surface is created with the correct parameters, according to the canopy and atmosphere.""" from mitsuba.core import ScalarTransform4f ctx = KernelDictContext() s = Rami4ATMExperiment( atmosphere=HomogeneousAtmosphere(width=ureg.Quantity(42.0, "km")), canopy=DiscreteCanopy.homogeneous( lai=3.0, leaf_radius=0.1 * ureg.m, l_horizontal=10.0 * ureg.m, l_vertical=2.0 * ureg.m, padding=0, ), surface=CentralPatchSurface(central_patch=LambertianSurface(), background_surface=LambertianSurface()), ) expected_trafo = ScalarTransform4f.scale( 1400) * ScalarTransform4f.translate((-0.499642857, -0.499642857, 0.0)) kernel_dict = s.kernel_dict(ctx=ctx) assert np.allclose(kernel_dict["bsdf_surface"]["weight"]["to_uv"].matrix, expected_trafo.matrix)
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': '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 test_construct(variant_scalar_rgb): from mitsuba.core.xml import load_dict from mitsuba.core import ScalarTransform4f # Test construct from to_world sensor = make_sensor(to_world=ScalarTransform4f.look_at( origin=[0, 0, 0], target=[0, 1, 0], up=[0, 0, 1] )) assert not sensor.bbox().valid() # Degenerate bounding box assert ek.allclose( sensor.world_transform().eval(0.).matrix, [[-1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]] ) # Test construct from origin and direction sensor = make_sensor(origin=[0, 0, 0], direction=[0, 1, 0]) assert not sensor.bbox().valid() # Degenerate bounding box assert ek.allclose( sensor.world_transform().eval(0.).matrix, [[0, 0, 1, 0], [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1]] ) # Test to_world overriding direction + origin sensor = make_sensor( to_world=ScalarTransform4f.look_at( origin=[0, 0, 0], target=[0, 1, 0], up=[0, 0, 1] ), origin=[1, 0, 0], direction=[4, 1, 0] ) assert not sensor.bbox().valid() # Degenerate bounding box assert ek.allclose( sensor.world_transform().eval(0.).matrix, [[-1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]] ) # Test raise on missing direction or origin with pytest.raises(RuntimeError): sensor = make_sensor(direction=[0, 1, 0]) with pytest.raises(RuntimeError): sensor = make_sensor(origin=[0, 1, 0]) # Test raise on wrong film size with pytest.raises(RuntimeError): sensor = make_sensor(pixels=2)
def velocity_transform(dr, dq, dt): linvel = dr * dt rotvel_z = ScalarTransform4f.rotate([0, 0, 1], dq[2] * dt) rotvel_y = ScalarTransform4f.rotate([0, 1, 0], dq[1] * dt) rotvel_x = ScalarTransform4f.rotate([1, 0, 0], dq[0] * dt) rotvel = rotvel_x * rotvel_y * rotvel_z return ScalarTransform4f.translate(linvel) * rotvel
def position_transform(r, q): pos = r rot_z = ScalarTransform4f.rotate([0, 0, 1], q[2]) rot_y = ScalarTransform4f.rotate([0, 1, 0], q[1]) rot_x = ScalarTransform4f.rotate([1, 0, 0], q[0]) rot = rot_x * rot_y * rot_z return ScalarTransform4f.translate(pos) * rot
def shapes(self, ctx: KernelDictContext) -> t.Dict: """ Return shape plugin specifications. Parameters ---------- ctx : :class:`.KernelDictContext` A context data structure containing parameters relevant for kernel dictionary generation. Returns ------- dict A dictionary suitable for merge with a :class:`~eradiate.scenes.core.KernelDict` containing all the shapes in the abstract tree. """ from mitsuba.core import ScalarTransform4f kernel_length = uck.get("length") kernel_height = self.trunk_height.m_as(kernel_length) kernel_radius = self.trunk_radius.m_as(kernel_length) leaf_cloud = self.leaf_cloud.translated( [0.0, 0.0, kernel_height] * kernel_length + self.leaf_cloud_extra_offset.to(kernel_length)) if ctx.ref: bsdf = {"type": "ref", "id": f"bsdf_{self.id}"} else: bsdf = self.bsdfs(ctx=ctx)[f"bsdf_{self.id}"] shapes_dict = leaf_cloud.shapes(ctx=ctx) shapes_dict[f"trunk_cyl_{self.id}"] = { "type": "cylinder", "bsdf": bsdf, "radius": kernel_radius, "p0": [0, 0, -0.1], "p1": [0, 0, kernel_height], } shapes_dict[f"trunk_cap_{self.id}"] = { "type": "disk", "bsdf": bsdf, "to_world": ScalarTransform4f.scale(kernel_radius) * ScalarTransform4f.translate(((0, 0, kernel_height))), } return shapes_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 test_onedim_experiment_kernel_dict(modes_all): """ Test non-trivial kernel dict generation behaviour. """ from mitsuba.core import ScalarTransform4f ctx = KernelDictContext() # Surface width is appropriately inherited from atmosphere exp = OneDimExperiment(atmosphere=HomogeneousAtmosphere( width=ureg.Quantity(42.0, "km"))) kernel_dict = exp.kernel_dict(ctx) assert np.allclose( kernel_dict["surface"]["to_world"].matrix, ScalarTransform4f.scale([21000, 21000, 1]).matrix, ) # Setting atmosphere to None exp = OneDimExperiment( atmosphere=None, surface={ "type": "lambertian", "width": 100.0, "width_units": "m" }, measures=[ { "type": "distant", "id": "distant_measure" }, { "type": "radiancemeter", "origin": [1, 0, 0], "id": "radiancemeter" }, ], ) # -- Surface width is not overridden kernel_dict = exp.kernel_dict(ctx) assert np.allclose( kernel_dict["surface"]["to_world"].matrix, ScalarTransform4f.scale([50, 50, 1]).matrix, ) # -- Atmosphere is not in kernel dictionary assert "atmosphere" not in kernel_dict # -- Measures get no external medium assigned assert "medium" not in kernel_dict["distant_measure"] assert "medium" not in kernel_dict["radiancemeter"]
def _kernel_dict(self, sensor_id, spp): from mitsuba.core import ScalarTransform4f target = self.target.m_as(uck.get("length")) origin = self.origin.m_as(uck.get("length")) result = { "type": "perspective", "id": sensor_id, "far_clip": self.far_clip.m_as(uck.get("length")), "fov": self.fov.m_as(ureg.deg), "to_world": ScalarTransform4f.look_at(origin=origin, target=target, up=self.up), "sampler": { "type": "independent", "sample_count": spp, }, "film": { "type": "hdrfilm", "width": self.film_resolution[0], "height": self.film_resolution[1], "pixel_format": "luminance", "component_format": "float32", "rfilter": { "type": "box" }, }, } return result
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 shapes(self, ctx: KernelDictContext) -> t.Dict: from mitsuba.core import ScalarTransform4f if ctx.ref: bsdf = {"type": "ref", "id": f"bsdf_{self.id}"} else: bsdf = self.bsdfs(ctx=ctx)[f"bsdf_{self.id}"] if self.mesh_units is None: scaling_factor = 1.0 else: kernel_length = uck.get("length") scaling_factor = (1.0 * self.mesh_units).m_as(kernel_length) base_dict = { "filename": str(self.mesh_filename), "bsdf": bsdf, "to_world": ScalarTransform4f.scale(scaling_factor), } if self.mesh_filename.suffix == ".obj": base_dict["type"] = "obj" elif self.mesh_filename.suffix == ".ply": base_dict["type"] = "ply" else: raise ValueError( f"unsupported file extension '{self.mesh_filename.suffix}'") return {self.id: base_dict}
def instances(self, ctx: KernelDictContext) -> t.Dict: """ Return instance plugin specifications. Parameters ---------- ctx : :class:`.KernelDictContext` A context data structure containing parameters relevant for kernel dictionary generation. Returns ------- dict A dictionary suitable for merge with a :class:`~eradiate.scenes.core.KernelDict` containing instances. """ from mitsuba.core import ScalarTransform4f kernel_length = uck.get("length") return { f"{self.canopy_element.id}_instance_{i}": { "type": "instance", "group": { "type": "ref", "id": self.canopy_element.id }, "to_world": ScalarTransform4f.translate(position.m_as(kernel_length)), } for i, position in enumerate(self.instance_positions) }
def shapes(self, ctx: KernelDictContext) -> t.Dict: """ Return shape plugin specifications. Parameters ---------- ctx : :class:`.KernelDictContext` A context data structure containing parameters relevant for kernel dictionary generation. Returns ------- dict A dictionary suitable for merge with a :class:`.KernelDict` containing all the shapes in the leaf cloud. """ from mitsuba.core import ScalarTransform4f, coordinate_system kernel_length = uck.get("length") shapes_dict = {} if ctx.ref: bsdf = {"type": "ref", "id": f"bsdf_{self.id}"} else: bsdf = self.bsdfs(ctx=ctx)[f"bsdf_{self.id}"] for i_leaf, (position, normal, radius) in enumerate( zip( self.leaf_positions.m_as(kernel_length), self.leaf_orientations, self.leaf_radii.m_as(kernel_length), ) ): _, up = coordinate_system(normal) to_world = ScalarTransform4f.look_at( origin=position, target=position + normal, up=up ) * ScalarTransform4f.scale(radius) shapes_dict[f"{self.id}_leaf_{i_leaf}"] = { "type": "disk", "bsdf": bsdf, "to_world": to_world, } return shapes_dict
def kernel_item(self) -> t.Dict: """Return kernel item.""" from mitsuba.core import ScalarTransform4f xmin = self.xmin.m_as(uck.get("length")) xmax = self.xmax.m_as(uck.get("length")) ymin = self.ymin.m_as(uck.get("length")) ymax = self.ymax.m_as(uck.get("length")) z = self.z.m_as(uck.get("length")) dx = xmax - xmin dy = ymax - ymin to_world = ScalarTransform4f.translate([ 0.5 * dx + xmin, 0.5 * dy + ymin, z ]) * ScalarTransform4f.scale([0.5 * dx, 0.5 * dy, 1.0]) return {"type": "rectangle", "to_world": to_world}
def test_centralpatch_scale_kernel_dict(mode_mono): from mitsuba.core import ScalarTransform4f cs = CentralPatchSurface( width=3000.0 * ureg.km, central_patch=LambertianSurface(width=100 * ureg.km), id="surface", ) ctx = KernelDictContext() kernel_dict = cs.bsdfs(ctx=ctx) assert np.allclose( kernel_dict["bsdf_surface"]["weight"]["to_uv"].matrix, (ScalarTransform4f.scale(10) * ScalarTransform4f.translate( (-0.45, -0.45, 0))).matrix, )
def camera(origin, lookat, up, fov, ext=None, near=0.01, far=1000.0, w=256, h=256, nsamples=4): if (not (ext is None)): transform = ScalarTransform4f(ext.cpu().numpy()[0]) elif (type(origin) == torch.Tensor): origin = origin[0] lookat = lookat[0] up = up[0] transform = ScalarTransform4f.look_at(origin=origin, target=lookat, up=up) film = """<film type="hdrfilm"> <integer name="width" value="%i"/> <integer name="height" value="%i"/> <rfilter type="gaussian"/> </film>""" % (w, h) sampler = """<sampler type="independent"> <integer name="sample_count" value="%i"/> </sampler>""" % (nsamples) transform = """<transform version="2.0.0" name="to_world">\n <lookat origin="%f, %f, %f" target="%f, %f, %f" up="%f, %f, %f"/>\n </transform>""" % (origin[0], origin[1], origin[2], lookat[0], lookat[1], lookat[2], up[0], up[1], up[2]) xmlstr = """<sensor version="2.0.0" type="perspective">\n %s\n <float name="near_clip" value="%f"/>\n <float name="far_clip" value="%f"/>\n <float name="fov" value="%f"/>\n %s\n %s\n </sensor>""" % (transform, near, far, fov, film, sampler) return xmlstr
def map_cube(xmin: float, xmax: float, ymin: float, ymax: float, zmin: float, zmax: float) -> "mitsuba.core.ScalarTransform4f": r""" Map the cube :math:`[-1, 1]^3` to :math:`[x_\mathrm{min}, x_\mathrm{max}] \times [y_\mathrm{min}, y_\mathrm{max}] \times [z_\mathrm{min}, z_\mathrm{max}]`. Parameters ---------- xmin : float Minimum X value. xmax : float Maximum X value. ymin : float Minimum Y value. ymax : float Maximum Y value. zmin : float Minimum Z value. zmax : float Maximum Z value. Returns ------- :class:`mitsuba.core.ScalarTransform4f` Computed transform matrix. Warnings -------- You must select a Mitsuba variant before calling this function. """ from mitsuba.core import ScalarTransform4f half_dx = (xmax - xmin) * 0.5 half_dy = (ymax - ymin) * 0.5 half_dz = (zmax - zmin) * 0.5 scale_trafo = ScalarTransform4f.scale([half_dx, half_dy, half_dz]) translate_trafo = ScalarTransform4f.translate( [xmin + half_dx, ymin + half_dy, half_dz + zmin]) return translate_trafo * scale_trafo
def test_ramiatm_experiment_kernel_dict(mode_mono, padding): from mitsuba.core import ScalarTransform4f ctx = KernelDictContext() # Surface width is appropriately inherited from canopy, when no atmosphere is present s = Rami4ATMExperiment( atmosphere=None, canopy=DiscreteCanopy.homogeneous( lai=3.0, leaf_radius=0.1 * ureg.m, l_horizontal=10.0 * ureg.m, l_vertical=2.0 * ureg.m, padding=padding, ), measures=[ { "type": "distant", "id": "distant_measure" }, { "type": "radiancemeter", "origin": [1, 0, 0], "id": "radiancemeter" }, ], ) kernel_scene = s.kernel_dict(ctx) assert np.allclose( kernel_scene["surface"]["to_world"].transform_point([1, -1, 0]), [5 * (2 * padding + 1), -5 * (2 * padding + 1), 0], ) # -- Measures get no external medium assigned assert "medium" not in kernel_scene["distant_measure"] assert "medium" not in kernel_scene["radiancemeter"] # Surface width is appropriately inherited from atmosphere s = Rami4ATMExperiment( atmosphere=HomogeneousAtmosphere(width=ureg.Quantity(42.0, "km")), canopy=DiscreteCanopy.homogeneous( lai=3.0, leaf_radius=0.1 * ureg.m, l_horizontal=10.0 * ureg.m, l_vertical=2.0 * ureg.m, padding=padding, ), ) kernel_dict = s.kernel_dict(ctx) assert np.allclose( kernel_dict["surface"]["to_world"].matrix, ScalarTransform4f.scale([21000, 21000, 1]).matrix, )
def shapes(self, ctx: KernelDictContext) -> KernelDict: """ Return shape plugin specifications only. Parameters ---------- ctx : :class:`.KernelDictContext` A context data structure containing parameters relevant for kernel dictionary generation. Returns ------- :class:`.KernelDict` A kernel dictionary containing all the shapes attached to the surface. """ from mitsuba.core import ScalarTransform4f, ScalarVector3f if ctx.ref: bsdf = {"type": "ref", "id": f"bsdf_{self.id}"} else: bsdf = self.bsdfs(ctx)[f"bsdf_{self.id}"] w = self.kernel_width(ctx).m_as(uck.get("length")) z = self.altitude.m_as(uck.get("length")) translate_trafo = ScalarTransform4f.translate( ScalarVector3f(0.0, 0.0, z)) scale_trafo = ScalarTransform4f.scale( ScalarVector3f(w / 2.0, w / 2.0, 1.0)) trafo = translate_trafo * scale_trafo return KernelDict({ f"shape_{self.id}": { "type": "rectangle", "to_world": trafo, "bsdf": bsdf, } })
def sensor_shape_dict(radius, center): from mitsuba.core import ScalarTransform4f d = { "type": "sphere", "radius": radius, "to_world": ScalarTransform4f.translate(center), "sensor": { "type": "irradiancemeter", "film": { "type": "hdrfilm", "width": 1, "height": 1, "rfilter": {"type": "box"} }, } } return d
def genXML(lx, ly, material, scale): scene = xml.load_dict({ "type": "scene", "myintegrator": { "type": "path", }, "mysensor": { "type": "perspective", "near_clip": 0.1, "far_clip": 1000.0, "to_world": ScalarTransform4f.look_at(origin=[0.0, 0.001, 1], target=[0, 0, 0], up=[0, 0, 1]), "myfilm": { "type": "hdrfilm", "rfilter": { "type": "box" }, "width": 256, "height": 256, }, "mysampler": { "type": "independent", "sample_count": 4, }, }, "myemitter": { "type": "point", "intensity": 1.0, 'position': [lx * scale, ly * scale, 1.1] }, "myshape": { "type": "sphere", "radius": 0.2, "mybsdf": material, } }) return scene
def _kernel_dict(self, sensor_id, spp): from mitsuba.core import ScalarTransform4f, ScalarVector3f, coordinate_system _, up = coordinate_system(self.direction) result = { "type": "distantflux", "id": sensor_id, "to_world": ScalarTransform4f.look_at( origin=[0, 0, 0], target=ScalarVector3f(self.direction), up=up, ), "sampler": { "type": "independent", "sample_count": spp, }, "film": { "type": "hdrfilm", "width": self.film_resolution[0], "height": self.film_resolution[1], "pixel_format": "luminance", "component_format": "float32", "rfilter": { "type": "box" }, }, } if self.target is not None: result["target"] = self.target.kernel_item() return result
def add_object(self, scene_dict): """ Add registered meshes to given scene file format """ if len(self.bssrdf) != len(self.mesh): exit("The number of registerd mesh and bssrdf are different!") num_mesh = len(self.bssrdf) num_obj = len(self.bssrdf_obj) for i in range(num_obj): i += 1 scene_dict["obj_" + str(i)] = { "type": "shapegroup" } for i in range(num_mesh): i += 1 bssrdf = self.bssrdf[i] mesh = self.mesh[i] axis = None if(mesh["rotate"]["axis"] == "x"): axis = [1, 0, 0] elif(mesh["rotate"]["axis"] == "y"): axis = [0, 1, 0] elif(mesh["rotate"]["axis"] == "z"): axis = [0, 0, 1] angle = mesh["rotate"]["angle"] if mesh["type"] == "rectangle": shape = { "type": mesh["type"], "to_world": ScalarTransform4f.translate(mesh["translate"]) * ScalarTransform4f.rotate(axis, angle) * ScalarTransform4f.scale(mesh["scale"]), } else: shape = { "type": mesh["type"], "filename": mesh["filename"], "to_world": ScalarTransform4f.translate(mesh["translate"]) * ScalarTransform4f.rotate(axis, angle) * ScalarTransform4f.scale(mesh["scale"]), } bssrdf["trans"] = mesh["translate"] if(mesh["rotate"]["axis"] == "x"): bssrdf["rotate_x"] = angle elif(mesh["rotate"]["axis"] == "y"): bssrdf["rotate_y"] = angle elif(mesh["rotate"]["axis"] == "z"): bssrdf["rotate_z"] = angle bssrdf["height_max"] = mesh["height_max"] bsdf = { "bsdf_" + str(i): bssrdf } shape.update(bsdf) for j in range(num_obj): j += 1 if i in self.bssrdf_obj[j]: scene_dict["obj_" + str(j)][str(i)] = shape for i in range(num_obj): i += 1 scene_dict["instance_" + str(i)] = { "type": "instance", "group":{ "type": "ref", "id": "obj_" + str(i) } } return scene_dict
params = traverse(scene) print(params) positions_buf = params['grid_mesh.vertex_positions_buf'] positions_initial = ravel(positions_buf) normals_initial = ravel(params['grid_mesh.vertex_normals_buf']) vertex_count = ek.slices(positions_initial) filename = 'scene/diffuser_surface_1.jpg' Thread.thread().file_resolver().append(os.path.dirname(filename)) # Create a texture with the reference displacement map disp_tex_1 = xml.load_dict({ "type" : "bitmap", "filename": "diffuser_surface_1.jpg", "to_uv" : ScalarTransform4f.scale([1, -1, 1]) # texture is upside-down }).expand()[0] # Create a texture with another displacement map disp_tex_2 = xml.load_dict({ "type" : "bitmap", "filename": "diffuser_surface_2.jpg", "to_uv" : ScalarTransform4f.scale([1, -1, 1]) # texture is upside-down }).expand()[0] # Create a fake surface interaction with an entry per vertex on the mesh mesh_si = SurfaceInteraction3f.zero(vertex_count) mesh_si.uv = ravel(params['grid_mesh.vertex_texcoords_buf'], dim=2) # Evaluate the displacement map for the entire mesh disp_tex_diffuser_1 = disp_tex_1.eval_1(mesh_si)
def scene_dict(sensor_to_world=None): if sensor_to_world is None: sensor_to_world = ScalarTransform4f.look_at( origin=[0, 0, 0], target=[0, 0, 1], up=[0, 1, 0], ) return { "type": "scene", "shape": { "type": "rectangle", "bsdf": { "type": "roughconductor" }, }, "illumination_r": { "type": "directional", "direction": direction_r, "irradiance": { "type": "rgb", "value": [1, 0, 0], }, }, "illumination_g": { "type": "directional", "direction": direction_g, "irradiance": { "type": "rgb", "value": [0, 1, 0], }, }, "illumination_b": { "type": "directional", "direction": direction_b, "irradiance": { "type": "rgb", "value": [0, 0, 1], }, }, "hdistant": { "type": "hdistant", "to_world": sensor_to_world, "sampler": { "type": "independent", "sample_count": 3200, }, "film": { "type": "hdrfilm", "width": film_resolution, "height": film_resolution, "pixel_format": "rgb", "component_format": "float32", "rfilter": { "type": "box" }, } }, #"camera": { # "type": "perspective", # "to_world": ScalarTransform4f.look_at( # origin=[5, 5, 5], # target=[0, 0, 0], # up=[0, 0, 1], # ), # "sampler": { # "type": "independent", # "sample_count": 32, # }, # "film": { # "type": "hdrfilm", # "width": 320, # "height": 240, # "pixel_format": "luminance", # "component_format": "float32", # } #}, "integrator": { "type": "path" }, }
def test_maximum_scene_size(mode_mono_double, json_metadata): r""" Maximum scene size (``path``) ============================= This test searches for an order of magnitude of the maximum size a scene using a ``distant`` sensor without ray origin control can have. An arbitrary threshold is used as the pass/fail criterion for regression control. Rationale --------- - Geometry: a square surface with increasing sizes from 1.0 to 1e9. and a Lambertian BRDF with reflectance :math:`\rho = 0.5`. - Illumination: a directional light source at the zenith with radiance :math:`L_\mathrm{i} = 1.0`. - Sensor: a ``distant`` sensor targeting (0, 0, 0) with default ray origin control. Expected behaviour ------------------ For all scene sizes below the parametrized size :code:`min_expected_size` the computational results must be equal to the theoretical prediction within a relative tolerance of 1e-5. """ from mitsuba.core import ScalarTransform4f, ScalarVector3f min_expected_size = 1e2 results = dict() spp = 1 rho = 0.5 li = 1.0 expected = rho * li / np.pi for scene_size in sorted( [10.0 ** i for i in range(1, 9)] + [2.0 * 10 ** i for i in range(1, 8)] + [5.0 * 10 ** i for i in range(1, 8)] ): kernel_dict = KernelDict( { "type": "scene", "bsdf_surface": { "type": "diffuse", "reflectance": rho, }, "surface": { "type": "rectangle", "to_world": ScalarTransform4f.scale( ScalarVector3f(scene_size, scene_size, 1) ), "bsdf": {"type": "ref", "id": "bsdf_surface"}, }, "illumination": { "type": "directional", "direction": [0, 0, -1], "irradiance": li, }, "measure": { "type": "distant", "id": "measure", "ray_target": [0, 0, 0], "sampler": {"type": "independent", "sample_count": spp}, "film": { "type": "hdrfilm", "width": 32, "height": 32, "pixel_format": "luminance", "component_format": "float32", "rfilter": {"type": "box"}, }, }, "integrator": {"type": "path"}, } ) result = mitsuba_run(kernel_dict)["values"]["measure"].img results[scene_size] = np.allclose(result, expected, rtol=1e-5) # Report test metrics passed_sizes = [size for size in results if results[size]] maxsize = np.max(passed_sizes) json_metadata["metrics"] = { "test_maximum_scene_size": { "name": "Maximum scene size", "description": "The maximum scene size is:", "value": f"{float(maxsize):1.1e}", "units": "length units", } } # Final assertion assert np.all( [ result for result in [ results[size] for size in results if size <= min_expected_size ] ] )
# "height": 240, # "pixel_format": "luminance", # "component_format": "float32", # } #}, "integrator": { "type": "path" }, } for name, sensor_to_world in { "default": ScalarTransform4f.look_at( origin=[0, 0, 0], target=[0, 0, 1], up=[0, 1, 0], ), "rotated": ScalarTransform4f.look_at( origin=[0, 0, 0], target=[0, 0, 1], up=[1, 1, 0], ), }.items(): scene = load_dict(scene_dict(sensor_to_world=sensor_to_world)) sensor = scene.sensors()[0] scene.integrator().render(scene, sensor) # Plot recorded leaving radiance img = np.array(sensor.film().bitmap()).squeeze()