2025-12-01
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
from typing import List, Tuple
|
||||
from typing import Dict, List, Tuple
|
||||
import os
|
||||
|
||||
import bpy
|
||||
@@ -57,6 +57,8 @@ LOD_DESCS = {
|
||||
LOD_NAME = "{0} ({1})"
|
||||
LOD_DESCRIPTION_FBX = _t("Import the {0} level of detail (LOD) FBX file")
|
||||
|
||||
PROP_LIBRARY_LINKED = "poliigon_linked"
|
||||
|
||||
|
||||
class POLIIGON_OT_model(Operator):
|
||||
bl_idname = "poliigon.poliigon_model"
|
||||
@@ -223,7 +225,7 @@ class POLIIGON_OT_model(Operator):
|
||||
else:
|
||||
empty = None
|
||||
|
||||
if self.do_use_collection is True:
|
||||
if self.do_use_collection:
|
||||
# Move the objects into a subcollection, and place in scene.
|
||||
if did_fresh_import:
|
||||
# Always create a new collection if did a fresh import.
|
||||
@@ -235,25 +237,22 @@ class POLIIGON_OT_model(Operator):
|
||||
cache_coll.objects.link(_obj)
|
||||
|
||||
# Now add the cache collection to the layer, but unchecked.
|
||||
layer = context.view_layer.active_layer_collection
|
||||
layer.collection.children.link(cache_coll)
|
||||
for _child in layer.children:
|
||||
layer_coll = context.view_layer.active_layer_collection
|
||||
layer_coll.collection.children.link(cache_coll)
|
||||
for _child in layer_coll.children:
|
||||
if _child.collection == cache_coll:
|
||||
_child.exclude = True
|
||||
else:
|
||||
cache_coll = bpy.data.collections.get(asset_name)
|
||||
|
||||
# Now finally add the instance to the scene.
|
||||
if cache_coll:
|
||||
inst = self.create_instance(context, cache_coll, size, lod)
|
||||
# layer = context.view_layer.active_layer_collection
|
||||
# layer.collection.objects.link(inst)
|
||||
else:
|
||||
if cache_coll is None:
|
||||
err = _t("Failed to get new collection to instance")
|
||||
self.report({"ERROR"}, err)
|
||||
return {"CANCELLED"}
|
||||
|
||||
elif not blend_import:
|
||||
# Now finally add the instance to the scene.
|
||||
inst = self.create_instance(context, cache_coll, size, lod)
|
||||
else:
|
||||
# Make sure the objects imported are all part of the same coll.
|
||||
self.append_cleanup(context, empty)
|
||||
|
||||
@@ -282,6 +281,7 @@ class POLIIGON_OT_model(Operator):
|
||||
|
||||
if self.exec_count == 0:
|
||||
cTB.signal_import_asset(asset_id=self.asset_id)
|
||||
cTB.set_first_local_asset()
|
||||
self.exec_count += 1
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -302,7 +302,12 @@ class POLIIGON_OT_model(Operator):
|
||||
break
|
||||
return all_lod_fbxs
|
||||
|
||||
def get_model_data(self, asset_data: AssetData):
|
||||
def get_model_data(
|
||||
self,
|
||||
asset_data: AssetData
|
||||
) -> Tuple[List[str], List[str], str, str]:
|
||||
"""Returns details for Model import from a Model asset."""
|
||||
|
||||
asset_type_data = asset_data.get_type_data()
|
||||
|
||||
# Get the intended material size and LOD import to use.
|
||||
@@ -393,7 +398,7 @@ class POLIIGON_OT_model(Operator):
|
||||
|
||||
return files_project, files_tex, size, lod
|
||||
|
||||
def _load_blend(self, path_proj: str):
|
||||
def _load_blend(self, path_proj: str) -> List[bpy.types.Object]:
|
||||
"""Loads all objects from a .blend file."""
|
||||
|
||||
path_proj_norm = os.path.normpath(path_proj)
|
||||
@@ -412,7 +417,8 @@ class POLIIGON_OT_model(Operator):
|
||||
s = splits[0]
|
||||
return s
|
||||
|
||||
def _reuse_materials(self, imported_objs: List, imported_mats: List):
|
||||
def _reuse_materials(
|
||||
self, imported_objs: List, imported_mats: List) -> None:
|
||||
"""Re-uses previously imported materials after a .blend import"""
|
||||
|
||||
if not self.do_reuse_materials or self.do_link_blend:
|
||||
@@ -481,6 +487,272 @@ class POLIIGON_OT_model(Operator):
|
||||
return _variant
|
||||
return None
|
||||
|
||||
def _run_fresh_import_blend(
|
||||
self,
|
||||
context,
|
||||
path_proj: str,
|
||||
filename_base: str,
|
||||
size: str
|
||||
) -> None:
|
||||
"""Imports from blend files."""
|
||||
|
||||
cTB.logger.debug("POLIIGON_OT_model BLEND IMPORT")
|
||||
filename = filename_base + ".blend"
|
||||
|
||||
if self.do_link_blend and filename in bpy.data.libraries.keys():
|
||||
lib = bpy.data.libraries[filename]
|
||||
if lib[PROP_LIBRARY_LINKED]:
|
||||
linked_objs = []
|
||||
for obj in bpy.data.objects:
|
||||
if obj.library == lib:
|
||||
linked_objs.append(obj)
|
||||
|
||||
imported_objs = []
|
||||
for obj in linked_objs:
|
||||
imported_objs.append(obj.copy())
|
||||
else:
|
||||
imported_objs = self._load_blend(path_proj)
|
||||
else:
|
||||
imported_objs = self._load_blend(path_proj)
|
||||
|
||||
if filename in bpy.data.libraries.keys():
|
||||
lib = bpy.data.libraries[filename]
|
||||
lib[PROP_LIBRARY_LINKED] = self.do_link_blend
|
||||
|
||||
for obj in context.view_layer.objects:
|
||||
obj.select_set(False)
|
||||
layer = context.view_layer.active_layer_collection
|
||||
imported_mats = []
|
||||
for obj in imported_objs:
|
||||
if obj is None:
|
||||
continue
|
||||
obj_copy = obj.copy()
|
||||
layer.collection.objects.link(obj_copy)
|
||||
obj_copy.select_set(True)
|
||||
if obj_copy.active_material is None:
|
||||
pass
|
||||
elif obj_copy.active_material not in imported_mats:
|
||||
imported_mats.append(obj_copy.active_material)
|
||||
|
||||
files_dict = {}
|
||||
asset_type_data = self.asset_data.get_type_data()
|
||||
asset_type_data.get_files(files_dict)
|
||||
asset_files = list(files_dict.keys())
|
||||
replace_tex_size(
|
||||
imported_mats,
|
||||
asset_files,
|
||||
size,
|
||||
self.do_link_blend
|
||||
)
|
||||
self._reuse_materials(imported_objs, imported_mats)
|
||||
|
||||
def _run_fresh_import_fbx(self, path_proj: str) -> bool:
|
||||
"""Imports from FBX files."""
|
||||
|
||||
cTB.logger.debug("POLIIGON_OT_model FBX IMPORT")
|
||||
if "fbx" not in dir(bpy.ops.import_scene):
|
||||
try:
|
||||
bpy.ops.preferences.addon_enable(module="io_scene_fbx")
|
||||
self.report(
|
||||
{"INFO"},
|
||||
_t("FBX importer addon enabled for import")
|
||||
)
|
||||
except RuntimeError:
|
||||
self.report(
|
||||
{"ERROR"},
|
||||
_t("Built-in FBX importer could not be found, "
|
||||
"check Blender install")
|
||||
)
|
||||
return False
|
||||
try:
|
||||
# Note on use_custom_normals parameter:
|
||||
# It always defaulted to True. But in Blender 4.0+
|
||||
# it started to cause issues.
|
||||
# Mateusz sync'ed with Stephen and recommended to turn it
|
||||
# off regardless of Blender version.
|
||||
bpy.ops.import_scene.fbx(filepath=path_proj,
|
||||
axis_up="-Z",
|
||||
use_custom_normals=False)
|
||||
except Exception as e:
|
||||
self.report({"ERROR"},
|
||||
_t("FBX importer exception:") + str(e))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def _run_fresh_import_create_materials(
|
||||
self,
|
||||
*,
|
||||
path_proj: str,
|
||||
filename_base: str,
|
||||
imported_proj: List[str],
|
||||
files_tex: List[str],
|
||||
objs_from_file: List[bpy.types.Object],
|
||||
dict_mats_imported: Dict[str, bpy.types.Material],
|
||||
size: str,
|
||||
lod: str
|
||||
) -> None:
|
||||
"""Creates materials after successful FBX import."""
|
||||
|
||||
asset_name = self.asset_data.asset_name
|
||||
|
||||
for _mesh in objs_from_file:
|
||||
if _mesh.type == "EMPTY":
|
||||
continue
|
||||
|
||||
name_mat_imported = ""
|
||||
if _mesh.active_material is not None:
|
||||
name_mat_imported = _mesh.active_material.name
|
||||
|
||||
# Note: Of course the check if "_mat" is contained could be
|
||||
# written in one line. But I wouldn't consider "_mat"
|
||||
# unlikely in arbitrary filenames. Thus I chose to
|
||||
# explicitly compare for "_mat" at the end and
|
||||
# additionally check if "_mat_" is contained, in order
|
||||
# to at least reduce the chance of false positives a bit.
|
||||
name_mat_imported_lower = name_mat_imported.lower()
|
||||
name_tex_remastered = ""
|
||||
name_tex_on_obj = ""
|
||||
ends_remastered = name_mat_imported_lower.endswith("_mat")
|
||||
contains_remastered = "_mat_" in name_mat_imported_lower
|
||||
if ends_remastered or contains_remastered:
|
||||
pos_remastered = name_mat_imported_lower.rfind("_mat", 1)
|
||||
name_tex_remastered = name_mat_imported[:pos_remastered]
|
||||
else:
|
||||
name_tex_on_obj = name_mat_imported.split("_")[0]
|
||||
|
||||
name_mesh_base = _mesh.name.split(".")[0].split("_")[0]
|
||||
|
||||
variant_mesh = self.f_GetVar(_mesh.name)
|
||||
variant_name = variant_mesh
|
||||
if variant_mesh is None:
|
||||
# This is a fallback for models,
|
||||
# where the object name does not contain a variant indicator.
|
||||
# As None is covered explicitly in the loop below,
|
||||
# this should do no harm.
|
||||
variant_mesh = "VAR1"
|
||||
variant_name = ""
|
||||
|
||||
name_mat = name_mesh_base
|
||||
files_tex_filtered = []
|
||||
if len(name_tex_remastered) > 0:
|
||||
# Remastered textures
|
||||
files_tex_filtered = [
|
||||
_file
|
||||
for _file in files_tex
|
||||
if os.path.basename(_file).startswith(
|
||||
name_tex_remastered)
|
||||
]
|
||||
name_mat = name_mat_imported
|
||||
else:
|
||||
for vCheck in [name_mesh_base,
|
||||
filename_base.split("_")[0],
|
||||
asset_name,
|
||||
name_tex_on_obj]:
|
||||
files_tex_filtered = [
|
||||
_file
|
||||
for _file in files_tex
|
||||
if os.path.basename(_file).startswith(vCheck)
|
||||
if self.f_GetVar(f_FName(_file)) in [None,
|
||||
variant_mesh]
|
||||
]
|
||||
name_mat = vCheck
|
||||
if len(files_tex_filtered) > 0:
|
||||
break
|
||||
|
||||
if len(files_tex_filtered) == 0:
|
||||
err = f"No Textures found for: {self.asset_id} {_mesh.name}"
|
||||
reporting.capture_message(
|
||||
"model_texture_missing", err, "info")
|
||||
continue
|
||||
|
||||
name_mat += f"_{size}"
|
||||
|
||||
if size not in name_mat:
|
||||
name_mat += f"_{size}"
|
||||
|
||||
if variant_name != "":
|
||||
name_mat += f"_{variant_name}"
|
||||
|
||||
# TODO(Andreas): Not sure, why these lines are commented out.
|
||||
# Looks reasonable to me.
|
||||
# if name_mat in bpy.data.materials and self.do_reuse_materials:
|
||||
# mat = bpy.data.materials[name_mat]
|
||||
# el
|
||||
# TODO(Andreas): Not sure, this should also be depending on
|
||||
# self.do_reuse_materials?
|
||||
if name_mat in dict_mats_imported.keys():
|
||||
# Already built in previous iteration
|
||||
mat = dict_mats_imported[name_mat]
|
||||
else:
|
||||
mat = cTB.mat_import.import_material(
|
||||
asset_data=self.asset_data,
|
||||
do_apply=False,
|
||||
workflow="METALNESS",
|
||||
size=size,
|
||||
size_bg=None,
|
||||
lod=lod,
|
||||
variant=variant_name if variant_name != "" else None,
|
||||
name_material=name_mat,
|
||||
name_mesh=name_mesh_base,
|
||||
ref_objs=None,
|
||||
projection="UV",
|
||||
use_16bit=True,
|
||||
mode_disp="NORMAL", # We never want model dispalcement
|
||||
translate_x=0.0,
|
||||
translate_y=0.0,
|
||||
scale=1.0,
|
||||
global_rotation=0.0,
|
||||
aspect_ratio=1.0,
|
||||
displacement=0.0,
|
||||
keep_unused_tex_nodes=False,
|
||||
reuse_existing=self.do_reuse_materials
|
||||
)
|
||||
if mat is None:
|
||||
msg = f"{self.asset_id}: Failed to build matrial: {name_mat}"
|
||||
reporting.capture_message(
|
||||
"could_not_create_fbx_mat", msg, "error")
|
||||
self.report(
|
||||
{"ERROR"}, _t("Material could not be created."))
|
||||
imported_proj.remove(path_proj)
|
||||
break
|
||||
|
||||
dict_mats_imported[name_mat] = mat
|
||||
|
||||
# This sequence is important!
|
||||
# 1) Setting the material slot to None
|
||||
# 2) Changing the link mode
|
||||
# 3) Assigning our generated material
|
||||
# Any other order of these statements will get us into trouble
|
||||
# one way or another.
|
||||
_mesh.active_material = None
|
||||
if len(_mesh.material_slots) > 0:
|
||||
_mesh.material_slots[0].link = "OBJECT"
|
||||
_mesh.active_material = mat
|
||||
|
||||
if variant_mesh is not None:
|
||||
if len(_mesh.material_slots) == 0:
|
||||
_mesh.data.materials.append(mat)
|
||||
else:
|
||||
_mesh.material_slots[0].link = "OBJECT"
|
||||
_mesh.material_slots[0].material = mat
|
||||
_mesh.material_slots[0].link = "OBJECT"
|
||||
|
||||
# Ensure we can identify the mesh & LOD even on name change.
|
||||
# TODO(Andreas): Remove old properties?
|
||||
_mesh.poliigon = f"Models;{asset_name}"
|
||||
if lod is not None:
|
||||
_mesh.poliigon_lod = lod
|
||||
self.set_poliigon_props_model(_mesh, lod)
|
||||
|
||||
# Finally try to remove the originally imported materials
|
||||
if name_mat_imported not in bpy.data.materials:
|
||||
continue
|
||||
mat_imported = bpy.data.materials[name_mat_imported]
|
||||
if mat_imported.users == 0:
|
||||
mat_imported.user_clear()
|
||||
bpy.data.materials.remove(mat_imported)
|
||||
|
||||
def run_fresh_import(self,
|
||||
context,
|
||||
project_files: List[str],
|
||||
@@ -503,8 +775,6 @@ class POLIIGON_OT_model(Operator):
|
||||
Tuple[3] - True, if an error occurred during FBX loading
|
||||
"""
|
||||
|
||||
PROP_LIBRARY_LINKED = "poliigon_linked"
|
||||
|
||||
asset_name = self.asset_data.asset_name
|
||||
|
||||
meshes_all = []
|
||||
@@ -518,7 +788,8 @@ class POLIIGON_OT_model(Operator):
|
||||
err = _t("Couldn't load project file: {0} {1}").format(
|
||||
asset_name, path_proj)
|
||||
self.report({"ERROR"}, err)
|
||||
err = f"Couldn't load project file: {self.asset_id} {path_proj}"
|
||||
err = ("Couldn't load project file: "
|
||||
f"{self.asset_id} {path_proj}")
|
||||
reporting.capture_message("model_fbx_missing", err, "info")
|
||||
continue
|
||||
|
||||
@@ -526,91 +797,12 @@ class POLIIGON_OT_model(Operator):
|
||||
|
||||
ext_proj = f_FExt(path_proj)
|
||||
if ext_proj == ".blend":
|
||||
cTB.logger.debug("POLIIGON_OT_model BLEND IMPORT")
|
||||
filename = filename_base + ".blend"
|
||||
|
||||
if self.do_link_blend and filename in bpy.data.libraries.keys():
|
||||
lib = bpy.data.libraries[filename]
|
||||
if lib[PROP_LIBRARY_LINKED]:
|
||||
linked_objs = []
|
||||
for obj in bpy.data.objects:
|
||||
if obj.library == lib:
|
||||
linked_objs.append(obj)
|
||||
|
||||
imported_objs = []
|
||||
for obj in linked_objs:
|
||||
imported_objs.append(obj.copy())
|
||||
else:
|
||||
imported_objs = self._load_blend(path_proj)
|
||||
else:
|
||||
imported_objs = self._load_blend(path_proj)
|
||||
|
||||
if filename in bpy.data.libraries.keys():
|
||||
lib = bpy.data.libraries[filename]
|
||||
lib[PROP_LIBRARY_LINKED] = self.do_link_blend
|
||||
|
||||
for obj in context.view_layer.objects:
|
||||
obj.select_set(False)
|
||||
layer = context.view_layer.active_layer_collection
|
||||
imported_mats = []
|
||||
for obj in imported_objs:
|
||||
if obj is None:
|
||||
continue
|
||||
obj_copy = obj.copy()
|
||||
layer.collection.objects.link(obj_copy)
|
||||
obj_copy.select_set(True)
|
||||
if obj_copy.active_material is None:
|
||||
pass
|
||||
elif obj_copy.active_material not in imported_mats:
|
||||
imported_mats.append(obj_copy.active_material)
|
||||
|
||||
files_dict = {}
|
||||
asset_type_data = self.asset_data.get_type_data()
|
||||
asset_type_data.get_files(files_dict)
|
||||
asset_files = list(files_dict.keys())
|
||||
replace_tex_size(
|
||||
imported_mats,
|
||||
asset_files,
|
||||
size,
|
||||
self.do_link_blend
|
||||
)
|
||||
self._reuse_materials(imported_objs, imported_mats)
|
||||
|
||||
self._run_fresh_import_blend(
|
||||
context, path_proj, filename_base, size)
|
||||
blend_import = True
|
||||
else:
|
||||
cTB.logger.debug("POLIIGON_OT_model FBX IMPORT")
|
||||
if "fbx" not in dir(bpy.ops.import_scene):
|
||||
try:
|
||||
bpy.ops.preferences.addon_enable(module="io_scene_fbx")
|
||||
self.report(
|
||||
{"INFO"},
|
||||
_t("FBX importer addon enabled for import")
|
||||
)
|
||||
except RuntimeError:
|
||||
self.report(
|
||||
{"ERROR"},
|
||||
_t("Built-in FBX importer could not be found, check Blender install")
|
||||
)
|
||||
did_full_import = False
|
||||
meshes_all = []
|
||||
blend_import = False
|
||||
fbx_error = True
|
||||
return (did_full_import,
|
||||
meshes_all,
|
||||
blend_import,
|
||||
fbx_error)
|
||||
try:
|
||||
# Note on use_custom_normals parameter:
|
||||
# It always defaulted to True. But in Blender 4.0+
|
||||
# it started to cause issues.
|
||||
# Mateusz sync'ed with Stephen and recommended to turn it
|
||||
# off regardless of Blender version.
|
||||
bpy.ops.import_scene.fbx(filepath=path_proj,
|
||||
axis_up="-Z",
|
||||
use_custom_normals=False)
|
||||
except Exception as e:
|
||||
self.report({"ERROR"},
|
||||
_t("FBX importer exception:") + str(e))
|
||||
import_ok = self._run_fresh_import_fbx(path_proj)
|
||||
if not import_ok:
|
||||
did_full_import = False
|
||||
meshes_all = []
|
||||
blend_import = False
|
||||
@@ -621,13 +813,13 @@ class POLIIGON_OT_model(Operator):
|
||||
fbx_error)
|
||||
|
||||
imported_proj.append(path_proj)
|
||||
vMeshes = [_obj for _obj in list(context.scene.objects)
|
||||
if _obj not in list_objs_before]
|
||||
objs_from_file = [_obj for _obj in list(context.scene.objects)
|
||||
if _obj not in list_objs_before]
|
||||
|
||||
meshes_all += vMeshes
|
||||
meshes_all += objs_from_file
|
||||
|
||||
if ext_proj == ".blend":
|
||||
for _mesh in vMeshes:
|
||||
for _mesh in objs_from_file:
|
||||
# Ensure we can identify the mesh & LOD even on name change
|
||||
# TODO(Andreas): Remove old properties?
|
||||
_mesh.poliigon = f"Models;{asset_name}"
|
||||
@@ -636,160 +828,15 @@ class POLIIGON_OT_model(Operator):
|
||||
self.set_poliigon_props_model(_mesh, lod)
|
||||
continue
|
||||
|
||||
for _mesh in vMeshes:
|
||||
if _mesh.type == "EMPTY":
|
||||
continue
|
||||
|
||||
name_mat_imported = ""
|
||||
if _mesh.active_material is not None:
|
||||
name_mat_imported = _mesh.active_material.name
|
||||
|
||||
# Note: Of course the check if "_mat" is contained could be
|
||||
# written in one line. But I wouldn't consider "_mat"
|
||||
# unlikely in arbitrary filenames. Thus I chose to
|
||||
# explicitly compare for "_mat" at the end and
|
||||
# additionally check if "_mat_" is contained, in order
|
||||
# to at least reduce the chance of false positives a bit.
|
||||
name_mat_imported_lower = name_mat_imported.lower()
|
||||
name_tex_remastered = ""
|
||||
name_tex_on_obj = ""
|
||||
ends_remastered = name_mat_imported_lower.endswith("_mat")
|
||||
contains_remastered = "_mat_" in name_mat_imported_lower
|
||||
if ends_remastered or contains_remastered:
|
||||
pos_remastered = name_mat_imported_lower.rfind("_mat", 1)
|
||||
name_tex_remastered = name_mat_imported[:pos_remastered]
|
||||
else:
|
||||
name_tex_on_obj = name_mat_imported.split("_")[0]
|
||||
|
||||
name_mesh_base = _mesh.name.split(".")[0].split("_")[0]
|
||||
|
||||
variant_mesh = self.f_GetVar(_mesh.name)
|
||||
variant_name = variant_mesh
|
||||
if variant_mesh is None:
|
||||
# This is a fallback for models,
|
||||
# where the object name does not contain a variant indicator.
|
||||
# As None is covered explicitly in the loop below,
|
||||
# this should do no harm.
|
||||
variant_mesh = "VAR1"
|
||||
variant_name = ""
|
||||
|
||||
name_mat = name_mesh_base
|
||||
files_tex_filtered = []
|
||||
if len(name_tex_remastered) > 0:
|
||||
# Remastered textures
|
||||
files_tex_filtered = [
|
||||
_file
|
||||
for _file in files_tex
|
||||
if os.path.basename(_file).startswith(
|
||||
name_tex_remastered)
|
||||
]
|
||||
name_mat = name_mat_imported
|
||||
else:
|
||||
for vCheck in [name_mesh_base,
|
||||
filename_base.split("_")[0],
|
||||
asset_name,
|
||||
name_tex_on_obj]:
|
||||
files_tex_filtered = [
|
||||
_file
|
||||
for _file in files_tex
|
||||
if os.path.basename(_file).startswith(vCheck)
|
||||
if self.f_GetVar(f_FName(_file)) in [None,
|
||||
variant_mesh]
|
||||
]
|
||||
name_mat = vCheck
|
||||
if len(files_tex_filtered) > 0:
|
||||
break
|
||||
|
||||
if len(files_tex_filtered) == 0:
|
||||
err = f"No Textures found for: {self.asset_id} {_mesh.name}"
|
||||
reporting.capture_message(
|
||||
"model_texture_missing", err, "info")
|
||||
continue
|
||||
|
||||
name_mat += f"_{size}"
|
||||
|
||||
if size not in name_mat:
|
||||
name_mat += f"_{size}"
|
||||
|
||||
if variant_name != "":
|
||||
name_mat += f"_{variant_name}"
|
||||
|
||||
# TODO(Andreas): Not sure, why these lines are commented out.
|
||||
# Looks reasonable to me.
|
||||
# if name_mat in bpy.data.materials and self.do_reuse_materials:
|
||||
# mat = bpy.data.materials[name_mat]
|
||||
# el
|
||||
# TODO(Andreas): Not sure, this should also be dependening on self.do_reuse_materials?
|
||||
if name_mat in dict_mats_imported.keys():
|
||||
# Already built in previous iteration
|
||||
mat = dict_mats_imported[name_mat]
|
||||
else:
|
||||
mat = cTB.mat_import.import_material(
|
||||
asset_data=self.asset_data,
|
||||
do_apply=False,
|
||||
workflow="METALNESS",
|
||||
size=size,
|
||||
size_bg=None,
|
||||
lod=lod,
|
||||
variant=variant_name if variant_name != "" else None,
|
||||
name_material=name_mat,
|
||||
name_mesh=name_mesh_base,
|
||||
ref_objs=None,
|
||||
projection="UV",
|
||||
use_16bit=True,
|
||||
mode_disp="NORMAL", # We never want model dispalcement
|
||||
translate_x=0.0,
|
||||
translate_y=0.0,
|
||||
scale=1.0,
|
||||
global_rotation=0.0,
|
||||
aspect_ratio=1.0,
|
||||
displacement=0.0,
|
||||
keep_unused_tex_nodes=False,
|
||||
reuse_existing=self.do_reuse_materials
|
||||
)
|
||||
if mat is None:
|
||||
msg = f"{self.asset_id}: Failed to build matrial: {name_mat}"
|
||||
reporting.capture_message(
|
||||
"could_not_create_fbx_mat", msg, "error")
|
||||
self.report(
|
||||
{"ERROR"}, _t("Material could not be created."))
|
||||
imported_proj.remove(path_proj)
|
||||
break
|
||||
|
||||
dict_mats_imported[name_mat] = mat
|
||||
|
||||
# This sequence is important!
|
||||
# 1) Setting the material slot to None
|
||||
# 2) Changing the link mode
|
||||
# 3) Assigning our generated material
|
||||
# Any other order of these statements will get us into trouble
|
||||
# one way or another.
|
||||
_mesh.active_material = None
|
||||
if len(_mesh.material_slots) > 0:
|
||||
_mesh.material_slots[0].link = "OBJECT"
|
||||
_mesh.active_material = mat
|
||||
|
||||
if variant_mesh is not None:
|
||||
if len(_mesh.material_slots) == 0:
|
||||
_mesh.data.materials.append(mat)
|
||||
else:
|
||||
_mesh.material_slots[0].link = "OBJECT"
|
||||
_mesh.material_slots[0].material = mat
|
||||
_mesh.material_slots[0].link = "OBJECT"
|
||||
|
||||
# Ensure we can identify the mesh & LOD even on name change.
|
||||
# TODO(Andreas): Remove old properties?
|
||||
_mesh.poliigon = f"Models;{asset_name}"
|
||||
if lod is not None:
|
||||
_mesh.poliigon_lod = lod
|
||||
self.set_poliigon_props_model(_mesh, lod)
|
||||
|
||||
# Finally try to remove the originally imported materials
|
||||
if name_mat_imported in bpy.data.materials:
|
||||
mat_imported = bpy.data.materials[name_mat_imported]
|
||||
if mat_imported.users == 0:
|
||||
mat_imported.user_clear()
|
||||
bpy.data.materials.remove(mat_imported)
|
||||
self._run_fresh_import_create_materials(
|
||||
path_proj=path_proj,
|
||||
filename_base=filename_base,
|
||||
imported_proj=imported_proj,
|
||||
files_tex=files_tex,
|
||||
objs_from_file=objs_from_file,
|
||||
dict_mats_imported=dict_mats_imported,
|
||||
size=size,
|
||||
lod=lod)
|
||||
|
||||
# There could have been multiple FBXs, consider fully imported
|
||||
# for user-popup reporting if all FBX files imported.
|
||||
@@ -852,7 +899,8 @@ class POLIIGON_OT_model(Operator):
|
||||
|
||||
return empty
|
||||
|
||||
def create_instance(self, context, coll, size, lod):
|
||||
def create_instance(
|
||||
self, context, coll, size: str, lod: str) -> bpy.types.Object:
|
||||
"""Creates an instance of an existing collection int he active view."""
|
||||
|
||||
asset_name = self.asset_data.asset_name
|
||||
@@ -861,8 +909,8 @@ class POLIIGON_OT_model(Operator):
|
||||
inst = bpy.data.objects.new(name=inst_name, object_data=None)
|
||||
inst.instance_collection = coll
|
||||
inst.instance_type = "COLLECTION"
|
||||
lc = context.view_layer.active_layer_collection
|
||||
lc.collection.objects.link(inst)
|
||||
layer_coll = context.view_layer.active_layer_collection
|
||||
layer_coll.collection.objects.link(inst)
|
||||
inst.location = context.scene.cursor.location
|
||||
inst.empty_display_size = 0.01
|
||||
|
||||
@@ -873,11 +921,12 @@ class POLIIGON_OT_model(Operator):
|
||||
context.view_layer.objects.active = inst
|
||||
return inst
|
||||
|
||||
def append_cleanup(self, context, root_empty):
|
||||
def append_cleanup(self, context, root_empty: bpy.types.Object) -> None:
|
||||
"""Performs selection and placement cleanup after an import/append."""
|
||||
|
||||
if not root_empty:
|
||||
cTB.logger.error("root_empty was not a valid object, exiting cleanup")
|
||||
if root_empty is None:
|
||||
cTB.logger.error(
|
||||
"root_empty was not a valid object, exiting cleanup")
|
||||
return
|
||||
|
||||
# Set empty location
|
||||
|
||||
Reference in New Issue
Block a user