Merge pull request #4588 from ynput/feature/OP-3129_houdini-bgeo-publishing

This commit is contained in:
Ondřej Samohel 2023-07-17 16:38:02 +02:00 committed by GitHub
commit b26b5fdb88
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 228 additions and 12 deletions

View file

@ -69,6 +69,8 @@ class HoudiniLegacyConvertor(SubsetConvertorPlugin):
"creator_identifier": self.family_to_id[family],
"instance_node": subset.path()
}
if family == "pointcache":
data["families"] = ["abc"]
self.log.info("Converting {} to {}".format(
subset.path(), self.family_to_id[family]))
imprint(subset, data)

View file

@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
"""Creator plugin for creating pointcache bgeo files."""
from openpype.hosts.houdini.api import plugin
from openpype.pipeline import CreatedInstance, CreatorError
from openpype.lib import EnumDef
class CreateBGEO(plugin.HoudiniCreator):
"""BGEO pointcache creator."""
identifier = "io.openpype.creators.houdini.bgeo"
label = "BGEO PointCache"
family = "pointcache"
icon = "gears"
def create(self, subset_name, instance_data, pre_create_data):
import hou
instance_data.pop("active", None)
instance_data.update({"node_type": "geometry"})
instance = super(CreateBGEO, self).create(
subset_name,
instance_data,
pre_create_data) # type: CreatedInstance
instance_node = hou.node(instance.get("instance_node"))
file_path = "{}{}".format(
hou.text.expandString("$HIP/pyblish/"),
"{}.$F4.{}".format(
subset_name,
pre_create_data.get("bgeo_type") or "bgeo.sc")
)
parms = {
"sopoutput": file_path
}
instance_node.parm("trange").set(1)
if self.selected_nodes:
# if selection is on SOP level, use it
if isinstance(self.selected_nodes[0], hou.SopNode):
parms["soppath"] = self.selected_nodes[0].path()
else:
# try to find output node with the lowest index
outputs = [
child for child in self.selected_nodes[0].children()
if child.type().name() == "output"
]
if not outputs:
instance_node.setParms(parms)
raise CreatorError((
"Missing output node in SOP level for the selection. "
"Please select correct SOP path in created instance."
))
outputs.sort(key=lambda output: output.evalParm("outputidx"))
parms["soppath"] = outputs[0].path()
instance_node.setParms(parms)
def get_pre_create_attr_defs(self):
attrs = super().get_pre_create_attr_defs()
bgeo_enum = [
{
"value": "bgeo",
"label": "uncompressed bgeo (.bgeo)"
},
{
"value": "bgeosc",
"label": "BLOSC compressed bgeo (.bgeosc)"
},
{
"value": "bgeo.sc",
"label": "BLOSC compressed bgeo (.bgeo.sc)"
},
{
"value": "bgeo.gz",
"label": "GZ compressed bgeo (.bgeo.gz)"
},
{
"value": "bgeo.lzma",
"label": "LZMA compressed bgeo (.bgeo.lzma)"
},
{
"value": "bgeo.bz2",
"label": "BZip2 compressed bgeo (.bgeo.bz2)"
}
]
return attrs + [
EnumDef("bgeo_type", bgeo_enum, label="BGEO Options"),
]

View file

@ -13,7 +13,8 @@ class CollectFrames(pyblish.api.InstancePlugin):
order = pyblish.api.CollectorOrder + 0.01
label = "Collect Frames"
families = ["vdbcache", "imagesequence", "ass", "redshiftproxy", "review"]
families = ["vdbcache", "imagesequence", "ass",
"redshiftproxy", "review", "bgeo"]
def process(self, instance):
@ -32,9 +33,9 @@ class CollectFrames(pyblish.api.InstancePlugin):
output = output_parm.eval()
_, ext = lib.splitext(
output,
allowed_multidot_extensions=[".ass.gz"]
)
output, allowed_multidot_extensions=[
".ass.gz", ".bgeo.sc", ".bgeo.gz",
".bgeo.lzma", ".bgeo.bz2"])
file_name = os.path.basename(output)
result = file_name
@ -76,7 +77,7 @@ class CollectFrames(pyblish.api.InstancePlugin):
frame = match.group(1)
padding = len(frame)
# Get the parts of the filename surrounding the frame number
# Get the parts of the filename surrounding the frame number,
# so we can put our own frame numbers in.
span = match.span(1)
prefix = match.string[: span[0]]

View file

