Add Qt dialog to support users to choose their templates for project creation

This commit is contained in:
Kayla Man 2024-04-17 22:45:47 +08:00
parent 38d6a34b9b
commit d4fdf85306
3 changed files with 145 additions and 110 deletions

View file

@ -640,86 +640,3 @@ def prompt_new_file_with_mesh(mesh_filepath):
return
return project_mesh
def convert_substance_object_to_python(subst_proj_option="default"):
"""Function to convert substance C++ objects to python instance.
It is made to avoid any possible ValueError when C++ objects casting
as python instance.
Args:
subst_proj_option (str, optional): Substance project option.
Defaults to "default".
Raises:
ValueError: Raise Error when unsupported Substance
Project was detected
Returns:
python instance: converted python instance of the C++ objects.
"""
if subst_proj_option == "default":
return substance_painter.project.ProjectWorkflow.Default
elif subst_proj_option == "uvTile":
return substance_painter.project.ProjectWorkflow.UVTile
elif subst_proj_option == "textureSetPerUVTile":
return substance_painter.project.ProjectWorkflow.TextureSetPerUVTile
elif subst_proj_option == "PerFragment":
return substance_painter.project.TangentSpace.PerFragment
elif subst_proj_option == "PerVertex":
return substance_painter.project.TangentSpace.PerVertex
elif subst_proj_option == "DirectX":
return substance_painter.project.NormalMapFormat.DirectX
elif subst_proj_option == "OpenGL":
return substance_painter.project.NormalMapFormat.OpenGL
else:
raise ValueError(
f"Unsupported Substance Objects: {subst_proj_option}")
def parse_substance_attributes_setting(template_name, project_templates):
"""Function to parse the dictionary from the AYON setting to be used
as the attributes for Substance Project Creation
Args:
template_name (str): name of the template from the setting
project_templates (dict): project template data from the setting
Returns:
dict: data to be used as attributes for Substance Project Creation
"""
attributes_data = {}
for template in project_templates:
if template["name"] == template_name:
attributes_data.update(template)
attributes_data["normal_map_format"] = convert_substance_object_to_python(
subst_proj_option=attributes_data["normal_map_format"])
attributes_data["project_workflow"] = convert_substance_object_to_python(
subst_proj_option=attributes_data["project_workflow"])
attributes_data["tangent_space_mode"] = convert_substance_object_to_python(
subst_proj_option=attributes_data["tangent_space_mode"])
attributes_data.pop("name")
attributes_data.pop("preserve_strokes")
return attributes_data
def parse_subst_attrs_reloading_mesh(template_name, project_templates):
"""Function to parse the substances attributes ('import_cameras'
and 'preserve_strokes') for reloading mesh
with the existing projects.
Args:
template_name (str): name of the template from the setting
project_templates (dict): project template data from the setting
Returns:
dict: data to be used as attributes for reloading mesh with the
existing project
"""
attributes_data = {}
for template in project_templates:
if template["name"] == template_name:
for key, value in template.items():
if isinstance(value, bool):
attributes_data.update({key: value})
return attributes_data

View file

