mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 08:24:53 +01:00
Implement more generic ExtractROP extractor
This commit is contained in:
parent
f56f0cc3d7
commit
2ce5087037
10 changed files with 134 additions and 454 deletions
|
|
@ -1,44 +0,0 @@
|
|||
import os
|
||||
import hou
|
||||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_houdini.api import plugin
|
||||
from ayon_houdini.api.lib import render_rop
|
||||
|
||||
|
||||
class ExtractAlembic(plugin.HoudiniExtractorPlugin):
|
||||
|
||||
order = pyblish.api.ExtractorOrder
|
||||
label = "Extract Alembic"
|
||||
families = ["abc", "camera"]
|
||||
targets = ["local", "remote"]
|
||||
|
||||
def process(self, instance):
|
||||
if instance.data.get("farm"):
|
||||
self.log.debug("Should be processed on farm, skipping.")
|
||||
return
|
||||
|
||||
ropnode = hou.node(instance.data["instance_node"])
|
||||
|
||||
# Get the filename from the filename parameter
|
||||
output = ropnode.evalParm("filename")
|
||||
staging_dir = os.path.dirname(output)
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
|
||||
# We run the render
|
||||
self.log.info("Writing alembic '%s' to '%s'" % (output,
|
||||
staging_dir))
|
||||
|
||||
render_rop(ropnode)
|
||||
|
||||
if "representations" not in instance.data:
|
||||
instance.data["representations"] = []
|
||||
|
||||
representation = {
|
||||
'name': 'abc',
|
||||
'ext': 'abc',
|
||||
'files': instance.data["frames"],
|
||||
"stagingDir": staging_dir,
|
||||
}
|
||||
instance.data["representations"].append(representation)
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
import os
|
||||
import hou
|
||||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_houdini.api import plugin
|
||||
from ayon_houdini.api.lib import render_rop
|
||||
|
||||
|
||||
class ExtractAss(plugin.HoudiniExtractorPlugin):
|
||||
|
||||
order = pyblish.api.ExtractorOrder + 0.1
|
||||
label = "Extract Ass"
|
||||
families = ["ass"]
|
||||
targets = ["local", "remote"]
|
||||
|
||||
def process(self, instance):
|
||||
if instance.data.get("farm"):
|
||||
self.log.debug("Should be processed on farm, skipping.")
|
||||
return
|
||||
ropnode = hou.node(instance.data["instance_node"])
|
||||
|
||||
# Get the filename from the filename parameter
|
||||
# `.evalParm(parameter)` will make sure all tokens are resolved
|
||||
output = ropnode.evalParm("ar_ass_file")
|
||||
staging_dir = os.path.dirname(output)
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
file_name = os.path.basename(output)
|
||||
|
||||
# We run the render
|
||||
self.log.info("Writing ASS '%s' to '%s'" % (file_name, staging_dir))
|
||||
|
||||
render_rop(ropnode)
|
||||
|
||||
# Unfortunately user interrupting the extraction does not raise an
|
||||
# error and thus still continues to the integrator. To capture that
|
||||
# we make sure all files exist
|
||||
self.validate_expected_frames(instance, staging_dir)
|
||||
|
||||
if "representations" not in instance.data:
|
||||
instance.data["representations"] = []
|
||||
|
||||
# Allow ass.gz extension as well
|
||||
ext = "ass.gz" if file_name.endswith(".ass.gz") else "ass"
|
||||
|
||||
representation = {
|
||||
'name': 'ass',
|
||||
'ext': ext,
|
||||
"files": instance.data["frames"],
|
||||
"stagingDir": staging_dir,
|
||||
"frameStart": instance.data["frameStartHandle"],
|
||||
"frameEnd": instance.data["frameEndHandle"],
|
||||
}
|
||||
instance.data["representations"].append(representation)
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
import os
|
||||
import hou
|
||||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_houdini.api import lib, plugin
|
||||
|
||||
|
||||
class ExtractBGEO(plugin.HoudiniExtractorPlugin):
|
||||
|
||||
order = pyblish.api.ExtractorOrder
|
||||
label = "Extract BGEO"
|
||||
families = ["bgeo"]
|
||||
|
||||
def process(self, instance):
|
||||
if instance.data.get("farm"):
|
||||
self.log.debug("Should be processed on farm, skipping.")
|
||||
return
|
||||
ropnode = hou.node(instance.data["instance_node"])
|
||||
|
||||
# Get the filename from the filename parameter
|
||||
sop_output = ropnode.evalParm("sopoutput")
|
||||
staging_dir, file_name = os.path.split(sop_output)
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
|
||||
# We run the render
|
||||
self.log.info("Writing bgeo files '{}' to '{}'.".format(
|
||||
file_name, staging_dir))
|
||||
|
||||
# write files
|
||||
lib.render_rop(ropnode)
|
||||
|
||||
_, ext = lib.splitext(
|
||||
sop_output, allowed_multidot_extensions=[
|
||||
".ass.gz", ".bgeo.sc", ".bgeo.gz",
|
||||
".bgeo.lzma", ".bgeo.bz2"])
|
||||
|
||||
if "representations" not in instance.data:
|
||||
instance.data["representations"] = []
|
||||
|
||||
representation = {
|
||||
"name": "bgeo",
|
||||
"ext": ext.lstrip("."),
|
||||
"files": instance.data["frames"],
|
||||
"stagingDir": staging_dir,
|
||||
"frameStart": instance.data["frameStartHandle"],
|
||||
"frameEnd": instance.data["frameEndHandle"]
|
||||
}
|
||||
instance.data["representations"].append(representation)
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
import os
|
||||
import hou
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.pipeline import publish
|
||||
from ayon_houdini.api import plugin
|
||||
from ayon_houdini.api.lib import render_rop, splitext
|
||||
|
||||
|
||||
class ExtractComposite(plugin.HoudiniExtractorPlugin,
|
||||
publish.ColormanagedPyblishPluginMixin):
|
||||
|
||||
order = pyblish.api.ExtractorOrder
|
||||
label = "Extract Composite (Image Sequence)"
|
||||
families = ["imagesequence"]
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
ropnode = hou.node(instance.data["instance_node"])
|
||||
|
||||
# Get the filename from the copoutput parameter
|
||||
# `.evalParm(parameter)` will make sure all tokens are resolved
|
||||
cop_output = ropnode.evalParm("copoutput")
|
||||
staging_dir, file_name = os.path.split(cop_output)
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
|
||||
self.log.info("Writing comp '%s' to '%s'" % (file_name, staging_dir))
|
||||
|
||||
render_rop(ropnode)
|
||||
|
||||
_, ext = splitext(file_name, [])
|
||||
ext = ext.lstrip(".")
|
||||
|
||||
if "representations" not in instance.data:
|
||||
instance.data["representations"] = []
|
||||
|
||||
representation = {
|
||||
"name": ext,
|
||||
"ext": ext,
|
||||
"files": instance.data["frames"],
|
||||
"stagingDir": staging_dir,
|
||||
"frameStart": instance.data["frameStartHandle"],
|
||||
"frameEnd": instance.data["frameEndHandle"],
|
||||
}
|
||||
|
||||
if ext.lower() == "exr":
|
||||
# Inject colorspace with 'scene_linear' as that's the
|
||||
# default Houdini working colorspace and all extracted
|
||||
# OpenEXR images should be in that colorspace.
|
||||
# https://www.sidefx.com/docs/houdini/render/linear.html#image-formats
|
||||
self.set_representation_colorspace(
|
||||
representation, instance.context,
|
||||
colorspace="scene_linear"
|
||||
)
|
||||
|
||||
instance.data["representations"].append(representation)
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Fbx Extractor for houdini. """
|
||||
|
||||
import os
|
||||
import hou
|
||||
import pyblish.api
|
||||
from ayon_houdini.api import plugin
|
||||
from ayon_houdini.api.lib import render_rop
|
||||
|
||||
|
||||
class ExtractFBX(plugin.HoudiniExtractorPlugin):
|
||||
|
||||
label = "Extract FBX"
|
||||
families = ["fbx"]
|
||||
|
||||
order = pyblish.api.ExtractorOrder + 0.1
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
# get rop node
|
||||
ropnode = hou.node(instance.data.get("instance_node"))
|
||||
output_file = ropnode.evalParm("sopoutput")
|
||||
|
||||
# get staging_dir and file_name
|
||||
staging_dir = os.path.normpath(os.path.dirname(output_file))
|
||||
file_name = os.path.basename(output_file)
|
||||
|
||||
# render rop
|
||||
self.log.debug("Writing FBX '%s' to '%s'", file_name, staging_dir)
|
||||
render_rop(ropnode)
|
||||
|
||||
# prepare representation
|
||||
representation = {
|
||||
"name": "fbx",
|
||||
"ext": "fbx",
|
||||
"files": file_name,
|
||||
"stagingDir": staging_dir
|
||||
}
|
||||
|
||||
# A single frame may also be rendered without start/end frame.
|
||||
if "frameStartHandle" in instance.data and "frameEndHandle" in instance.data: # noqa
|
||||
representation["frameStart"] = instance.data["frameStartHandle"]
|
||||
representation["frameEnd"] = instance.data["frameEndHandle"]
|
||||
|
||||
# set value type for 'representations' key to list
|
||||
if "representations" not in instance.data:
|
||||
instance.data["representations"] = []
|
||||
|
||||
# update instance data
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
instance.data["representations"].append(representation)
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
import os
|
||||
import hou
|
||||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_houdini.api import plugin
|
||||
|
||||
|
||||
class ExtractMantraIFD(plugin.HoudiniExtractorPlugin):
|
||||
|
||||
order = pyblish.api.ExtractorOrder
|
||||
label = "Extract Mantra ifd"
|
||||
families = ["mantraifd"]
|
||||
targets = ["local", "remote"]
|
||||
|
||||
def process(self, instance):
|
||||
if instance.data.get("farm"):
|
||||
self.log.debug("Should be processed on farm, skipping.")
|
||||
return
|
||||
|
||||
ropnode = hou.node(instance.data.get("instance_node"))
|
||||
output = ropnode.evalParm("soho_diskfile")
|
||||
staging_dir = os.path.dirname(output)
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
|
||||
self.validate_expected_frames(instance, staging_dir)
|
||||
|
||||
if "representations" not in instance.data:
|
||||
instance.data["representations"] = []
|
||||
|
||||
representation = {
|
||||
'name': 'ifd',
|
||||
'ext': 'ifd',
|
||||
'files': instance.data["frames"],
|
||||
"stagingDir": staging_dir,
|
||||
"frameStart": instance.data["frameStart"],
|
||||
"frameEnd": instance.data["frameEnd"],
|
||||
}
|
||||
instance.data["representations"].append(representation)
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
import os
|
||||
import hou
|
||||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.pipeline import publish
|
||||
from ayon_houdini.api import plugin
|
||||
from ayon_houdini.api.lib import render_rop
|
||||
|
||||
|
||||
class ExtractOpenGL(plugin.HoudiniExtractorPlugin,
|
||||
publish.ColormanagedPyblishPluginMixin):
|
||||
|
||||
order = pyblish.api.ExtractorOrder - 0.01
|
||||
label = "Extract OpenGL"
|
||||
families = ["review"]
|
||||
|
||||
def process(self, instance):
|
||||
ropnode = hou.node(instance.data.get("instance_node"))
|
||||
|
||||
# This plugin is triggered when marking render as reviewable.
|
||||
# Therefore, this plugin will run on over wrong instances.
|
||||
# TODO: Don't run this plugin on wrong instances.
|
||||
# This plugin should run only on review product type
|
||||
# with instance node of opengl type.
|
||||
if ropnode.type().name() != "opengl":
|
||||
self.log.debug("Skipping OpenGl extraction. Rop node {} "
|
||||
"is not an OpenGl node.".format(ropnode.path()))
|
||||
return
|
||||
|
||||
output = ropnode.evalParm("picture")
|
||||
staging_dir = os.path.normpath(os.path.dirname(output))
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
file_name = os.path.basename(output)
|
||||
|
||||
self.log.info("Extracting '%s' to '%s'" % (file_name,
|
||||
staging_dir))
|
||||
|
||||
render_rop(ropnode)
|
||||
|
||||
tags = ["review"]
|
||||
if not instance.data.get("keepImages"):
|
||||
tags.append("delete")
|
||||
|
||||
representation = {
|
||||
"name": instance.data["imageFormat"],
|
||||
"ext": instance.data["imageFormat"],
|
||||
"files": instance.data["frames"],
|
||||
"stagingDir": staging_dir,
|
||||
"frameStart": instance.data["frameStartHandle"],
|
||||
"frameEnd": instance.data["frameEndHandle"],
|
||||
"tags": tags,
|
||||
"preview": True,
|
||||
"camera_name": instance.data.get("review_camera")
|
||||
}
|
||||
|
||||
if ropnode.evalParm("colorcorrect") == 2: # OpenColorIO enabled
|
||||
colorspace = ropnode.evalParm("ociocolorspace")
|
||||
# inject colorspace data
|
||||
self.set_representation_colorspace(
|
||||
representation, instance.context,
|
||||
colorspace=colorspace
|
||||
)
|
||||
|
||||
if "representations" not in instance.data:
|
||||
instance.data["representations"] = []
|
||||
instance.data["representations"].append(representation)
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
import os
|
||||
import hou
|
||||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_houdini.api import plugin
|
||||
from ayon_houdini.api.lib import render_rop
|
||||
|
||||
|
||||
class ExtractRedshiftProxy(plugin.HoudiniExtractorPlugin):
|
||||
|
||||
order = pyblish.api.ExtractorOrder + 0.1
|
||||
label = "Extract Redshift Proxy"
|
||||
families = ["redshiftproxy"]
|
||||
targets = ["local", "remote"]
|
||||
|
||||
def process(self, instance):
|
||||
if instance.data.get("farm"):
|
||||
self.log.debug("Should be processed on farm, skipping.")
|
||||
return
|
||||
ropnode = hou.node(instance.data.get("instance_node"))
|
||||
|
||||
# Get the filename from the filename parameter
|
||||
# `.evalParm(parameter)` will make sure all tokens are resolved
|
||||
output = ropnode.evalParm("RS_archive_file")
|
||||
staging_dir = os.path.normpath(os.path.dirname(output))
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
file_name = os.path.basename(output)
|
||||
|
||||
self.log.info("Writing Redshift Proxy '%s' to '%s'" % (file_name,
|
||||
staging_dir))
|
||||
|
||||
render_rop(ropnode)
|
||||
|
||||
if "representations" not in instance.data:
|
||||
instance.data["representations"] = []
|
||||
|
||||
representation = {
|
||||
"name": "rs",
|
||||
"ext": "rs",
|
||||
"files": instance.data["frames"],
|
||||
"stagingDir": staging_dir,
|
||||
}
|
||||
|
||||
# A single frame may also be rendered without start/end frame.
|
||||
if "frameStartHandle" in instance.data and "frameEndHandle" in instance.data: # noqa
|
||||
representation["frameStart"] = instance.data["frameStartHandle"]
|
||||
representation["frameEnd"] = instance.data["frameEndHandle"]
|
||||
|
||||
instance.data["representations"].append(representation)
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
import os
|
||||
import hou
|
||||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.pipeline import publish
|
||||
from ayon_houdini.api import plugin
|
||||
from ayon_houdini.api.lib import render_rop, get_output_parameter, splitext
|
||||
|
||||
|
||||
class ExtractROP(plugin.HoudiniExtractorPlugin):
|
||||
"""Generic Extractor for any ROP node."""
|
||||
label = "Extract ROP"
|
||||
order = pyblish.api.ExtractorOrder
|
||||
|
||||
families = ["abc", "camera", "bgeo", "pointcache", "fbx", "imagesequence",
|
||||
"vdbcache", "ass", "redshiftproxy", "mantraifd"]
|
||||
targets = ["local", "remote"]
|
||||
|
||||
def process(self, instance: pyblish.api.Instance):
|
||||
if instance.data.get("farm"):
|
||||
self.log.debug("Should be processed on farm, skipping.")
|
||||
return
|
||||
|
||||
rop_node = hou.node(instance.data["instance_node"])
|
||||
|
||||
parm = get_output_parameter(rop_node)
|
||||
filepath = parm.eval()
|
||||
staging_dir = os.path.dirname(filepath)
|
||||
_, ext = splitext(
|
||||
filepath, allowed_multidot_extensions=[
|
||||
".ass.gz", ".bgeo.sc", ".bgeo.gz",
|
||||
".bgeo.lzma", ".bgeo.bz2"]
|
||||
)
|
||||
|
||||
render_rop(rop_node)
|
||||
self.validate_expected_frames(instance, staging_dir)
|
||||
|
||||
# In some cases representation name is not the the extension
|
||||
# TODO: Preferably we remove this very specific naming
|
||||
product_type = instance.data["productType"]
|
||||
name = {
|
||||
"bgeo": "bgeo",
|
||||
"rs": "rs",
|
||||
"ass": "ass",
|
||||
}.get(product_type, ext)
|
||||
|
||||
representation = {
|
||||
"name": name,
|
||||
"ext": ext,
|
||||
"files": instance.data["frames"],
|
||||
"stagingDir": staging_dir,
|
||||
"frameStart": instance.data["frameStartHandle"],
|
||||
"frameEnd": instance.data["frameEndHandle"],
|
||||
}
|
||||
representation = self.update_representation_data(instance,
|
||||
representation)
|
||||
instance.data.setdefault("representations", []).append(representation)
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
|
||||
def update_representation_data(self,
|
||||
instance: pyblish.api.Instance,
|
||||
representation: dict):
|
||||
"""Allow subclass to override the representation data in-place"""
|
||||
pass
|
||||
|
||||
|
||||
class ExtractOpenGL(ExtractROP,
|
||||
publish.ColormanagedPyblishPluginMixin):
|
||||
|
||||
order = pyblish.api.ExtractorOrder - 0.01
|
||||
label = "Extract OpenGL"
|
||||
families = ["review"]
|
||||
|
||||
def process(self, instance):
|
||||
# This plugin is triggered when marking render as reviewable.
|
||||
# Therefore, this plugin will run over wrong instances.
|
||||
# TODO: Don't run this plugin on wrong instances.
|
||||
# This plugin should run only on review product type
|
||||
# with instance node of opengl type.
|
||||
instance_node = instance.data.get("instance_node")
|
||||
if not instance_node:
|
||||
self.log.debug("Skipping instance without instance node.")
|
||||
return
|
||||
|
||||
rop_node = hou.node(instance_node)
|
||||
if rop_node.type().name() != "opengl":
|
||||
self.log.debug("Skipping OpenGl extraction. Rop node {} "
|
||||
"is not an OpenGl node.".format(rop_node.path()))
|
||||
return
|
||||
|
||||
super(ExtractOpenGL, self).process(instance)
|
||||
|
||||
def update_representation_data(self,
|
||||
instance: pyblish.api.Instance,
|
||||
representation: dict):
|
||||
|
||||
tags = ["review"]
|
||||
if not instance.data.get("keepImages"):
|
||||
tags.append("delete")
|
||||
|
||||
representation.update({
|
||||
# TODO: Avoid this override?
|
||||
"name": instance.data["imageFormat"],
|
||||
"ext": instance.data["imageFormat"],
|
||||
|
||||
"tags": tags,
|
||||
"preview": True,
|
||||
"camera_name": instance.data.get("review_camera")
|
||||
})
|
||||
return representation
|
||||
|
||||
|
||||
class ExtractComposite(ExtractROP,
|
||||
publish.ColormanagedPyblishPluginMixin):
|
||||
|
||||
label = "Extract Composite (Image Sequence)"
|
||||
families = ["imagesequence"]
|
||||
|
||||
def update_representation_data(self,
|
||||
instance: pyblish.api.Instance,
|
||||
representation: dict):
|
||||
|
||||
if representation["ext"].lower() != "exr":
|
||||
return
|
||||
|
||||
# Inject colorspace with 'scene_linear' as that's the
|
||||
# default Houdini working colorspace and all extracted
|
||||
# OpenEXR images should be in that colorspace.
|
||||
# https://www.sidefx.com/docs/houdini/render/linear.html#image-formats
|
||||
self.set_representation_colorspace(
|
||||
representation, instance.context,
|
||||
colorspace="scene_linear"
|
||||
)
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
import os
|
||||
import hou
|
||||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_houdini.api import plugin
|
||||
from ayon_houdini.api.lib import render_rop
|
||||
|
||||
|
||||
class ExtractVDBCache(plugin.HoudiniExtractorPlugin):
|
||||
|
||||
order = pyblish.api.ExtractorOrder + 0.1
|
||||
label = "Extract VDB Cache"
|
||||
families = ["vdbcache"]
|
||||
|
||||
def process(self, instance):
|
||||
if instance.data.get("farm"):
|
||||
self.log.debug("Should be processed on farm, skipping.")
|
||||
return
|
||||
ropnode = hou.node(instance.data["instance_node"])
|
||||
|
||||
# Get the filename from the filename parameter
|
||||
# `.evalParm(parameter)` will make sure all tokens are resolved
|
||||
sop_output = ropnode.evalParm("sopoutput")
|
||||
staging_dir = os.path.normpath(os.path.dirname(sop_output))
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
file_name = os.path.basename(sop_output)
|
||||
|
||||
self.log.info("Writing VDB '%s' to '%s'" % (file_name, staging_dir))
|
||||
|
||||
render_rop(ropnode)
|
||||
|
||||
if "representations" not in instance.data:
|
||||
instance.data["representations"] = []
|
||||
|
||||
representation = {
|
||||
"name": "vdb",
|
||||
"ext": "vdb",
|
||||
"files": instance.data["frames"],
|
||||
"stagingDir": staging_dir,
|
||||
"frameStart": instance.data["frameStartHandle"],
|
||||
"frameEnd": instance.data["frameEndHandle"],
|
||||
}
|
||||
instance.data["representations"].append(representation)
|
||||
Loading…
Add table
Add a link
Reference in a new issue