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

Substance Painter: Support for exporting maps/layer stacks with specific channels #532

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f08443f
supports exporting layer stack with specific channel & output with sp…
moonyuet May 21, 2024
f3b1d34
check substance version when adding use selection into setting & tool…
moonyuet May 22, 2024
597f4a2
code clean up & rename the contextmanager function to set_layer_stack…
moonyuet May 22, 2024
2dd6c12
rename the contextlib function
moonyuet May 22, 2024
9570d0b
use dict as item values for export channel settings
moonyuet May 22, 2024
a97a33a
add channel mapping setting into ayon project setting
moonyuet May 23, 2024
ced2ac0
Update client/ayon_core/hosts/substancepainter/api/lib.py
moonyuet May 23, 2024
d970539
code tweaks - big roy's comment
moonyuet May 23, 2024
e9a56f3
implement backward compatibility for the channel setting in creator
moonyuet May 23, 2024
b70e0b3
renaming filtered_nodes to excluded_nodes & make sure the code implme…
moonyuet May 23, 2024
63398b1
make sure the code doesn't break the integration
moonyuet May 23, 2024
b578547
make sure the export channel filtering function is working
moonyuet May 23, 2024
f3033a0
rename channel name to channel map
moonyuet May 23, 2024
cc600bd
add roughness, roughness, height option into the channel_mapping
moonyuet May 23, 2024
6d03f7b
support to validate the texture maps filtering when no texture map af…
moonyuet May 24, 2024
fb2e41c
support to validate multiple export channel filtering
moonyuet May 24, 2024
bd3be36
edit error message
moonyuet May 24, 2024
339eea0
improve the validation on invalid channel function
moonyuet May 24, 2024
9f09b75
Merge branch 'develop' into enhancement/AY-5104_Substance-selective-e…
moonyuet May 28, 2024
0ebda1d
code tweaks and clean up --BigRoy's comment
moonyuet May 28, 2024
119428b
improve publish validation message
moonyuet May 28, 2024
447edbe
cosmetic fix
moonyuet May 28, 2024
5f950b7
improve debug msg
moonyuet May 28, 2024
a392567
improve debug msg
moonyuet May 28, 2024
3b074c9
code tweaks - big roy's comment
moonyuet May 29, 2024
eeb4544
code tweaks - big roy's comment
moonyuet May 29, 2024
984592d
Merge branch 'develop' into enhancement/AY-5104_Substance-selective-e…
moonyuet May 29, 2024
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
57 changes: 57 additions & 0 deletions client/ayon_core/hosts/substancepainter/api/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import json
from collections import defaultdict

import contextlib
import substance_painter as sp
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
import substance_painter.project
import substance_painter.resource
import substance_painter.js
Expand Down Expand Up @@ -640,3 +642,58 @@ def _setup_prompt():
return

return project_mesh


def get_export_presets_by_filtering(export_preset_name, channel_type_list):
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
new_maps = []

export_presets = get_export_presets()
resource_presets = substance_painter.export.list_resource_export_presets()
preset = next((preset for preset in resource_presets
if preset.resource_id.name == (
export_presets[export_preset_name])), None)
moonyuet marked this conversation as resolved.
Show resolved Hide resolved

if preset is not None:
maps = preset.list_output_maps()
for channel_map in maps:
for n in channel_type_list:
if n in channel_map["fileName"]:
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
new_maps.append(channel_map)
# Create a new preset
return {
"exportPresets": [
{
"name": export_preset_name,
"maps": new_maps
}
],
}
return {}
moonyuet marked this conversation as resolved.
Show resolved Hide resolved


@contextlib.contextmanager
def supsend_publish_layer_stack(node_ids, channel_type):
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
all_selected_nodes = []
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
opacity_set_list = []
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
stack = sp.textureset.get_active_stack()
stack_root_layers = sp.layerstack.get_root_layer_nodes(stack)
if node_ids and channel_type:
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
for node_id in node_ids:
node = sp.layerstack.get_node_by_uid(int(node_id))
all_selected_nodes.append(node)
filtered_nodes = [node for node in stack_root_layers
if node not in all_selected_nodes]
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
for node in filtered_nodes:
for channel in channel_type:
chan = getattr(sp.textureset.ChannelType, channel)
opacity_set_list.append((chan, node.get_opacity(chan)))
try:
for node in filtered_nodes:
for channel, _ in opacity_set_list:
node.set_opacity(0.0, channel)
yield
finally:
for node in filtered_nodes:
for channel, opacity in opacity_set_list:
node.set_opacity(opacity, channel)

Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
"""Creator plugin for creating textures."""