@ -0,0 +1,21 @@
"""Collector for pointcache types.
This will add additional family to pointcache instance based on
the creator_identifier parameter.
"""
import pyblish.api
class CollectPointcacheType(pyblish.api.InstancePlugin):
"""Collect data type for pointcache instance."""
order = pyblish.api.CollectorOrder
hosts = ["houdini"]
families = ["pointcache"]
label = "Collect type of pointcache"
def process(self, instance):
if instance.data["creator_identifier"] == "io.openpype.creators.houdini.bgeo": # noqa: E501
instance.data["families"] += ["bgeo"]
elif instance.data["creator_identifier"] == "io.openpype.creators.houdini.alembic": # noqa: E501
instance.data["families"] += ["abc"]

View file

@ -13,7 +13,7 @@ class ExtractAlembic(publish.Extractor):
order = pyblish.api.ExtractorOrder
label = "Extract Alembic"
hosts = ["houdini"]
families = ["pointcache", "camera"]
families = ["abc", "camera"]
def process(self, instance):

View file

@ -0,0 +1,53 @@
import os
import pyblish.api
from openpype.pipeline import publish
from openpype.hosts.houdini.api.lib import render_rop
from openpype.hosts.houdini.api import lib
import hou
class ExtractBGEO(publish.Extractor):
order = pyblish.api.ExtractorOrder
label = "Extract BGEO"
hosts = ["houdini"]
families = ["bgeo"]
def process(self, instance):
ropnode = hou.node(instance.data["instance_node"])
# Get the filename from the filename parameter
output = ropnode.evalParm("sopoutput")
staging_dir, file_name = os.path.split(output)
instance.data["stagingDir"] = staging_dir
# We run the render
self.log.info("Writing bgeo files '{}' to '{}'.".format(
file_name, staging_dir))
# write files
render_rop(ropnode)
output = instance.data["frames"]
_, ext = lib.splitext(
output[0], 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": output,
"stagingDir": staging_dir,
"frameStart": instance.data["frameStart"],
"frameEnd": instance.data["frameEnd"]
}
instance.data["representations"].append(representation)

View file

@ -17,7 +17,7 @@ class ValidateAbcPrimitiveToDetail(pyblish.api.InstancePlugin):
"""
order = pyblish.api.ValidatorOrder + 0.1
families = ["pointcache"]
families = ["abc"]
hosts = ["houdini"]
label = "Validate Primitive to Detail (Abc)"

View file

@ -18,7 +18,7 @@ class ValidateAlembicROPFaceSets(pyblish.api.InstancePlugin):
"""
order = pyblish.api.ValidatorOrder + 0.1
families = ["pointcache"]
families = ["abc"]
hosts = ["houdini"]
label = "Validate Alembic ROP Face Sets"

View file

@ -14,7 +14,7 @@ class ValidateAlembicInputNode(pyblish.api.InstancePlugin):
"""
order = pyblish.api.ValidatorOrder + 0.1
families = ["pointcache"]
families = ["abc"]
hosts = ["houdini"]
label = "Validate Input Node (Abc)"

View file

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""Validator plugin for SOP Path in bgeo isntance."""
import pyblish.api
from openpype.pipeline import PublishValidationError
class ValidateNoSOPPath(pyblish.api.InstancePlugin):
"""Validate if SOP Path in BGEO instance exists."""
order = pyblish.api.ValidatorOrder
families = ["bgeo"]
label = "Validate BGEO SOP Path"
def process(self, instance):
import hou
node = hou.node(instance.data.get("instance_node"))
sop_path = node.evalParm("soppath")
if not sop_path:
raise PublishValidationError(
("Empty SOP Path ('soppath' parameter) found in "
f"the BGEO instance Geometry - {node.path()}"))
if not isinstance(hou.node(sop_path), hou.SopNode):
raise PublishValidationError(
"SOP path is not pointing to valid SOP node.")

View file

@ -19,12 +19,11 @@ class ValidateFileExtension(pyblish.api.InstancePlugin):
"""
order = pyblish.api.ValidatorOrder
families = ["pointcache", "camera", "vdbcache"]
families = ["camera", "vdbcache"]
hosts = ["houdini"]
label = "Output File Extension"
family_extensions = {
"pointcache": ".abc",
"camera": ".abc",
"vdbcache": ".vdb",
}

View file

@ -24,7 +24,7 @@ class ValidatePrimitiveHierarchyPaths(pyblish.api.InstancePlugin):
"""
order = ValidateContentsOrder + 0.1
families = ["pointcache"]
families = ["abc"]
hosts = ["houdini"]
label = "Validate Prims Hierarchy Path"
actions = [AddDefaultPathAction]