@ -1,23 +1,130 @@
from qtpy import QtWidgets, QtCore
from ayon_core.pipeline import (
load,
get_representation_path,
)
from ayon_core.lib import EnumDef
from ayon_core.pipeline.load import LoadError
from ayon_core.hosts.substancepainter.api.pipeline import (
imprint_container,
set_container_metadata,
remove_container_metadata
)
from ayon_core.hosts.substancepainter.api.lib import (
parse_substance_attributes_setting,
parse_subst_attrs_reloading_mesh
)
import substance_painter.project
def _convert(subst_attr):
"""Function to convert substance C++ objects to python instance.
It is made to avoid any possible ValueError when C++ objects casting
as python instance.
Args:
subst_attr (str): Substance attributes
Raises:
ValueError: Raise Error when unsupported Substance
Project was detected
Returns:
python instance: converted python instance of the C++ objects.
"""
if subst_attr in {"Default", "UVTile", "TextureSetPerUVTile"}:
return getattr(substance_painter.project.ProjectWorkflow, subst_attr)
elif subst_attr in {"PerFragment", "PerVertex"}:
return getattr(substance_painter.project.TangentSpace, subst_attr)
elif subst_attr in {"DirectX", "OpenGL"}:
return getattr(substance_painter.project.NormalMapFormat, subst_attr)
else:
raise ValueError(
f"Unsupported Substance Objects: {subst_attr}")
def parse_substance_attributes_setting(template_name, project_templates):
"""Function to parse the dictionary from the AYON setting to be used
as the attributes for Substance Project Creation
Args:
template_name (str): name of the template from the setting
project_templates (dict): project template data from the setting
Returns:
dict: data to be used as attributes for Substance Project Creation
"""
attributes_data = {}
for template in project_templates:
if template["name"] == template_name:
attributes_data.update(template)
attributes_data["normal_map_format"] = _convert(
attributes_data["normal_map_format"])
attributes_data["project_workflow"] = _convert(
attributes_data["project_workflow"])
attributes_data["tangent_space_mode"] = _convert(
attributes_data["tangent_space_mode"])
attributes_data.pop("name")
attributes_data.pop("preserve_strokes")
return attributes_data
def parse_subst_attrs_reloading_mesh(template_name, project_templates):
"""Function to parse the substances attributes ('import_cameras'
and 'preserve_strokes') for reloading mesh
with the existing projects.
Args:
template_name (str): name of the template from the setting
project_templates (dict): project template data from the setting
Returns:
dict: data to be used as attributes for reloading mesh with the
existing project
"""
attributes_data = {}
for template in project_templates:
if template["name"] == template_name:
for key, value in template.items():
if isinstance(value, bool):
attributes_data.update({key: value})
return attributes_data
class SubstanceProjectConfigurationWindow(QtWidgets.QDialog):
"""The pop-up dialog allows users to choose material
duplicate options for importing Max objects when updating
or switching assets.
"""
def __init__(self, project_templates):
super(SubstanceProjectConfigurationWindow, self).__init__()
self.setWindowFlags(self.windowFlags() | QtCore.Qt.FramelessWindowHint)
self.template_name = None
self.project_templates = project_templates
self.widgets = {
"label": QtWidgets.QLabel("Project Configuration"),
"template_options": QtWidgets.QComboBox(),
"buttons": QtWidgets.QWidget(),
"okButton": QtWidgets.QPushButton("Ok"),
}
for template in project_templates:
self.widgets["template_options"].addItem(template)
# Build buttons.
layout = QtWidgets.QHBoxLayout(self.widgets["buttons"])
layout.addWidget(self.widgets["template_options"])
layout.addWidget(self.widgets["okButton"])
# Build layout.
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.widgets["label"])
layout.addWidget(self.widgets["buttons"])
self.widgets["okButton"].pressed.connect(self.on_ok_pressed)
def on_ok_pressed(self):
self.template_name = (
self.widgets["template_options"].currentText()
)
self.close()
class SubstanceLoadProjectMesh(load.LoaderPlugin):
"""Load mesh for project"""
@ -30,20 +137,13 @@ class SubstanceLoadProjectMesh(load.LoaderPlugin):
color = "orange"
project_templates = []
@classmethod
def get_options(cls, contexts):
template_enum = [template["name"] for template in cls.project_templates]
return [
EnumDef("project_template",
items=template_enum,
default="default",
label="Project Template")
]
def load(self, context, name, namespace, options=None):
# Get user inputs
template_name = options.get("project_template", "default")
template_enum = [template["name"] for template in self.project_templates]
window = SubstanceProjectConfigurationWindow(template_enum)
window.exec_()
template_name = window.template_name
template_settings = parse_substance_attributes_setting(
template_name, self.project_templates)
sp_settings = substance_painter.project.Settings(**template_settings)

View file

@ -10,17 +10,17 @@ def normal_map_format_enum():
def tangent_space_enum():
return [
{"label": "PerFragment", "value": "PerFragment"},
{"label": "PerVertex", "value": "PerVertex"},
{"label": "Per Fragment", "value": "PerFragment"},
{"label": "Per Vertex", "value": "PerVertex"},
]
def uv_workflow_enum():
return [
{"label": "Default", "value": "default"},
{"label": "UV Tile", "value": "uvTile"},
{"label": "Default", "value": "Default"},
{"label": "UV Tile", "value": "UVTile"},
{"label": "Texture Set Per UV Tile",
"value": "textureSetPerUVTile"}
"value": "TextureSetPerUVTile"}
]
@ -54,7 +54,7 @@ class ProjectTemplatesModel(BaseSettingsModel):
"creating new project.")
)
project_workflow: str = SettingsField(
"default", enum_resolver=uv_workflow_enum,
"Default", enum_resolver=uv_workflow_enum,
title="UV Tile Settings",
description=("Set UV workflow when "
"creating new project.")
@ -90,11 +90,29 @@ class LoadersModel(BaseSettingsModel):
DEFAULT_LOADER_SETTINGS = {
"SubstanceLoadProjectMesh":{
"project_templates": [{
"name": "default",
"default_texture_resolution": 1024,
"name": "2K(Default)",
"default_texture_resolution": 2048,
"import_cameras": True,
"normal_map_format": "DirectX",
"project_workflow": "default",
"project_workflow": "Default",
"tangent_space_mode": "PerFragment",
"preserve_strokes": True
},
{
"name": "2K(UV tile)",
"default_texture_resolution": 2048,
"import_cameras": True,
"normal_map_format": "DirectX",
"project_workflow": "UVTile",
"tangent_space_mode": "PerFragment",
"preserve_strokes": True
},
{
"name": "4K(Custom)",
"default_texture_resolution": 4096,
"import_cameras": True,
"normal_map_format": "OpenGL",
"project_workflow": "UVTile",
"tangent_space_mode": "PerFragment",
"preserve_strokes": True
}]