def pyrpr_init(bindings_import_path, rprsdk_bin_path): log("pyrpr_init: bindings_path=%s, rpr_bin_path=%s" % (bindings_import_path, rprsdk_bin_path)) if bindings_import_path not in sys.path: sys.path.append(bindings_import_path) try: import pyrpr import pyhybrid import pyrpr2 rpr_version = utils.core_ver_str(full=True) log.info(f"RPR Core version: {rpr_version}") pyrpr.lib_wrapped_log_calls = config.pyrpr_log_calls pyrpr.init(logging.Log(tag='core'), rprsdk_bin_path=rprsdk_bin_path) import pyrpr_load_store pyrpr_load_store.init(rprsdk_bin_path) import pyrprimagefilters rif_version = utils.rif_ver_str(full=True) log.info(f"Image Filters version {rif_version}") pyrprimagefilters.lib_wrapped_log_calls = config.pyrprimagefilters_log_calls pyrprimagefilters.init(log, rprsdk_bin_path=rprsdk_bin_path) # import pyrprgltf # pyrprgltf.lib_wrapped_log_calls = config.pyrprgltf_log_calls # 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
# # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # 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. #******************************************************************** from . import render_engine from . import context_hybrid from rprblender.operators.world import FOG_KEY from rprblender.utils import logging log = logging.Log(tag='render_engine_hybrid') class RenderEngine(render_engine.RenderEngine): _RPRContext = context_hybrid.RPRContext def sync(self, depsgraph): super().sync(depsgraph) depsgraph.scene.rpr.export_render_quality(self.rpr_context) log('Finish sync') def depsgraph_objects(self, depsgraph, with_camera=False): for obj in super().depsgraph_objects(depsgraph, with_camera): if obj.name == FOG_KEY: continue
# 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. #******************************************************************** """ This module exports following blender object types: 'CURVE', 'FONT', 'SURFACE', 'META'. It converts such blender object into blender mesh and exports it as mesh. """ import bpy from . import object, mesh from rprblender.utils import logging log = logging.Log(tag='export.to_mesh') def sync(rpr_context, obj: bpy.types.Object, **kwargs): """ Converts object into blender's mesh and exports it as mesh """ try: # This operation adds new mesh into bpy.data.meshes, that's why it should be removed after usage. # obj.to_mesh() could also return None for META objects. new_mesh = obj.to_mesh() log("sync", obj, new_mesh) if new_mesh: mesh.sync(rpr_context, obj, mesh=new_mesh, **kwargs) return True
# You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # 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 numpy as np import bpy from . import object, light, mesh from rprblender.utils import logging log = logging.Log(tag='export.instance') def key(instance: bpy.types.DepsgraphObjectInstance): return (object.key(instance.parent), instance.random_id) def get_transform(instance: bpy.types.DepsgraphObjectInstance): return np.array(instance.matrix_world, dtype=np.float32).reshape(4, 4) def sync(rpr_context, instance: bpy.types.DepsgraphObjectInstance, **kwargs): """ sync the blender instance """ assert instance.is_instance # expecting: instance.is_instance == True
# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # 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 bpy import pyrpr from .engine import Engine from rprblender.export import object, camera, particle, world from rprblender.utils import logging log = logging.Log(tag='PreviewEngine') CONTEXT_LIFETIME = 300.0 # 5 minutes in seconds class PreviewEngine(Engine): """ Render engine for preview material, lights, environment """ TYPE = 'PREVIEW' rpr_context = None def __init__(self, rpr_engine): super().__init__(rpr_engine) self.is_synced = False
# # Unless required by applicable law or agreed to in writing, software # 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 numpy as np import functools import pyrpr from rprblender.config import hybrid_unsupported_log_warn from rprblender.utils import logging log = logging.Log(tag='hybrid') def ignore_unsupported(function): """Function decorator which ignores UNSUPPORTED and INVALID_PARAMETER core errors""" @functools.wraps(function) def wrapper(*args, **kwargs): try: return function(*args, **kwargs) except pyrpr.CoreError as e: if e.status not in (pyrpr.ERROR_UNSUPPORTED, pyrpr.ERROR_INVALID_PARAMETER): raise if hybrid_unsupported_log_warn:
# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # 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 numpy as np import bpy from . import mesh, light, camera, to_mesh, volume, openvdb, particle, hair from rprblender.utils import logging log = logging.Log(tag='export.object') def key(obj: bpy.types.Object): return obj.name def get_transform(obj: bpy.types.Object): return np.array(obj.matrix_world, dtype=np.float32).reshape(4, 4) def sync(rpr_context, obj: bpy.types.Object, **kwargs): """ sync the object and any data attached """ from rprblender.engine.render_engine import RenderEngine
# # Unless required by applicable law or agreed to in writing, software # 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 numpy as np import bpy import mathutils from . import mesh, material, object from rprblender.utils import logging log = logging.Log(tag='export.particle') def key(p_sys: bpy.types.ParticleSystem, emitter: bpy.types.Object): return (object.key(emitter), p_sys.name) def get_particle_system_material(rpr_context, p_sys, emitter): """Returns the material set for this particle system or None if none set or some other issue""" if len(emitter.material_slots) == 0: return None if (p_sys.settings.material - 1) < len(emitter.material_slots): slot = emitter.material_slots[p_sys.settings.material - 1] else:
# # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # 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 bpy from rprblender.engine.context import RPRContext from rprblender.nodes.blender_nodes import ShaderNodeOutputMaterial from rprblender.utils import logging log = logging.Log(tag='export.Material') def key(material: bpy.types.Material, obj=None, input_socket_key='Surface'): mat_key = material.name_full obj_name = obj.name_full if obj is not None else '' return (mat_key, obj_name, input_socket_key) def get_material_output_node(material): """ Finds output node in material tree and exports it """ if not material.node_tree: # there could be a situation when node_tree is None return None
# # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # 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. #******************************************************************** from . import viewport_engine from . import context_hybrid from rprblender.operators.world import FOG_KEY from rprblender.utils import logging log = logging.Log(tag='viewport_engine_hybrid') class ViewportEngine(viewport_engine.ViewportEngine): _RPRContext = context_hybrid.RPRContext def __init__(self, rpr_engine): super().__init__(rpr_engine) self.render_image = None def sync(self, context, depsgraph): super().sync(context, depsgraph) depsgraph.scene.rpr.export_render_quality(self.rpr_context) log('Finish sync')
# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # 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"))
# # Unless required by applicable law or agreed to in writing, software # 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 sys import traceback from rprblender import config from rprblender import utils from rprblender.utils import logging log = logging.Log(tag='engine.init') def pyrpr_init(bindings_import_path, rprsdk_bin_path): log("pyrpr_init: bindings_path=%s, rpr_bin_path=%s" % (bindings_import_path, rprsdk_bin_path)) if bindings_import_path not in sys.path: sys.path.append(bindings_import_path) try: import pyrpr import pyhybrid import pyrpr2 rpr_version = utils.core_ver_str(full=True)
# See the License for the specific language governing permissions and # limitations under the License. #******************************************************************** from dataclasses import dataclass import numpy as np import math import bpy import pyrpr from rprblender.engine.context import RPRContext from . import object from rprblender.utils import logging log = logging.Log(tag='export.camera') # Core has issues with drawing faces in orthographic camera view with big # ortho depth (far_clip_plane - near_clip_plane). # Experimentally found quite suited value = 200 MAX_ORTHO_DEPTH = 200.0 @dataclass(init=False, eq=True) class CameraData: """ Comparable dataclass which holds all camera settings """ mode: int = None clip_plane: (float, float) = None focal_length: float = None sensor_size: (float, float) = None
#******************************************************************** import os import numpy as np import math import bpy from rprblender.engine.context import RPRContext from rprblender.properties.light import MAX_LUMINOUS_EFFICACY from . import mesh, image, object from rprblender.utils.conversion import convert_kelvins_to_rgb from rprblender import utils from rprblender.utils import logging log = logging.Log(tag='export.light') def get_radiant_power(light: bpy.types.Light, area=0.0): """ Return light radiant power depending of light type and selected units """ rpr = light.rpr # calculating color intensity color = np.array(light.color) if rpr.use_temperature: color *= convert_kelvins_to_rgb(rpr.temperature) intensity = color * rpr.intensity default_intensity = color * light.energy # calculating radian power for core
#******************************************************************** import math import bpy from bpy.props import ( BoolProperty, FloatProperty, PointerProperty, IntProperty, EnumProperty, ) import pyrpr from . import RPR_Properties from rprblender.utils import logging log = logging.Log(tag='properties.object') class RPR_ObjectProperites(RPR_Properties): """ Properties for objects. Should be available only for meshes and area lights """ # Visibility visibility_in_primary_rays: BoolProperty( name="Camera", description="This object will be visible in camera rays", default=True, ) reflection_visibility: BoolProperty( name="Reflections", description="This object will be visible in reflections", default=True,
# See the License for the specific language governing permissions and # limitations under the License. #******************************************************************** import numpy as np import os from pathlib import Path import bpy import bpy_extras from rprblender import utils from rprblender.utils import logging from rprblender.utils import get_sequence_frame_file_path log = logging.Log(tag='export.image') UNSUPPORTED_IMAGES = ('.tiff', '.tif', '.exr') # image format conversion for packed pixel/generated images IMAGE_FORMATS = { 'OPEN_EXR_MULTILAYER': ('OPEN_EXR', 'exr'), 'OPEN_EXR': ('OPEN_EXR', 'exr'), 'HDR': ('HDR', 'hdr'), # 'TIFF': ('TIFF', 'tiff'), # Seems tiff is not working properly in RPR 'TARGA': ('TARGA', 'tga'), 'TARGA_RAW': ('TARGA', 'tga'), # everything else will be stored as PNG } DEFAULT_FORMAT = ('PNG', 'png')
# Unless required by applicable law or agreed to in writing, software # 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 threading import time import pyrpr from .render_engine import RenderEngine from .context import RPRContext2 from rprblender.utils import logging log = logging.Log(tag='RenderEngine2') class RenderEngine2(RenderEngine): _RPRContext = RPRContext2 def __init__(self, rpr_engine): super(RenderEngine2, self).__init__(rpr_engine) self.cryptomatte_allowed = True def _update_athena_data(self, data): data['Quality'] = "rpr2" def _render(self): resolve_event = threading.Event() is_finished = False
import pyrpr import pyhybrid import pyrpr2 from bpy.props import (BoolProperty, FloatProperty, IntProperty, PointerProperty, BoolVectorProperty, EnumProperty, StringProperty, IntVectorProperty) import platform from rprblender import utils from rprblender.utils.user_settings import get_user_settings, on_settings_changed from . import RPR_Properties from rprblender.engine import context from rprblender.utils import logging log = logging.Log(tag='properties.render') class RPR_RenderLimits(bpy.types.PropertyGroup): """ Properties for render limits: we use both a time and a max sample limit. if noise threshold > 0 then use adaptive sampling. """ min_samples: IntProperty( name="Min Samples", description= "Minimum number of samples to render for each pixel. After this, adaptive " "sampling will stop sampling pixels where noise is less than threshold.", min=16, default=64,
import bpy from bpy.props import ( BoolProperty, FloatVectorProperty, FloatProperty, IntProperty, StringProperty, EnumProperty, PointerProperty, ) from . import RPR_Properties from rprblender.utils import logging log = logging.Log(tag='properties.world') class RPR_EnvironmentSunSky(bpy.types.PropertyGroup): type: EnumProperty( name="Sun & Sky System", items=(('ANALYTICAL', "Analytical Sky", "Analytical Sky"), ('DATE_TIME_LOCATION', "Date, Time and Location", "Date, Time and Location")), description="Sun & Sky System", default='ANALYTICAL', ) # Analytical Sky azimuth: FloatProperty(
#******************************************************************** import math import bpy from bpy.props import ( PointerProperty, EnumProperty, FloatProperty, BoolProperty, IntProperty, StringProperty, ) from . import RPR_Properties from rprblender.utils import logging log = logging.Log(tag='properties.light') MAX_LUMINOUS_EFFICACY = 683.0 # luminous efficacy of ideal monochromatic 555 nm source class RPR_LightProperties(RPR_Properties): """ Light properties """ # LIGHT INTENSITY intensity: FloatProperty( name="Intensity", description="Light Intensity", min=0.0, step=20, default=100.0, )
# # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # 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 math import pyrpr from rprblender.engine import context_hybrid from rprblender.utils import logging log = logging.Log(tag='export.node') class NodeItem: ''' This class is a wrapper used for doing operations on material nodes. rpr_context is referenced to create new nodes A Nodeitem can hold a float, vector, or Node value. Node Items can then be simply multiplied, divided, etc by using operator overloading. If the values are fixed, math operations will be applied, otherwise an RPR arithmetic node will be created. NodeItems can retrieve their data with () operator, or index RGBA etc with [] ''' def __init__(self, rpr_context, data: [tuple, float, pyrpr.MaterialNode]):
# # Unless required by applicable law or agreed to in writing, software # 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. #******************************************************************** from dataclasses import dataclass import numpy as np import bpy from . import particle, object from rprblender.utils import logging log = logging.Log(tag='export.hair') def key(p_sys, emitter): return particle.key(p_sys, emitter) @dataclass(init=False) class CurveData: points: np.array uvs: np.array points_radii: np.array @staticmethod def init(p_sys: bpy.types.ParticleSystem, obj: bpy.types.Object, use_final_settings: bool):
# 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 bpy from bpy.props import ( PointerProperty, IntProperty, StringProperty, ) from . import RPR_Properties from rprblender.utils import logging log = logging.Log(tag='properties.mesh') class RPR_MeshProperites(RPR_Properties): secondary_uv_layer_name: StringProperty( name="Secondary UV Map", description="Secondary UV Map", default="", ) @property def primary_uv_layer(self): """ Get the mesh primary UV if present """ uv_layers = self.id_data.uv_layers return next((uv for uv in uv_layers if uv.active_render), None)
# limitations under the License. #******************************************************************** import os import numpy as np import bpy import pyrpr from rprblender.utils import helper_lib, IS_WIN, IS_MAC, is_zero from rprblender.utils import get_sequence_frame_file_path from . import mesh, object, material from rprblender.utils import logging log = logging.Log(tag='export.openvdb') def key(obj: bpy.types.Object): return (object.key(obj), 'openvdb') def get_transform(obj: bpy.types.Object): # creating bound transform matrix min_xyz = tuple(min(b[i] for b in obj.bound_box) for i in range(3)) max_xyz = tuple(max(b[i] for b in obj.bound_box) for i in range(3)) d = tuple(max_xyz[i] - min_xyz[i] for i in range(3)) c = tuple((max_xyz[i] + min_xyz[i]) / 2 for i in range(3)) bound_mat = np.array( (d[0], 0, 0, c[0], 0, d[1], 0, c[1], 0, 0, d[2], c[2], 0, 0, 0, 1),
import bgl from gpu_extras.presets import draw_texture_2d from bpy_extras import view3d_utils import pyrpr from .engine import Engine from . import image_filter from rprblender.export import camera, material, world, object, instance from rprblender.export.mesh import assign_materials from rprblender.utils import gl from rprblender import utils from rprblender.utils.user_settings import get_user_settings from rprblender.utils import logging log = logging.Log(tag='viewport_engine') MIN_ADAPT_RATIO_DIFF = 0.2 MIN_ADAPT_RESOLUTION_RATIO_DIFF = 0.1 @dataclass(init=False, eq=True) class ViewportSettings: """ Comparable dataclass which holds render settings for ViewportEngine: - camera viewport settings - render resolution - screen resolution - render border """
# Unless required by applicable law or agreed to in writing, software # 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 numpy as np import math import bpy from . import object, material from rprblender.utils import BLENDER_VERSION, get_prop_array_data, is_zero from rprblender.utils import logging log = logging.Log(tag='export.volume') def key(obj: bpy.types.Object, smoke_modifier): return (object.key(obj), smoke_modifier.name) def get_transform(obj: bpy.types.Object): # Set volume transform. Note: it should be scaled by 2.0 transform = object.get_transform(obj) scale = np.identity(4, dtype=np.float32) scale[0, 0], scale[1, 1], scale[2, 2] = 2.0, 2.0, 2.0 return transform @ scale def get_smoke_modifier(obj: bpy.types.Object):
# # Unless required by applicable law or agreed to in writing, software # 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 pyrpr import pyhybrid from . import context from rprblender.config import hybrid_unsupported_log_warn from rprblender.utils import logging log = logging.Log(tag='context_hybrid') class RPRContext(context.RPRContext): """ Manager of pyhybrid and pyrpr calls """ _Context = pyhybrid.Context _Scene = pyhybrid.Scene _MaterialNode = pyhybrid.MaterialNode _PointLight = pyhybrid.PointLight _SphereLight = pyhybrid.PointLight _DirectionalLight = pyhybrid.DirectionalLight _SpotLight = pyhybrid.SpotLight _DiskLight = pyhybrid.SpotLight
import weakref import numpy as np import bpy import mathutils import pyrpr from .context import RPRContext from rprblender.export import object, instance from rprblender.properties.view_layer import RPR_ViewLayerProperites from . import image_filter from rprblender.utils import logging log = logging.Log(tag='Engine') ITERATED_OBJECT_TYPES = ('MESH', 'LIGHT', 'CURVE', 'FONT', 'SURFACE', 'META', 'VOLUME') class Engine: """ This is the basic Engine class """ TYPE = None # RPRContext class _RPRContext = RPRContext def __init__(self, rpr_engine): self.rpr_engine = weakref.proxy(rpr_engine)
from bpy.props import ( BoolProperty, PointerProperty, BoolVectorProperty, EnumProperty, IntProperty, FloatProperty, ) import pyrpr from rprblender import utils from rprblender.utils import logging from . import RPR_Properties log = logging.Log(tag='properties.view_layer') class RPR_DenoiserProperties(RPR_Properties): """ Denoiser properties. This is a child property in RPR_ViewLayerProperties """ enable: BoolProperty( description="Enable RPR Denoiser", default=False, ) # only enable ML denoiser on windows items = (('BILATERAL', "Bilateral", "Bilateral", 0), ('LWR', "Local Weighted Regression", "Local Weighted Regression", 1), ('EAW', "Edge Avoiding Wavelets", "Edge Avoiding Wavelets", 2), ('ML', "Machine Learning", "Machine Learning", 3))
# 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 bpy from bpy.props import ( PointerProperty, FloatProperty, BoolProperty, ) from . import RPR_Properties from rprblender.utils import logging log = logging.Log(tag='properties.camera') class RPR_CameraProperties(RPR_Properties): """ Camera properties """ motion_blur_exposure: FloatProperty( name="Exposure", description="Camera motion blur exposure", min=0.0, soft_max=1.0, default=1.0, ) @classmethod def register(cls):