Skip to content

Commit

Permalink
Merge branch 'dev' into 'main'
Browse files Browse the repository at this point in the history
Merge dev to main

See merge request renderman/projects/RenderManForBlender!25
  • Loading branch information
Ian Hsieh committed Aug 20, 2024
2 parents 8027a96 + 2a3c754 commit 56f26d0
Show file tree
Hide file tree
Showing 33 changed files with 711 additions and 342 deletions.
2 changes: 1 addition & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
bl_info = {
"name": "RenderMan For Blender",
"author": "Pixar",
"version": (26, 1, 0),
"version": (26, 2, 0),
"blender": (2, 93, 0),
"location": "Render Properties > Render Engine > RenderMan",
"description": "RenderMan 26 integration",
Expand Down
78 changes: 71 additions & 7 deletions rfb_utils/display_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,20 @@ def __init__(self, channelType, channelName, channelSource="", channelStatistics

# Settings copied from RfK
# They seem to be slightly different from batch render version
DENOISER_ALBEDO = OutputChannel("color", "albedo", "color lpe:nothruput;noinfinitecheck;noclamp;unoccluded;overwrite;C<.S'passthru'>*((U2L)|O)")
DENOISER_NORMAL = OutputChannel("normal", "normal", "normal Nn")
__INTERACTIVE_DENOISE_CHANNELS = [
OutputChannel("color", "Ci"),
OutputChannel("float", "a"),
OutputChannel("color", "albedo", "color lpe:nothruput;noinfinitecheck;noclamp;unoccluded;overwrite;C<.S'passthru'>*((U2L)|O)"),
DENOISER_ALBEDO,
OutputChannel("color", "albedo_var", "color lpe:nothruput;noinfinitecheck;noclamp;unoccluded;overwrite;C<.S'passthru'>*((U2L)|O)", "variance"),
OutputChannel("color", "albedo_mse", "color lpe:nothruput;noinfinitecheck;noclamp;unoccluded;overwrite;C<.S'passthru'>*((U2L)|O)", "mse"),
OutputChannel("vector", "backward", "vector motionBack"),
OutputChannel("color", "diffuse", "color lpe:C(D[DS]*[LO])|O"),
OutputChannel("color", "diffuse_mse", "color lpe:C(D[DS]*[LO])|O", "mse"),
OutputChannel("vector", "forward", "vector motionFore"),
OutputChannel("color", "mse", "color Ci", "mse"),
OutputChannel("normal", "normal", "normal Nn"),
DENOISER_NORMAL,
OutputChannel("normal", "normal_var", "normal Nn", "variance"),
OutputChannel("color", "normal_mse", "normal Nn", "mse"),
OutputChannel("color", "specular", "color lpe:CS[DS]*[LO]"),
Expand All @@ -49,6 +51,12 @@ def __init__(self, channelType, channelName, channelSource="", channelStatistics
OutputChannel("float", "sampleCount", "sampleCount")
]

# extra channels for the Optix denoiser
OPTIX_DENOISE_CHANNELS = [
DENOISER_ALBEDO,
DENOISER_NORMAL
]

def get_beauty_filepath(bl_scene, use_blender_frame=False, expand_tokens=False, no_ext=False):
dspy_info = dict()
view_layer = bpy.context.view_layer
Expand Down Expand Up @@ -131,7 +139,9 @@ def _add_stylized_channels(dspys_dict, dspy_drv, rman_scene, expandTokens):
chan_src = settings['channelSource']
chan_type = settings['channelType']
d[u'channelSource'] = {'type': u'string', 'value': chan_src}
d[u'channelType'] = { 'type': u'string', 'value': chan_type}
d[u'channelType'] = { 'type': u'string', 'value': chan_type}
if 'filter'in settings:
d[u'filter'] = {'type': u'string', 'value': settings['filter']}
dspys_dict['channels'][chan] = d
dspy_params['displayChannels'].append(chan)

Expand Down Expand Up @@ -159,7 +169,9 @@ def _add_stylized_channels(dspys_dict, dspy_drv, rman_scene, expandTokens):
chan_src = settings['channelSource']
chan_type = settings['channelType']
d[u'channelSource'] = {'type': u'string', 'value': chan_src}
d[u'channelType'] = { 'type': u'string', 'value': chan_type}
d[u'channelType'] = { 'type': u'string', 'value': chan_type}
if 'filter'in settings:
d[u'filter'] = {'type': u'string', 'value': settings['filter']}
dspys_dict['channels'][chan] = d
dspy_params['displayChannels'].append(chan)

Expand Down Expand Up @@ -201,6 +213,8 @@ def _add_denoiser_channels(dspys_dict, dspy_params, rman_scene):
d[u'channelType'] = { 'type': u'string', 'value': settings['channelType']}
if 'statistics' in settings:
d[u'statistics'] = { 'type': u'string', 'value': settings['statistics']}
if 'filter'in settings:
d[u'filter'] = {'type': u'string', 'value': settings['filter']}
dspys_dict['channels'][chan] = d

dspys_dict['displays']['beauty']['params']['displayChannels'].append(chan)
Expand All @@ -213,6 +227,8 @@ def _add_interactive_denoiser_channels(dspys_dict, dspy_params, rman_scene):
the beauty display will be used as the variance file
"""

from .envconfig_utils import envconfig

for output_chan in __INTERACTIVE_DENOISE_CHANNELS:
dspy_channels = dspys_dict['displays']['beauty']['params']['displayChannels']
if output_chan.name in dspy_channels:
Expand All @@ -231,6 +247,47 @@ def _add_interactive_denoiser_channels(dspys_dict, dspy_params, rman_scene):
dspys_dict['displays']['beauty']['params']['displayChannels'].append(output_chan.name)

dspys_dict['displays']['beauty']['is_variance'] = True

if rman_scene.is_viewport_render:
param_list = rman_scene.rman.Types.ParamList()
rm = rman_scene.bl_scene.renderman
if rman_scene.ipr_render_into == "blender":
qn_passthru = envconfig().get_qn_dspy('blender')
else:
qn_passthru = envconfig().get_qn_dspy('socket')
param_list.SetString('dspyDSOPath', qn_passthru)
param_list.SetInteger('cheapPass', int(rm.blender_ipr_aidenoiser_cheapFirstPass))
param_list.SetInteger('minSamples', rm.blender_ipr_aidenoiser_minSamples)
param_list.SetInteger('interval', rm.blender_ipr_aidenoiser_interval)
param_list.SetInteger('immediateClose', 1)

dspys_dict['displays']['beauty']['dspyDriverParams'] = param_list

def _add_optix_denoiser_channels(dspys_dict, rman_scene):

for output_chan in OPTIX_DENOISE_CHANNELS:
if output_chan.name not in dspys_dict['channels']:
d = _default_dspy_params()

if output_chan.source != "":
d[u'channelSource'] = {'type': u'string', 'value': output_chan.source}
d[u'channelType'] = { 'type': u'string', 'value': output_chan.type}
if output_chan.statistics != '':
d[u'statistics'] = { 'type': u'string', 'value': output_chan.statistics}
dspys_dict['channels'][output_chan.name] = d

dn_nm = 'optix_denoiser_%s' % output_chan.name
dspys_dict['displays'][dn_nm] = {
'driverNode': 'blender',
'filePath': dn_nm,
'denoise': False,
'denoise_mode': 'singleframe',
'camera': None,
'bake_mode': None,
'params': {},
'dspyDriverParams': None}

dspys_dict['displays'][dn_nm]['params']['displayChannels'] = [output_chan.name]

def _set_blender_dspy_dict(layer, dspys_dict, dspy_drv, rman_scene, expandTokens, do_optix_denoise=False):

Expand All @@ -243,7 +300,7 @@ def _set_blender_dspy_dict(layer, dspys_dict, dspy_drv, rman_scene, expandTokens
display_driver = __BLENDER_TO_RMAN_DSPY__.get(rman_scene.bl_scene.render.image_settings.file_format, 'openexr')
param_list = rman_scene.rman.Types.ParamList()
if display_driver == 'openexr':
param_list.SetInteger('asrgba', 1)
param_list.SetInteger('asrgba', 1)

if display_driver == 'blender' and do_optix_denoise:
aov_denoise = True
Expand Down Expand Up @@ -278,9 +335,10 @@ def _set_blender_dspy_dict(layer, dspys_dict, dspy_drv, rman_scene, expandTokens
'bake_mode': None,
'params': dspy_params,
'dspyDriverParams': param_list}

if display_driver == 'blender' and rman_scene.is_viewport_render:
display_driver = 'null'

elif display_driver == "quicklyNoiseless":
_add_interactive_denoiser_channels(dspys_dict, dspy_params, rman_scene)
display_driver = 'null'
Expand Down Expand Up @@ -359,7 +417,10 @@ def _set_blender_dspy_dict(layer, dspys_dict, dspy_drv, rman_scene, expandTokens
'camera': None,
'bake_mode': None,
'params': dspy_params,
'dspyDriverParams': None}
'dspyDriverParams': None}

if do_optix_denoise:
_add_optix_denoiser_channels(dspys_dict, rman_scene)

def _get_real_chan_name(chan):
""" Get the real channel name
Expand Down Expand Up @@ -563,6 +624,9 @@ def _set_rman_dspy_dict(rm_rl, dspys_dict, dspy_drv, rman_scene, expandTokens, d
'params': dspy_params,
'dspyDriverParams': None}

if do_optix_denoise:
_add_optix_denoiser_channels(dspys_dict, rman_scene)

def _set_rman_holdouts_dspy_dict(dspys_dict, dspy_drv, rman_scene, expandTokens, include_holdouts=True):

rm = rman_scene.bl_scene.renderman
Expand Down
82 changes: 58 additions & 24 deletions rfb_utils/draw_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,17 +226,22 @@ def _draw_ui_from_rman_config(config_name, panel, context, layout, parent):
curr_col = row_dict['default']

conditionalVisOps = getattr(ndp, 'conditionalVisOps', None)
conditionalLockOps = getattr(ndp, 'conditionalLockOps', None)
if conditionalVisOps:
# check if the conditionalVisOp to see if we're disabled
# eval the conditionalVisOps to see if we should be visible
expr = conditionalVisOps.get('expr', None)
node = parent
if expr and not eval(expr):
# conditionalLockOps disable the prop rather
# than hide them
if not hasattr(ndp, 'conditionalLockOps'):
continue
else:
is_enabled = False
continue

if conditionalVisOps and conditionalLockOps:
# check if there is a conditionalLockOps
expr = conditionalVisOps.get('lock_expr', None)
if expr is None:
expr = conditionalVisOps.get('expr', None)
node = parent
if expr and not eval(expr):
is_enabled = False

label = ndp.label if hasattr(ndp, 'label') else ndp.name
row = curr_col.row()
Expand Down Expand Up @@ -316,6 +321,14 @@ def draw_prop(node, prop_name, layout, level=0, nt=None, context=None, sticky=Fa
rfb_log().error("Error handling conditionalVisOp: %s" % str(err))
pass

if bl_prop_info.conditionalLockOps and bl_prop_info.lock_expr:
try:
locked = not eval(bl_prop_info.lock_expr)
bl_prop_info.prop_disabled = locked
except Exception as err:
rfb_log().error("Error handling conditionalVisOp: %s" % str(err))
pass

if bl_prop_info.prop_hidden:
return

Expand Down Expand Up @@ -749,25 +762,45 @@ def draw_node_properties_recursive(layout, context, nt, node, level=0, single_no
for input in node.inputs:
if input.is_linked:
input_node = shadergraph_utils.socket_node_input(nt, input)
icon = get_open_close_icon(input.show_expanded)
do_single_view = single_node_view and prefs_utils.single_node_view()
if do_single_view:
icon = get_open_close_icon(False)

split = layout.split(factor=NODE_LAYOUT_SPLIT)
row = split.row()
draw_indented_label(row, None, level)
split = layout.split()
row = split.row()
draw_indented_label(row, None, level)
label = input.name

rman_icon = rfb_icons.get_node_icon(input_node.bl_label)
row.label(text=label + ' (%s):' % input_node.name)

label = input.name
rman_icon = rfb_icons.get_node_icon(input_node.bl_label)
row.prop(input, "show_expanded", icon=icon, text='',
icon_only=True, emboss=False)
row.label(text=label + ' (%s):' % input_node.name)
row.context_pointer_set("socket", input)
row.context_pointer_set("node", node)
row.context_pointer_set("nodetree", nt)
row.menu('NODE_MT_renderman_connection_menu', text='', icon_value=rman_icon.icon_id)
row.context_pointer_set("node", input_node)
row.context_pointer_set("nodetree", nt)
row.operator('node.rman_select_nodetree_node', text='', icon=icon)
row.context_pointer_set("socket", input)
row.context_pointer_set("node", node)
row.context_pointer_set("nodetree", nt)
row.menu('NODE_MT_renderman_connection_menu', text='', icon_value=rman_icon.icon_id)
else:
icon = get_open_close_icon(input.show_expanded)

split = layout.split(factor=NODE_LAYOUT_SPLIT)
row = split.row()
draw_indented_label(row, None, level)

if input.show_expanded:
draw_node_properties_recursive(layout, context, nt,
input_node, level=level + 1, single_node_view=single_node_view)
label = input.name
rman_icon = rfb_icons.get_node_icon(input_node.bl_label)
row.prop(input, "show_expanded", icon=icon, text='',
icon_only=True, emboss=False)
row.label(text=label + ' (%s):' % input_node.name)
row.context_pointer_set("socket", input)
row.context_pointer_set("node", node)
row.context_pointer_set("nodetree", nt)
row.menu('NODE_MT_renderman_connection_menu', text='', icon_value=rman_icon.icon_id)

if input.show_expanded:
draw_node_properties_recursive(layout, context, nt,
input_node, level=level + 1, single_node_view=single_node_view)
else:
row = layout.row(align=True)
draw_indented_label(row, None, level)
Expand All @@ -782,7 +815,8 @@ def draw_node_properties_recursive(layout, context, nt, node, level=0, single_no
row.context_pointer_set("socket", input)
row.context_pointer_set("node", node)
row.context_pointer_set("nodetree", nt)
row.menu('NODE_MT_renderman_connection_menu', text='', icon='NODE_MATERIAL')
rman_icon = rfb_icons.get_icon('rman_connection_menu')
row.menu('NODE_MT_renderman_connection_menu', text='', icon_value=rman_icon.icon_id)

else:
draw_props(node, node.prop_names, layout, level, nt=nt, context=context, single_node_view=single_node_view)
Expand Down
10 changes: 9 additions & 1 deletion rfb_utils/envconfig_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,15 @@ def set_qn_dspy(self, dspy, immediate_close=True):
if immediate_close:
self.setenv('RMAN_QN_IMMEDIATE_CLOSE', '1')
else:
self.unsetenv('RMAN_QN_IMMEDIATE_CLOSE')
self.unsetenv('RMAN_QN_IMMEDIATE_CLOSE')

def get_qn_dspy(self, dspy, immediate_close=True):
ext = '.so'
if sys.platform == ("win32"):
ext = '.dll'
d = os.path.join(self.rmantree, 'lib', 'plugins', 'd_%s%s' % (dspy, ext))
return d


def read_envvars_file(self):
bl_config_path = bpy.utils.user_resource('CONFIG')
Expand Down
20 changes: 10 additions & 10 deletions rfb_utils/object_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,9 @@ def prototype_key(ob):
if isinstance(ob, bpy.types.DepsgraphObjectInstance):
if ob.is_instance:
if ob.object.data:
return '%s-DATA' % ob.object.data.name_full
return '%s-%s-DATA' % (ob.object.type, ob.object.data.name_full)
else:
return '%s-OBJECT' % ob.object.name_full
return '%s-%s-OBJECT' % (ob.object.type, ob.object.name_full)
if ob.object.data:
if isinstance(ob.object.data, bpy.types.Mesh) and use_gpu_subdiv:
'''
Expand All @@ -201,17 +201,17 @@ def prototype_key(ob):
https://projects.blender.org/blender/blender/issues/111393
'''
data_ob = bpy.data.objects[ob.object.name]
return '%s-DATA' % data_ob.original.data.name_full
return '%s-MESH-DATA' % data_ob.original.data.name_full

elif BLENDER_HAS_CURVES_NODE and isinstance(ob.object.data, bpy.types.Curves):
'''
Looks like a similar problem as above happens with Curves as well. The data block
name is not unique when you have multiple Curves object.
'''
data_ob = bpy.data.objects[ob.object.name]
return '%s-DATA' % data_ob.original.data.name_full
return '%s-DATA' % ob.object.data.name_full
return '%s-OBJECT' % ob.object.original.name_full
return '%s-CURVES-DATA' % data_ob.original.data.name_full
return '%s-%s-DATA' % (ob.object.type, ob.object.data.name_full)
return '%s-%s-OBJECT' % (ob.object.type, ob.object.original.name_full)
elif ob.data:
if isinstance(ob.data, bpy.types.Mesh) and use_gpu_subdiv:
'''
Expand All @@ -227,17 +227,17 @@ def prototype_key(ob):
https://projects.blender.org/blender/blender/issues/111393
'''
data_ob = bpy.data.objects[ob.name]
return '%s-DATA' % data_ob.original.data.name_full
return '%s-MESH-DATA' % data_ob.original.data.name_full

elif BLENDER_HAS_CURVES_NODE and isinstance(ob.data, bpy.types.Curves):
'''
Looks like a similar problem as above happens with Curves as well. The data block
name is not unique when you have multiple Curves object.
'''
data_ob = bpy.data.objects[ob.name]
return '%s-DATA' % data_ob.original.data.name_full
return '%s-DATA' % ob.original.data.original.name_full
return '%s-OBJECT' % ob.original.name_full
return '%s-CURVES-DATA' % data_ob.original.data.name_full
return '%s-%s-DATA' % (ob.type, ob.original.data.original.name_full)
return '%s-%s-OBJECT' % (ob.type, ob.original.name_full)

def curve_is_mesh(ob):
'''
Expand Down
1 change: 1 addition & 0 deletions rfb_utils/osl_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def readOSO(filePath):
IO = "out"

prop_meta = {"type": type, "IO": IO}
prop_meta['renderman_type'] = type

# default
if not pdict['isstruct']:
Expand Down
Loading

0 comments on commit 56f26d0

Please sign in to comment.