From 0b068dbaa0db62f18b938538e2d56705b62ea678 Mon Sep 17 00:00:00 2001 From: ud18010 Date: Wed, 15 Jul 2026 12:00:50 +0800 Subject: [PATCH] ModelTranslator: dedupe sanitized material names, set alphaIsTransparency for alpha-test textures --- Tools/ModelTranslator/bl_convert.py | 20 ++++++++++++++----- Tools/ModelTranslator/model_translator.py | 5 +++-- .../tests/test_unity_assets.py | 7 +++++++ Tools/ModelTranslator/unity_assets.py | 7 ++++--- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Tools/ModelTranslator/bl_convert.py b/Tools/ModelTranslator/bl_convert.py index b0fa02d2..42f0604e 100644 --- a/Tools/ModelTranslator/bl_convert.py +++ b/Tools/ModelTranslator/bl_convert.py @@ -132,7 +132,7 @@ def _channel(pixels, ch): return pixels[..., ch if ch is not None else 0] -def _save_png(path, rgba, srgb_view=False): +def _save_png(path, rgba): """float32 (h,w,4) -> PNG。写原始值(Non-Color,避免色彩管理改写数据)。""" import bpy h, w = rgba.shape[:2] @@ -146,7 +146,7 @@ def _save_png(path, rgba, srgb_view=False): bpy.data.images.remove(img) -def _convert_material(mat, model_name, outdir, max_size): +def _convert_material(mat, model_name, outdir, max_size, used_snames): warnings = [] maps, consts = _material_maps(mat, warnings) tw, th = _target_size(maps, max_size) @@ -192,7 +192,15 @@ def _convert_material(mat, model_name, outdir, max_size): else: mix[..., 3] = consts["roughness"] - sname = safe_name(mat.name) + # 中文等非 ASCII 材质名会同样退化(如都变 "mat"),加序号防止互相覆盖 + sname = base_sname = safe_name(mat.name) + n = 1 + while sname in used_snames: + n += 1 + sname = "%s_%d" % (base_sname, n) + used_snames.add(sname) + if sname != base_sname: + warnings.append("材质名 %s 清洗后与其它材质重名,输出改用 %s" % (mat.name, sname)) base_png = os.path.abspath(os.path.join(outdir, "%s_%s_base.png" % (model_name, sname))) mix_png = os.path.abspath(os.path.join(outdir, "%s_%s_mix.png" % (model_name, sname))) _save_png(base_png, base) @@ -242,7 +250,9 @@ def main(): if slot.material and slot.material not in used_mats: used_mats.append(slot.material) - results = [_convert_material(m, model_name, outdir, max_size) for m in used_mats] + used_snames = set() + results = [_convert_material(m, model_name, outdir, max_size, used_snames) + for m in used_mats] _strip_textures() fbx_out = os.path.join(outdir, model_name + ".fbx") @@ -253,5 +263,5 @@ def main(): ensure_ascii=False)) -if __name__ == "__main__" and "--" in __import__("sys").argv: +if __name__ == "__main__" and "--" in sys.argv: main() diff --git a/Tools/ModelTranslator/model_translator.py b/Tools/ModelTranslator/model_translator.py index 4bf50045..168a88ed 100644 --- a/Tools/ModelTranslator/model_translator.py +++ b/Tools/ModelTranslator/model_translator.py @@ -44,15 +44,16 @@ def write_unity_assets(outdir, summary, max_size): mix_png = os.path.join(outdir, m["mix_png"]) base_guid = ua.guid_for(base_png) mix_guid = ua.guid_for(mix_png) + alpha_test = m["alpha_mode"] == "transparency" with open(base_png + ".meta", "w", encoding="utf-8", newline="\n") as f: - f.write(ua.texture_meta(base_guid, srgb=True, max_size=max_size)) + f.write(ua.texture_meta(base_guid, srgb=True, max_size=max_size, + alpha_is_transparency=alpha_test)) with open(mix_png + ".meta", "w", encoding="utf-8", newline="\n") as f: f.write(ua.texture_meta(mix_guid, srgb=False, max_size=max_size)) mat_name = "%s_%s" % (summary["model"], m["safe_name"]) mat_path = os.path.join(outdir, mat_name + ".mat") mat_guid = ua.guid_for(mat_path) - alpha_test = m["alpha_mode"] == "transparency" with open(mat_path, "w", encoding="utf-8", newline="\n") as f: f.write(ua.material_yaml(mat_name, ua.XPBR_SHADER_GUID, base_guid, mix_guid, alpha_test)) diff --git a/Tools/ModelTranslator/tests/test_unity_assets.py b/Tools/ModelTranslator/tests/test_unity_assets.py index 505abc77..cb32fec3 100644 --- a/Tools/ModelTranslator/tests/test_unity_assets.py +++ b/Tools/ModelTranslator/tests/test_unity_assets.py @@ -35,6 +35,13 @@ class TestTemplates(unittest.TestCase): self.assertIn("maxTextureSize: 2048", on) self.assertIn("guid: " + "a" * 32, on) + def test_texture_meta_alpha_is_transparency(self): + default = ua.texture_meta("a" * 32, srgb=True, max_size=2048) + ait = ua.texture_meta("a" * 32, srgb=True, max_size=2048, + alpha_is_transparency=True) + self.assertIn("alphaIsTransparency: 0", default) + self.assertIn("alphaIsTransparency: 1", ait) + def test_material_yaml_refs_and_keyword(self): y = ua.material_yaml("tong_wood", "s" * 32, "c" * 32, "d" * 32, alpha_test=True) self.assertIn("m_Name: tong_wood", y) diff --git a/Tools/ModelTranslator/unity_assets.py b/Tools/ModelTranslator/unity_assets.py index 93e006e7..e7797f50 100644 --- a/Tools/ModelTranslator/unity_assets.py +++ b/Tools/ModelTranslator/unity_assets.py @@ -33,7 +33,7 @@ def safe_name(name): return re.sub(r"[^0-9A-Za-z_\-]", "_", name).strip("_") or "mat" -def texture_meta(guid, srgb, max_size): +def texture_meta(guid, srgb, max_size, alpha_is_transparency=False): return """fileFormatVersion: 2 guid: {guid} TextureImporter: @@ -88,7 +88,7 @@ TextureImporter: spriteBorder: {{x: 0, y: 0, z: 0, w: 0}} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 - alphaIsTransparency: 0 + alphaIsTransparency: {ait} spriteTessellationDetail: -1 textureType: 0 textureShape: 1 @@ -135,7 +135,8 @@ TextureImporter: userData: assetBundleName: assetBundleVariant: -""".format(guid=guid, srgb=1 if srgb else 0, max_size=max_size) +""".format(guid=guid, srgb=1 if srgb else 0, max_size=max_size, + ait=1 if alpha_is_transparency else 0) def material_yaml(name, shader_guid, base_tex_guid, mix_tex_guid, alpha_test):