mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-02 08:54:53 +01:00
match maya render mask in houdini
This commit is contained in:
parent
1c667f91f9
commit
d2140c3619
4 changed files with 126 additions and 34 deletions
|
|
@ -649,3 +649,56 @@ def get_color_management_preferences():
|
|||
"display": hou.Color.ocio_defaultDisplay(),
|
||||
"view": hou.Color.ocio_defaultView()
|
||||
}
|
||||
|
||||
|
||||
def get_current_asset_doc():
|
||||
"""Get asset document of the current asset. """
|
||||
|
||||
project_name = get_current_project_name()
|
||||
asset_name = get_current_asset_name()
|
||||
asset_doc = get_asset_by_name(project_name, asset_name)
|
||||
|
||||
return asset_doc
|
||||
|
||||
|
||||
def get_resolution_from_data(doc):
|
||||
if not doc or "data" not in doc:
|
||||
print("Entered document is not valid. \"{}\"".format(str(doc)))
|
||||
return None
|
||||
|
||||
resolution_width = doc["data"].get("resolutionWidth")
|
||||
resolution_height = doc["data"].get("resolutionHeight")
|
||||
|
||||
# Make sure both width and height are set
|
||||
if resolution_width is None or resolution_height is None:
|
||||
print("No resolution information found for \"{}\"".format(doc["name"]))
|
||||
return None
|
||||
|
||||
return int(resolution_width), int(resolution_height)
|
||||
|
||||
|
||||
def set_camera_resolution(camera, asset_doc=None):
|
||||
"""Apply resolution to camera from asset document of the publish"""
|
||||
|
||||
if not asset_doc:
|
||||
asset_doc = get_current_asset_doc()
|
||||
|
||||
resolution = get_resolution_from_data(asset_doc)
|
||||
|
||||
if resolution:
|
||||
print("Setting camera resolution: {} -> {}x{}".format(
|
||||
camera.name(), resolution[0], resolution[1]
|
||||
))
|
||||
camera.parm("resx").set(resolution[0])
|
||||
camera.parm("resy").set(resolution[1])
|
||||
|
||||
|
||||
def get_camera_from_container(container):
|
||||
"""Get camera from container node. """
|
||||
|
||||
cameras = container.recursiveGlob("*",
|
||||
filter=hou.nodeTypeFilter.ObjCamera,
|
||||
include_subnets=False)
|
||||
|
||||
assert len(cameras) == 1, "Camera instance must have only one camera"
|
||||
return cameras[0]
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import pyblish.api
|
|||
from openpype.pipeline import (
|
||||
register_creator_plugin_path,
|
||||
register_loader_plugin_path,
|
||||
register_inventory_action_path,
|
||||
AVALON_CONTAINER_ID,
|
||||
)
|
||||
from openpype.pipeline.load import any_outdated_containers
|
||||
|
|
@ -55,6 +56,7 @@ class HoudiniHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
|
|||
pyblish.api.register_plugin_path(PUBLISH_PATH)
|
||||
register_loader_plugin_path(LOAD_PATH)
|
||||
register_creator_plugin_path(CREATE_PATH)
|
||||
register_inventory_action_path(INVENTORY_PATH)
|
||||
|
||||
log.info("Installing callbacks ... ")
|
||||
# register_event_callback("init", on_init)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
from openpype.pipeline import InventoryAction
|
||||
from openpype.hosts.houdini.api.lib import (
|
||||
get_camera_from_container,
|
||||
set_camera_resolution
|
||||
)
|
||||
|
||||
class SetAssetResolution(InventoryAction):
|
||||
|
||||
label = "Set Asset Resolution"
|
||||
icon = "desktop"
|
||||
color = "orange"
|
||||
|
||||
@staticmethod
|
||||
def is_compatible(container):
|
||||
print(container)
|
||||
return (
|
||||
container.get("loader") == "CameraLoader"
|
||||
)
|
||||
|
||||
def process(self, containers):
|
||||
for container in containers:
|
||||
node = container["node"]
|
||||
camera = get_camera_from_container(node)
|
||||
set_camera_resolution(camera)
|
||||
|
|
@ -4,6 +4,13 @@ from openpype.pipeline import (
|
|||
)
|
||||
from openpype.hosts.houdini.api import pipeline
|
||||
|
||||
from openpype.hosts.houdini.api.lib import (
|
||||
set_camera_resolution,
|
||||
get_camera_from_container
|
||||
)
|
||||
|
||||
import hou
|
||||
|
||||
|
||||
ARCHIVE_EXPRESSION = ('__import__("_alembic_hom_extensions")'
|
||||
'.alembicGetCameraDict')
|
||||
|
|
@ -25,7 +32,15 @@ def transfer_non_default_values(src, dest, ignore=None):
|
|||
channel expression and ignore certain Parm types.
|
||||
|
||||
"""
|
||||
import hou
|
||||
|
||||
ignore_types = {
|
||||
hou.parmTemplateType.Toggle,
|
||||
hou.parmTemplateType.Menu,
|
||||
hou.parmTemplateType.Button,
|
||||
hou.parmTemplateType.FolderSet,
|
||||
hou.parmTemplateType.Separator,
|
||||
hou.parmTemplateType.Label,
|
||||
}
|
||||
|
||||
src.updateParmStates()
|
||||
|
||||
|
|
@ -62,14 +77,6 @@ def transfer_non_default_values(src, dest, ignore=None):
|
|||
continue
|
||||
|
||||
# Ignore folders, separators, etc.
|
||||
ignore_types = {
|
||||
hou.parmTemplateType.Toggle,
|
||||
hou.parmTemplateType.Menu,
|
||||
hou.parmTemplateType.Button,
|
||||
hou.parmTemplateType.FolderSet,
|
||||
hou.parmTemplateType.Separator,
|
||||
hou.parmTemplateType.Label,
|
||||
}
|
||||
if parm.parmTemplate().type() in ignore_types:
|
||||
continue
|
||||
|
||||
|
|
@ -90,13 +97,8 @@ class CameraLoader(load.LoaderPlugin):
|
|||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
|
||||
import os
|
||||
import hou
|
||||
|
||||
# Format file name, Houdini only wants forward slashes
|
||||
file_path = self.filepath_from_context(context)
|
||||
file_path = os.path.normpath(file_path)
|
||||
file_path = file_path.replace("\\", "/")
|
||||
file_path = self.fname.replace("\\", "/")
|
||||
|
||||
# Get the root node
|
||||
obj = hou.node("/obj")
|
||||
|
|
@ -106,19 +108,21 @@ class CameraLoader(load.LoaderPlugin):
|
|||
node_name = "{}_{}".format(namespace, name) if namespace else name
|
||||
|
||||
# Create a archive node
|
||||
container = self.create_and_connect(obj, "alembicarchive", node_name)
|
||||
node = self.create_and_connect(obj, "alembicarchive", node_name)
|
||||
|
||||
# TODO: add FPS of project / asset
|
||||
container.setParms({"fileName": file_path,
|
||||
"channelRef": True})
|
||||
node.setParms({"fileName": file_path, "channelRef": True})
|
||||
|
||||
# Apply some magic
|
||||
container.parm("buildHierarchy").pressButton()
|
||||
container.moveToGoodPosition()
|
||||
node.parm("buildHierarchy").pressButton()
|
||||
node.moveToGoodPosition()
|
||||
|
||||
# Create an alembic xform node
|
||||
nodes = [container]
|
||||
nodes = [node]
|
||||
|
||||
camera = get_camera_from_container(node)
|
||||
self._match_maya_render_mask(camera)
|
||||
set_camera_resolution(camera, asset_doc=context["asset"])
|
||||
self[:] = nodes
|
||||
|
||||
return pipeline.containerise(node_name,
|
||||
|
|
@ -143,14 +147,14 @@ class CameraLoader(load.LoaderPlugin):
|
|||
# Store the cam temporarily next to the Alembic Archive
|
||||
# so that we can preserve parm values the user set on it
|
||||
# after build hierarchy was triggered.
|
||||
old_camera = self._get_camera(node)
|
||||
old_camera = get_camera_from_container(node)
|
||||
temp_camera = old_camera.copyTo(node.parent())
|
||||
|
||||
# Rebuild
|
||||
node.parm("buildHierarchy").pressButton()
|
||||
|
||||
# Apply values to the new camera
|
||||
new_camera = self._get_camera(node)
|
||||
new_camera = get_camera_from_container(node)
|
||||
transfer_non_default_values(temp_camera,
|
||||
new_camera,
|
||||
# The hidden uniform scale attribute
|
||||
|
|
@ -158,6 +162,9 @@ class CameraLoader(load.LoaderPlugin):
|
|||
# "icon_scale" just skip that completely
|
||||
ignore={"scale"})
|
||||
|
||||
self._match_maya_render_mask(new_camera)
|
||||
set_camera_resolution(new_camera)
|
||||
|
||||
temp_camera.destroy()
|
||||
|
||||
def remove(self, container):
|
||||
|
|
@ -165,15 +172,6 @@ class CameraLoader(load.LoaderPlugin):
|
|||
node = container["node"]
|
||||
node.destroy()
|
||||
|
||||
def _get_camera(self, node):
|
||||
import hou
|
||||
cameras = node.recursiveGlob("*",
|
||||
filter=hou.nodeTypeFilter.ObjCamera,
|
||||
include_subnets=False)
|
||||
|
||||
assert len(cameras) == 1, "Camera instance must have only one camera"
|
||||
return cameras[0]
|
||||
|
||||
def create_and_connect(self, node, node_type, name=None):
|
||||
"""Create a node within a node which and connect it to the input
|
||||
|
||||
|
|
@ -194,5 +192,20 @@ class CameraLoader(load.LoaderPlugin):
|
|||
new_node.moveToGoodPosition()
|
||||
return new_node
|
||||
|
||||
def switch(self, container, representation):
|
||||
self.update(container, representation)
|
||||
def _match_maya_render_mask(self, camera):
|
||||
"""Workaround to match Maya render mask in Houdini"""
|
||||
|
||||
# print("Setting match maya render mask ")
|
||||
parm = camera.parm("aperture")
|
||||
expression = parm.expression()
|
||||
expression = expression.replace("return ", "aperture = ")
|
||||
expression += """
|
||||
# Match maya render mask (logic from Houdini's own FBX importer)
|
||||
node = hou.pwd()
|
||||
resx = node.evalParm('resx')
|
||||
resy = node.evalParm('resy')
|
||||
aspect = node.evalParm('aspect')
|
||||
aperture *= min(1, (resx / resy * aspect) / 1.5)
|
||||
return aperture
|
||||
"""
|
||||
parm.setExpression(expression, language=hou.exprLanguage.Python)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue