forked from blender/blender-addons
BLEN-350: Fix error with Add shader node #3
@ -10,7 +10,6 @@ import bpy
|
|||||||
from bpy_extras.io_utils import ImportHelper, ExportHelper
|
from bpy_extras.io_utils import ImportHelper, ExportHelper
|
||||||
|
|
||||||
from . import utils
|
from . import utils
|
||||||
from .utils import import_materialx_from_file, export
|
|
||||||
from .preferences import addon_preferences
|
from .preferences import addon_preferences
|
||||||
|
|
||||||
from .utils import logging
|
from .utils import logging
|
||||||
@ -39,7 +38,7 @@ class MATERIALX_OP_import_file(bpy.types.Operator, ImportHelper):
|
|||||||
search_path.append(str(utils.MX_LIBS_DIR))
|
search_path.append(str(utils.MX_LIBS_DIR))
|
||||||
try:
|
try:
|
||||||
mx.readFromXmlFile(doc, str(mtlx_file))
|
mx.readFromXmlFile(doc, str(mtlx_file))
|
||||||
import_materialx_from_file(mx_node_tree, doc, mtlx_file)
|
utils.import_materialx_from_file(mx_node_tree, doc, mtlx_file)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(traceback.format_exc(), mtlx_file)
|
log.error(traceback.format_exc(), mtlx_file)
|
||||||
@ -53,7 +52,6 @@ class MATERIALX_OP_export_file(bpy.types.Operator, ExportHelper):
|
|||||||
bl_label = "Export to File"
|
bl_label = "Export to File"
|
||||||
bl_description = "Export material as MaterialX node tree to .mtlx file"
|
bl_description = "Export material as MaterialX node tree to .mtlx file"
|
||||||
|
|
||||||
# region properties
|
|
||||||
filename_ext = ".mtlx"
|
filename_ext = ".mtlx"
|
||||||
|
|
||||||
filepath: bpy.props.StringProperty(
|
filepath: bpy.props.StringProperty(
|
||||||
@ -66,52 +64,47 @@ class MATERIALX_OP_export_file(bpy.types.Operator, ExportHelper):
|
|||||||
default="*.mtlx",
|
default="*.mtlx",
|
||||||
options={'HIDDEN'},
|
options={'HIDDEN'},
|
||||||
)
|
)
|
||||||
is_export_deps: bpy.props.BoolProperty(
|
export_textures: bpy.props.BoolProperty(
|
||||||
name="Include dependencies",
|
name="Export Textures",
|
||||||
description="Export used MaterialX dependencies",
|
|
||||||
default=False
|
|
||||||
)
|
|
||||||
is_export_textures: bpy.props.BoolProperty(
|
|
||||||
name="Export textures",
|
|
||||||
description="Export bound textures to corresponded folder",
|
description="Export bound textures to corresponded folder",
|
||||||
default=True
|
default=True
|
||||||
)
|
)
|
||||||
is_clean_texture_folder: bpy.props.BoolProperty(
|
|
||||||
name="Сlean texture folder",
|
|
||||||
description="Сlean texture folder before export",
|
|
||||||
default=False
|
|
||||||
)
|
|
||||||
texture_dir_name: bpy.props.StringProperty(
|
texture_dir_name: bpy.props.StringProperty(
|
||||||
name="Folder name",
|
name="Folder Name",
|
||||||
description="Texture folder name used for exporting files",
|
description="Texture folder name used for exporting files",
|
||||||
default='textures',
|
default='textures',
|
||||||
maxlen=1024,
|
maxlen=1024,
|
||||||
)
|
)
|
||||||
# endregion
|
export_deps: bpy.props.BoolProperty(
|
||||||
|
name="Export Dependencies",
|
||||||
|
description="Export MaterialX library dependencies",
|
||||||
|
default=True
|
||||||
|
)
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
doc = export(context.material, None)
|
doc = utils.export(context.material, None)
|
||||||
if not doc:
|
if not doc:
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
|
|
||||||
utils.export_mx_to_file(doc, self.filepath,
|
utils.export_to_file(doc, self.filepath,
|
||||||
mx_node_tree=None,
|
export_textures=self.export_textures,
|
||||||
# is_export_deps=self.is_export_deps,
|
texture_dir_name=self.texture_dir_name,
|
||||||
is_export_textures=self.is_export_textures,
|
export_deps=self.export_deps,
|
||||||
texture_dir_name=self.texture_dir_name)
|
copy_deps=self.export_deps)
|
||||||
|
|
||||||
|
log.info(f"Succesfully exported material '{context.material.name}' into {self.filepath}")
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
# self.layout.prop(self, 'is_export_deps')
|
|
||||||
|
|
||||||
col = self.layout.column(align=False)
|
col = self.layout.column(align=False)
|
||||||
col.prop(self, 'is_export_textures')
|
col.prop(self, 'export_textures')
|
||||||
|
|
||||||
row = col.row()
|
row = col.row()
|
||||||
row.enabled = self.is_export_textures
|
row.enabled = self.export_textures
|
||||||
row.prop(self, 'texture_dir_name', text='')
|
row.prop(self, 'texture_dir_name', text='')
|
||||||
|
|
||||||
|
self.layout.prop(self, 'export_deps')
|
||||||
|
|
||||||
|
|
||||||
class MATERIALX_OP_export_console(bpy.types.Operator):
|
class MATERIALX_OP_export_console(bpy.types.Operator):
|
||||||
bl_idname = utils.with_prefix('materialx_export_console')
|
bl_idname = utils.with_prefix('materialx_export_console')
|
||||||
@ -119,7 +112,7 @@ class MATERIALX_OP_export_console(bpy.types.Operator):
|
|||||||
bl_description = "Export material as MaterialX node tree to console"
|
bl_description = "Export material as MaterialX node tree to console"
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
doc = export(context.material, context.object)
|
doc = utils.export(context.material, context.object)
|
||||||
if not doc:
|
if not doc:
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
@ -25,10 +25,6 @@ MX_ADDON_LIBS_DIR = ADDON_ROOT_DIR / MX_LIBS_FOLDER
|
|||||||
NODE_CLASSES_FOLDER = "materialx_nodes"
|
NODE_CLASSES_FOLDER = "materialx_nodes"
|
||||||
NODE_CLASSES_DIR = ADDON_DATA_DIR / NODE_CLASSES_FOLDER
|
NODE_CLASSES_DIR = ADDON_DATA_DIR / NODE_CLASSES_FOLDER
|
||||||
|
|
||||||
MATLIB_FOLDER = "matlib"
|
|
||||||
MATLIB_DIR = ADDON_DATA_DIR / MATLIB_FOLDER
|
|
||||||
MATLIB_URL = "https://api.matlib.gpuopen.com/api"
|
|
||||||
|
|
||||||
TEMP_FOLDER = "bl-materialx"
|
TEMP_FOLDER = "bl-materialx"
|
||||||
|
|
||||||
NODE_LAYER_SEPARATION_WIDTH = 280
|
NODE_LAYER_SEPARATION_WIDTH = 280
|
||||||
@ -246,76 +242,60 @@ def get_socket_color(mx_type):
|
|||||||
return (0.63, 0.63, 0.63, 1.0)
|
return (0.63, 0.63, 0.63, 1.0)
|
||||||
|
|
||||||
|
|
||||||
def export_mx_to_file(doc, filepath, *, mx_node_tree=None, is_export_deps=False,
|
def export_to_file(doc, filepath, *, export_textures=False, texture_dir_name='textures',
|
||||||
is_export_textures=False, texture_dir_name='textures',
|
export_deps=False, copy_deps=False):
|
||||||
is_clean_texture_folder=True, is_clean_deps_folders=True):
|
|
||||||
root_dir = Path(filepath).parent
|
root_dir = Path(filepath).parent
|
||||||
|
root_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
if not os.path.isdir(root_dir):
|
if export_textures:
|
||||||
Path(root_dir).mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
if is_export_deps and mx_node_tree:
|
|
||||||
mx_libs_dir = root_dir / MX_LIBS_FOLDER
|
|
||||||
if os.path.isdir(mx_libs_dir) and is_clean_deps_folders:
|
|
||||||
shutil.rmtree(mx_libs_dir)
|
|
||||||
|
|
||||||
# we need to export every deps only once
|
|
||||||
unique_paths = set(node._file_path for node in mx_node_tree.nodes)
|
|
||||||
|
|
||||||
for mtlx_path in unique_paths:
|
|
||||||
# defining paths
|
|
||||||
source_path = MX_LIBS_DIR.parent / mtlx_path
|
|
||||||
full_dest_path = root_dir / mtlx_path
|
|
||||||
rel_dest_path = full_dest_path.relative_to(root_dir / MX_LIBS_FOLDER)
|
|
||||||
dest_path = root_dir / rel_dest_path
|
|
||||||
|
|
||||||
Path(dest_path.parent).mkdir(parents=True, exist_ok=True)
|
|
||||||
shutil.copy(source_path, dest_path)
|
|
||||||
|
|
||||||
mx.prependXInclude(doc, str(rel_dest_path))
|
|
||||||
|
|
||||||
if is_export_textures:
|
|
||||||
texture_dir = root_dir / texture_dir_name
|
texture_dir = root_dir / texture_dir_name
|
||||||
if os.path.isdir(texture_dir) and is_clean_texture_folder:
|
|
||||||
shutil.rmtree(texture_dir)
|
|
||||||
|
|
||||||
image_paths = set()
|
image_paths = set()
|
||||||
|
mx_input_files = (v for v in doc.traverseTree() if isinstance(v, mx.Input) and v.getType() == 'filename')
|
||||||
|
for mx_input in mx_input_files:
|
||||||
|
texture_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
i = 0
|
val = mx_input.getValue()
|
||||||
|
if not val:
|
||||||
input_files = (v for v in doc.traverseTree() if isinstance(v, mx.Input) and v.getType() == 'filename')
|
log.warn(f"Skipping wrong {mx_input.getType()} input value. Expected: path, got {val}")
|
||||||
for mx_input in input_files:
|
|
||||||
if not os.path.isdir(texture_dir):
|
|
||||||
Path(texture_dir).mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
mx_value = mx_input.getValue()
|
|
||||||
if not mx_value:
|
|
||||||
log.warn(f"Skipping wrong {mx_input.getType()} input value. Expected: path, got {mx_value}")
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
source_path = Path(mx_value)
|
source_path = Path(val)
|
||||||
if not os.path.isfile(source_path):
|
if not source_path.is_file():
|
||||||
log.warn("Image is missing", source_path)
|
log.warn("Image is missing", source_path)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if source_path in image_paths:
|
||||||
|
continue
|
||||||
|
|
||||||
dest_path = texture_dir / source_path.name
|
dest_path = texture_dir / source_path.name
|
||||||
|
|
||||||
if source_path not in image_paths:
|
if source_path not in image_paths:
|
||||||
image_paths.update([source_path])
|
image_paths.add(source_path)
|
||||||
|
dest_path = texture_dir / source_path.name
|
||||||
if os.path.isfile(dest_path):
|
|
||||||
i += 1
|
|
||||||
dest_path = texture_dir / f"{source_path.stem}_{i}{source_path.suffix}"
|
|
||||||
else:
|
|
||||||
dest_path = texture_dir / f"{source_path.stem}{source_path.suffix}"
|
|
||||||
|
|
||||||
shutil.copy(source_path, dest_path)
|
shutil.copy(source_path, dest_path)
|
||||||
log(f"Export file {source_path} to {dest_path}: completed successfully")
|
log(f"Export file {source_path} to {dest_path}: completed successfully")
|
||||||
|
|
||||||
rel_dest_path = dest_path.relative_to(root_dir)
|
rel_dest_path = dest_path.relative_to(root_dir)
|
||||||
mx_input.setValue(str(rel_dest_path), mx_input.getType())
|
mx_input.setValue(rel_dest_path.as_posix(), mx_input.getType())
|
||||||
|
|
||||||
mx.writeToXmlFile(doc, filepath)
|
if export_deps:
|
||||||
|
from .nodes import get_mx_node_cls
|
||||||
|
|
||||||
|
deps_files = {get_mx_node_cls(mx_node)[0]._file_path
|
||||||
|
for mx_node in (it for it in doc.traverseTree() if isinstance(it, mx.Node))}
|
||||||
|
|
||||||
|
for deps_file in deps_files:
|
||||||
|
deps_file = Path(deps_file)
|
||||||
|
if copy_deps:
|
||||||
|
rel_path = deps_file.relative_to(deps_file.parent.parent)
|
||||||
|
dest_path = root_dir / rel_path
|
||||||
|
dest_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
shutil.copy(deps_file, dest_path)
|
||||||
|
deps_file = rel_path
|
||||||
|
|
||||||
|
mx.prependXInclude(doc, str(deps_file))
|
||||||
|
|
||||||
|
mx.writeToXmlFile(doc, str(filepath))
|
||||||
log(f"Export MaterialX to {filepath}: completed successfully")
|
log(f"Export MaterialX to {filepath}: completed successfully")
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user