Skip to content

Commit

Permalink
Added support for RenderMan ROP node
Browse files Browse the repository at this point in the history
  • Loading branch information
gillesvink committed Apr 5, 2022
1 parent dbd2bc1 commit fcb328a
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 39 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)

# tk-houdini-renderman
RenderMan integration for Houdini ShotGrid. Mainly written for Solaris.
## Features:
- Specify the name for the render node (default main) to specify the rendered image sequence name.
- Automatically creates paths.
- Deadline Renderfarm submissions directly from within the node (only tested on Windows) using an easy UI.
- On Solaris just click Display Filter, and all paths are automatically created. (For like a Cryptomatte)
- Support for publishing (look at tk-houdini [collector.py](https://github.com/nfa-vfxim/tk-houdini/blob/master/hooks/tk-multi-publish2/basic/collector.py))

_Solaris_![](images/solaris.png)
_Deadline Submission_![](images/deadline.png)

## Todo
- Add readme.md
- Add complete readme.md including installation instructions.
- WIP: ROP integration for RenderMan (currently working version in pre-release)
- ROP version: Add support for Display filters like Cryptomatte (already done for Solaris)
15 changes: 8 additions & 7 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,20 @@ def init_app(self):
tk_houdini_usdrop = self.import_module("tk_houdini_renderman")
self.handler = tk_houdini_usdrop.TkRenderManNodeHandler(self)

def execute_render(self, node):
self.handler.execute_render(node)
def execute_render(self, node, network):
self.handler.execute_render(node, network)

def submit_to_farm(self, node):
self.handler.submit_to_farm(node)
def submit_to_farm(self, node, network):
self.handler.submit_to_farm(node, network)

def copy_to_clipboard(self, node):
self.handler.copy_to_clipboard(node)
def copy_to_clipboard(self, node, network):
self.handler.copy_to_clipboard(node, network)

@staticmethod
def get_all_renderman_nodes():
# Get all nodes from node type sgtk_hdprman
nodes = hou.lopNodeTypeCategory().nodeType("sgtk_hdprman").instances()
lop_nodes = hou.lopNodeTypeCategory().nodeType("sgtk_hdprman").instances()
nodes = lop_nodes + hou.ropNodeTypeCategory().nodeType("sgtk_ris").instances()
return nodes

@staticmethod
Expand Down
Binary file added images/deadline.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/solaris.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified otls/sgtk_renderman.otl
Binary file not shown.
Binary file added otls/sgtk_ris.otl
Binary file not shown.
6 changes: 4 additions & 2 deletions python/tk_houdini_renderman/farm_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@


class FarmSubmission(QtWidgets.QWidget):
def __init__(self, app, node, submission_name, priority, framerange, parent=None):
def __init__(self, app, node, submission_name, priority, framerange, network, parent=None):
QtWidgets.QWidget.__init__(self, parent)
self.setWindowTitle("Submit to Farm")
self.app = app
self.node = node
self.network = network

layout = QtWidgets.QVBoxLayout()

Expand Down Expand Up @@ -96,7 +97,8 @@ def __submit_to_farm(self):
houdini_version = hou.applicationVersion()
houdini_version = str(houdini_version[0]) + "." + str(houdini_version[1])

render_filepath = self.node.parm("picture").eval()
file_parameter = "picture"
render_filepath = self.node.parm(file_parameter).eval()

output_directory = os.path.dirname(render_filepath)
output_filename = os.path.basename(render_filepath)
Expand Down
100 changes: 71 additions & 29 deletions python/tk_houdini_renderman/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,20 @@ def __init__(self, app):
self.app = app
self.sg = self.app.shotgun

def submit_to_farm(self, node):
if not self.__validate_node(node):
def submit_to_farm(self, node, network):
if not self.__validate_node(node, network):
return

# Set paths and prepare node
render_name = node.parm("name").eval()
render_path = self.__calculate_path(node)
self.__apply_path(node, render_path)
render_path = self.__calculate_path(node, network)
self.__apply_path(node, render_path, network)
self.__create_directory(render_path)

# Set filters
filters = self.__check_filters(node)
self.__set_filter_filename(node, filters)
if network == "lop":
filters = self.__check_filters(node)
self.__set_filter_filename(node, filters)

# Determine basic variables for submission
file_name = hou.hipFile.name()
Expand All @@ -68,27 +69,31 @@ def submit_to_farm(self, node):

# Start submission panel
global submission
submission = FarmSubmission(self.app, node, file_name, "50", framerange)
submission = FarmSubmission(self.app, node, file_name, "50", framerange, network=network)
submission.show()

def execute_render(self, node):
def execute_render(self, node, network):
# Validate node
if not self.__validate_node(node):
if not self.__validate_node(node, network):
return

# Prepare node and set all parameters
render_path = self.__calculate_path(node)
self.__apply_path(node, render_path)
render_path = self.__calculate_path(node, network)
self.__apply_path(node, render_path, network)
self.__create_directory(render_path)

# Set filters
filters = self.__check_filters(node)
self.__set_filter_filename(node, filters)
if network == "lop":
filters = self.__check_filters(node)
self.__set_filter_filename(node, filters)

# Execute rendering
node.node("rop_usdrender").parm("execute").pressButton()
if network == "lop":
node.node("rop_usdrender").parm("execute").pressButton()
else:
node.node("ris1").parm("execute").pressButton()

def copy_to_clipboard(self, node):
def copy_to_clipboard(self, node, network):
# Function to copy the path directly to the clipboard, currently only Windows is supported
if platform.system() == "Windows":
render_path = node.parm("picture").eval()
Expand All @@ -101,7 +106,7 @@ def copy_to_clipboard(self, node):
)

@staticmethod
def __validate_node(node):
def __validate_node(node, network):
# This function will make sure all the paramaters are filled in and setup correctly.
# First we'll check if there is a name
render_name = node.parm("name").eval()
Expand All @@ -113,29 +118,65 @@ def __validate_node(node):
return False
else:
# Make sure the node has an input to render
inputs = node.inputs()
if len(inputs) <= 0:
hou.ui.displayMessage(
"Node doesn't have input, please connect this "
"ShotGrid RenderMan render node to the stage to render.",
severity=hou.severityType.Error,
)
return False
if network == "lop":
inputs = node.inputs()
if len(inputs) <= 0:
hou.ui.displayMessage(
"Node doesn't have input, please connect this "
"ShotGrid RenderMan render node to the stage to render.",
severity=hou.severityType.Error,
)
return False
else:
return True
else:
return True

def __calculate_path(self, node):
def __calculate_path(self, node, network):
# Get all necessary data
current_filepath = hou.hipFile.path()
work_template = self.app.get_template("work_file_template")
render_template = self.app.get_template("output_render_template")

resolution_x_field = "resolutionx"
resolution_y_field = "resolutiony"

resolution_x = 0
resolution_y = 0

evaluate_parm = True

# Because RenderMan in the rop network uses different parameter names, we need to change some bits
if network == "rop":
camera = node.parm("camera").eval()

evaluate_parm = False
resolution_x = hou.node(camera).parm("resx").eval()
resolution_y = hou.node(camera).parm("resy").eval()

if node.parm("override_camerares").eval():
res_fraction = node.parm("res_fraction").eval()

if res_fraction == "specific":
evaluate_parm = True
resolution_x_field = "res_overridex"
resolution_y_field = "res_overridey"

else:
resolution_x = resolution_x * res_fraction
resolution_y = resolution_y * res_fraction

# Set fields
fields = work_template.get_fields(current_filepath)
fields["SEQ"] = "FORMAT: $F"
fields["name"] = node.parm("name").eval()
fields["width"] = node.parm("resolutionx").eval()
fields["height"] = node.parm("resolutiony").eval()
if evaluate_parm is True:
fields["width"] = node.parm(resolution_x_field).eval()
fields["height"] = node.parm(resolution_y_field).eval()

else:
fields["width"] = resolution_x
fields["height"] = resolution_y

# Apply fields
render_path = render_template.apply_fields(fields).replace(os.sep, "/")
Expand Down Expand Up @@ -163,9 +204,10 @@ def __calculate_filter_path(self, node, filter):

return render_path

def __apply_path(self, node, render_path):
def __apply_path(self, node, render_path, network):
# Set render path on specified node
node.parm("picture").set(render_path)
parameter = "picture"
node.parm(parameter).set(render_path)
self.app.logger.debug("Set render path on %s" % str(node))

def __create_directory(self, render_path):
Expand Down

0 comments on commit fcb328a

Please sign in to comment.