Exemple #1
0
    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')
Exemple #6
0
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