Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support to export texture sets as single output per texture map #25

Open
wants to merge 16 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ def create(self, product_name, instance_data, pre_create_data):
"exportPadding",
"exportDilationDistance",
"useCustomExportPreset",
"exportChannel"
"exportChannel",
"exportTextureSets",
"flattenTextureSets"
]:
if key in pre_create_data:
creator_attributes[key] = pre_create_data[key]
Expand Down Expand Up @@ -152,6 +154,11 @@ def get_instance_attr_defs(self):
label="Review",
tooltip="Mark as reviewable",
default=True),
BoolDef("flattenTextureSets",
label="Flatten Texture Sets As One Texture Output",
tooltip="Export multiple texture set(s) "
"as one Texture Output",
default=False),
EnumDef("exportTextureSets",
items=export_texture_set_enum,
multiselection=True,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ def create_image_instance(self, instance, template, outputs,

context = instance.context
first_filepath = outputs[0]["filepath"]
is_single_output = instance.data["creator_attributes"].get(
"flattenTextureSets", False)
fnames = [os.path.basename(output["filepath"]) for output in outputs]
ext = os.path.splitext(first_filepath)[1]
assert ext.lstrip("."), f"No extension: {ext}"
Expand Down Expand Up @@ -146,6 +148,22 @@ def create_image_instance(self, instance, template, outputs,
image_instance.data["families"] = [product_type, "textures"]
if instance.data["creator_attributes"].get("review"):
image_instance.data["families"].append("review")
if is_single_output:
# Function to remove textureSet from filepath
def remove_texture_set_token(filepath, texture_set):
return filepath.replace(f".{texture_set}", "")

single_fnames = {
remove_texture_set_token(
output["output"], output["udim"]
)
for output in outputs
}

image_instance.data["image_outputs"] = [
os.path.basename(fname) for fname in single_fnames
]
self.log.debug(f"image_outputs: {fnames}")

image_instance.data["representations"] = [representation]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ def process(self, instance):
return

representations: "list[dict]" = instance.data["representations"]

# If a tx representation is present we skip extraction
if any(repre["name"] == "tx" for repre in representations):
return
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import os

from ayon_core.pipeline import publish
from ayon_core.lib import (
get_oiio_tool_args,
run_subprocess,
)


def get_texture_outputs(staging_dir, image_outputs):
"""Getting the expected texture output(s) before merging
them with oiio tools.

Args:
staging_dir (str): staging dir
image_outputs (list): source image outputs

Returns:
list: Texture outputs which are used for merging.
"""
return [
os.path.join(staging_dir, output) for output in image_outputs
]


def convert_texture_maps_as_single_output(staging_dir, source_image_outputs,
dest_image_outputs, log=None):
oiio_tool_args = get_oiio_tool_args("oiiotool")

source_maps = get_texture_outputs(
staging_dir, source_image_outputs)
dest_map = next(
(dest_texture for dest_texture in
get_texture_outputs(
staging_dir, dest_image_outputs)), None)

log.info(f"{source_maps} composited as {dest_map}")
oiio_cmd = oiio_tool_args + source_maps + [
"--mosaic",
"{}x1".format(len(source_maps)),
"-o",
dest_map
]

env = os.environ.copy()

try:
run_subprocess(oiio_cmd, env=env)
except Exception as exc:
raise RuntimeError("Flattening texture stack to single output image failed") from exc


class ExtractTexturesAsSingleOutput(publish.Extractor):
"""Extract Texture As Single Output

Combine the multliple texture sets into one single texture output.

"""

label = "Extract Texture Sets as Single Texture Output"
hosts = ["substancepainter"]
families = ["image"]
settings_category = "substancepainter"

# Run directly after textures export
order = publish.Extractor.order - 0.0991

def process(self, instance):
if not instance.data.get("creator_attributes", {}).get(
"flattenTextureSets", False):
self.log.debug(
"Skipping to export texture sets as single texture output.."
)
return

representations: "list[dict]" = instance.data["representations"]
repre = representations[0]

staging_dir = instance.data["stagingDir"]
dest_image_outputs = instance.data["image_outputs"]
source_image = repre["files"]
is_sequence = isinstance(source_image, (list, tuple))
if not is_sequence:
source_image_outputs = [source_image]
else:
source_image_outputs = source_image
repre["files"] = dest_image_outputs[0]
repre.pop("udim", None)

convert_texture_maps_as_single_output(
staging_dir, source_image_outputs,
dest_image_outputs, log=self.log
)