from ayon_core.pipeline import CreatedInstance, Creator, CreatorError
from ayon_core.lib import (
EnumDef,
Expand All @@ -18,6 +17,7 @@
from ayon_core.hosts.substancepainter.api.lib import get_export_presets

import substance_painter.project
import substance_painter as sp


class CreateTextures(Creator):
Expand All @@ -42,10 +42,20 @@ def create(self, product_name, instance_data, pre_create_data):
"exportFileFormat",
"exportSize",
"exportPadding",
"exportDilationDistance"
"exportDilationDistance",
"useCustomExportPreset",
"exportChannel"
]:
if key in pre_create_data:
creator_attributes[key] = pre_create_data[key]
#TODO: add the layer stack option
if sp.application.version_info()[0] >= 10 or (
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
pre_create_data.get("use_selection")):
stack = sp.textureset.get_active_stack()

instance_data["selected_node_id"] = [
node_number.uid() for node_number in
sp.layerstack.get_selected_nodes(stack)]

instance = self.create_instance_in_context(product_name,
instance_data)
Expand Down Expand Up @@ -88,8 +98,25 @@ def create_instance_in_context_from_existing(self, data):
return instance

def get_instance_attr_defs(self):

layer_stack_channel_enum = ["BaseColor", "Metallic", "Roughness",
"Normal", "Height", "Specular",
"SpecularEdgeColor", "Emissive", "Opacity",
"Displacement", "Glossiness", "Anisotropylevel",
"AO", "Anisotropyangle", "Transmissive",
"Reflection", "Diffuse", "Ior",
"Specularlevel", "BlendingMask", "Translucency",
"Scattering", "ScatterColor", "SheenOpacity",
"SheenRoughness", "SheenColor", "CoatOpacity",
"CoatColor", "CoatRoughness", "CoatSpecularLevel",
"CoatNormal"]
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
return [
EnumDef("exportChannel",
items=layer_stack_channel_enum,
multiselection=True,
default=None,
label="Export Channel(s)",
tooltip="Choose the channel which you "
"want to solely export"),
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
EnumDef("exportPresetUrl",
items=get_export_presets(),
label="Output Template"),
Expand Down Expand Up @@ -149,7 +176,6 @@ def get_instance_attr_defs(self):
},
default=None,
label="Size"),

EnumDef("exportPadding",
items={
"passthrough": "No padding (passthrough)",
Expand All @@ -172,4 +198,7 @@ def get_instance_attr_defs(self):

def get_pre_create_attr_defs(self):
# Use same attributes as for instance attributes
return self.get_instance_attr_defs()
return [
BoolDef("use_selection", label="Use selection",
tooltip="Select Layer Stack(s) for exporting")
] + self.get_instance_attr_defs()
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from ayon_core.pipeline import publish
from ayon_core.hosts.substancepainter.api.lib import (
get_parsed_export_maps,
get_export_presets_by_filtering,
strip_template
)
from ayon_core.pipeline.create import get_product_name
Expand Down Expand Up @@ -207,5 +208,8 @@ def get_export_config(self, instance):
for key, value in dict(parameters).items():
if value is None:
parameters.pop(key)

channel_layer = creator_attrs.get("exportChannel", [])
if channel_layer:
maps = get_export_presets_by_filtering(preset_url, channel_layer)
config.update(maps)
return config
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import substance_painter.export

from ayon_core.pipeline import KnownPublishError, publish
from ayon_core.hosts.substancepainter.api.lib import supsend_publish_layer_stack


class ExtractTextures(publish.Extractor,
Expand All @@ -25,19 +25,24 @@ class ExtractTextures(publish.Extractor,
def process(self, instance):

config = instance.data["exportConfig"]
result = substance_painter.export.export_project_textures(config)

if result.status != substance_painter.export.ExportStatus.Success:
raise KnownPublishError(
"Failed to export texture set: {}".format(result.message)
)

# Log what files we generated
for (texture_set_name, stack_name), maps in result.textures.items():
# Log our texture outputs
self.log.info(f"Exported stack: {texture_set_name} {stack_name}")
for texture_map in maps:
self.log.info(f"Exported texture: {texture_map}")
creator_attrs = instance.data["creator_attributes"]
export_channel = creator_attrs.get("exportChannel", [])
node_ids = instance.data.get("selected_node_id", [])

with supsend_publish_layer_stack(node_ids, export_channel):
moonyuet marked this conversation as resolved.
Show resolved Hide resolved
result = substance_painter.export.export_project_textures(config)

if result.status != substance_painter.export.ExportStatus.Success:
raise KnownPublishError(
"Failed to export texture set: {}".format(result.message)
)

# Log what files we generated
for (texture_set_name, stack_name), maps in result.textures.items():
# Log our texture outputs
self.log.info(f"Exported stack: {texture_set_name} {stack_name}")
for texture_map in maps:
self.log.info(f"Exported texture: {texture_map}")

# We'll insert the color space data for each image instance that we
# added into this texture set. The collector couldn't do so because
Expand Down
Loading