def test_modes(): import mitsuba # Check that switching to double precision mode works eradiate.set_mode("mono_double") # We expect that the kernel variant is appropriately selected assert mitsuba.variant() == "scalar_mono_double" # Check that switching to mono mode works eradiate.set_mode("mono") # We expect that the kernel variant is appropriately selected assert mitsuba.variant() == "scalar_mono"
def create_stairs_packet(num_steps): assert mitsuba.variant() == 'packet_rgb' from mitsuba.render import Mesh size_step = 1.0 / num_steps m = Mesh("stairs", vertex_struct, 4 * num_steps, index_struct, 4 * num_steps - 2) v = m.vertices() f = m.faces() for i in range(num_steps): h = i * size_step s1 = i * size_step s2 = (i + 1) * size_step k = 4 * i v[k + 0] = (0.0, s1, h) v[k + 1] = (1.0, s1, h) v[k + 2] = (0.0, s2, h) v[k + 3] = (1.0, s2, h) f[k] = (k, k + 1, k + 2) f[k + 1] = (k + 1, k + 3, k + 2) if i < num_steps - 1: f[k + 2] = (k + 2, k + 3, k + 5) f[k + 3] = (k + 5, k + 4, k + 2) m.recompute_bbox() return m
def check(self) -> None: """ Perform basic checks on the dictionary: * check that the ``"type"`` parameter is included; * check if the variant for which the kernel dictionary was created is the same as the current one. Raises ------ ValueError If the ``"type"`` parameter is missing. :class:`.KernelVariantError` If the variant for which the kernel dictionary was created is not the same as the current one """ variant = mitsuba.variant() if self.variant != variant: raise KernelVariantError( f"scene dictionary created for kernel variant '{self.variant}', " f"incompatible with current variant '{variant}'" ) if "type" not in self: raise ValueError("kernel scene dictionary is missing a 'type' parameter")
def __init__(self, path, split_files=False): from mitsuba import variant if not variant(): mitsuba.set_variant('scalar_rgb') from mitsuba.core import PluginManager self.pmgr = PluginManager.instance() self.split_files = split_files self.scene_data = [ { 'type': 'scene' }, #MAIN {}, #MATS {}, #GEOM {}, #EMIT {} ] #CAMS self.com_count = 0 # Counter for comment ids self.exported_ids = set() self.copy_count = { 'tex': 0, 'mesh': 0, 'spectrum': 0 } # Counters for giving unique names to copied files self.copied_paths = {} self.files = [] self.file_names = [] # Relative paths to the fragment files self.file_tabs = [] self.file_stack = [] self.current_file = Files.MAIN self.directory = '' # scene foler self.set_filename(path)
def check_scene(int_name, scene_name, is_empty=False): from mitsuba.core.xml import load_string from mitsuba.core import Bitmap, Struct variant_name = mitsuba.variant() print("variant_name:", variant_name) integrator = make_integrator(int_name, "") scene = SCENES[scene_name]['factory']() integrator_type = { 'direct': 'direct', 'depth': 'depth', # All other integrators: 'full' }.get(int_name, 'full') sensor = scene.sensors()[0] avg = SCENES[scene_name][integrator_type] film = sensor.film() status = integrator.render(scene, sensor) assert status, "Rendering ({}) failed".format(variant_name) if False: _save(film, int_name, suffix='_' + variant_name) converted = film.bitmap(raw=True).convert(Bitmap.PixelFormat.RGBA, Struct.Type.Float32, False) values = np.array(converted, copy=False) means = np.mean(values, axis=(0, 1)) # Very noisy images, so we add a tolerance assert ek.allclose(means, avg, rtol=5e-2), \ "Mismatch: {} integrator, {} scene, {}".format( int_name, scene_name, variant_name) return np.array(film.bitmap(raw=False), copy=True)
def get_ref_fname(scene_path): for color_mode in color_modes: if color_mode in mitsuba.variant(): return join( dirname(scene_path), 'refs', os.path.splitext(basename(scene_path))[0] + '_ref_' + color_mode + '.exr') assert False
def get_ref_fname(scene_fname): for color_mode in color_modes: if color_mode in mitsuba.variant(): ref_fname = join(dirname(scene_fname), 'refs', splitext( basename(scene_fname))[0] + '_ref_' + color_mode + '.exr') var_fname = ref_fname.replace('.exr', '_var.exr') return ref_fname, var_fname assert False
def _kernel_dict_get_mts_variant(): variant = mitsuba.variant() if variant is not None: return variant else: raise KernelVariantError( "a kernel variant must be selected to create a KernelDict instance" )
def fresolver_append_path(func): """Function decorator that adds the mitsuba project root to the FileResolver's search path. This is useful in particular for tests that e.g. load scenes, and need to specify paths to resources. The file resolver is restored to its previous state once the test's execution has finished. """ if mitsuba.variant() == None: mitsuba.set_variant('scalar_rgb') from mitsuba.core import Thread, FileResolver par = os.path.dirname # Get the path to the source file from which this function is # being called. # Source: https://stackoverflow.com/a/24439444/3792942 caller = getframeinfo(stack()[1][0]) caller_path = par(caller.filename) # Heuristic to find the project's root directory def is_root(path): if not path: return False children = os.listdir(path) return ('ext' in children) and ('include' in children) \ and ('src' in children) and ('resources' in children) root_path = caller_path while not is_root(root_path) and (par(root_path) != root_path): root_path = par(root_path) # The @wraps decorator properly sets __name__ and other properties, so that # pytest-xdist can keep track of the original test function. @wraps(func) def f(*args, **kwargs): # New file resolver thread = Thread.thread() fres_old = thread.file_resolver() fres = FileResolver(fres_old) # Append current test directory and project root to the # search path. fres.append(caller_path) fres.append(root_path) thread.set_file_resolver(fres) # Run actual function res = func(*args, **kwargs) # Restore previous file resolver thread.set_file_resolver(fres_old) return res return f
def get_plugin_tag(self, plugin_type): ''' Get the corresponding tag of a given plugin (e.g. 'bsdf' for 'diffuse') If the given type (e.g. 'transform') is not a plugin, returns None. Params ------ plugin_type: Name of the type (e.g. 'diffuse', 'ply'...) ''' from mitsuba import variant class_ = self.pmgr.get_plugin_class(plugin_type, variant()) if not class_: # If get_plugin_class returns None, there is not corresponding plugin return None class_ = class_.parent() while class_.alias() == class_.name(): class_ = class_.parent() return class_.alias()
def test10_ray_intersect_preliminary(variants_all_rgb): if 'packet' in mitsuba.variant(): pytest.skip( "pi.compute_surface_interaction isn't bound for packet modes") from mitsuba.core import xml, Ray3f, Vector3f, UInt32 from mitsuba.render import HitComputeFlags scene = xml.load_string(''' <scene version="2.0.0"> <shape type="obj"> <string name="filename" value="resources/data/common/meshes/rectangle.obj"/> </shape> </scene> ''') ray = Ray3f(Vector3f(-0.3, -0.3, -10.0), Vector3f(0.0, 0.0, 1.0), 0, []) pi = scene.ray_intersect_preliminary(ray) assert ek.allclose(pi.t, 10) assert pi.prim_index == 0 assert ek.allclose(pi.prim_uv, [0.35, 0.3]) si = pi.compute_surface_interaction(ray) assert ek.allclose(si.t, 10) assert ek.allclose(si.p, [-0.3, -0.3, 0.0]) assert ek.allclose(si.uv, [0.35, 0.35]) assert ek.allclose(si.dp_du, [2.0, 0.0, 0.0]) assert ek.allclose(si.dp_dv, [0.0, 2.0, 0.0]) ray = Ray3f(Vector3f(0.3, 0.3, -10.0), Vector3f(0.0, 0.0, 1.0), 0, []) pi = scene.ray_intersect_preliminary(ray) assert ek.allclose(pi.t, 10) assert pi.prim_index == 1 assert ek.allclose(pi.prim_uv, [0.3, 0.35]) si = pi.compute_surface_interaction(ray) assert ek.allclose(si.t, 10) assert ek.allclose(si.p, [0.3, 0.3, 0.0]) assert ek.allclose(si.uv, [0.65, 0.65]) assert ek.allclose(si.dp_du, [2.0, 0.0, 0.0]) assert ek.allclose(si.dp_dv, [0.0, 2.0, 0.0])
def test_render(variants_all, scene_fname): from mitsuba.core import Bitmap, Struct, Thread scene_dir = dirname(scene_fname) if os.path.split(scene_dir)[1] in EXCLUDE_FOLDERS: pytest.skip(f"Skip rendering scene {scene_fname}") Thread.thread().file_resolver().append(scene_dir) ref_fname = get_ref_fname(scene_fname) assert os.path.exists(ref_fname) scene = mitsuba.core.xml.load_file(scene_fname, parameters=[('spp', str(32))]) scene.integrator().render(scene, scene.sensors()[0]) film = scene.sensors()[0].film() cur_bitmap = film.bitmap(raw=True).convert(Bitmap.PixelFormat.RGB, Struct.Type.Float32, False) cur_image = np.array(cur_bitmap, copy=False) ref_bitmap = Bitmap(ref_fname).convert(Bitmap.PixelFormat.RGB, Struct.Type.Float32, False) ref_image = np.array(ref_bitmap, copy=False) error = np.mean(np.mean(np.abs(ref_image - cur_image))) threshold = 0.5 * np.mean(np.mean(ref_image)) success = error < threshold if not success: print("Failed. error: {} // threshold: {}".format(error, threshold)) # Write rendered image to a file cur_fname = os.path.splitext( scene_fname)[0] + '_render_' + mitsuba.variant() + '.exr' cur_bitmap.write(cur_fname) print('Saved rendered image to: ' + cur_fname) assert False
def _check_variant(): variant = mitsuba.variant() if variant not in _SUPPORTED_VARIANTS: raise KernelVariantError(f"unsupported kernel variant '{variant}'")
def test_render(variants_all, scene_fname): from mitsuba.core import Bitmap, Struct, Thread, set_thread_count scene_dir = dirname(scene_fname) if os.path.split(scene_dir)[1] in EXCLUDE_FOLDERS: pytest.skip(f"Skip rendering scene {scene_fname}") Thread.thread().file_resolver().prepend(scene_dir) ref_fname, ref_var_fname = get_ref_fname(scene_fname) if not (exists(ref_fname) and exists(ref_var_fname)): pytest.skip("Non-existent reference data.") ref_bmp = read_rgb_bmp_to_xyz(ref_fname) ref_img = np.array(ref_bmp, copy=False) ref_var_bmp = read_rgb_bmp_to_xyz(ref_var_fname) ref_var_img = np.array(ref_var_bmp, copy=False) significance_level = 0.01 # Compute spp budget sample_budget = int(2e6) pixel_count = ek.hprod(ref_bmp.size()) spp = sample_budget // pixel_count # Load and render scene = mitsuba.core.xml.load_file(scene_fname, spp=spp) scene.integrator().render(scene, scene.sensors()[0]) # Compute variance image bmp = scene.sensors()[0].film().bitmap(raw=False) img, var_img = bitmap_extract(bmp) # Compute Z-test p-value p_value = z_test(img, spp, ref_img, ref_var_img) # Apply the Sidak correction term, since we'll be conducting multiple independent # hypothesis tests. This accounts for the fact that the probability of a failure # increases quickly when several hypothesis tests are run in sequence. alpha = 1.0 - (1.0 - significance_level) ** (1.0 / pixel_count) success = (p_value > alpha) if (np.count_nonzero(success) / 3) >= (0.9975 * pixel_count): print('Accepted the null hypothesis (min(p-value) = %f, significance level = %f)' % (np.min(p_value), alpha)) else: print('Reject the null hypothesis (min(p-value) = %f, significance level = %f)' % (np.min(p_value), alpha)) output_dir = join(scene_dir, 'error_output') if not exists(output_dir): os.makedirs(output_dir) output_prefix = join(output_dir, splitext( basename(scene_fname))[0] + '_' + mitsuba.variant()) img_rgb_bmp = xyz_to_rgb_bmp(img) fname = output_prefix + '_img.exr' img_rgb_bmp.write(fname) print('Saved rendered image to: ' + fname) var_fname = output_prefix + '_var.exr' xyz_to_rgb_bmp(var_img).write(var_fname) print('Saved variance image to: ' + var_fname) err_fname = output_prefix + '_error.exr' err_img = 0.02 * np.array(img_rgb_bmp) err_img[~success] = 1.0 err_bmp = Bitmap(err_img).write(err_fname) print('Saved error image to: ' + err_fname) pvalue_fname = output_prefix + '_pvalue.exr' xyz_to_rgb_bmp(p_value).write(pvalue_fname) print('Saved error image to: ' + pvalue_fname) assert False
def test02_render_empty_scene(variants_all_rgb, int_name): if not mitsuba.variant().startswith('gpu'): check_scene(int_name, 'empty', is_empty=True)
import mitsuba if mitsuba.variant() == None: mitsuba.set_variant('scalar_rgb') from mitsuba.core import Struct # Some helper functions to generate simple meshes vertex_struct = Struct() \ .append("x", Struct.Type.Float32) \ .append("y", Struct.Type.Float32) \ .append("z", Struct.Type.Float32) vdt = vertex_struct.dtype() index_struct = Struct() \ .append("i0", Struct.Type.UInt32) \ .append("i1", Struct.Type.UInt32) \ .append("i2", Struct.Type.UInt32) idt = vertex_struct.dtype() def create_single_triangle(): from mitsuba.render import Mesh m = Mesh("tri", vertex_struct, 3, index_struct, 1) v = m.vertices() f = m.faces() v[0] = (0, 0, 0) v[1] = (1, 0.2, 0) v[2] = (0.2, 1, 0) f[0] = (0, 1, 2)