def _create_filter(self): devices = self.get_devices() use_oidn = (utils.IS_WIN or utils.IS_MAC) and devices.cpu_state if use_oidn: self.filter = self.context.create_filter(rif.IMAGE_FILTER_OPENIMAGE_DENOISE) else: self.filter = self.context.create_filter(rif.IMAGE_FILTER_AI_DENOISE) self.filter.set_parameter('useHDR', True) models_path = utils.package_root_dir() / 'data/models' if not models_path.is_dir(): # set alternative path models_path = utils.package_root_dir() / '../../.sdk/rif/models' self.filter.set_parameter('modelPath', str(models_path)) ml_output_image = self.context.create_image(self.width, self.height, 3) use_color_only = 'normal' not in self.inputs if use_color_only: self.filter.set_parameter('colorImg', self.inputs['color']) else: # setup remap normals filter normal_remap_filter = self.context.create_filter(rif.IMAGE_FILTER_REMAP_RANGE) normal_remap_filter.set_parameter('dstLo', 0.0) normal_remap_filter.set_parameter('dstHi', 1.0) normal_remap_image = self.context.create_image(self.width, self.height) self.command_queue.attach_image_filter(normal_remap_filter, self.inputs['normal'], normal_remap_image) # setup remap depth filter depth_remap_filter = self.context.create_filter(rif.IMAGE_FILTER_REMAP_RANGE) depth_remap_filter.set_parameter('dstLo', 0.0) depth_remap_filter.set_parameter('dstHi', 1.0) depth_remap_image = self.context.create_image(self.width, self.height) self.command_queue.attach_image_filter(depth_remap_filter, self.inputs['depth'], depth_remap_image) # configure Filter self.filter.set_parameter('colorImg', self.inputs['color']) self.filter.set_parameter('normalsImg', normal_remap_image) self.filter.set_parameter('depthImg', depth_remap_image) self.filter.set_parameter('albedoImg', self.inputs['albedo']) # setup resample filter output_resample_filter = self.context.create_filter(rif.IMAGE_FILTER_RESAMPLE) output_resample_filter.set_parameter('interpOperator', rif.IMAGE_INTERPOLATION_NEAREST) output_resample_filter.set_parameter('outSize', (self.width, self.height)) # attach filters self.command_queue.attach_image_filter(self.filter, self.inputs['color'], ml_output_image) # attach output resample filter self.command_queue.attach_image_filter(output_resample_filter, ml_output_image, self.output_image)
def _create_filter(self): self.filter = self.context.create_filter(rif.IMAGE_FILTER_AI_UPSCALE) models_path = utils.package_root_dir() / 'data/models' if not models_path.is_dir(): # set alternative path models_path = utils.package_root_dir() / '../../.sdk/rif/models' self.filter.set_parameter('modelPath', str(models_path)) self.filter.set_parameter('mode', rif.AI_UPSCALE_MODE_BEST_2X) self.output_image = self.context.create_image(self.width * 2, self.height * 2) self.command_queue.attach_image_filter(self.filter, self.inputs['color'], self.output_image)
def register_plugins(): rprsdk_bin_path = utils.package_root_dir() if not utils.IS_DEBUG_MODE else \ utils.package_root_dir().parent.parent / '.sdk/rpr/bin' def register_plugin(ContextCls, lib_name, cache_path): lib_path = rprsdk_bin_path / lib_name ContextCls.register_plugin(lib_path, cache_path) log(f"Registered plugin: plugin_id={ContextCls.plugin_id}, " f"lib_path={lib_path}, cache_path={cache_path}") cache_dir = utils.core_cache_dir() register_plugin( pyrpr.Context, { 'Windows': 'Tahoe64.dll', 'Linux': 'libTahoe64.so', 'Darwin': 'libTahoe64.dylib' }[utils.OS], cache_dir / f"{hex(pyrpr.API_VERSION)}_rpr") # enabling hybrid only for Windows and Linux pyhybrid.enabled = config.enable_hybrid and (utils.IS_WIN or utils.IS_LINUX) if pyhybrid.enabled: try: register_plugin(pyhybrid.Context, { 'Windows': 'Hybrid.dll', 'Linux': 'Hybrid.so' }[utils.OS], cache_dir / f"{hex(pyrpr.API_VERSION)}_hybrid") except RuntimeError as err: log.warn(err) pyhybrid.enabled = False # enabling RPR 2 try: register_plugin( pyrpr2.Context, { 'Windows': 'Northstar64.dll', 'Linux': 'libNorthstar64.so', 'Darwin': 'libNorthstar64.dylib' }[utils.OS], cache_dir / f"{hex(pyrpr.API_VERSION)}_rpr2") except RuntimeError as err: log.warn(err)
# distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #******************************************************************** import os import sys from rprblender import config from rprblender import utils from rprblender.utils import logging log = logging.Log(tag='engine.init') if utils.IS_DEBUG_MODE: project_root = utils.package_root_dir().parent.parent rpr_lib_dir = project_root / '.sdk/rpr/bin' rif_lib_dir = project_root / '.sdk/rif/bin' if utils.IS_WIN: os.environ['PATH'] = f"{rpr_lib_dir};{rif_lib_dir};" \ f"{os.environ.get('PATH', '')}" else: os.environ['LD_LIBRARY_PATH'] = f"{rpr_lib_dir}:{rif_lib_dir}:" \ f"{os.environ.get('LD_LIBRARY_PATH', '')}" sys.path.append(str(project_root / "src/bindings/pyrpr/.build")) sys.path.append(str(project_root / "src/bindings/pyrpr/src")) else: rpr_lib_dir = rif_lib_dir = utils.package_root_dir()
# pyrprgltf.init(log, rprsdk_bin_path=rprsdk_bin_path) except: logging.critical(traceback.format_exc(), tag='') return False finally: sys.path.remove(bindings_import_path) return True if 'pyrpr' not in sys.modules: # try loading pyrpr for installed addon bindings_import_path = str(utils.package_root_dir()) rprsdk_bin_path = utils.package_root_dir() if not pyrpr_init(bindings_import_path, rprsdk_bin_path): logging.warn( "Failed to load rpr from %s. One more attempt will be provided." % bindings_import_path) # try loading pyrpr from source src = utils.package_root_dir().parent project_root = src.parent rprsdk_bin_path = project_root / ".sdk/rpr/bin" bindings_import_path = str(src / 'bindings/pyrpr/.build') pyrpr_import_path = str(src / 'bindings/pyrpr/src')
class RPR_RenderProperties(RPR_Properties): """ Main render properties. Available from scene.rpr """ saved_addon_version: bpy.props.IntVectorProperty(name="Version") # RENDER DEVICES for development debug mode; standalone settings are saved as addon properties debug_user_settings: PointerProperty(type=RPR_UserSettings) # DEBUG OPTIONS def update_log_min_level(self, context): logging.limit_log('default', getattr(logging, self.log_min_level)) log_min_level: EnumProperty( name="Log Min Level", description="Log minimum level", items=( ('DEBUG', "Debug", "Show all log: Debug, Info, Warning, Error"), ('INFO', "Info", "Show log: Info, Warning, Error"), ('WARN', "Warning", "Show log: Warning, Error"), ('ERROR', "Error", "Show log: Error"), ), default='INFO', update=update_log_min_level) trace_dump: BoolProperty(name="Trace Dump", description="Enable Trace Dump", default=False) trace_dump_folder: StringProperty(name='Trace Dump Folder', description='Trace Dump Folder', subtype='DIR_PATH', default=str(utils.get_temp_dir() / "tracedump")) texture_cache_dir: StringProperty( name='Texture Cache Dir', description='Dirctory used for texture cache', subtype='DIR_PATH', default=str(utils.package_root_dir() / ".tex_cache")) # RENDER LIMITS limits: PointerProperty(type=RPR_RenderLimits) viewport_limits: PointerProperty(type=RPR_RenderLimits) # RENDER TILES use_tile_render: BoolProperty( name="Tiled rendering", description= "Use tiles to do final rendering. Available with Full render quality only", default=False, ) tile_x: IntProperty( name="Tile X", description="Horizontal tile size to use while rendering", min=32, max=2048, default=512, ) tile_y: IntProperty( name="Y", description="Vertical tile size to use while rendering", min=32, max=2048, default=512, ) tile_order: EnumProperty(name="Tile Order", items=( ('CENTER_SPIRAL', "Center Spiral", "Render from center by spiral"), ('VERTICAL', "Vertical", "Render from vertically from left to right"), ('HORIZONTAL', "Horizontal", "Render horizontally from top to bottom"), ), default='CENTER_SPIRAL') @property def is_tile_render_available(self): return self.use_tile_render and self.render_quality == 'FULL' # RAY DEPTH PROPERTIES use_clamp_radiance: BoolProperty( name="Clamp", description="Use clamp radiance", default=False, ) clamp_radiance: FloatProperty( name="Clamp Radiance", description="Clamp radiance", min=1.0, default=1.0, ) max_ray_depth: IntProperty( name="Total", description="Max total ray depth", min=0, soft_min=2, soft_max=50, default=8, ) diffuse_depth: IntProperty( name="Diffuse", description="Diffuse ray depth", min=0, soft_min=2, soft_max=50, default=3, ) glossy_depth: IntProperty( name="Glossy", description="Glossy ray depth", min=0, soft_min=2, soft_max=50, default=5, ) shadow_depth: IntProperty( name="Shadow", description="Shadow depth", min=0, soft_min=2, soft_max=50, default=5, ) refraction_depth: IntProperty( name="Refraction", description="Refraction ray depth", min=0, soft_min=2, soft_max=50, default=5, ) glossy_refraction_depth: IntProperty( name="Glossy Refraction", description="Glossy refraction ray depth", min=0, soft_min=2, soft_max=50, default=5, ) ray_cast_epsilon: FloatProperty( name="Ray Cast Epsilon (mm)", description="Ray cast epsilon (in millimeters)", min=0.0, soft_max=2.0, default=0.02, ) # RENDER EFFECTS use_render_stamp: BoolProperty(name="Render Stamp", description="Use render stamp", default=False) render_stamp: StringProperty( name="Render Stamp", description="\ Render stamp: \n\ %pt - performance time \n\ %pp - performance samples \n\ %sl - scene lights \n\ %so - scene objects \n\ %c - CPU \n\ %g - GPU \n\ %r - rendering mode \n\ %h - hardware for rendering \n\ %i - computer name \n\ %d - current date \n\ %b - build number", default= "Radeon ProRender for Blender %b | %h | Time: %pt | Samples: %pp | Objects: %so | Lights: %sl", ) render_mode: EnumProperty( name="Render Mode", description="Override render mode", items=( ('GLOBAL_ILLUMINATION', "Global Illumination", "Global illumination render mode"), ('DIRECT_ILLUMINATION', "Direct Illumination", "Direct illumination render mode"), ('DIRECT_ILLUMINATION_NO_SHADOW', "Direct Illumination no Shadows", "Direct illumination without shadows render mode"), ('WIREFRAME', "Wireframe", "Wireframe render mode"), ('MATERIAL_INDEX', "Material Index", "Material index render mode"), ('POSITION', "World Position", "World position render mode"), ('NORMAL', "Shading Normal", "Shading normal render mode"), ('TEXCOORD', "Texture Coordinate", "Texture coordinate render mode"), ('AMBIENT_OCCLUSION', "Ambient Occlusion", "Ambient occlusion render mode"), ('DIFFUSE', "Diffuse", "Diffuse render mode"), ), default='GLOBAL_ILLUMINATION', ) pixel_filter: EnumProperty( name="Pixel Filter", description="Filter used for anti aliasing", items=( ('BOX', "Box", "Box Filter"), ('TRIANGLE', "Triangle", "Triangle Filter"), ('GAUSSIAN', "Gaussian", "Gaussian Filter"), ('MITCHELL', "Mitchell", "Mitchell Filter"), ('LANCZOS', "Lanczos", "Lanczos Filter"), ('BLACKMANHARRIS', "Blackman-Harris", "Blackman-Harris Filter"), ), default='BLACKMANHARRIS', ) pixel_filter_width: FloatProperty( name="Width", description="Pixel Filter Width", min=0, soft_max=5, default=1.5, ) render_quality_items = [( 'FULL2', "Full", "Full render quality using RPR 2, including hardware ray tracing support." ), ('FULL', "Legacy", "Full render quality using RPR 1.")] if pyhybrid.enabled: render_quality_items += [ ('HIGH', "High", "High render quality"), ('MEDIUM', "Medium", "Medium render quality"), ('LOW', "Low", "Low render quality"), ] def update_render_quality(self, context): if self.render_quality in ('FULL', 'FULL2'): return settings = get_user_settings() settings.final_devices.cpu_state = False settings.viewport_devices.cpu_state = False render_quality: EnumProperty(name="Render Quality", description="RPR render quality", items=render_quality_items, default='FULL2', update=update_render_quality) hybrid_low_mem: BoolProperty( name="Use 4GB memory", description="Enable to support GPUs with 4Gb VRAM or less", default=False, ) motion_blur_in_velocity_aov: BoolProperty( name="Only in Velocity AOV", description= "Apply Motion Blur in Velocity AOV only\nOnly for Full render quality", default=False, ) # CONTOUR render mode settings use_contour_render: BoolProperty( name="Contour", description="Use Contour rendering mode. Final render only", default=False) contour_use_object_id: BoolProperty( name="Use Object ID", description="Use Object ID for Contour rendering", default=True, ) contour_use_material_id: BoolProperty( name="Use Material Index", description="Use Material Index for Contour rendering", default=True, ) contour_use_shading_normal: BoolProperty( name="Use Shading Normal", description="Use Shading Normal for Contour rendering", default=True, ) contour_object_id_line_width: FloatProperty( name="Line Width Object", description="Line width for Object ID contours", min=1.0, max=10.0, default=1.0, ) contour_material_id_line_width: FloatProperty( name="Line Width Material", description="Line width for Material Index contours", min=1.0, max=10.0, default=1.0, ) contour_shading_normal_line_width: FloatProperty( name="Line Width Normal", description="Line width for Shading Normal contours", min=1.0, max=10.0, default=1.0, ) contour_normal_threshold: FloatProperty( name="Normal Threshold", description="Threshold for normals, in degrees", subtype='ANGLE', min=0.0, max=math.radians(180.0), default=math.radians(45.0), ) contour_antialiasing: FloatProperty( name="Antialiasing", min=0.0, max=1.0, default=1.0, ) contour_debug_flag: BoolProperty( name="Feature Debug", default=False, ) def init_rpr_context(self, rpr_context, is_final_engine=True, use_gl_interop=False, use_contour_integrator=False): """ Initializes rpr_context by device settings """ scene = self.id_data log("Syncing scene: %s" % scene.name) devices = self.get_devices(is_final_engine) context_flags = set() # enable CMJ sampler for adaptive sampling context_props = [ pyrpr.CONTEXT_SAMPLER_TYPE, pyrpr.CONTEXT_SAMPLER_TYPE_CMJ ] if devices.cpu_state: context_flags |= {pyrpr.Context.cpu_device['flag']} context_props.extend( [pyrpr.CONTEXT_CPU_THREAD_LIMIT, devices.cpu_threads]) metal_enabled = False for i, gpu_state in enumerate(devices.available_gpu_states): if gpu_state: context_flags |= {pyrpr.Context.gpu_devices[i]['flag']} if use_gl_interop: context_flags |= {pyrpr.CREATION_FLAGS_ENABLE_GL_INTEROP} if not metal_enabled and platform.system() == 'Darwin'\ and not isinstance(rpr_context, context.RPRContext2): # only enable metal once and if a GPU is turned on metal_enabled = True context_flags |= {pyrpr.CREATION_FLAGS_ENABLE_METAL} if self.render_quality in ('LOW', 'MEDIUM', 'HIGH') and self.hybrid_low_mem: # set these props to use < 4gb vertex_mem_size = pyrpr.ffi.new('int*', 768 * 1024 * 1024) # 768mb texture memory acc_mem_size = pyrpr.ffi.new('int*', 1024**3) # 1gb for bvh memry context_props.extend([ pyrpr.CONTEXT_CREATEPROP_HYBRID_VERTEX_MEMORY_SIZE, vertex_mem_size, pyrpr.CONTEXT_CREATEPROP_HYBRID_ACC_MEMORY_SIZE, acc_mem_size ]) context_props.append(0) # should be followed by 0 if self.trace_dump: if not os.path.isdir(self.trace_dump_folder): os.mkdir(self.trace_dump_folder) pyrpr.Context.set_parameter(None, pyrpr.CONTEXT_TRACING_PATH, self.trace_dump_folder) pyrpr.Context.set_parameter(None, pyrpr.CONTEXT_TRACING_ENABLED, True) else: pyrpr.Context.set_parameter(None, pyrpr.CONTEXT_TRACING_ENABLED, False) rpr_context.init(context_flags, context_props, use_contour_integrator=use_contour_integrator) if metal_enabled: mac_vers_major = platform.mac_ver()[0].split('.')[1] # if this is mojave turn on MPS if float(mac_vers_major) >= 14: rpr_context.set_parameter( pyrpr.CONTEXT_METAL_PERFORMANCE_SHADER, 1) # enable texture cache for RPR2 if isinstance(rpr_context, context.RPRContext2): if not os.path.isdir(self.texture_cache_dir): os.mkdir(self.texture_cache_dir) rpr_context.set_parameter(pyrpr.CONTEXT_TEXTURE_CACHE_PATH, self.texture_cache_dir) def get_devices(self, is_final_engine=True): """ Get render devices settings for current mode """ devices_settings = get_user_settings() if is_final_engine or not devices_settings.separate_viewport_devices: return devices_settings.final_devices return devices_settings.viewport_devices def export_ray_depth(self, rpr_context): """ Exports ray depth settings """ res = False res |= rpr_context.set_parameter(pyrpr.CONTEXT_MAX_RECURSION, self.max_ray_depth) res |= rpr_context.set_parameter(pyrpr.CONTEXT_MAX_DEPTH_DIFFUSE, self.diffuse_depth) res |= rpr_context.set_parameter(pyrpr.CONTEXT_MAX_DEPTH_GLOSSY, self.glossy_depth) res |= rpr_context.set_parameter(pyrpr.CONTEXT_MAX_DEPTH_SHADOW, self.shadow_depth) res |= rpr_context.set_parameter(pyrpr.CONTEXT_MAX_DEPTH_REFRACTION, self.refraction_depth) res |= rpr_context.set_parameter( pyrpr.CONTEXT_MAX_DEPTH_GLOSSY_REFRACTION, self.glossy_refraction_depth) res |= rpr_context.set_parameter(pyrpr.CONTEXT_RADIANCE_CLAMP, self.clamp_radiance if \ self.use_clamp_radiance else sys.float_info.max) res |= rpr_context.set_parameter( pyrpr.CONTEXT_RAY_CAST_EPISLON, self.ray_cast_epsilon * 0.001) # Convert millimeters to meters return res def export_render_mode(self, rpr_context): return rpr_context.set_parameter( pyrpr.CONTEXT_RENDER_MODE, getattr(pyrpr, 'RENDER_MODE_' + self.render_mode)) @property def is_contour_used(self): return self.render_quality == 'FULL2' and self.use_contour_render def export_contour_mode(self, rpr_context): """ set Contour render mode parameters """ rpr_context.set_parameter(pyrpr.CONTEXT_CONTOUR_USE_OBJECTID, self.contour_use_object_id) rpr_context.set_parameter(pyrpr.CONTEXT_CONTOUR_USE_MATERIALID, self.contour_use_material_id) rpr_context.set_parameter(pyrpr.CONTEXT_CONTOUR_USE_NORMAL, self.contour_use_shading_normal) rpr_context.set_parameter(pyrpr.CONTEXT_CONTOUR_LINEWIDTH_OBJECTID, self.contour_object_id_line_width) rpr_context.set_parameter(pyrpr.CONTEXT_CONTOUR_LINEWIDTH_MATERIALID, self.contour_material_id_line_width) rpr_context.set_parameter(pyrpr.CONTEXT_CONTOUR_LINEWIDTH_NORMAL, self.contour_shading_normal_line_width) rpr_context.set_parameter(pyrpr.CONTEXT_CONTOUR_NORMAL_THRESHOLD, math.degrees(self.contour_normal_threshold)) rpr_context.set_parameter(pyrpr.CONTEXT_CONTOUR_ANTIALIASING, self.contour_antialiasing) rpr_context.set_parameter(pyrpr.CONTEXT_CONTOUR_DEBUG_ENABLED, self.contour_debug_flag) rpr_context.enable_aov(pyrpr.AOV_OBJECT_ID) rpr_context.enable_aov(pyrpr.AOV_MATERIAL_ID) rpr_context.enable_aov(pyrpr.AOV_SHADING_NORMAL) def export_pixel_filter(self, rpr_context): """ Exports pixel filter settings """ filter_type = getattr(pyrpr, f"FILTER_{self.pixel_filter}") filter_radius = getattr( pyrpr, f"CONTEXT_IMAGE_FILTER_{self.pixel_filter}_RADIUS") res = False res |= rpr_context.set_parameter(pyrpr.CONTEXT_IMAGE_FILTER_TYPE, filter_type) res |= rpr_context.set_parameter(filter_radius, self.pixel_filter_width) return res def export_render_quality(self, rpr_context): if self.render_quality == 'FULL': return False quality = getattr(pyrpr, 'RENDER_QUALITY_' + self.render_quality) return rpr_context.set_parameter(pyrpr.CONTEXT_RENDER_QUALITY, quality) @classmethod def register(cls): log("Register") bpy.types.Scene.rpr = PointerProperty( name="RPR Render Settings", description="RPR render settings", type=cls, ) @classmethod def unregister(cls): log("Unregister") del bpy.types.Scene.rpr