def save_settings(context): scene = context.scene config_updates = {} jar_path = os.path.abspath(efutil.filesystem_path(scene.sunflow_renderconfigure.sunflowPath)) if os.path.exists(jar_path): config_updates['jar_path'] = jar_path else: sunflowLog("Unable to find path jar_path") java_path = os.path.abspath(efutil.filesystem_path(scene.sunflow_renderconfigure.javaPath)) # if os.path.isdir(java_path) and os.path.exists(java_path): if os.path.exists(java_path): config_updates['java_path'] = java_path else: sunflowLog("Unable to find path java_path") memoryalloc = scene.sunflow_renderconfigure.memoryAllocated config_updates['memoryalloc'] = memoryalloc try: for k, v in config_updates.items(): efutil.write_config_value('sunflow', 'defaults', k, v) sunflowLog("writing values") except Exception as err: sunflowLog('WARNING: Saving sunflow configuration failed, please set your user scripts dir: %s' % err)
def save_settings(context): scene = context.scene config_updates = {} jar_path = os.path.abspath( efutil.filesystem_path(scene.sunflow_renderconfigure.sunflowPath)) if os.path.exists(jar_path): config_updates['jar_path'] = jar_path else: sunflowLog("Unable to find path jar_path") java_path = os.path.abspath( efutil.filesystem_path(scene.sunflow_renderconfigure.javaPath)) # if os.path.isdir(java_path) and os.path.exists(java_path): if os.path.exists(java_path): config_updates['java_path'] = java_path else: sunflowLog("Unable to find path java_path") memoryalloc = scene.sunflow_renderconfigure.memoryAllocated config_updates['memoryalloc'] = memoryalloc try: for k, v in config_updates.items(): efutil.write_config_value('sunflow', 'defaults', k, v) sunflowLog("writing values") except Exception as err: sunflowLog( 'WARNING: Saving sunflow configuration failed, please set your user scripts dir: %s' % err)
def process_filepath_data(scene, obj, file_path, paramset, parameter_name): file_basename = os.path.basename(file_path) library_filepath = obj.library.filepath if (hasattr(obj, 'library') and obj.library) else '' file_library_path = efutil.filesystem_path(bpy.path.abspath(file_path, library_filepath)) file_relative = efutil.filesystem_path(file_library_path) if (hasattr(obj, 'library') and obj.library) else efutil.filesystem_path(file_path) if scene.luxrender_engine.allow_file_embed(): paramset.add_string(parameter_name, file_basename) encoded_data, encoded_size = bencode_file2string_with_size(file_relative) paramset.increase_size('%s_data' % parameter_name, encoded_size) paramset.add_string('%s_data' % parameter_name, encoded_data.splitlines() ) else: paramset.add_string(parameter_name, file_relative)
def get_additional_elements(self, obj): d = {} for ms in obj.material_slots: mat = ms.material if mat == None: continue ie = mat.indigo_material.indigo_material_emission if ie.emission_enabled and ie.emit_ies: d['ies_profile'] = { 'material_name': [mat.name], 'path': [efutil.filesystem_path(ie.emit_ies_path)] } for ms in obj.material_slots: mat = ms.material if mat == None: continue ie = mat.indigo_material.indigo_material_emission if ie.emission_enabled and ie.emission_scale: d['emission_scale'] = { 'material_name': [mat.name], 'measure': [ie.emission_scale_measure], 'value': [ie.emission_scale_value * 10**ie.emission_scale_exp] } if(obj.data != None and obj.data.indigo_mesh.invisible_to_camera): d['invisible_to_camera'] = ["true"] return d
def getInstallPath(scene=None): # Can use scene.indigo_engine.exe_path as a hint, if available if scene != None: sip = filesystem_path(scene.indigo_engine.install_path) if sip != "" and os.path.exists(sip): if os.path.isdir(sip): return sip else: return os.path.dirname(sip) if isLinux(): return "" # TODO if isMac(): return "/Applications/Indigo Renderer/Indigo.app" # Assumption if isWindows(): import winreg try: hKey = winreg.OpenKey( winreg.HKEY_CURRENT_USER, r"Software\Glare Technologies\Indigo Renderer") value = winreg.QueryValueEx(hKey, "InstallDirectory")[0] except: value = "" return value return ""
def get_pbrt_dir(): return_path = exporter_common.getPreference().pbrt_export_path if return_path is '': return '' if platform.system() == 'Windows': return return_path return efutil.filesystem_path(return_path) + "/"
def getInstallPath(scene=None): # Can use scene.indigo_engine.exe_path as a hint, if available if scene != None: sip = efutil.filesystem_path(scene.indigo_engine.install_path) if sip != "" and os.path.exists(sip): if os.path.isdir(sip): return sip else: return os.path.dirname(sip) if isLinux(): return "" # TODO if isMac(): return "/Applications/Indigo Renderer/Indigo.app" # Assumption if isWindows(): import winreg try: hKey = winreg.OpenKey (winreg.HKEY_CURRENT_USER, r"Software\Glare Technologies\Indigo Renderer") value = winreg.QueryValueEx (hKey, "InstallDirectory")[0] except: value = "" return value return ""
def check_output_path(self, path): efutil.export_path = efutil.filesystem_path(path) if not os.path.isdir(efutil.export_path): parent_dir = os.path.realpath( os.path.join(efutil.export_path, os.path.pardir) ) if not self.check_write(parent_dir): indigo_log('Output path "%s" is not writable' % parent_dir) raise Exception('Output path is not writable') try: os.makedirs(efutil.export_path) except: indigo_log('Could not create output path %s' % efutil.export_path) raise Exception('Could not create output path') if not self.check_write(efutil.export_path): indigo_log('Output path "%s" is not writable' % efutil.export_path) raise Exception('Output path is not writable') igs_filename = '/'.join( (efutil.export_path, self.properties.filename) ) # indigo_log('Writing to %s'%igs_filename) if efutil.export_path[-1] not in ('/', '\\'): efutil.export_path += '/' try: out_file = open(igs_filename, 'w') out_file.close() except: indigo_log('Failed to open output file "%s" for writing: check output path setting' % igs_filename) raise Exception('Failed to open output file for writing: check output path setting') return igs_filename
def get_sort_dir(force_debug=False): addon_prefs = bpy.context.user_preferences.addons[common.preference_bl_name].preferences debug = bpy.context.scene.debug_prop return_path = addon_prefs.install_path if debug is True: return_path = addon_prefs.install_path_debug if force_debug: return_path = addon_prefs.install_path_debug return efutil.filesystem_path(return_path) + "/"
def process_filepath_data(scene, obj, file_path, paramset, parameter_name): file_basename = os.path.basename(file_path) library_filepath = obj.library.filepath if (hasattr(obj, 'library') and obj.library) else '' file_library_path = efutil.filesystem_path( bpy.path.abspath(file_path, library_filepath)) file_relative = efutil.filesystem_path(file_library_path) if (hasattr( obj, 'library') and obj.library) else efutil.filesystem_path(file_path) if scene.luxrender_engine.allow_file_embed(): paramset.add_string(parameter_name, file_basename) encoded_data, encoded_size = bencode_file2string_with_size( file_relative) paramset.increase_size('%s_data' % parameter_name, encoded_size) paramset.add_string('%s_data' % parameter_name, encoded_data.splitlines()) else: paramset.add_string(parameter_name, file_relative)
def getServices(): cube = bpy.context.scene.objects['Cube'] path = cube.material_slots[0].material.texture_slots[0].texture.image.filepath xfac = efutil.filesystem_path(path) print("path now>> %s" % xfac) abs = os.path.abspath(xfac) print("path abs>> %s" % abs) rel = efutil.path_relative_to_export(path) print("path rel>> %s" % rel)
def getServices(): cube = bpy.context.scene.objects['Cube'] path = cube.material_slots[0].material.texture_slots[ 0].texture.image.filepath xfac = efutil.filesystem_path(path) print("path now>> %s" % xfac) abs = os.path.abspath(xfac) print("path abs>> %s" % abs) rel = efutil.path_relative_to_export(path) print("path rel>> %s" % rel)
def get_sort_dir(force_debug=False): addon_prefs = bpy.context.user_preferences.addons[ common.preference_bl_name].preferences debug = bpy.context.scene.debug_prop return_path = addon_prefs.install_path if debug is True: return_path = addon_prefs.install_path_debug if force_debug: return_path = addon_prefs.install_path_debug return efutil.filesystem_path(return_path) + "/"
def set_export_path(self, scene): # replace /tmp/ with the real %temp% folder on Windows # OSX also has a special temp location that we should use fp = scene.render.filepath output_path_split = list(os.path.split(fp)) if sys.platform in ('win32', 'darwin') and output_path_split[0] == '/tmp': output_path_split[0] = efutil.temp_directory() fp = '/'.join(output_path_split) scene_path = efutil.filesystem_path(fp) if os.path.isdir(scene_path): self.output_dir = scene_path else: self.output_dir = os.path.dirname(scene_path) if self.output_dir[-1] not in ('/', '\\'): self.output_dir += '/' if scene.luxrender_engine.export_type == 'INT': write_files = scene.luxrender_engine.write_files if write_files: api_type = 'FILE' else: api_type = 'API' if sys.platform == 'darwin': self.output_dir = efutil.filesystem_path(bpy.app.tempdir) else: self.output_dir = efutil.temp_directory() else: api_type = 'FILE' write_files = True efutil.export_path = self.output_dir return api_type, write_files
def set_export_path(self, scene): # replace /tmp/ with the real %temp% folder on Windows # OSX also has a special temp location that we should use fp = scene.render.filepath output_path_split = list(os.path.split(fp)) if sys.platform in ('win32', 'darwin') and output_path_split[0] == '/tmp': output_path_split[0] = efutil.temp_directory() fp = '/'.join(output_path_split) scene_path = efutil.filesystem_path( fp ) if os.path.isdir(scene_path): self.output_dir = scene_path else: self.output_dir = os.path.dirname( scene_path ) if self.output_dir[-1] not in ('/', '\\'): self.output_dir += '/' if scene.luxrender_engine.export_type == 'INT': write_files = scene.luxrender_engine.write_files if write_files: api_type = 'FILE' else: api_type = 'API' if sys.platform == 'darwin': self.output_dir = efutil.filesystem_path( bpy.app.tempdir ) else: self.output_dir = efutil.temp_directory() else: api_type = 'FILE' write_files = True efutil.export_path = self.output_dir return api_type, write_files
def build_xml_element(self, scene): xml = self.Element('tonemapping') # format needs to be entirely generated at export time if self.tonemap_type == 'reinhard': xml_format = { 'reinhard': { 'pre_scale': 'reinhard_pre', 'post_scale': 'reinhard_post', 'burn': 'reinhard_burn', } } elif self.tonemap_type == 'linear': xml_format = { 'linear': { 'scale': 'linear_unit', } } elif self.tonemap_type == 'camera': if self.camera_response_type == 'preset': crf = [self.camera_response_preset] elif self.camera_response_file!="" and os.path.exists(efutil.filesystem_path(self.camera_response_file)): crf = 'camera_response_file' else: indigo_log('WARNING: Invalid camera tonemapping, using default dscs315.txt') crf = ['data/camera_response_functions/dscs315.txt'] xml_format = { 'camera': { 'response_function_path': crf, 'ev_adjust': 'camera_ev', 'film_iso': [scene.camera.data.indigo_camera.iso] } } elif self.tonemap_type == 'filmic': xml_format = { 'filmic': { 'scale': 'filmic_scale', } } else: xml_format = {} self.build_subelements(scene, xml_format, xml) return xml
def build_xml_element(self, scene): xml = self.Element('tonemapping') # format needs to be entirely generated at export time if self.tonemap_type == 'reinhard': xml_format = { 'reinhard': { 'pre_scale': 'reinhard_pre', 'post_scale': 'reinhard_post', 'burn': 'reinhard_burn', } } elif self.tonemap_type == 'linear': xml_format = { 'linear': { 'scale': 'linear_unit', } } elif self.tonemap_type == 'camera': if self.camera_response_type == 'preset': crf = [self.camera_response_preset] elif self.camera_response_file!="" and os.path.exists(efutil.filesystem_path(self.camera_response_file)): crf = 'camera_response_file' else: indigo_log('WARNING: Invalid camera tonemapping, using default dscs315.txt') crf = ['data/camera_response_functions/dscs315.txt'] xml_format = { 'camera': { 'response_function_path': crf, 'ev_adjust': 'camera_ev', 'film_iso': [scene.camera.data.indigo_camera.iso] } } else: xml_format = {} self.build_subelements(scene, xml_format, xml) return xml
def render(self, scene): if self is None or scene is None: MtsLog('ERROR: Scene is missing!') return if scene.mitsuba_engine.binary_path == '': MtsLog('ERROR: The binary path is unspecified!') return with self.render_lock: # just render one thing at a time if scene.name == 'preview': self.render_preview(scene) return config_updates = {} binary_path = os.path.abspath(efutil.filesystem_path(scene.mitsuba_engine.binary_path)) if os.path.isdir(binary_path) and os.path.exists(binary_path): config_updates['binary_path'] = binary_path try: for k, v in config_updates.items(): efutil.write_config_value('mitsuba', 'defaults', k, v) except Exception as err: MtsLog('WARNING: Saving Mitsuba configuration failed, please set your user scripts dir: %s' % err) scene_path = efutil.filesystem_path(scene.render.filepath) if os.path.isdir(scene_path): output_dir = scene_path else: output_dir = os.path.dirname(scene_path) MtsLog('MtsBlend: Current directory = "%s"' % output_dir) output_basename = efutil.scene_filename() + '.%s.%05i' % (scene.name, scene.frame_current) result = SceneExporter( directory = output_dir, filename = output_basename, ).export(scene) if not result: MtsLog('Error while exporting -- check the console for details.') return if scene.mitsuba_engine.export_mode == 'render': MtsLog("MtsBlend: Launching renderer ..") if scene.mitsuba_engine.render_mode == 'gui': MtsLaunch(scene.mitsuba_engine.binary_path, output_dir, ['mtsgui', efutil.export_path]) elif scene.mitsuba_engine.render_mode == 'cli': output_file = efutil.export_path[:-4] + "." + scene.camera.data.mitsuba_film.fileExtension mitsuba_process = MtsLaunch(scene.mitsuba_engine.binary_path, output_dir, ['mitsuba', '-r', str(scene.mitsuba_engine.refresh_interval), '-o', output_file, efutil.export_path] ) framebuffer_thread = MtsFilmDisplay() framebuffer_thread.set_kick_period(scene.mitsuba_engine.refresh_interval) framebuffer_thread.begin(self, output_file, resolution(scene)) render_update_timer = None while mitsuba_process.poll() == None and not self.test_break(): render_update_timer = threading.Timer(1, self.process_wait_timer) render_update_timer.start() if render_update_timer.isAlive(): render_update_timer.join() # If we exit the wait loop (user cancelled) and mitsuba is still running, then send SIGINT if mitsuba_process.poll() == None: # Use SIGTERM because that's the only one supported on Windows mitsuba_process.send_signal(subprocess.signal.SIGTERM) # Stop updating the render result and load the final image framebuffer_thread.stop() framebuffer_thread.join() if mitsuba_process.poll() != None and mitsuba_process.returncode != 0: MtsLog("MtsBlend: Rendering failed -- check the console") else: framebuffer_thread.kick(render_end=True) framebuffer_thread.shutdown()
def render(self, scene): if self is None or scene is None: MtsLog('ERROR: Scene is missing!') return if scene.mitsuba_engine.binary_path == '': MtsLog('ERROR: The binary path is unspecified!') return with self.render_lock: # just render one thing at a time if scene.name == 'preview': self.render_preview(scene) return config_updates = {} binary_path = os.path.abspath( efutil.filesystem_path(scene.mitsuba_engine.binary_path)) if os.path.isdir(binary_path) and os.path.exists(binary_path): config_updates['binary_path'] = binary_path try: for k, v in config_updates.items(): efutil.write_config_value('mitsuba', 'defaults', k, v) except Exception as err: MtsLog( 'WARNING: Saving Mitsuba configuration failed, please set your user scripts dir: %s' % err) scene_path = efutil.filesystem_path(scene.render.filepath) if os.path.isdir(scene_path): output_dir = scene_path else: output_dir = os.path.dirname(scene_path) MtsLog('MtsBlend: Current directory = "%s"' % output_dir) output_basename = efutil.scene_filename() + '.%s.%05i' % ( scene.name, scene.frame_current) result = SceneExporter( directory=output_dir, filename=output_basename, ).export(scene) if not result: MtsLog( 'Error while exporting -- check the console for details.') return if scene.mitsuba_engine.export_mode == 'render': MtsLog("MtsBlend: Launching renderer ..") if scene.mitsuba_engine.render_mode == 'gui': MtsLaunch(scene.mitsuba_engine.binary_path, output_dir, ['mtsgui', efutil.export_path]) elif scene.mitsuba_engine.render_mode == 'cli': output_file = efutil.export_path[: -4] + "." + scene.camera.data.mitsuba_film.fileExtension mitsuba_process = MtsLaunch( scene.mitsuba_engine.binary_path, output_dir, [ 'mitsuba', '-r', str(scene.mitsuba_engine.refresh_interval), '-o', output_file, efutil.export_path ]) framebuffer_thread = MtsFilmDisplay() framebuffer_thread.set_kick_period( scene.mitsuba_engine.refresh_interval) framebuffer_thread.begin(self, output_file, resolution(scene)) render_update_timer = None while mitsuba_process.poll( ) == None and not self.test_break(): render_update_timer = threading.Timer( 1, self.process_wait_timer) render_update_timer.start() if render_update_timer.isAlive(): render_update_timer.join() # If we exit the wait loop (user cancelled) and mitsuba is still running, then send SIGINT if mitsuba_process.poll() == None: # Use SIGTERM because that's the only one supported on Windows mitsuba_process.send_signal(subprocess.signal.SIGTERM) # Stop updating the render result and load the final image framebuffer_thread.stop() framebuffer_thread.join() if mitsuba_process.poll( ) != None and mitsuba_process.returncode != 0: MtsLog( "MtsBlend: Rendering failed -- check the console") else: framebuffer_thread.kick(render_end=True) framebuffer_thread.shutdown()
def convert_texture(scene, texture, variant_hint=None): # Lux only supports blender's textures in float variant (except for image/ocean, but both of these are exported as imagemap) variant = 'float' paramset = ParamSet() lux_tex_name = 'blender_%s' % texture.type.lower() mapping_type = '3D' if texture.type not in ('IMAGE', 'OCEAN'): paramset.add_float('bright', texture.intensity) paramset.add_float('contrast', texture.contrast) if texture.type == 'BLEND': progression_map = { 'LINEAR': 'lin', 'QUADRATIC': 'quad', 'EASING': 'ease', 'DIAGONAL': 'diag', 'SPHERICAL': 'sphere', 'QUADRATIC_SPHERE': 'halo', 'RADIAL': 'radial', } paramset.add_bool('flipxy', texture.use_flip_axis) \ .add_string('type', progression_map[texture.progression]) if texture.type == 'CLOUDS': paramset.add_string('noisetype', texture.noise_type.lower() ) \ .add_string('noisebasis', texture.noise_basis.lower() ) \ .add_float('noisesize', texture.noise_scale) \ .add_integer('noisedepth', texture.noise_depth) if texture.type == 'DISTORTED_NOISE': lux_tex_name = 'blender_distortednoise' paramset.add_string('type', texture.noise_distortion.lower()) \ .add_string('noisebasis', texture.noise_basis.lower() ) \ .add_float('distamount', texture.distortion) \ .add_float('noisesize', texture.noise_scale) \ .add_float('nabla', texture.nabla) if texture.type == 'MAGIC': paramset.add_integer('noisedepth', texture.noise_depth) \ .add_float('turbulence', texture.turbulence) if texture.type == 'MARBLE': paramset.add_string('type', texture.marble_type.lower() ) \ .add_string('noisetype', texture.noise_type.lower() ) \ .add_string('noisebasis', texture.noise_basis.lower() ) \ .add_string('noisebasis2', texture.noise_basis_2.lower() ) \ .add_float('noisesize', texture.noise_scale) \ .add_float('turbulence', texture.turbulence) \ .add_integer('noisedepth', texture.noise_depth) if texture.type == 'MUSGRAVE': paramset.add_string('type', texture.musgrave_type.lower() ) \ .add_float('h', texture.dimension_max) \ .add_float('lacu', texture.lacunarity) \ .add_string('noisebasis', texture.noise_basis.lower() ) \ .add_float('noisesize', texture.noise_scale) \ .add_float('octs', texture.octaves) # NOISE shows no params ? if texture.type == 'STUCCI': paramset.add_string('type', texture.stucci_type.lower() ) \ .add_string('noisetype', texture.noise_type.lower() ) \ .add_string('noisebasis', texture.noise_basis.lower() ) \ .add_float('noisesize', texture.noise_scale) \ .add_float('turbulence', texture.turbulence) if texture.type == 'VORONOI': distancem_map = { 'DISTANCE': 'actual_distance', 'DISTANCE_SQUARED': 'distance_squared', 'MANHATTAN': 'manhattan', 'CHEBYCHEV': 'chebychev', 'MINKOVSKY_HALF': 'minkovsky_half', 'MINKOVSKY_FOUR': 'minkovsky_four', 'MINKOVSKY': 'minkovsky' } paramset.add_string('distmetric', distancem_map[texture.distance_metric]) \ .add_float('minkovsky_exp', texture.minkovsky_exponent) \ .add_float('noisesize', texture.noise_scale) \ .add_float('nabla', texture.nabla) \ .add_float('w1', texture.weight_1) \ .add_float('w2', texture.weight_2) \ .add_float('w3', texture.weight_3) \ .add_float('w4', texture.weight_4) if texture.type == 'WOOD': paramset.add_string('noisebasis', texture.noise_basis.lower() ) \ .add_string('noisebasis2', texture.noise_basis_2.lower() ) \ .add_float('noisesize', texture.noise_scale) \ .add_string('noisetype', texture.noise_type.lower() ) \ .add_float('turbulence', texture.turbulence) \ .add_string('type', texture.wood_type.lower() ) # Translate Blender Image/movie into lux tex if texture.type == 'IMAGE' and texture.image and texture.image.source in [ 'GENERATED', 'FILE', 'SEQUENCE' ]: extract_path = os.path.join(efutil.scene_filename(), bpy.path.clean_name(scene.name), '%05d' % scene.frame_current) if texture.image.source == 'GENERATED': tex_image = 'luxblend_baked_image_%s.%s' % (bpy.path.clean_name( texture.name), scene.render.image_settings.file_format) tex_image = os.path.join(extract_path, tex_image) texture.image.save_render(tex_image, scene) if texture.image.source == 'FILE': if texture.image.packed_file: tex_image = 'luxblend_extracted_image_%s.%s' % ( bpy.path.clean_name( texture.name), scene.render.image_settings.file_format) tex_image = os.path.join(extract_path, tex_image) texture.image.save_render(tex_image, scene) else: if texture.library is not None: f_path = efutil.filesystem_path( bpy.path.abspath(texture.image.filepath, texture.library.filepath)) else: f_path = efutil.filesystem_path(texture.image.filepath) if not os.path.exists(f_path): raise Exception( 'Image referenced in blender texture %s doesn\'t exist: %s' % (texture.name, f_path)) tex_image = efutil.filesystem_path(f_path) if texture.image.source == 'SEQUENCE': if texture.image.packed_file: tex_image = 'luxblend_extracted_image_%s.%s' % ( bpy.path.clean_name( texture.name), scene.render.image_settings.file_format) tex_image = os.path.join(extract_path, tex_image) texture.image.save_render(tex_image, scene) else: # sequence params from blender sequence = bpy.data.textures[(texture.name).replace( '.001', '' )].image_user # remove tex_preview extension to avoid error seqframes = sequence.frame_duration seqoffset = sequence.frame_offset seqstartframe = sequence.frame_start # the global frame at which the imagesequence starts seqcyclic = sequence.use_cyclic currentframe = scene.frame_current if texture.library is not None: f_path = efutil.filesystem_path( bpy.path.abspath(texture.image.filepath, texture.library.filepath)) else: f_path = efutil.filesystem_path(texture.image.filepath) if currentframe < seqstartframe: fnumber = 1 + seqoffset else: fnumber = currentframe - (seqstartframe - 1) + seqoffset if fnumber > seqframes: if seqcyclic == False: fnumber = seqframes else: fnumber = (currentframe - (seqstartframe - 1)) % seqframes if fnumber == 0: fnumber = seqframes import re def get_seq_filename(number, f_path): m = re.findall(r'(\d+)', f_path) if len(m) == 0: return "ERR: Can't find pattern" rightmost_number = m[len(m) - 1] seq_length = len(rightmost_number) nstr = "%i" % number new_seq_number = nstr.zfill(seq_length) return f_path.replace(rightmost_number, new_seq_number) f_path = get_seq_filename(fnumber, f_path) # print("-----------------", f_path) if not os.path.exists(f_path): raise Exception( 'Image referenced in blender texture %s doesn\'t exist: %s' % (texture.name, f_path)) tex_image = efutil.filesystem_path(f_path) lux_tex_name = 'imagemap' sampling = texture.luxrender_texture.luxrender_tex_imagesampling if variant_hint: variant = variant_hint else: variant = 'color' paramset.add_string('filename', tex_image) if variant_hint == float: paramset.add_string('channel', sampling.channel) paramset.add_integer('discardmipmaps', sampling.discardmipmaps) paramset.add_float('gain', sampling.gain) paramset.add_float('gamma', sampling.gamma) paramset.add_float('maxanisotropy', sampling.maxanisotropy) paramset.add_string('wrap', sampling.wrap) mapping_type = '2D' # Similar to image handler, but for Ocean tex if texture.type == 'OCEAN': if texture.ocean.output == 'FOAM': ocean_mods = [ m for m in texture.ocean.ocean_object.modifiers if m.type == 'OCEAN' ] if len(ocean_mods) == 0: print('No ocean modifiers!') else: ocean_mod = ocean_mods[0] if texture.ocean.output == 'FOAM': tex_image = efutil.filesystem_path( os.path.join(ocean_mod.filepath, 'foam_%04d.exr' % scene.frame_current)) #SOON! (until 3D disp support...) #elif texture.ocean.output == 'DISPLACEMENT': #tex_image = os.path.join(ocean_mod.filepath, 'disp_%04d.exr' % scene.frame_current) lux_tex_name = 'imagemap' if variant_hint: variant = variant_hint else: variant = 'color' paramset.add_string('filename', tex_image) paramset.add_float('gamma', 1.0) mapping_type = '2D' else: lux_tex_name = 'constant' if mapping_type == '3D': paramset.update( texture.luxrender_texture.luxrender_tex_transform.get_paramset( scene)) else: paramset.update( texture.luxrender_texture.luxrender_tex_mapping.get_paramset( scene)) return variant, lux_tex_name, paramset
def convert_texture(scene, texture, variant_hint=None): # Lux only supports blender's textures in float variant (except for image/ocean, but both of these are exported as imagemap) variant = 'float' paramset = ParamSet() lux_tex_name = 'blender_%s' % texture.type.lower() mapping_type = '3D' if texture.type not in ('IMAGE', 'OCEAN'): paramset.add_float('bright', texture.intensity) paramset.add_float('contrast', texture.contrast) if texture.type == 'BLEND': progression_map = { 'LINEAR': 'lin', 'QUADRATIC': 'quad', 'EASING': 'ease', 'DIAGONAL': 'diag', 'SPHERICAL': 'sphere', 'QUADRATIC_SPHERE': 'halo', 'RADIAL': 'radial', } paramset.add_bool('flipxy', texture.use_flip_axis) \ .add_string('type', progression_map[texture.progression]) if texture.type == 'CLOUDS': paramset.add_string('noisetype', texture.noise_type.lower() ) \ .add_string('noisebasis', texture.noise_basis.lower() ) \ .add_float('noisesize', texture.noise_scale) \ .add_integer('noisedepth', texture.noise_depth) if texture.type == 'DISTORTED_NOISE': lux_tex_name = 'blender_distortednoise' paramset.add_string('type', texture.noise_distortion.lower()) \ .add_string('noisebasis', texture.noise_basis.lower() ) \ .add_float('distamount', texture.distortion) \ .add_float('noisesize', texture.noise_scale) \ .add_float('nabla', texture.nabla) if texture.type == 'MAGIC': paramset.add_integer('noisedepth', texture.noise_depth) \ .add_float('turbulence', texture.turbulence) if texture.type == 'MARBLE': paramset.add_string('type', texture.marble_type.lower() ) \ .add_string('noisetype', texture.noise_type.lower() ) \ .add_string('noisebasis', texture.noise_basis.lower() ) \ .add_string('noisebasis2', texture.noise_basis_2.lower() ) \ .add_float('noisesize', texture.noise_scale) \ .add_float('turbulence', texture.turbulence) \ .add_integer('noisedepth', texture.noise_depth) if texture.type == 'MUSGRAVE': paramset.add_string('type', texture.musgrave_type.lower() ) \ .add_float('h', texture.dimension_max) \ .add_float('lacu', texture.lacunarity) \ .add_string('noisebasis', texture.noise_basis.lower() ) \ .add_float('noisesize', texture.noise_scale) \ .add_float('octs', texture.octaves) # NOISE shows no params ? if texture.type == 'STUCCI': paramset.add_string('type', texture.stucci_type.lower() ) \ .add_string('noisetype', texture.noise_type.lower() ) \ .add_string('noisebasis', texture.noise_basis.lower() ) \ .add_float('noisesize', texture.noise_scale) \ .add_float('turbulence', texture.turbulence) if texture.type == 'VORONOI': distancem_map = { 'DISTANCE': 'actual_distance', 'DISTANCE_SQUARED': 'distance_squared', 'MANHATTAN': 'manhattan', 'CHEBYCHEV': 'chebychev', 'MINKOVSKY_HALF': 'minkovsky_half', 'MINKOVSKY_FOUR': 'minkovsky_four', 'MINKOVSKY': 'minkovsky' } paramset.add_string('distmetric', distancem_map[texture.distance_metric]) \ .add_float('minkovsky_exp', texture.minkovsky_exponent) \ .add_float('noisesize', texture.noise_scale) \ .add_float('nabla', texture.nabla) \ .add_float('w1', texture.weight_1) \ .add_float('w2', texture.weight_2) \ .add_float('w3', texture.weight_3) \ .add_float('w4', texture.weight_4) if texture.type == 'WOOD': paramset.add_string('noisebasis', texture.noise_basis.lower() ) \ .add_string('noisebasis2', texture.noise_basis_2.lower() ) \ .add_float('noisesize', texture.noise_scale) \ .add_string('noisetype', texture.noise_type.lower() ) \ .add_float('turbulence', texture.turbulence) \ .add_string('type', texture.wood_type.lower() ) # Translate Blender Image/movie into lux tex if texture.type == 'IMAGE' and texture.image and texture.image.source in ['GENERATED', 'FILE', 'SEQUENCE']: extract_path = os.path.join( efutil.scene_filename(), bpy.path.clean_name(scene.name), '%05d' % scene.frame_current ) if texture.image.source == 'GENERATED': tex_image = 'luxblend_baked_image_%s.%s' % (bpy.path.clean_name(texture.name), scene.render.image_settings.file_format) tex_image = os.path.join(extract_path, tex_image) texture.image.save_render(tex_image, scene) if texture.image.source == 'FILE': if texture.image.packed_file: tex_image = 'luxblend_extracted_image_%s.%s' % (bpy.path.clean_name(texture.name), scene.render.image_settings.file_format) tex_image = os.path.join(extract_path, tex_image) texture.image.save_render(tex_image, scene) else: if texture.library is not None: f_path = efutil.filesystem_path(bpy.path.abspath( texture.image.filepath, texture.library.filepath)) else: f_path = efutil.filesystem_path(texture.image.filepath) if not os.path.exists(f_path): raise Exception('Image referenced in blender texture %s doesn\'t exist: %s' % (texture.name, f_path)) tex_image = efutil.filesystem_path(f_path) if texture.image.source == 'SEQUENCE': if texture.image.packed_file: tex_image = 'luxblend_extracted_image_%s.%s' % (bpy.path.clean_name(texture.name), scene.render.image_settings.file_format) tex_image = os.path.join(extract_path, tex_image) texture.image.save_render(tex_image, scene) else: # sequence params from blender sequence = bpy.data.textures[(texture.name).replace('.001', '')].image_user # remove tex_preview extension to avoid error seqframes = sequence.frame_duration seqoffset = sequence.frame_offset seqstartframe = sequence.frame_start # the global frame at which the imagesequence starts seqcyclic = sequence.use_cyclic currentframe = scene.frame_current if texture.library is not None: f_path = efutil.filesystem_path(bpy.path.abspath( texture.image.filepath, texture.library.filepath)) else: f_path = efutil.filesystem_path(texture.image.filepath) if currentframe < seqstartframe: fnumber = 1 + seqoffset else: fnumber = currentframe - (seqstartframe-1) + seqoffset if fnumber > seqframes: if seqcyclic == False: fnumber = seqframes else: fnumber = (currentframe - (seqstartframe-1)) % seqframes if fnumber == 0: fnumber = seqframes import re def get_seq_filename(number, f_path): m = re.findall(r'(\d+)', f_path) if len(m) == 0: return "ERR: Can't find pattern" rightmost_number = m[len(m)-1] seq_length = len(rightmost_number) nstr = "%i" %number new_seq_number = nstr.zfill(seq_length) return f_path.replace(rightmost_number, new_seq_number) f_path = get_seq_filename(fnumber, f_path) # print("-----------------", f_path) if not os.path.exists(f_path): raise Exception('Image referenced in blender texture %s doesn\'t exist: %s' % (texture.name, f_path)) tex_image = efutil.filesystem_path(f_path) lux_tex_name = 'imagemap' sampling = texture.luxrender_texture.luxrender_tex_imagesampling if variant_hint: variant = variant_hint else: variant = 'color' paramset.add_string('filename', tex_image) if variant_hint == float: paramset.add_string('channel', sampling.channel) paramset.add_integer('discardmipmaps', sampling.discardmipmaps) paramset.add_float('gain', sampling.gain) paramset.add_float('gamma', sampling.gamma) paramset.add_float('maxanisotropy', sampling.maxanisotropy) paramset.add_string('wrap', sampling.wrap) mapping_type = '2D' # Similar to image handler, but for Ocean tex if texture.type == 'OCEAN': if texture.ocean.output == 'FOAM': ocean_mods = [m for m in texture.ocean.ocean_object.modifiers if m.type == 'OCEAN'] if len(ocean_mods) == 0: print ('No ocean modifiers!') else: ocean_mod = ocean_mods[0] if texture.ocean.output == 'FOAM': tex_image = efutil.filesystem_path(os.path.join(ocean_mod.filepath, 'foam_%04d.exr' % scene.frame_current)) #SOON! (until 3D disp support...) #elif texture.ocean.output == 'DISPLACEMENT': #tex_image = os.path.join(ocean_mod.filepath, 'disp_%04d.exr' % scene.frame_current) lux_tex_name = 'imagemap' if variant_hint: variant = variant_hint else: variant = 'color' paramset.add_string('filename', tex_image) paramset.add_float('gamma', 1.0) mapping_type = '2D' else: lux_tex_name = 'constant' if mapping_type == '3D': paramset.update( texture.luxrender_texture.luxrender_tex_transform.get_paramset(scene) ) else: paramset.update( texture.luxrender_texture.luxrender_tex_mapping.get_paramset(scene) ) return variant, lux_tex_name, paramset
def convert_texture(scene, texture, variant_hint=None): # Lux only supports blender's textures in float variant (except for image/ocean (both of these are exported as imagemap) variant = 'float' paramset = ParamSet() lux_tex_name = 'blender_%s' % texture.type.lower() mapping_type = '3D' if texture.type not in ('IMAGE', 'OCEAN'): paramset.add_float('bright', texture.intensity) paramset.add_float('contrast', texture.contrast) if texture.type == 'BLEND': progression_map = { 'LINEAR': 'lin', 'QUADRATIC': 'quad', 'EASING': 'ease', 'DIAGONAL': 'diag', 'SPHERICAL': 'sphere', 'QUADRATIC_SPHERE': 'halo', 'RADIAL': 'radial', } paramset.add_bool('flipxy', texture.use_flip_axis) \ .add_string('type', progression_map[texture.progression]) if texture.type == 'CLOUDS': paramset.add_string('noisetype', texture.noise_type.lower() ) \ .add_string('noisebasis', texture.noise_basis.lower() ) \ .add_float('noisesize', texture.noise_scale) \ .add_integer('noisedepth', texture.noise_depth) if texture.type == 'DISTORTED_NOISE': lux_tex_name = 'blender_distortednoise' paramset.add_string('type', texture.noise_distortion.lower()) \ .add_string('noisebasis', texture.noise_basis.lower() ) \ .add_float('distamount', texture.distortion) \ .add_float('noisesize', texture.noise_scale) \ .add_float('nabla', texture.nabla) if texture.type == 'MAGIC': paramset.add_integer('noisedepth', texture.noise_depth) \ .add_float('turbulence', texture.turbulence) if texture.type == 'MARBLE': paramset.add_string('type', texture.marble_type.lower() ) \ .add_string('noisetype', texture.noise_type.lower() ) \ .add_string('noisebasis', texture.noise_basis.lower() ) \ .add_string('noisebasis2', texture.noise_basis_2.lower() ) \ .add_float('noisesize', texture.noise_scale) \ .add_float('turbulence', texture.turbulence) \ .add_integer('noisedepth', texture.noise_depth) if texture.type == 'MUSGRAVE': paramset.add_string('type', texture.musgrave_type.lower() ) \ .add_float('h', texture.dimension_max) \ .add_float('lacu', texture.lacunarity) \ .add_string('noisebasis', texture.noise_basis.lower() ) \ .add_float('noisesize', texture.noise_scale) \ .add_float('octs', texture.octaves) # NOISE shows no params ? if texture.type == 'STUCCI': paramset.add_string('type', texture.stucci_type.lower() ) \ .add_string('noisetype', texture.noise_type.lower() ) \ .add_string('noisebasis', texture.noise_basis.lower() ) \ .add_float('noisesize', texture.noise_scale) \ .add_float('turbulence', texture.turbulence) if texture.type == 'VORONOI': distancem_map = { 'DISTANCE': 'actual_distance', 'DISTANCE_SQUARED': 'distance_squared', 'MANHATTAN': 'manhattan', 'CHEBYCHEV': 'chebychev', 'MINKOVSKY_HALF': 'minkovsky_half', 'MINKOVSKY_FOUR': 'minkovsky_four', 'MINKOVSKY': 'minkovsky' } paramset.add_string('distmetric', distancem_map[texture.distance_metric]) \ .add_float('minkovsky_exp', texture.minkovsky_exponent) \ .add_float('noisesize', texture.noise_scale) \ .add_float('nabla', texture.nabla) \ .add_float('w1', texture.weight_1) \ .add_float('w2', texture.weight_2) \ .add_float('w3', texture.weight_3) \ .add_float('w4', texture.weight_4) if texture.type == 'WOOD': paramset.add_string('noisebasis', texture.noise_basis.lower() ) \ .add_string('noisebasis2', texture.noise_basis_2.lower() ) \ .add_float('noisesize', texture.noise_scale) \ .add_string('noisetype', texture.noise_type.lower() ) \ .add_float('turbulence', texture.turbulence) \ .add_string('type', texture.wood_type.lower() ) # Translate Blender Image/movie into lux tex if texture.type == 'IMAGE' and texture.image and texture.image.source in ['GENERATED', 'FILE']: extract_path = os.path.join( efutil.scene_filename(), bpy.path.clean_name(scene.name), '%05d' % scene.frame_current ) if texture.image.source == 'GENERATED': tex_image = 'luxblend_baked_image_%s.%s' % (bpy.path.clean_name(texture.name), scene.render.image_settings.file_format) tex_image = os.path.join(extract_path, tex_image) texture.image.save_render(tex_image, scene) if texture.image.source == 'FILE': if texture.image.packed_file: tex_image = 'luxblend_extracted_image_%s.%s' % (bpy.path.clean_name(texture.name), scene.render.image_settings.file_format) tex_image = os.path.join(extract_path, tex_image) texture.image.save_render(tex_image, scene) else: if texture.library is not None: f_path = efutil.filesystem_path(bpy.path.abspath( texture.image.filepath, texture.library.filepath)) else: f_path = efutil.filesystem_path(texture.image.filepath) if not os.path.exists(f_path): raise Exception('Image referenced in blender texture %s doesn\'t exist: %s' % (texture.name, f_path)) tex_image = efutil.filesystem_path(f_path) lux_tex_name = 'imagemap' if variant_hint: variant = variant_hint else: variant = 'color' paramset.add_string('filename', tex_image) paramset.add_float('gamma', 2.2) mapping_type = '2D' # Similar to image handler, but for Ocean tex if texture.type == 'OCEAN': if texture.ocean.output == 'FOAM': ocean_mods = [m for m in texture.ocean.ocean_object.modifiers if m.type == 'OCEAN'] if len(ocean_mods) == 0: print ('No ocean modifiers!') else: ocean_mod = ocean_mods[0] if texture.ocean.output == 'FOAM': tex_image = efutil.filesystem_path(os.path.join(ocean_mod.filepath, 'foam_%04d.exr' % scene.frame_current)) #SOON! (until 3D disp support...) #elif texture.ocean.output == 'DISPLACEMENT': #tex_image = os.path.join(ocean_mod.filepath, 'disp_%04d.exr' % scene.frame_current) lux_tex_name = 'imagemap' if variant_hint: variant = variant_hint else: variant = 'color' paramset.add_string('filename', tex_image) paramset.add_float('gamma', 1.0) mapping_type = '2D' else: lux_tex_name = 'constant' if mapping_type == '3D': paramset.update( texture.luxrender_texture.luxrender_tex_transform.get_paramset(scene) ) else: paramset.update( texture.luxrender_texture.luxrender_tex_mapping.get_paramset(scene) ) return variant, lux_tex_name, paramset
def api_output(self): ''' Calculate type and parameters for LuxRender Film statement Returns tuple(2) (string, list) ''' scene = LuxManager.CurrentScene xr, yr = self.resolution(scene) params = ParamSet() if scene.render.use_border: #Border rendering handler, this gets a bit tricky. Blender ALWAYS expects to get back a cropped image, it will handle the padding itself if the user asked for it. if scene.render.use_crop_to_border: #user asked to crop, so always crop (x1,x2,y1,y2) = [ scene.render.border_min_x, scene.render.border_max_x, scene.render.border_min_y, scene.render.border_max_y ] # Set resolution # This is a new method of "rounding" the cropped image to match blenders expected rectangle_size # I tested this with several cases which failed with the former rounding, pls check - Jens params.add_integer('xresolution', int((xr*x2)-(xr*x1)+1)) params.add_integer('yresolution', int((yr*y2)-(yr*y1)+1)) if not scene.render.use_crop_to_border: #user asked for padded-to-full-frame output, there are a few cases where Lux needs to do this itself since the rendered image will not be returned to Blender if scene.luxrender_engine.render == False or (scene.luxrender_engine.export_type == 'EXT' and scene.luxrender_engine.binary_name == 'luxrender' and scene.luxrender_engine.monitor_external == False): #If run-renderer (scene.luxrender_engine.render) is disabled or we are in un-monitored external mode, we do not return the image to Blender and Lux must pad the image itself cropwindow = [ scene.render.border_min_x, scene.render.border_max_x, 1-scene.render.border_min_y, 1-scene.render.border_max_y ] #Subtract scene.render.border Y values from 1 to translate between Blender and Lux conventions params.add_float('cropwindow', cropwindow) params.add_integer('xresolution', xr) #Don't forget to set full frame resolution params.add_integer('yresolution', yr) else: #we are returning the image to blender which will pad for us, so have LuxRender send back a cropped frame anyway (x1,x2,y1,y2) = [ scene.render.border_min_x, scene.render.border_max_x, scene.render.border_min_y, scene.render.border_max_y ] # Set resolution # This is a new method of "rounding" the cropped image to match blenders expected rectangle_size # I tested this with several cases which failed with the former rounding, pls check - Jens params.add_integer('xresolution', int((xr*x2)-(xr*x1)+1)) params.add_integer('yresolution', int((yr*y2)-(yr*y1)+1)) else: # Set resolution params.add_integer('xresolution', xr) params.add_integer('yresolution', yr) # ColourSpace if self.luxrender_colorspace.preset: cs_object = getattr(colorspace_presets, self.luxrender_colorspace.preset_name) else: cs_object = self.luxrender_colorspace params.add_float('gamma', self.get_gamma()) params.add_float('colorspace_white', [cs_object.cs_whiteX, cs_object.cs_whiteY]) params.add_float('colorspace_red', [cs_object.cs_redX, cs_object.cs_redY]) params.add_float('colorspace_green', [cs_object.cs_greenX, cs_object.cs_greenY]) params.add_float('colorspace_blue', [cs_object.cs_blueX, cs_object.cs_blueY]) # Camera Response Function if LUXRENDER_VERSION >= '0.8' and self.luxrender_colorspace.use_crf == 'file': if scene.camera.library is not None: local_crf_filepath = bpy.path.abspath(self.luxrender_colorspace.crf_file, scene.camera.library.filepath) else: local_crf_filepath = self.luxrender_colorspace.crf_file local_crf_filepath = efutil.filesystem_path( local_crf_filepath ) if scene.luxrender_engine.allow_file_embed(): from ..util import bencode_file2string params.add_string('cameraresponse', os.path.basename(local_crf_filepath)) encoded_data = bencode_file2string(local_crf_filepath) params.add_string('cameraresponse_data', encoded_data.splitlines() ) else: params.add_string('cameraresponse', local_crf_filepath) if LUXRENDER_VERSION >= '0.8' and self.luxrender_colorspace.use_crf == 'preset': params.add_string('cameraresponse', self.luxrender_colorspace.crf_preset) # Output types params.add_string('filename', get_output_filename(scene)) params.add_bool('write_resume_flm', self.write_flm) params.add_bool('restart_resume_flm', self.restart_flm) params.add_bool('write_flm_direct', self.write_flm_direct) if self.output_alpha: output_channels = 'RGBA' params.add_bool('premultiplyalpha', self.premultiply_alpha) else: output_channels = 'RGB' if scene.luxrender_engine.export_type == 'INT' and scene.luxrender_engine.integratedimaging: # Set up params to enable z buffer # we use the colorspace gamma, else autolinear gives wrong estimation, gamma 1.0 per pixel is recalculated in pylux after # Also, this requires tonemapped EXR output params.add_string('write_exr_channels', 'RGBA') params.add_bool('write_exr_halftype', False) params.add_bool('write_exr_applyimaging', True) params.add_bool('premultiplyalpha', True if self.output_alpha else False) # Blender 2.66 always expects premultiplyalpha params.add_bool('write_exr_ZBuf', True) params.add_string('write_exr_zbuf_normalizationtype', 'Camera Start/End clip') else: # Otherwise let the user decide on tonemapped EXR and other EXR settings params.add_bool('write_exr_halftype', self.write_exr_halftype) params.add_bool('write_exr_applyimaging', self.write_exr_applyimaging) params.add_bool('write_exr_ZBuf', self.write_zbuf) params.add_string('write_exr_compressiontype', self.write_exr_compressiontype) params.add_string('write_exr_zbuf_normalizationtype', self.zbuf_normalization) params.add_bool('write_exr', self.write_exr) params.add_string('write_exr_channels', output_channels) params.add_bool('write_png', self.write_png) params.add_string('write_png_channels', output_channels) if self.write_png: params.add_bool('write_png_16bit', self.write_png_16bit) params.add_bool('write_tga', self.write_tga) params.add_string('write_tga_channels', output_channels) if self.write_tga: params.add_bool('write_tga_ZBuf', self.write_zbuf) params.add_string('write_tga_zbuf_normalizationtype', self.zbuf_normalization) params.add_string('ldr_clamp_method', self.ldr_clamp_method) if scene.luxrender_engine.export_type == 'EXT': params.add_integer('displayinterval', self.displayinterval) params.add_integer('writeinterval', self.writeinterval) params.add_integer('flmwriteinterval', self.flmwriteinterval) else: params.add_integer('writeinterval', self.internal_updateinterval) # Halt conditions if scene.luxrender_halt.haltspp > 0: params.add_integer('haltspp', scene.luxrender_halt.haltspp) if scene.luxrender_halt.halttime > 0: params.add_integer('halttime', scene.luxrender_halt.halttime) if scene.luxrender_halt.haltthreshold > 0: params.add_float('haltthreshold', 1 - ( scene.luxrender_halt.haltthreshold / 100.00 )) # Convergence Test if scene.luxrender_halt.convergencestep != 32: params.add_float('convergencestep', scene.luxrender_halt.convergencestep) # Filename for User Sampling Map if scene.luxrender_sampler.usersamplingmap_filename != '': if scene.luxrender_sampler.usersamplingmap_filename.endswith('.exr'): params.add_string('usersamplingmap_filename', scene.luxrender_sampler.usersamplingmap_filename) else: params.add_string('usersamplingmap_filename', scene.luxrender_sampler.usersamplingmap_filename + '.exr') if self.outlierrejection_k > 0 and scene.luxrender_rendermode.renderer != 'sppm': params.add_integer('outlierrejection_k', self.outlierrejection_k) params.add_integer('tilecount', self.tilecount) # update the film settings with tonemapper settings params.update( self.luxrender_tonemapping.get_paramset() ) return ('fleximage', params)
def make_path_real(path): xfac = efutil.filesystem_path(path) return os.path.abspath(xfac)
def valid_proxy(self): proxy_path = filesystem_path(self.mesh_path) return self.mesh_proxy and os.path.exists(proxy_path)
def get_sort_dir(): return_path = exporter_common.getPreference().install_path if platform.system() == 'Windows': return return_path return efutil.filesystem_path(return_path) + "/"
def build_xml_element(self, scene, matrix_list): xml = self.Element('camera') xml_format = { 'aperture_radius': [aperture_radius(scene, self)], 'sensor_width': [scene.camera.data.sensor_width / 1000.0], 'lens_sensor_dist': [lens_sensor_dist(scene, self)], 'aspect_ratio': [aspect_ratio(scene, self)], 'exposure_duration': 'exposure', } if self.whitebalance == 'Custom': xml_format['white_point'] = { 'chromaticity_coordinates': { 'x': [self.whitebalanceX], 'y': [self.whitebalanceY], } } else: xml_format['white_balance'] = 'whitebalance', ws = get_worldscale(scene) if(scene.camera.data.type == 'ORTHO'): xml_format['camera_type'] = ['orthographic'] xml_format['sensor_width'] = [scene.camera.data.ortho_scale * ws] # Blender seems to use 'ortho_scale' for the sensor width. mat = matrix_list[0][1].transposed() xml_format['pos'] = [ i*ws for i in mat[3][0:3]] xml_format['forwards'] = [-i*ws for i in mat[2][0:3]] xml_format['up'] = [ i*ws for i in mat[1][0:3]] if len(matrix_list) > 1: # Remove pos, conflicts with keyframes. del(xml_format['pos']) keyframes = exportutil.matrixListToKeyframes(scene, scene.camera, matrix_list) xml_format['keyframe'] = tuple(keyframes) if self.autofocus: xml_format['autofocus'] = '' # is empty element xml_format['focus_distance'] = [10.0] # any non-zero value will do else: if scene.camera.data.dof_object is not None: xml_format['focus_distance'] = [((scene.camera.location - scene.camera.data.dof_object.location).length*ws)] elif scene.camera.data.dof_distance > 0: xml_format['focus_distance'] = [scene.camera.data.dof_distance*ws] else: #autofocus xml_format['autofocus'] = '' # is empty element xml_format['focus_distance'] = [10.0] # any non-zero value will do if self.ad: xml_format.update({ 'aperture_shape': {} }) if self.ad_obstacle != '': ad_obstacle = efutil.filesystem_path(self.ad_obstacle) if os.path.exists(ad_obstacle): xml_format.update({ 'obstacle_map': { 'path': [efutil.path_relative_to_export(ad_obstacle)] } }) else: indigo_log('WARNING: Camera Obstacle Map specified, but image path is not valid') if self.ad_type == 'image': ad_image = efutil.filesystem_path(self.ad_image) if os.path.exists(ad_image): xml_format['aperture_shape'].update({ 'image': { 'path': [efutil.path_relative_to_export(ad_image)] } }) else: indigo_log('WARNING: Camera Aperture Diffraction type "Image" selected, but image path is not valid') elif self.ad_type == 'generated': xml_format['aperture_shape'].update({ 'generated': { 'num_blades': [self.ad_blades], 'start_angle': [self.ad_angle], 'blade_offset': [self.ad_offset], 'blade_curvature_radius': [self.ad_curvature] } }) elif self.ad_type == 'circular': xml_format['aperture_shape'][self.ad_type] = {} aspect = aspect_ratio(scene, self) if scene.camera.data.shift_x != 0: sx = scene.camera.data.shift_x * 0.001*scene.camera.data.sensor_width if aspect < 1.0: sx /= aspect xml_format['lens_shift_right_distance'] = [sx] if scene.camera.data.shift_y != 0: sy = scene.camera.data.shift_y * 0.001*scene.camera.data.sensor_width if aspect < 1.0: sy /= aspect xml_format['lens_shift_up_distance'] = [sy] self.build_subelements(scene, xml_format, xml) return xml
def render(self, context): ''' Render the scene file, or in our case, export the frame(s) and launch an Indigo process. ''' with RENDERENGINE_indigo.render_lock: # Just render one thing at a time. self.renderer = None self.message_thread = None self.stats_thread = None self.framebuffer_thread = None self.render_update_timer = None self.rendering = False # force scene update to current rendering frame # Not sure why - Yves #context.frame_set(context.frame_current) #------------------------------------------------------------------------------ # Export the Scene # Get the frame path. frame_path = efutil.filesystem_path(context.render.frame_path()) # Get the filename for the frame sans extension. image_out_path = os.path.splitext(frame_path)[0] # Generate the name for the scene file(s). if context.indigo_engine.use_output_path == True: # Get the output path from the frame path. output_path = os.path.dirname(frame_path) # Generate the output filename output_filename = '%s.%s.%05i.igs' % ( efutil.scene_filename(), bpy.path.clean_name( context.name), context.frame_current) else: # Get export path from the indigo_engine. export_path = efutil.filesystem_path( context.indigo_engine.export_path) # Get the directory name from the output path. output_path = os.path.dirname(export_path) # Get the filename from the output path and remove the extension. output_filename = os.path.splitext( os.path.basename(export_path))[0] # Count contiguous # chars and replace them with the frame number. # If the hash count is 0 and we are exporting an animation, append the frame numbers. hash_count = util.count_contiguous('#', output_filename) if hash_count != 0: output_filename = output_filename.replace( '#' * hash_count, ('%%0%0ii' % hash_count) % context.frame_current) elif self.is_animation: output_filename = output_filename + ( '%%0%0ii' % 4) % context.frame_current # Add .igs extension. output_filename += '.igs' # The full path of the exported scene file. exported_file = '/'.join([output_path, output_filename]) # Create output_path if it does not exist. if not os.path.exists(output_path): os.makedirs(output_path) # If an animation is rendered, write an indigo queue file (.igq). if self.is_animation: igq_filename = '%s/%s.%s.igq' % ( output_path, efutil.scene_filename(), bpy.path.clean_name(context.name)) if context.frame_current == context.frame_start: # Start a new igq file. igq_file = open(igq_filename, 'w') igq_file.write( '<?xml version="1.0" encoding="utf-8" standalone="no" ?>\n' ) igq_file.write('<render_queue>\n') else: # Append to existing igq. igq_file = open(igq_filename, 'a') rnd = random.Random() rnd.seed(context.frame_current) # Write igq item. igq_file.write('\t<item>\n') igq_file.write('\t\t<scene_path>%s</scene_path>\n' % exported_file) igq_file.write('\t\t<halt_time>%d</halt_time>\n' % context.indigo_engine.halttime) igq_file.write('\t\t<halt_spp>%d</halt_spp>\n' % context.indigo_engine.haltspp) igq_file.write('\t\t<output_path>%s</output_path>\n' % image_out_path) igq_file.write('\t\t<seed>%s</seed>\n' % rnd.randint(1, 1000000)) igq_file.write('\t</item>\n') # If this is the last frame, write the closing tag. if context.frame_current == context.frame_end: igq_file.write('</render_queue>\n') igq_file.close() # Calculate the progress by frame with frame range (fr) and frame offset (fo). fr = context.frame_end - context.frame_start fo = context.frame_current - context.frame_start self.update_progress(fo / fr) scene_writer = indigo.operators._Impl_OT_indigo( directory=output_path, filename=output_filename).set_report(self.report) # Write the scene file. export_result = scene_writer.execute(context) # Return if the export didn't finish. if not 'FINISHED' in export_result: return #------------------------------------------------------------------------------ # Update indigo defaults config file . config_updates = { 'auto_start': context.indigo_engine.auto_start, 'console_output': context.indigo_engine.console_output } if context.indigo_engine.use_console: indigo_path = getConsolePath(context) else: indigo_path = getGuiPath(context) if os.path.exists(indigo_path): config_updates['install_path'] = getInstallPath(context) try: for k, v in config_updates.items(): efutil.write_config_value('indigo', 'defaults', k, v) except Exception as err: indigo_log('Saving indigo config failed: %s' % err, message_type='ERROR') # Make sure that the Indigo we are going to launch is at least as # new as the exporter version. version_ok = True if not context.indigo_engine.skip_version_check: iv = getVersion(context) for i in range(3): version_ok &= iv[i] >= bl_info['version'][i] #------------------------------------------------------------------------------ # Conditionally Spawn Indigo. if context.indigo_engine.auto_start: exe_path = efutil.filesystem_path(indigo_path) if not os.path.exists(exe_path): print("Failed to find indigo at '" + str(exe_path) + "'") msg = "Failed to find indigo at '" + str(exe_path) + "'." msg + "\n " msg += "Please make sure you have Indigo installed, and that the path to indigo in the 'Indigo Render Engine Settings' is set correctly." self.report({'ERROR'}, msg) #if not version_ok: #indigo_log("Unsupported version v%s; Cannot start Indigo with this scene" % ('.'.join(['%s'%i for i in iv])), message_type='ERROR') #return # if it's an animation, don't execute until final frame if self.is_animation and context.frame_current != context.frame_end: return # if animation and final frame, launch queue instead of single frame if self.is_animation and context.frame_current == context.frame_end: exported_file = igq_filename indigo_args = [exe_path, exported_file] else: indigo_args = [ exe_path, exported_file, '-o', image_out_path + '.png' ] # Set master or working master command line args. if context.indigo_engine.network_mode == 'master': indigo_args.extend(['-n', 'm']) elif context.indigo_engine.network_mode == 'working_master': indigo_args.extend(['-n', 'wm']) # Set port arg if network rendering is enabled. if context.indigo_engine.network_mode in [ 'master', 'working_master' ]: indigo_args.extend( ['-p', '%i' % context.indigo_engine.network_port]) # Set hostname and port arg. if context.indigo_engine.network_mode == 'manual': indigo_args.extend([ '-h', '%s:%i' % (context.indigo_engine.network_host, context.indigo_engine.network_port) ]) # indigo_log("Starting indigo: %s" % indigo_args) # If we're starting a console or should wait for the process, listen to the output. if context.indigo_engine.use_console or context.indigo_engine.wait_for_process: f_stdout = subprocess.PIPE else: f_stdout = None # Launch the Indigo process. indigo_proc = subprocess.Popen(indigo_args, stdout=f_stdout) indigo_pid = indigo_proc.pid indigo_log('Started Indigo process, PID: %i' % indigo_pid) # Wait for the render to finish if we use the console or should wait for the process. if context.indigo_engine.use_console or context.indigo_engine.wait_for_process: while indigo_proc.poll() == None: indigo_proc.communicate() time.sleep(2) indigo_proc.wait() if not indigo_proc.stdout.closed: indigo_proc.communicate() if indigo_proc.returncode == -1: sys.exit(-1) else: indigo_log("Scene was exported to %s" % exported_file) #------------------------------------------------------------------------------ # Finished return
def exportLamp(self, scene, lamp, idx): ltype = lamp.data.type name = translate_id(lamp.name) mult = lamp.data.mitsuba_lamp.intensity if lamp.data.mitsuba_lamp.inside_medium: self.exportMedium(scene.mitsuba_media.media[lamp.data.mitsuba_lamp.lamp_medium]) if ltype == 'POINT': self.openElement('luminaire', { 'type' : 'point', 'id' : '%s-light' % name }) self.exportWorldTrafo(lamp.matrix_world) self.parameter('rgb', 'intensity', {'value' : "%f %f %f" % (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)}) self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight}) if lamp.data.mitsuba_lamp.inside_medium: self.element('ref', {'id' : lamp.data.mitsuba_lamp.lamp_medium}) self.closeElement() elif ltype == 'AREA': self.element('remove', { 'id' : '%s-light' % name}) self.openElement('shape', { 'type' : 'obj'} ) (size_x, size_y) = (lamp.data.size, lamp.data.size) if lamp.data.shape == 'RECTANGLE': size_y = lamp.data.size_y mult = mult / (2 * size_x * size_y) filename = "area_luminaire_%d.obj" % idx try: os.mkdir(self.meshes_dir) except OSError: pass self.parameter('string', 'filename', { 'value' : 'meshes/%s' % filename}) self.exportWorldTrafo(lamp.matrix_world) self.openElement('luminaire', { 'id' : '%s-arealight' % name, 'type' : 'area'}) if lamp.data.mitsuba_lamp.inside_medium: self.element('ref', {'id' : lamp.data.mitsuba_lamp.lamp_medium}) self.parameter('rgb', 'intensity', { 'value' : "%f %f %f" % (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)}) self.closeElement() self.openElement('bsdf', { 'type' : 'lambertian'}) self.parameter('spectrum', 'reflectance', {'value' : '0'}) self.closeElement() self.closeElement() path = os.path.join(self.meshes_dir, filename) objFile = open(path, 'w') objFile.write('v %f %f 0\n' % (-size_x/2, -size_y/2)) objFile.write('v %f %f 0\n' % ( size_x/2, -size_y/2)) objFile.write('v %f %f 0\n' % ( size_x/2, size_y/2)) objFile.write('v %f %f 0\n' % (-size_x/2, size_y/2)) objFile.write('f 4 3 2 1\n') objFile.close() elif ltype == 'SUN': self.openElement('luminaire', { 'id' : '%s-light' % name, 'type' : 'directional'}) scale = mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1])) self.exportWorldTrafo(lamp.matrix_world * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1]))) self.parameter('rgb', 'intensity', { 'value' : "%f %f %f" % (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)}) self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight}) self.closeElement() elif ltype == 'SPOT': self.openElement('luminaire', { 'id' : '%s-light' % name, 'type' : 'spot'}) self.exportWorldTrafo(lamp.matrix_world * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1]))) self.parameter('rgb', 'intensity', { 'value' : "%f %f %f" % (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)}) self.parameter('float', 'cutoffAngle', {'value' : '%f' % (lamp.data.spot_size * 180 / (math.pi * 2))}) self.parameter('float', 'beamWidth', {'value' : '%f' % (lamp.data.spot_blend * lamp.data.spot_size * 180 / (math.pi * 2))}) self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight}) if lamp.data.mitsuba_lamp.inside_medium: self.element('ref', {'id' : lamp.data.mitsuba_lamp.lamp_medium}) self.closeElement() elif ltype == 'HEMI': if lamp.data.mitsuba_lamp.envmap_type == 'constant': self.openElement('luminaire', { 'id' : '%s-light' % name, 'type' : 'constant'}) self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight}) self.parameter('rgb', 'intensity', { 'value' : "%f %f %f" % (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)}) self.closeElement() elif lamp.data.mitsuba_lamp.envmap_type == 'envmap': self.openElement('luminaire', { 'id' : '%s-light' % name, 'type' : 'envmap'}) self.parameter('string', 'filename', {'value' : efutil.filesystem_path(lamp.data.mitsuba_lamp.envmap_file)}) self.exportWorldTrafo(lamp.matrix_world) self.parameter('float', 'intensityScale', {'value' : '%f' % lamp.data.mitsuba_lamp.intensity}) self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight}) self.closeElement()
def exportLamp(self, scene, lamp): ltype = lamp.data.type name = lamp.name mult = lamp.data.mitsuba_lamp.intensity if lamp.data.mitsuba_lamp.inside_medium: self.exportMedium(scene.mitsuba_media.media[lamp.data.mitsuba_lamp.lamp_medium]) if ltype == 'POINT': self.openElement('shape', { 'type' : 'sphere'}) self.exportPoint(lamp.location) self.parameter('float', 'radius', {'value' : lamp.data.mitsuba_lamp.radius}) self.openElement('emitter', { 'id' : '%s-light' % name, 'type' : 'area'}) self.parameter('rgb', 'radiance', { 'value' : "%f %f %f" % (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)}) self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight}) if lamp.data.mitsuba_lamp.inside_medium: self.element('ref', {'id' : lamp.data.mitsuba_lamp.lamp_medium}) self.closeElement() self.closeElement() elif ltype == 'AREA': self.openElement('shape', { 'type' : 'rectangle'} ) self.parameter('boolean', 'flipNormals', {'value' : 'true'}) (size_x, size_y) = (lamp.data.size/2.0, lamp.data.size/2.0) if lamp.data.shape == 'RECTANGLE': size_y = lamp.data.size_y/2.0 self.openElement('transform', {'name' : 'toWorld'}) loc, rot, sca = lamp.matrix_world.decompose() mat_loc = mathutils.Matrix.Translation(loc) mat_rot = rot.to_matrix().to_4x4() mat_sca = mathutils.Matrix(( (sca[0]*size_x,0,0,0), (0,sca[1]*size_y,0,0), (0,0,sca[2],0), (0,0,0,1), )) self.exportMatrix(mat_loc * mat_rot * mat_sca) self.closeElement() self.openElement('emitter', { 'id' : '%s-arealight' % name, 'type' : 'area'}) self.parameter('rgb', 'radiance', { 'value' : "%f %f %f" % (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)}) self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight}) if lamp.data.mitsuba_lamp.inside_medium: self.element('ref', {'id' : lamp.data.mitsuba_lamp.lamp_medium}) self.closeElement() self.openElement('bsdf', { 'type' : 'diffuse'}) self.parameter('spectrum', 'reflectance', {'value' : '0'}) self.closeElement() self.closeElement() elif ltype == 'SUN': # sun is considered hemi light by Mitsuba if self.hemi_lights >= 1: # Mitsuba supports only one hemi light return False self.hemi_lights += 1 invmatrix = lamp.matrix_world skyType = lamp.data.mitsuba_lamp.mitsuba_lamp_sun.sunsky_type LampParams = getattr(lamp.data.mitsuba_lamp, 'mitsuba_lamp_sun' ).get_paramset(lamp) if skyType == 'sunsky': self.openElement('emitter', { 'id' : '%s-light' % name, 'type' : 'sunsky'}) elif skyType == 'sun': self.openElement('emitter', { 'id' : '%s-light' % name, 'type' : 'sun'}) elif skyType == 'sky': self.openElement('emitter', { 'id' : '%s-light' % name, 'type' : 'sky'}) #self.parameter('boolean', 'extend', {'value' : '%s' % str(lamp.data.mitsuba_lamp.mitsuba_lamp_sun.extend).lower()}) LampParams.export(self) self.openElement('transform', {'name' : 'toWorld'}) #rotate around x to make z UP. Default Y - UP self.element('rotate', {'x' : '1', 'angle' : '90'}) self.closeElement() #self.exportWorldTrafo() #self.parameter('float', 'turbidity', {'value' : '%f' % (lamp.data.mitsuba_lamp.mitsuba_lamp_sun.turbidity)}) #ot_mat = mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1])) #to make Z up rotate 90 around X #rotatedSun = invmatrix * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([1, 0, 0])) * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1])) self.parameter('vector', 'sunDirection', {'x':'%f' % invmatrix[0][2], 'y':'%f' % invmatrix[1][2], 'z':'%f' % invmatrix[2][2]}) self.closeElement() elif ltype == 'SPOT': self.openElement('emitter', { 'id' : '%s-light' % name, 'type' : 'spot'}) self.exportWorldTrafo(lamp.matrix_world * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1]))) self.parameter('rgb', 'intensity', { 'value' : "%f %f %f" % (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)}) self.parameter('float', 'cutoffAngle', {'value' : '%f' % (lamp.data.spot_size * 180 / (math.pi * 2))}) self.parameter('float', 'beamWidth', {'value' : '%f' % ((1-lamp.data.spot_blend) * lamp.data.spot_size * 180 / (math.pi * 2))}) self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight}) if lamp.data.mitsuba_lamp.inside_medium: self.element('ref', {'id' : lamp.data.mitsuba_lamp.lamp_medium}) self.closeElement() elif ltype == 'HEMI': if self.hemi_lights >= 1: # Mitsuba supports only one hemi light return False self.hemi_lights += 1 if lamp.data.mitsuba_lamp.envmap_type == 'constant': self.openElement('emitter', { 'id' : '%s-light' % name, 'type' : 'constant'}) self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight}) self.parameter('rgb', 'radiance', { 'value' : "%f %f %f" % (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)}) self.closeElement() elif lamp.data.mitsuba_lamp.envmap_type == 'envmap': self.openElement('emitter', { 'id' : '%s-light' % name, 'type' : 'envmap'}) self.parameter('string', 'filename', {'value' : efutil.filesystem_path(lamp.data.mitsuba_lamp.envmap_file)}) self.exportWorldTrafo(lamp.matrix_world * mathutils.Matrix.Rotation(radians(90.0), 4, 'X')) self.parameter('float', 'scale', {'value' : '%f' % lamp.data.mitsuba_lamp.intensity}) self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight}) self.closeElement()
def realpath(path): return os.path.realpath(efutil.filesystem_path(path))
def api_output(self): ''' Calculate type and parameters for LuxRender Film statement Returns tuple(2) (string, list) ''' scene = LuxManager.CurrentScene xr, yr = self.resolution(scene) params = ParamSet() if scene.render.use_border: (x1,x2,y1,y2) = [ scene.render.border_min_x, scene.render.border_max_x, scene.render.border_min_y, scene.render.border_max_y ] # Set resolution params.add_integer('xresolution', round(xr*x2, 0)-round(xr*x1, 0)) params.add_integer('yresolution', round(yr*y2, 0)-round(yr*y1, 0)) else: # Set resolution params.add_integer('xresolution', xr) params.add_integer('yresolution', yr) # if scene.render.use_border: # cropwindow = [ # scene.render.border_min_x, scene.render.border_max_x, # scene.render.border_min_y, scene.render.border_max_y # ] # params.add_float('cropwindow', cropwindow) # ColourSpace if self.luxrender_colorspace.preset: cs_object = getattr(colorspace_presets, self.luxrender_colorspace.preset_name) else: cs_object = self.luxrender_colorspace params.add_float('gamma', self.get_gamma()) params.add_float('colorspace_white', [cs_object.cs_whiteX, cs_object.cs_whiteY]) params.add_float('colorspace_red', [cs_object.cs_redX, cs_object.cs_redY]) params.add_float('colorspace_green', [cs_object.cs_greenX, cs_object.cs_greenY]) params.add_float('colorspace_blue', [cs_object.cs_blueX, cs_object.cs_blueY]) # Camera Response Function if LUXRENDER_VERSION >= '0.8' and self.luxrender_colorspace.use_crf == 'file': if scene.camera.library is not None: local_crf_filepath = bpy.path.abspath(self.luxrender_colorspace.crf_file, scene.camera.library.filepath) else: local_crf_filepath = self.luxrender_colorspace.crf_file local_crf_filepath = efutil.filesystem_path( local_crf_filepath ) if scene.luxrender_engine.allow_file_embed(): from ..util import bencode_file2string params.add_string('cameraresponse', os.path.basename(local_crf_filepath)) encoded_data = bencode_file2string(local_crf_filepath) params.add_string('cameraresponse_data', encoded_data.splitlines() ) else: params.add_string('cameraresponse', local_crf_filepath) if LUXRENDER_VERSION >= '0.8' and self.luxrender_colorspace.use_crf == 'preset': params.add_string('cameraresponse', self.luxrender_colorspace.crf_preset) # Output types params.add_string('filename', get_output_filename(scene)) params.add_bool('write_resume_flm', self.write_flm) params.add_bool('restart_resume_flm', self.restart_flm) params.add_bool('write_flm_direct', self.write_flm_direct) if self.output_alpha: output_channels = 'RGBA' params.add_bool('premultiplyalpha', self.premultiply_alpha) else: output_channels = 'RGB' if scene.luxrender_engine.export_type == 'INT' and self.integratedimaging: # Set up params to enable z buffer and set gamma=1.0 # Also, this requires tonemapped EXR output params.add_string('write_exr_channels', 'RGBA') params.add_bool('write_exr_halftype', False) params.add_bool('write_exr_applyimaging', True) params.add_bool('premultiplyalpha', True) #Apparently, this should always be true with EXR params.add_bool('write_exr_ZBuf', True) params.add_string('write_exr_zbuf_normalizationtype', 'Camera Start/End clip') if scene.render.use_color_management: params.add_float('gamma', 1.0) # Linear workflow ! # else leave as pre-corrected gamma else: # Otherwise let the user decide on tonemapped EXR and other EXR settings params.add_bool('write_exr_halftype', self.write_exr_halftype) params.add_bool('write_exr_applyimaging', self.write_exr_applyimaging) params.add_bool('write_exr_ZBuf', self.write_zbuf) params.add_string('write_exr_compressiontype', self.write_exr_compressiontype) params.add_string('write_exr_zbuf_normalizationtype', self.zbuf_normalization) params.add_bool('write_exr', self.write_exr) if self.write_exr: params.add_string('write_exr_channels', output_channels) params.add_bool('write_png', self.write_png) if self.write_png: params.add_string('write_png_channels', output_channels) params.add_bool('write_png_16bit', self.write_png_16bit) params.add_bool('write_tga', self.write_tga) if self.write_tga: params.add_string('write_tga_channels', output_channels) params.add_string('write_tga_Zbuf', self.write_zbuf) params.add_string('write_tga_zbuf_normalizationtype', self.zbuf_normalization) params.add_string('ldr_clamp_method', self.ldr_clamp_method) if scene.luxrender_engine.export_type == 'EXT': params.add_integer('displayinterval', self.displayinterval) params.add_integer('writeinterval', self.writeinterval) params.add_integer('flmwriteinterval', self.flmwriteinterval) else: params.add_integer('writeinterval', self.internal_updateinterval) # Halt conditions if scene.luxrender_halt.haltspp > 0: params.add_integer('haltspp', scene.luxrender_halt.haltspp) if scene.luxrender_halt.halttime > 0: params.add_integer('halttime', scene.luxrender_halt.halttime) if self.outlierrejection_k > 0 and scene.luxrender_rendermode.renderer != 'sppm': params.add_integer('outlierrejection_k', self.outlierrejection_k) params.add_integer('tilecount', self.tilecount) # update the film settings with tonemapper settings params.update( self.luxrender_tonemapping.get_paramset() ) return ('fleximage', params)
def render(self, scene): if self is None or scene is None: sunflowLog('ERROR: Scene is missing!') return scene.render.use_placeholder = False with self.render_lock: # just render one thing at a time if scene.name == 'preview': self.render_preview(scene) return scene_path = efutil.filesystem_path(scene.render.filepath) if os.path.isdir(scene_path): output_dir = scene_path else: output_dir = os.path.dirname(scene_path) output_dir = os.path.abspath(os.path.join(output_dir , efutil.scene_filename())) if not os.path.exists(output_dir): os.mkdir(output_dir) #----------- sunflowLog('Sunflow: Current directory = "%s"' % output_dir) #--------------------------------------- if DEBUG: pydevd.settrace() if not getExporter (output_dir, scene.name, scene.frame_current): return if self.is_animation: return arguments = self.getCommandLineArgs(scene) jarpath = efutil.find_config_value('sunflow', 'defaults', 'jar_path', '') javapath = efutil.find_config_value('sunflow', 'defaults', 'java_path', '') memory = "-Xmx%sm" % efutil.find_config_value('sunflow', 'defaults', 'memoryalloc', '') image_name = "%s.%03d.%s" % (scene.name , scene.frame_current, arguments['format']) if scene.sunflow_performance.useRandom: image_name = self.check_randomname(output_dir, image_name) sunflow_file = "%s.%03d.sc" % (scene.name , scene.frame_current) image_file = os.path.abspath(os.path.join(output_dir , image_name)) sc_file_path = os.path.abspath(os.path.join(output_dir , sunflow_file)) cmd_line = [ javapath , memory , '-server' , '-jar' , jarpath ] final_line = ['-o', image_file , sc_file_path] extra = [] for key in arguments: if key == 'format': continue if arguments[key] != '': values = arguments[key].split() extra.extend(values) if arguments['format'] != 'png': extra.append('-nogui') cmd_line.extend(extra) cmd_line.extend(final_line) sunflow_process = subprocess.Popen(cmd_line) refresh_interval = 5 framebuffer_thread = sunflowFilmDisplay() framebuffer_thread.set_kick_period(refresh_interval) framebuffer_thread.begin(self, image_file, resolution(scene)) render_update_timer = None while sunflow_process.poll() == None and not self.test_break(): render_update_timer = threading.Timer(1, self.process_wait_timer) render_update_timer.start() if render_update_timer.isAlive(): render_update_timer.join() # If we exit the wait loop (user cancelled) and sunflow is still running, then send SIGINT if sunflow_process.poll() == None: # Use SIGTERM because that's the only one supported on Windows sunflow_process.send_signal(subprocess.signal.SIGTERM) # Stop updating the render result and load the final image framebuffer_thread.stop() framebuffer_thread.join() if sunflow_process.poll() != None and sunflow_process.returncode != 0: sunflowLog("Sunflow: Rendering failed -- check the console") else: framebuffer_thread.kick(render_end=True) framebuffer_thread.shutdown()
def exportMeshElement(self, obj): if OBJECT_ANALYSIS: indigo_log('exportMeshElement: %s' % obj) if obj.type in self.supported_mesh_types: start_time = time.time() # If this object has already been exported, then don't export it again. exported_mesh = self.ExportedMeshes.get(obj) if exported_mesh != None: self.total_mesh_export_time += time.time() - start_time return exported_mesh # Create mesh with applied modifiers mesh = obj.to_mesh(self.scene, True, 'RENDER') # Compute a hash over the mesh data (vertex positions, material names etc..) mesh_hash = self.meshHash(obj, mesh) # Form a mesh name like "4618cbf0bc13316135d676fffe0a74fc9b0577909246477354da9254" # The name cannot contain the objects name, as the name itself is always unique. exported_mesh_name = bpy.path.clean_name(mesh_hash) # If this mesh has already been exported, then don't export it again exported_mesh = self.MeshesOnDisk.get(exported_mesh_name) if exported_mesh != None: # Important! If an object is matched to a mesh on disk, add to ExportedMeshes. # Otherwise the mesh checksum will be computed over and over again. self.ExportedMeshes[obj] = exported_mesh bpy.data.meshes.remove(mesh) self.total_mesh_export_time += time.time() - start_time return exported_mesh # Make full mesh path. mesh_filename = exported_mesh_name + '.igmesh' full_mesh_path = efutil.filesystem_path( '/'.join([self.mesh_dir, mesh_filename]) ) #indigo_log('full_mesh_path: %s'%full_mesh_path) # pass the full mesh path to write to filesystem if the object is not a proxy if hasattr(obj.data, 'indigo_mesh') and not obj.data.indigo_mesh.valid_proxy(): if os.path.exists(full_mesh_path) and self.skip_existing_meshes: # if skipping mesh write, parse faces to gather used mats used_mat_indices = set() num_smooth = 0 for face in mesh.tessfaces: used_mat_indices.add(face.material_index) if face.use_smooth: num_smooth += 1 use_shading_normals = num_smooth > 0 else: # else let the igmesh_writer do its thing (used_mat_indices, use_shading_normals) = igmesh_writer.factory(self.scene, obj, full_mesh_path, mesh, debug=OBJECT_ANALYSIS) self.mesh_uses_shading_normals[full_mesh_path] = use_shading_normals else: # Assume igmesh has same number of mats as the proxy object used_mat_indices = range(len(obj.material_slots)) # Remove mesh. bpy.data.meshes.remove(mesh) # Export materials used by this mesh if len(obj.material_slots) > 0: for mi in used_mat_indices: mat = obj.material_slots[mi].material if mat == None or mat.name in self.ExportedMaterials: continue mat_xmls = mat.indigo_material.factory(obj, mat, self.scene) self.ExportedMaterials[mat.name] = mat_xmls # .. put the relative path in the mesh element filename = '/'.join([self.rel_mesh_dir, mesh_filename]) #print('MESH FILENAME %s' % filename) shading_normals = True if full_mesh_path in self.mesh_uses_shading_normals: shading_normals = self.mesh_uses_shading_normals[full_mesh_path] xml = obj.data.indigo_mesh.build_xml_element(obj, filename, shading_normals, exported_name=exported_mesh_name) mesh_definition = (exported_mesh_name, xml) self.MeshesOnDisk[exported_mesh_name] = mesh_definition self.ExportedMeshes[obj] = mesh_definition total = time.time() - start_time self.total_mesh_export_time += total if self.verbose: indigo_log('Mesh Export took: %f s' % total) return mesh_definition
def render_preview(self, scene): if sys.platform == 'darwin': self.output_dir = efutil.filesystem_path(bpy.app.tempdir) else: self.output_dir = efutil.temp_directory() if self.output_dir[-1] != '/': self.output_dir += '/' efutil.export_path = self.output_dir from ..outputs.pure_api import PYLUX_AVAILABLE if not PYLUX_AVAILABLE: self.bl_use_preview = False LuxLog('ERROR: Material previews require pylux') return from ..export import materials as export_materials # Iterate through the preview scene, finding objects with materials attached objects_mats = {} for obj in [ ob for ob in scene.objects if ob.is_visible(scene) and not ob.hide_render ]: for mat in export_materials.get_instance_materials(obj): if mat is not None: if not obj.name in objects_mats.keys(): objects_mats[obj] = [] objects_mats[obj].append(mat) PREVIEW_TYPE = None # 'MATERIAL' or 'TEXTURE' # find objects that are likely to be the preview objects preview_objects = [ o for o in objects_mats.keys() if o.name.startswith('preview') ] if len(preview_objects) > 0: PREVIEW_TYPE = 'MATERIAL' else: preview_objects = [ o for o in objects_mats.keys() if o.name.startswith('texture') ] if len(preview_objects) > 0: PREVIEW_TYPE = 'TEXTURE' if PREVIEW_TYPE == None: return # TODO: scene setup based on PREVIEW_TYPE # find the materials attached to the likely preview object likely_materials = objects_mats[preview_objects[0]] if len(likely_materials) < 1: print('no preview materials') return pm = likely_materials[0] pt = None LuxLog('Rendering material preview: %s' % pm.name) if PREVIEW_TYPE == 'TEXTURE': pt = pm.active_texture LM = LuxManager( scene.name, api_type='API', ) LuxManager.SetCurrentScene(scene) LuxManager.SetActive(LM) file_based_preview = False if file_based_preview: # Dump to file in temp dir for debugging from ..outputs.file_api import Custom_Context as lxs_writer preview_context = lxs_writer(scene.name) preview_context.set_filename(scene, 'luxblend25-preview', LXV=False) LM.lux_context = preview_context else: preview_context = LM.lux_context preview_context.logVerbosity('quiet') try: export_materials.ExportedMaterials.clear() export_materials.ExportedTextures.clear() from ..export import preview_scene xres, yres = scene.camera.data.luxrender_camera.luxrender_film.resolution( scene) # Don't render the tiny images if xres <= 96: raise Exception( 'Skipping material thumbnail update, image too small (%ix%i)' % (xres, yres)) preview_scene.preview_scene(scene, preview_context, obj=preview_objects[0], mat=pm, tex=pt) # render ! preview_context.worldEnd() if file_based_preview: preview_context = preview_context.parse( 'luxblend25-preview.lxs', True) LM.lux_context = preview_context while not preview_context.statistics('sceneIsReady'): time.sleep(0.05) def is_finished(ctx): return ctx.getAttribute('film', 'enoughSamples') def interruptible_sleep(sec, increment=0.05): sec_elapsed = 0.0 while not self.test_break() and sec_elapsed <= sec: sec_elapsed += increment time.sleep(increment) for i in range(multiprocessing.cpu_count() - 2): # -2 since 1 thread already created and leave 1 spare if is_finished(preview_context): break preview_context.addThread() while not is_finished(preview_context): if self.test_break( ) or bpy.context.scene.render.engine != 'LUXRENDER_RENDER': raise Exception('Render interrupted') # progressively update the preview time.sleep(0.2) # safety-sleep if preview_context.getAttribute('renderer_statistics', 'samplesPerPixel') > 6: if PREVIEW_TYPE == 'TEXTURE': interruptible_sleep( 0.8 ) # reduce update to every 1.0 sec until haltthreshold kills the render else: interruptible_sleep( 1.8 ) # reduce update to every 2.0 sec until haltthreshold kills the render preview_context.updateStatisticsWindow() LuxLog('Updating preview (%ix%i - %s)' % (xres, yres, preview_context.getAttribute( 'renderer_statistics_formatted_short', '_recommended_string'))) result = self.begin_result(0, 0, xres, yres) if hasattr(preview_context, 'blenderCombinedDepthBuffers'): # use fast buffers pb, zb = preview_context.blenderCombinedDepthBuffers() result.layers.foreach_set("rect", pb) else: lay = result.layers[0] lay.rect = preview_context.blenderCombinedDepthRects()[0] self.end_result( result, 0) if bpy.app.version > (2, 63, 17) else self.end_result( result) # cycles tiles adaption except Exception as exc: LuxLog('Preview aborted: %s' % exc) preview_context.exit() preview_context.wait() # cleanup() destroys the pylux Context preview_context.cleanup() LM.reset()
def get_process_args(self, scene, start_rendering): config_updates = {'auto_start': start_rendering} addon_prefs = LuxRenderAddon.get_prefs() luxrender_path = efutil.filesystem_path(addon_prefs.install_path) print('luxrender_path: ', luxrender_path) if luxrender_path == '': return [''] if luxrender_path[-1] != '/': luxrender_path += '/' if sys.platform == 'darwin': luxrender_path += 'LuxRender.app/Contents/MacOS/%s' % scene.luxrender_engine.binary_name # Get binary from OSX bundle if not os.path.exists(luxrender_path): LuxLog('LuxRender not found at path: %s' % luxrender_path, ', trying default LuxRender location') luxrender_path = '/Applications/LuxRender/LuxRender.app/Contents/MacOS/%s' % scene.luxrender_engine.binary_name # try fallback to default installation path elif sys.platform == 'win32': luxrender_path += '%s.exe' % scene.luxrender_engine.binary_name else: luxrender_path += scene.luxrender_engine.binary_name if not os.path.exists(luxrender_path): raise Exception('LuxRender not found at path: %s' % luxrender_path) cmd_args = [luxrender_path] # set log verbosity if scene.luxrender_engine.log_verbosity != 'default': cmd_args.append('--' + scene.luxrender_engine.log_verbosity) if scene.luxrender_engine.binary_name == 'luxrender': # Copy the GUI log to the console cmd_args.append('--logconsole') # Set number of threads for external processes if not scene.luxrender_engine.threads_auto: cmd_args.append('--threads=%i' % scene.luxrender_engine.threads) #Set fixed seeds, if enabled if scene.luxrender_engine.fixed_seed: cmd_args.append('--fixedseed') if scene.luxrender_networking.use_network_servers and scene.luxrender_networking.servers != '': for server in scene.luxrender_networking.servers.split(','): cmd_args.append('--useserver') cmd_args.append(server.strip()) cmd_args.append('--serverinterval') cmd_args.append('%i' % scene.luxrender_networking.serverinterval) config_updates['servers'] = scene.luxrender_networking.servers config_updates[ 'serverinterval'] = '%i' % scene.luxrender_networking.serverinterval config_updates[ 'use_network_servers'] = scene.luxrender_networking.use_network_servers # Save changed config items and then launch Lux try: for k, v in config_updates.items(): efutil.write_config_value('luxrender', 'defaults', k, v) except Exception as err: LuxLog( 'WARNING: Saving LuxRender config failed, please set your user scripts dir: %s' % err) return cmd_args
def render(self, scene): if self is None or scene is None: sunflowLog('ERROR: Scene is missing!') return scene.render.use_placeholder = False with self.render_lock: # just render one thing at a time if scene.name == 'preview': self.render_preview(scene) return scene_path = efutil.filesystem_path(scene.render.filepath) if os.path.isdir(scene_path): output_dir = scene_path else: output_dir = os.path.dirname(scene_path) output_dir = os.path.abspath( os.path.join(output_dir, efutil.scene_filename())) if not os.path.exists(output_dir): os.mkdir(output_dir) #----------- sunflowLog('Sunflow: Current directory = "%s"' % output_dir) #--------------------------------------- if DEBUG: pydevd.settrace() if not getExporter(output_dir, scene.name, scene.frame_current): return if self.is_animation: return arguments = self.getCommandLineArgs(scene) jarpath = efutil.find_config_value('sunflow', 'defaults', 'jar_path', '') javapath = efutil.find_config_value('sunflow', 'defaults', 'java_path', '') memory = "-Xmx%sm" % efutil.find_config_value( 'sunflow', 'defaults', 'memoryalloc', '') image_name = "%s.%03d.%s" % (scene.name, scene.frame_current, arguments['format']) if scene.sunflow_performance.useRandom: image_name = self.check_randomname(output_dir, image_name) sunflow_file = "%s.%03d.sc" % (scene.name, scene.frame_current) image_file = os.path.abspath(os.path.join(output_dir, image_name)) sc_file_path = os.path.abspath( os.path.join(output_dir, sunflow_file)) cmd_line = [javapath, memory, '-server', '-jar', jarpath] final_line = ['-o', image_file, sc_file_path] extra = [] for key in arguments: if key == 'format': continue if arguments[key] != '': values = arguments[key].split() extra.extend(values) if arguments['format'] != 'png': extra.append('-nogui') cmd_line.extend(extra) cmd_line.extend(final_line) sunflow_process = subprocess.Popen(cmd_line) refresh_interval = 5 framebuffer_thread = sunflowFilmDisplay() framebuffer_thread.set_kick_period(refresh_interval) framebuffer_thread.begin(self, image_file, resolution(scene)) render_update_timer = None while sunflow_process.poll() == None and not self.test_break(): render_update_timer = threading.Timer(1, self.process_wait_timer) render_update_timer.start() if render_update_timer.isAlive(): render_update_timer.join() # If we exit the wait loop (user cancelled) and sunflow is still running, then send SIGINT if sunflow_process.poll() == None: # Use SIGTERM because that's the only one supported on Windows sunflow_process.send_signal(subprocess.signal.SIGTERM) # Stop updating the render result and load the final image framebuffer_thread.stop() framebuffer_thread.join() if sunflow_process.poll( ) != None and sunflow_process.returncode != 0: sunflowLog("Sunflow: Rendering failed -- check the console") else: framebuffer_thread.kick(render_end=True) framebuffer_thread.shutdown()
def exportLamp(self, scene, lamp, idx): ltype = lamp.data.type name = translate_id(lamp.name) mult = lamp.data.mitsuba_lamp.intensity if lamp.data.mitsuba_lamp.inside_medium: self.exportMedium(scene.mitsuba_media.media[lamp.data.mitsuba_lamp.lamp_medium]) if ltype == 'POINT': self.element('remove', { 'id' : '%s-light' % name}) self.openElement('shape', { 'type' : 'sphere'}) self.exportPoint(lamp.location) self.parameter('float', 'radius', {'value' : lamp.data.mitsuba_lamp.radius}) self.openElement('luminaire', { 'id' : '%s-light' % name, 'type' : 'area'}) if lamp.data.mitsuba_lamp.inside_medium: self.element('ref', {'id' : lamp.data.mitsuba_lamp.lamp_medium}) self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight}) self.parameter('rgb', 'intensity', { 'value' : "%f %f %f" % (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)}) self.closeElement() self.closeElement() elif ltype == 'AREA': self.element('remove', { 'id' : '%s-light' % name}) self.openElement('shape', { 'type' : 'obj'} ) (size_x, size_y) = (lamp.data.size, lamp.data.size) if lamp.data.shape == 'RECTANGLE': size_y = lamp.data.size_y #mult = mult / (2 * size_x * size_y) #I like more absolute intensity that int/area #mult = mult / (size_x * size_y) filename = "area_luminaire_%d.obj" % idx try: os.mkdir(self.meshes_dir) except OSError: pass self.parameter('string', 'filename', { 'value' : 'meshes/%s' % filename}) self.exportWorldTrafo(lamp.matrix_world) self.openElement('luminaire', { 'id' : '%s-arealight' % name, 'type' : 'area'}) if lamp.data.mitsuba_lamp.inside_medium: self.element('ref', {'id' : lamp.data.mitsuba_lamp.lamp_medium}) self.parameter('rgb', 'intensity', { 'value' : "%f %f %f" % (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)}) self.closeElement() self.openElement('bsdf', { 'type' : 'diffuse'}) self.parameter('spectrum', 'reflectance', {'value' : '0'}) self.closeElement() self.closeElement() path = os.path.join(self.meshes_dir, filename) objFile = open(path, 'w') objFile.write('v %f %f 0\n' % (-size_x/2, -size_y/2)) objFile.write('v %f %f 0\n' % ( size_x/2, -size_y/2)) objFile.write('v %f %f 0\n' % ( size_x/2, size_y/2)) objFile.write('v %f %f 0\n' % (-size_x/2, size_y/2)) objFile.write('f 4 3 2 1\n') objFile.close() elif ltype == 'SUN': invmatrix = lamp.matrix_world skyType = lamp.data.mitsuba_lamp.mitsuba_lamp_sun.sunsky_type if skyType == 'sunsky': self.openElement('luminaire', { 'id' : '%s-light' % name, 'type' : 'sunsky'}) self.parameter('boolean', 'extend', {'value' : '%s' % str(lamp.data.mitsuba_lamp.mitsuba_lamp_sun.extend).lower()}) elif skyType == 'sun': self.openElement('luminaire', { 'id' : '%s-light' % name, 'type' : 'sun'}) elif skyType == 'sky': self.openElement('luminaire', { 'id' : '%s-light' % name, 'type' : 'sky'}) self.parameter('boolean', 'extend', {'value' : '%s' % str(lamp.data.mitsuba_lamp.mitsuba_lamp_sun.extend).lower()}) self.openElement('transform', {'name' : 'toWorld'}) #fixes 'up' orientation of sky to blender world. self.element('matrix', {'value' : '1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -1.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000'}) self.closeElement() #self.exportWorldTrafo() self.parameter('float', 'turbidity', {'value' : '%f' % (lamp.data.mitsuba_lamp.mitsuba_lamp_sun.turbidity)}) self.parameter('vector', 'sunDirection', {'x':'%f' % invmatrix[0][2], 'y':'%f' % invmatrix[1][2], 'z':'%f' % invmatrix[2][2]}) self.closeElement() #self.parameter('vector', 'sunDirection', {'x':'%f' % invmatrix[0][2], 'y':'%f' % invmatrix[1][2], 'z':'%f' % invmatrix[2][2]}) elif ltype == 'SPOT': self.openElement('luminaire', { 'id' : '%s-light' % name, 'type' : 'spot'}) self.exportWorldTrafo(lamp.matrix_world * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1]))) self.parameter('rgb', 'intensity', { 'value' : "%f %f %f" % (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)}) self.parameter('float', 'cutoffAngle', {'value' : '%f' % (lamp.data.spot_size * 180 / (math.pi * 2))}) self.parameter('float', 'beamWidth', {'value' : '%f' % ((1-lamp.data.spot_blend) * lamp.data.spot_size * 180 / (math.pi * 2))}) self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight}) if lamp.data.mitsuba_lamp.inside_medium: self.element('ref', {'id' : lamp.data.mitsuba_lamp.lamp_medium}) self.closeElement() elif ltype == 'HEMI': if lamp.data.mitsuba_lamp.envmap_type == 'constant': self.openElement('luminaire', { 'id' : '%s-light' % name, 'type' : 'constant'}) self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight}) self.parameter('rgb', 'intensity', { 'value' : "%f %f %f" % (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)}) self.closeElement() elif lamp.data.mitsuba_lamp.envmap_type == 'envmap': self.openElement('luminaire', { 'id' : '%s-light' % name, 'type' : 'envmap'}) self.parameter('string', 'filename', {'value' : efutil.filesystem_path(lamp.data.mitsuba_lamp.envmap_file)}) self.exportWorldTrafo(lamp.matrix_world) self.parameter('float', 'intensityScale', {'value' : '%f' % lamp.data.mitsuba_lamp.intensity}) self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight}) self.closeElement()
def render_preview(self, scene): if sys.platform == 'darwin': self.output_dir = efutil.filesystem_path( bpy.app.tempdir ) else: self.output_dir = efutil.temp_directory() if self.output_dir[-1] != '/': self.output_dir += '/' efutil.export_path = self.output_dir from ..outputs.pure_api import PYLUX_AVAILABLE if not PYLUX_AVAILABLE: self.bl_use_preview = False LuxLog('ERROR: Material previews require pylux') return from ..export import materials as export_materials # Iterate through the preview scene, finding objects with materials attached objects_mats = {} for obj in [ob for ob in scene.objects if ob.is_visible(scene) and not ob.hide_render]: for mat in export_materials.get_instance_materials(obj): if mat is not None: if not obj.name in objects_mats.keys(): objects_mats[obj] = [] objects_mats[obj].append(mat) PREVIEW_TYPE = None # 'MATERIAL' or 'TEXTURE' # find objects that are likely to be the preview objects preview_objects = [o for o in objects_mats.keys() if o.name.startswith('preview')] if len(preview_objects) > 0: PREVIEW_TYPE = 'MATERIAL' else: preview_objects = [o for o in objects_mats.keys() if o.name.startswith('texture')] if len(preview_objects) > 0: PREVIEW_TYPE = 'TEXTURE' if PREVIEW_TYPE == None: return # TODO: scene setup based on PREVIEW_TYPE # find the materials attached to the likely preview object likely_materials = objects_mats[preview_objects[0]] if len(likely_materials) < 1: print('no preview materials') return pm = likely_materials[0] pt = None LuxLog('Rendering material preview: %s' % pm.name) if PREVIEW_TYPE == 'TEXTURE': pt = pm.active_texture LM = LuxManager( scene.name, api_type = 'API', ) LuxManager.SetCurrentScene(scene) LuxManager.SetActive(LM) file_based_preview = False if file_based_preview: # Dump to file in temp dir for debugging from ..outputs.file_api import Custom_Context as lxs_writer preview_context = lxs_writer(scene.name) preview_context.set_filename(scene, 'luxblend25-preview', LXV=False) LM.lux_context = preview_context else: preview_context = LM.lux_context preview_context.logVerbosity('quiet') try: export_materials.ExportedMaterials.clear() export_materials.ExportedTextures.clear() from ..export import preview_scene xres, yres = scene.camera.data.luxrender_camera.luxrender_film.resolution(scene) # Don't render the tiny images if xres <= 96: raise Exception('Skipping material thumbnail update, image too small (%ix%i)' % (xres,yres)) preview_scene.preview_scene(scene, preview_context, obj=preview_objects[0], mat=pm, tex=pt) # render ! preview_context.worldEnd() if file_based_preview: preview_context = preview_context.parse('luxblend25-preview.lxs', True) LM.lux_context = preview_context while not preview_context.statistics('sceneIsReady'): time.sleep(0.05) def is_finished(ctx): return ctx.getAttribute('film', 'enoughSamples') def interruptible_sleep(sec, increment=0.05): sec_elapsed = 0.0 while not self.test_break() and sec_elapsed<=sec: sec_elapsed += increment time.sleep(increment) for i in range(multiprocessing.cpu_count()-2): # -2 since 1 thread already created and leave 1 spare if is_finished(preview_context): break preview_context.addThread() while not is_finished(preview_context): if self.test_break() or bpy.context.scene.render.engine != 'LUXRENDER_RENDER': raise Exception('Render interrupted') # progressively update the preview time.sleep(0.2) # safety-sleep if preview_context.getAttribute('renderer_statistics', 'samplesPerPixel') > 6: if PREVIEW_TYPE == 'TEXTURE': interruptible_sleep(0.8) # reduce update to every 1.0 sec until haltthreshold kills the render else: interruptible_sleep(1.8) # reduce update to every 2.0 sec until haltthreshold kills the render preview_context.updateStatisticsWindow() LuxLog('Updating preview (%ix%i - %s)' % (xres, yres, preview_context.getAttribute('renderer_statistics_formatted_short', '_recommended_string'))) result = self.begin_result(0, 0, xres, yres) if hasattr(preview_context, 'blenderCombinedDepthBuffers'): # use fast buffers pb, zb = preview_context.blenderCombinedDepthBuffers() result.layers.foreach_set("rect", pb) else: lay = result.layers[0] lay.rect = preview_context.blenderCombinedDepthRects()[0] self.end_result(result, 0) if bpy.app.version > (2, 63, 17 ) else self.end_result(result) # cycles tiles adaption except Exception as exc: LuxLog('Preview aborted: %s' % exc) preview_context.exit() preview_context.wait() # cleanup() destroys the pylux Context preview_context.cleanup() LM.reset()
def get_process_args(self, scene, start_rendering): config_updates = { 'auto_start': start_rendering } addon_prefs = LuxRenderAddon.get_prefs() luxrender_path = efutil.filesystem_path( addon_prefs.install_path ) print('luxrender_path: ', luxrender_path) if luxrender_path == '': return [''] if luxrender_path[-1] != '/': luxrender_path += '/' if sys.platform == 'darwin': luxrender_path += 'LuxRender.app/Contents/MacOS/%s' % scene.luxrender_engine.binary_name # Get binary from OSX bundle if not os.path.exists(luxrender_path): LuxLog('LuxRender not found at path: %s' % luxrender_path, ', trying default LuxRender location') luxrender_path = '/Applications/LuxRender/LuxRender.app/Contents/MacOS/%s' % scene.luxrender_engine.binary_name # try fallback to default installation path elif sys.platform == 'win32': luxrender_path += '%s.exe' % scene.luxrender_engine.binary_name else: luxrender_path += scene.luxrender_engine.binary_name if not os.path.exists(luxrender_path): raise Exception('LuxRender not found at path: %s' % luxrender_path) cmd_args = [luxrender_path] # set log verbosity if scene.luxrender_engine.log_verbosity != 'default': cmd_args.append('--' + scene.luxrender_engine.log_verbosity) if scene.luxrender_engine.binary_name == 'luxrender': # Copy the GUI log to the console cmd_args.append('--logconsole') # Set number of threads for external processes if not scene.luxrender_engine.threads_auto: cmd_args.append('--threads=%i' % scene.luxrender_engine.threads) #Set fixed seeds, if enabled if scene.luxrender_engine.fixed_seed: cmd_args.append('--fixedseed') if scene.luxrender_networking.use_network_servers and scene.luxrender_networking.servers != '': for server in scene.luxrender_networking.servers.split(','): cmd_args.append('--useserver') cmd_args.append(server.strip()) cmd_args.append('--serverinterval') cmd_args.append('%i' % scene.luxrender_networking.serverinterval) config_updates['servers'] = scene.luxrender_networking.servers config_updates['serverinterval'] = '%i' % scene.luxrender_networking.serverinterval config_updates['use_network_servers'] = scene.luxrender_networking.use_network_servers # Save changed config items and then launch Lux try: for k, v in config_updates.items(): efutil.write_config_value('luxrender', 'defaults', k, v) except Exception as err: LuxLog('WARNING: Saving LuxRender config failed, please set your user scripts dir: %s' % err) return cmd_args
def api_output(self): ''' Calculate type and parameters for LuxRender Film statement Returns tuple(2) (string, list) ''' scene = LuxManager.CurrentScene xr, yr = self.resolution(scene) params = ParamSet() if scene.render.use_border: #Border rendering handler, this gets a bit tricky. Blender ALWAYS expects to get back a cropped image, it will handle the padding itself if the user asked for it. if scene.render.use_crop_to_border: #user asked to crop, so always crop (x1,x2,y1,y2) = [ scene.render.border_min_x, scene.render.border_max_x, scene.render.border_min_y, scene.render.border_max_y ] # Set resolution # This is a new method of "rounding" the cropped image to match blenders expected rectangle_size # I tested this with several cases which failed with the former rounding, pls check - Jens params.add_integer('xresolution', int((xr*x2)-(xr*x1)+1)) params.add_integer('yresolution', int((yr*y2)-(yr*y1)+1)) if not scene.render.use_crop_to_border: #user asked for padded-to-full-frame output, there are a few cases where Lux needs to do this itself since the rendered image will not be returned to Blender if scene.luxrender_engine.render == False or (scene.luxrender_engine.export_type == 'EXT' and scene.luxrender_engine.binary_name == 'luxrender' and scene.luxrender_engine.monitor_external == False): #If run-renderer (scene.luxrender_engine.render) is disabled or we are in un-monitored external mode, we do not return the image to Blender and Lux must pad the image itself cropwindow = [ scene.render.border_min_x, scene.render.border_max_x, 1-scene.render.border_min_y, 1-scene.render.border_max_y ] #Subtract scene.render.border Y values from 1 to translate between Blender and Lux conventions params.add_float('cropwindow', cropwindow) params.add_integer('xresolution', xr) #Don't forget to set full frame resolution params.add_integer('yresolution', yr) else: #we are returning the image to blender which will pad for us, so have LuxRender send back a cropped frame anyway (x1,x2,y1,y2) = [ scene.render.border_min_x, scene.render.border_max_x, scene.render.border_min_y, scene.render.border_max_y ] # Set resolution # This is a new method of "rounding" the cropped image to match blenders expected rectangle_size # I tested this with several cases which failed with the former rounding, pls check - Jens params.add_integer('xresolution', int((xr*x2)-(xr*x1)+1)) params.add_integer('yresolution', int((yr*y2)-(yr*y1)+1)) else: # Set resolution params.add_integer('xresolution', xr) params.add_integer('yresolution', yr) # ColourSpace if self.luxrender_colorspace.preset: cs_object = getattr(colorspace_presets, self.luxrender_colorspace.preset_name) else: cs_object = self.luxrender_colorspace params.add_float('gamma', self.get_gamma()) params.add_float('colorspace_white', [cs_object.cs_whiteX, cs_object.cs_whiteY]) params.add_float('colorspace_red', [cs_object.cs_redX, cs_object.cs_redY]) params.add_float('colorspace_green', [cs_object.cs_greenX, cs_object.cs_greenY]) params.add_float('colorspace_blue', [cs_object.cs_blueX, cs_object.cs_blueY]) # Camera Response Function if self.luxrender_colorspace.use_crf == 'file'and self.luxrender_colorspace.crf_file != '': if scene.camera.library is not None: local_crf_filepath = bpy.path.abspath(self.luxrender_colorspace.crf_file, scene.camera.library.filepath) else: local_crf_filepath = self.luxrender_colorspace.crf_file local_crf_filepath = efutil.filesystem_path( local_crf_filepath ) if scene.luxrender_engine.allow_file_embed(): from ..util import bencode_file2string params.add_string('cameraresponse', os.path.basename(local_crf_filepath)) encoded_data = bencode_file2string(local_crf_filepath) params.add_string('cameraresponse_data', encoded_data.splitlines() ) else: params.add_string('cameraresponse', local_crf_filepath) if self.luxrender_colorspace.use_crf == 'preset': params.add_string('cameraresponse', self.luxrender_colorspace.crf_preset) # Output types params.add_string('filename', get_output_filename(scene)) params.add_bool('write_resume_flm', self.write_flm) params.add_bool('restart_resume_flm', self.restart_flm) params.add_bool('write_flm_direct', self.write_flm_direct) if self.output_alpha: output_channels = 'RGBA' params.add_bool('premultiplyalpha', True) else: output_channels = 'RGB' if scene.luxrender_engine.export_type == 'INT' and scene.luxrender_engine.integratedimaging: # Set up params to enable z buffer # we use the colorspace gamma, else autolinear gives wrong estimation, gamma 1.0 per pixel is recalculated in pylux after # Also, this requires tonemapped EXR output params.add_string('write_exr_channels', 'RGBA') params.add_bool('write_exr_halftype', False) params.add_bool('write_exr_applyimaging', True) params.add_bool('premultiplyalpha', True if self.output_alpha else False) # Blender 2.66 always expects premultiplyalpha params.add_bool('write_exr_ZBuf', True) params.add_string('write_exr_zbuf_normalizationtype', 'Camera Start/End clip') else: # Otherwise let the user decide on tonemapped EXR and other EXR settings params.add_bool('write_exr_halftype', self.write_exr_halftype) params.add_bool('write_exr_applyimaging', self.write_exr_applyimaging) params.add_bool('write_exr_ZBuf', self.write_zbuf) params.add_string('write_exr_compressiontype', self.write_exr_compressiontype) params.add_string('write_exr_zbuf_normalizationtype', self.zbuf_normalization) params.add_bool('write_exr', self.write_exr) params.add_string('write_exr_channels', output_channels) params.add_bool('write_png', self.write_png) params.add_string('write_png_channels', output_channels) if self.write_png: params.add_bool('write_png_16bit', self.write_png_16bit) params.add_bool('write_tga', self.write_tga) params.add_string('write_tga_channels', output_channels) if self.write_tga: params.add_bool('write_tga_ZBuf', self.write_zbuf) params.add_string('write_tga_zbuf_normalizationtype', self.zbuf_normalization) params.add_string('ldr_clamp_method', self.ldr_clamp_method) if scene.luxrender_engine.export_type == 'EXT': params.add_integer('displayinterval', self.displayinterval) params.add_integer('writeinterval', self.writeinterval) params.add_integer('flmwriteinterval', self.flmwriteinterval) else: params.add_integer('writeinterval', self.internal_updateinterval) # Halt conditions if scene.luxrender_halt.haltspp > 0: params.add_integer('haltspp', scene.luxrender_halt.haltspp) if scene.luxrender_halt.halttime > 0: params.add_integer('halttime', scene.luxrender_halt.halttime) if scene.luxrender_halt.haltthreshold > 0: params.add_float('haltthreshold', 1 / 10.0**scene.luxrender_halt.haltthreshold) # Convergence Test if scene.luxrender_halt.convergencestep != 32: params.add_float('convergencestep', scene.luxrender_halt.convergencestep) # Filename for User Sampling Map if scene.luxrender_sampler.usersamplingmap_filename != '': if scene.luxrender_sampler.usersamplingmap_filename.endswith('.exr'): params.add_string('usersamplingmap_filename', scene.luxrender_sampler.usersamplingmap_filename) else: params.add_string('usersamplingmap_filename', scene.luxrender_sampler.usersamplingmap_filename + '.exr') if self.outlierrejection_k > 0 and scene.luxrender_rendermode.renderer != 'sppm': params.add_integer('outlierrejection_k', self.outlierrejection_k) params.add_integer('tilecount', self.tilecount) # update the film settings with tonemapper settings params.update( self.luxrender_tonemapping.get_paramset() ) return ('fleximage', params)
def get_real_path(path): return os.path.realpath(efutil.filesystem_path(path))
def render(self, context): ''' Render the scene file, or in our case, export the frame(s) and launch an Indigo process. ''' with RENDERENGINE_indigo.render_lock: # Just render one thing at a time. self.renderer = None self.message_thread = None self.stats_thread = None self.framebuffer_thread = None self.render_update_timer = None self.rendering = False # force scene update to current rendering frame # Not sure why - Yves #context.frame_set(context.frame_current) #------------------------------------------------------------------------------ # Export the Scene # Get the frame path. frame_path = efutil.filesystem_path(context.render.frame_path()) # Get the filename for the frame sans extension. image_out_path = os.path.splitext(frame_path)[0] # Generate the name for the scene file(s). if context.indigo_engine.use_output_path == True: # Get the output path from the frame path. output_path = os.path.dirname(frame_path) # Generate the output filename output_filename = '%s.%s.%05i.igs' % (efutil.scene_filename(), bpy.path.clean_name(context.name), context.frame_current) else: # Get export path from the indigo_engine. export_path = efutil.filesystem_path(context.indigo_engine.export_path) # Get the directory name from the output path. output_path = os.path.dirname(export_path) # Get the filename from the output path and remove the extension. output_filename = os.path.splitext(os.path.basename(export_path))[0] # Count contiguous # chars and replace them with the frame number. # If the hash count is 0 and we are exporting an animation, append the frame numbers. hash_count = util.count_contiguous('#', output_filename) if hash_count != 0: output_filename = output_filename.replace('#'*hash_count, ('%%0%0ii'%hash_count)%context.frame_current) elif self.is_animation: output_filename = output_filename + ('%%0%0ii'%4)%context.frame_current # Add .igs extension. output_filename += '.igs' # The full path of the exported scene file. exported_file = '/'.join([ output_path, output_filename ]) # Create output_path if it does not exist. if not os.path.exists(output_path): os.makedirs(output_path) # If an animation is rendered, write an indigo queue file (.igq). if self.is_animation: igq_filename = '%s/%s.%s.igq'%(output_path, efutil.scene_filename(), bpy.path.clean_name(context.name)) if context.frame_current == context.frame_start: # Start a new igq file. igq_file = open(igq_filename, 'w') igq_file.write('<?xml version="1.0" encoding="utf-8" standalone="no" ?>\n') igq_file.write('<render_queue>\n') else: # Append to existing igq. igq_file = open(igq_filename, 'a') rnd = random.Random() rnd.seed(context.frame_current) # Write igq item. igq_file.write('\t<item>\n') igq_file.write('\t\t<scene_path>%s</scene_path>\n' % exported_file) igq_file.write('\t\t<halt_time>%d</halt_time>\n' % context.indigo_engine.halttime) igq_file.write('\t\t<halt_spp>%d</halt_spp>\n' % context.indigo_engine.haltspp) igq_file.write('\t\t<output_path>%s</output_path>\n' % image_out_path) igq_file.write('\t\t<seed>%s</seed>\n' % rnd.randint(1, 1000000)) igq_file.write('\t</item>\n') # If this is the last frame, write the closing tag. if context.frame_current == context.frame_end: igq_file.write('</render_queue>\n') igq_file.close() # Calculate the progress by frame with frame range (fr) and frame offset (fo). fr = context.frame_end - context.frame_start fo = context.frame_current - context.frame_start self.update_progress(fo/fr) scene_writer = indigo.operators._Impl_OT_indigo( directory = output_path, filename = output_filename ).set_report(self.report) # Write the scene file. export_result = scene_writer.execute(context) # Return if the export didn't finish. if not 'FINISHED' in export_result: return #------------------------------------------------------------------------------ # Update indigo defaults config file . config_updates = { 'auto_start': context.indigo_engine.auto_start, 'console_output': context.indigo_engine.console_output } if context.indigo_engine.use_console: indigo_path = getConsolePath(context) else: indigo_path = getGuiPath(context) if os.path.exists(indigo_path): config_updates['install_path'] = getInstallPath(context) try: for k,v in config_updates.items(): efutil.write_config_value('indigo', 'defaults', k, v) except Exception as err: indigo_log('Saving indigo config failed: %s' % err, message_type='ERROR') # Make sure that the Indigo we are going to launch is at least as # new as the exporter version. version_ok = True if not context.indigo_engine.skip_version_check: iv = getVersion(context) for i in range(3): version_ok &= iv[i]>=bl_info['version'][i] #------------------------------------------------------------------------------ # Conditionally Spawn Indigo. if context.indigo_engine.auto_start: exe_path = efutil.filesystem_path( indigo_path ) if not os.path.exists(exe_path): print("Failed to find indigo at '" + str(exe_path) + "'") msg = "Failed to find indigo at '" + str(exe_path) + "'." msg + "\n " msg += "Please make sure you have Indigo installed, and that the path to indigo in the 'Indigo Render Engine Settings' is set correctly." self.report({'ERROR'}, msg) #if not version_ok: #indigo_log("Unsupported version v%s; Cannot start Indigo with this scene" % ('.'.join(['%s'%i for i in iv])), message_type='ERROR') #return # if it's an animation, don't execute until final frame if self.is_animation and context.frame_current != context.frame_end: return # if animation and final frame, launch queue instead of single frame if self.is_animation and context.frame_current == context.frame_end: exported_file = igq_filename indigo_args = [ exe_path, exported_file ] else: indigo_args = [ exe_path, exported_file, '-o', image_out_path + '.png' ] # Set master or working master command line args. if context.indigo_engine.network_mode == 'master': indigo_args.extend(['-n', 'm']) elif context.indigo_engine.network_mode == 'working_master': indigo_args.extend(['-n', 'wm']) # Set port arg if network rendering is enabled. if context.indigo_engine.network_mode in ['master', 'working_master']: indigo_args.extend([ '-p', '%i' % context.indigo_engine.network_port ]) # Set hostname and port arg. if context.indigo_engine.network_mode == 'manual': indigo_args.extend([ '-h', '%s:%i' % (context.indigo_engine.network_host, context.indigo_engine.network_port) ]) # indigo_log("Starting indigo: %s" % indigo_args) # If we're starting a console or should wait for the process, listen to the output. if context.indigo_engine.use_console or context.indigo_engine.wait_for_process: f_stdout = subprocess.PIPE else: f_stdout = None # Launch the Indigo process. indigo_proc = subprocess.Popen(indigo_args, stdout=f_stdout) indigo_pid = indigo_proc.pid indigo_log('Started Indigo process, PID: %i' % indigo_pid) # Wait for the render to finish if we use the console or should wait for the process. if context.indigo_engine.use_console or context.indigo_engine.wait_for_process: while indigo_proc.poll() == None: indigo_proc.communicate() time.sleep(2) indigo_proc.wait() if not indigo_proc.stdout.closed: indigo_proc.communicate() if indigo_proc.returncode == -1: sys.exit(-1) else: indigo_log("Scene was exported to %s" % exported_file) #------------------------------------------------------------------------------ # Finished return
def get_intermediate_dir(force_debug=False): global intermediate_dir return_path = intermediate_dir if force_debug is True: return_path = get_sort_dir() return efutil.filesystem_path(return_path) + "/"
def get_sort_dir(): preferences = bpy.context.user_preferences.addons['sortblend'].preferences return_path = preferences.install_path if platform.system() == 'Windows': return return_path return efutil.filesystem_path(return_path) + "/"
def exportLamp(self, scene, lamp): ltype = lamp.data.type name = lamp.name mult = lamp.data.mitsuba_lamp.intensity if lamp.data.mitsuba_lamp.inside_medium: self.exportMedium( scene.mitsuba_media.media[lamp.data.mitsuba_lamp.lamp_medium]) if ltype == 'POINT': self.openElement('shape', {'type': 'sphere'}) self.exportPoint(lamp.location) self.parameter('float', 'radius', {'value': lamp.data.mitsuba_lamp.radius}) self.openElement('emitter', { 'id': '%s-light' % name, 'type': 'area' }) self.parameter( 'rgb', 'radiance', { 'value': "%f %f %f" % (lamp.data.color.r * mult, lamp.data.color.g * mult, lamp.data.color.b * mult) }) self.parameter( 'float', 'samplingWeight', {'value': '%f' % lamp.data.mitsuba_lamp.samplingWeight}) if lamp.data.mitsuba_lamp.inside_medium: self.element('ref', {'id': lamp.data.mitsuba_lamp.lamp_medium}) self.closeElement() self.closeElement() elif ltype == 'AREA': self.openElement('shape', {'type': 'rectangle'}) self.parameter('boolean', 'flipNormals', {'value': 'true'}) (size_x, size_y) = (lamp.data.size / 2.0, lamp.data.size / 2.0) if lamp.data.shape == 'RECTANGLE': size_y = lamp.data.size_y / 2.0 self.openElement('transform', {'name': 'toWorld'}) loc, rot, sca = lamp.matrix_world.decompose() mat_loc = mathutils.Matrix.Translation(loc) mat_rot = rot.to_matrix().to_4x4() mat_sca = mathutils.Matrix(( (sca[0] * size_x, 0, 0, 0), (0, sca[1] * size_y, 0, 0), (0, 0, sca[2], 0), (0, 0, 0, 1), )) self.exportMatrix(mat_loc * mat_rot * mat_sca) self.closeElement() self.openElement('emitter', { 'id': '%s-arealight' % name, 'type': 'area' }) self.parameter( 'rgb', 'radiance', { 'value': "%f %f %f" % (lamp.data.color.r * mult, lamp.data.color.g * mult, lamp.data.color.b * mult) }) self.parameter( 'float', 'samplingWeight', {'value': '%f' % lamp.data.mitsuba_lamp.samplingWeight}) if lamp.data.mitsuba_lamp.inside_medium: self.element('ref', {'id': lamp.data.mitsuba_lamp.lamp_medium}) self.closeElement() self.openElement('bsdf', {'type': 'diffuse'}) self.parameter('spectrum', 'reflectance', {'value': '0'}) self.closeElement() self.closeElement() elif ltype == 'SUN': # sun is considered hemi light by Mitsuba if self.hemi_lights >= 1: # Mitsuba supports only one hemi light return False self.hemi_lights += 1 invmatrix = lamp.matrix_world skyType = lamp.data.mitsuba_lamp.mitsuba_lamp_sun.sunsky_type LampParams = getattr(lamp.data.mitsuba_lamp, 'mitsuba_lamp_sun').get_paramset(lamp) if skyType == 'sunsky': self.openElement('emitter', { 'id': '%s-light' % name, 'type': 'sunsky' }) elif skyType == 'sun': self.openElement('emitter', { 'id': '%s-light' % name, 'type': 'sun' }) elif skyType == 'sky': self.openElement('emitter', { 'id': '%s-light' % name, 'type': 'sky' }) #self.parameter('boolean', 'extend', {'value' : '%s' % str(lamp.data.mitsuba_lamp.mitsuba_lamp_sun.extend).lower()}) LampParams.export(self) self.openElement('transform', {'name': 'toWorld'}) #rotate around x to make z UP. Default Y - UP self.element('rotate', {'x': '1', 'angle': '90'}) self.closeElement() #self.exportWorldTrafo() #self.parameter('float', 'turbidity', {'value' : '%f' % (lamp.data.mitsuba_lamp.mitsuba_lamp_sun.turbidity)}) #ot_mat = mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1])) #to make Z up rotate 90 around X #rotatedSun = invmatrix * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([1, 0, 0])) * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1])) self.parameter( 'vector', 'sunDirection', { 'x': '%f' % invmatrix[0][2], 'y': '%f' % invmatrix[1][2], 'z': '%f' % invmatrix[2][2] }) self.closeElement() elif ltype == 'SPOT': self.openElement('emitter', { 'id': '%s-light' % name, 'type': 'spot' }) self.exportWorldTrafo( lamp.matrix_world * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1]))) self.parameter( 'rgb', 'intensity', { 'value': "%f %f %f" % (lamp.data.color.r * mult, lamp.data.color.g * mult, lamp.data.color.b * mult) }) self.parameter( 'float', 'cutoffAngle', {'value': '%f' % (lamp.data.spot_size * 180 / (math.pi * 2))}) self.parameter( 'float', 'beamWidth', { 'value': '%f' % ((1 - lamp.data.spot_blend) * lamp.data.spot_size * 180 / (math.pi * 2)) }) self.parameter( 'float', 'samplingWeight', {'value': '%f' % lamp.data.mitsuba_lamp.samplingWeight}) if lamp.data.mitsuba_lamp.inside_medium: self.element('ref', {'id': lamp.data.mitsuba_lamp.lamp_medium}) self.closeElement() elif ltype == 'HEMI': if self.hemi_lights >= 1: # Mitsuba supports only one hemi light return False self.hemi_lights += 1 if lamp.data.mitsuba_lamp.envmap_type == 'constant': self.openElement('emitter', { 'id': '%s-light' % name, 'type': 'constant' }) self.parameter( 'float', 'samplingWeight', {'value': '%f' % lamp.data.mitsuba_lamp.samplingWeight}) self.parameter( 'rgb', 'radiance', { 'value': "%f %f %f" % (lamp.data.color.r * mult, lamp.data.color.g * mult, lamp.data.color.b * mult) }) self.closeElement() elif lamp.data.mitsuba_lamp.envmap_type == 'envmap': self.openElement('emitter', { 'id': '%s-light' % name, 'type': 'envmap' }) self.parameter( 'string', 'filename', { 'value': efutil.filesystem_path( lamp.data.mitsuba_lamp.envmap_file) }) self.exportWorldTrafo( lamp.matrix_world * mathutils.Matrix.Rotation(radians(90.0), 4, 'X')) self.parameter( 'float', 'scale', {'value': '%f' % lamp.data.mitsuba_lamp.intensity}) self.parameter( 'float', 'samplingWeight', {'value': '%f' % lamp.data.mitsuba_lamp.samplingWeight}) self.closeElement()
def exportLamp(self, scene, lamp, idx): ltype = lamp.data.type name = translate_id(lamp.name) mult = lamp.data.mitsuba_lamp.intensity if lamp.data.mitsuba_lamp.inside_medium: self.exportMedium( scene.mitsuba_media.media[lamp.data.mitsuba_lamp.lamp_medium]) if ltype == 'POINT': self.openElement('luminaire', { 'type': 'point', 'id': '%s-light' % name }) self.exportWorldTrafo(lamp.matrix_world) self.parameter( 'rgb', 'intensity', { 'value': "%f %f %f" % (lamp.data.color.r * mult, lamp.data.color.g * mult, lamp.data.color.b * mult) }) self.parameter( 'float', 'samplingWeight', {'value': '%f' % lamp.data.mitsuba_lamp.samplingWeight}) if lamp.data.mitsuba_lamp.inside_medium: self.element('ref', {'id': lamp.data.mitsuba_lamp.lamp_medium}) self.closeElement() elif ltype == 'AREA': self.element('remove', {'id': '%s-light' % name}) self.openElement('shape', {'type': 'obj'}) (size_x, size_y) = (lamp.data.size, lamp.data.size) if lamp.data.shape == 'RECTANGLE': size_y = lamp.data.size_y mult = mult / (2 * size_x * size_y) filename = "area_luminaire_%d.obj" % idx try: os.mkdir(self.meshes_dir) except OSError: pass self.parameter('string', 'filename', {'value': 'meshes/%s' % filename}) self.exportWorldTrafo(lamp.matrix_world) self.openElement('luminaire', { 'id': '%s-arealight' % name, 'type': 'area' }) if lamp.data.mitsuba_lamp.inside_medium: self.element('ref', {'id': lamp.data.mitsuba_lamp.lamp_medium}) self.parameter( 'rgb', 'intensity', { 'value': "%f %f %f" % (lamp.data.color.r * mult, lamp.data.color.g * mult, lamp.data.color.b * mult) }) self.closeElement() self.openElement('bsdf', {'type': 'lambertian'}) self.parameter('spectrum', 'reflectance', {'value': '0'}) self.closeElement() self.closeElement() path = os.path.join(self.meshes_dir, filename) objFile = open(path, 'w') objFile.write('v %f %f 0\n' % (-size_x / 2, -size_y / 2)) objFile.write('v %f %f 0\n' % (size_x / 2, -size_y / 2)) objFile.write('v %f %f 0\n' % (size_x / 2, size_y / 2)) objFile.write('v %f %f 0\n' % (-size_x / 2, size_y / 2)) objFile.write('f 4 3 2 1\n') objFile.close() elif ltype == 'SUN': self.openElement('luminaire', { 'id': '%s-light' % name, 'type': 'directional' }) scale = mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1])) self.exportWorldTrafo( lamp.matrix_world * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1]))) self.parameter( 'rgb', 'intensity', { 'value': "%f %f %f" % (lamp.data.color.r * mult, lamp.data.color.g * mult, lamp.data.color.b * mult) }) self.parameter( 'float', 'samplingWeight', {'value': '%f' % lamp.data.mitsuba_lamp.samplingWeight}) self.closeElement() elif ltype == 'SPOT': self.openElement('luminaire', { 'id': '%s-light' % name, 'type': 'spot' }) self.exportWorldTrafo( lamp.matrix_world * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1]))) self.parameter( 'rgb', 'intensity', { 'value': "%f %f %f" % (lamp.data.color.r * mult, lamp.data.color.g * mult, lamp.data.color.b * mult) }) self.parameter( 'float', 'cutoffAngle', {'value': '%f' % (lamp.data.spot_size * 180 / (math.pi * 2))}) self.parameter( 'float', 'beamWidth', { 'value': '%f' % (lamp.data.spot_blend * lamp.data.spot_size * 180 / (math.pi * 2)) }) self.parameter( 'float', 'samplingWeight', {'value': '%f' % lamp.data.mitsuba_lamp.samplingWeight}) if lamp.data.mitsuba_lamp.inside_medium: self.element('ref', {'id': lamp.data.mitsuba_lamp.lamp_medium}) self.closeElement() elif ltype == 'HEMI': if lamp.data.mitsuba_lamp.envmap_type == 'constant': self.openElement('luminaire', { 'id': '%s-light' % name, 'type': 'constant' }) self.parameter( 'float', 'samplingWeight', {'value': '%f' % lamp.data.mitsuba_lamp.samplingWeight}) self.parameter( 'rgb', 'intensity', { 'value': "%f %f %f" % (lamp.data.color.r * mult, lamp.data.color.g * mult, lamp.data.color.b * mult) }) self.closeElement() elif lamp.data.mitsuba_lamp.envmap_type == 'envmap': self.openElement('luminaire', { 'id': '%s-light' % name, 'type': 'envmap' }) self.parameter( 'string', 'filename', { 'value': efutil.filesystem_path( lamp.data.mitsuba_lamp.envmap_file) }) self.exportWorldTrafo(lamp.matrix_world) self.parameter( 'float', 'intensityScale', {'value': '%f' % lamp.data.mitsuba_lamp.intensity}) self.parameter( 'float', 'samplingWeight', {'value': '%f' % lamp.data.mitsuba_lamp.samplingWeight}) self.closeElement()