ModelTranslator: dedupe sanitized material names, set alphaIsTransparency for alpha-test textures
This commit is contained in:
@@ -132,7 +132,7 @@ def _channel(pixels, ch):
|
|||||||
return pixels[..., ch if ch is not None else 0]
|
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,避免色彩管理改写数据)。"""
|
"""float32 (h,w,4) -> PNG。写原始值(Non-Color,避免色彩管理改写数据)。"""
|
||||||
import bpy
|
import bpy
|
||||||
h, w = rgba.shape[:2]
|
h, w = rgba.shape[:2]
|
||||||
@@ -146,7 +146,7 @@ def _save_png(path, rgba, srgb_view=False):
|
|||||||
bpy.data.images.remove(img)
|
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 = []
|
warnings = []
|
||||||
maps, consts = _material_maps(mat, warnings)
|
maps, consts = _material_maps(mat, warnings)
|
||||||
tw, th = _target_size(maps, max_size)
|
tw, th = _target_size(maps, max_size)
|
||||||
@@ -192,7 +192,15 @@ def _convert_material(mat, model_name, outdir, max_size):
|
|||||||
else:
|
else:
|
||||||
mix[..., 3] = consts["roughness"]
|
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)))
|
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)))
|
mix_png = os.path.abspath(os.path.join(outdir, "%s_%s_mix.png" % (model_name, sname)))
|
||||||
_save_png(base_png, base)
|
_save_png(base_png, base)
|
||||||
@@ -242,7 +250,9 @@ def main():
|
|||||||
if slot.material and slot.material not in used_mats:
|
if slot.material and slot.material not in used_mats:
|
||||||
used_mats.append(slot.material)
|
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()
|
_strip_textures()
|
||||||
fbx_out = os.path.join(outdir, model_name + ".fbx")
|
fbx_out = os.path.join(outdir, model_name + ".fbx")
|
||||||
@@ -253,5 +263,5 @@ def main():
|
|||||||
ensure_ascii=False))
|
ensure_ascii=False))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__" and "--" in __import__("sys").argv:
|
if __name__ == "__main__" and "--" in sys.argv:
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -44,15 +44,16 @@ def write_unity_assets(outdir, summary, max_size):
|
|||||||
mix_png = os.path.join(outdir, m["mix_png"])
|
mix_png = os.path.join(outdir, m["mix_png"])
|
||||||
base_guid = ua.guid_for(base_png)
|
base_guid = ua.guid_for(base_png)
|
||||||
mix_guid = ua.guid_for(mix_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:
|
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:
|
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))
|
f.write(ua.texture_meta(mix_guid, srgb=False, max_size=max_size))
|
||||||
|
|
||||||
mat_name = "%s_%s" % (summary["model"], m["safe_name"])
|
mat_name = "%s_%s" % (summary["model"], m["safe_name"])
|
||||||
mat_path = os.path.join(outdir, mat_name + ".mat")
|
mat_path = os.path.join(outdir, mat_name + ".mat")
|
||||||
mat_guid = ua.guid_for(mat_path)
|
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:
|
with open(mat_path, "w", encoding="utf-8", newline="\n") as f:
|
||||||
f.write(ua.material_yaml(mat_name, ua.XPBR_SHADER_GUID,
|
f.write(ua.material_yaml(mat_name, ua.XPBR_SHADER_GUID,
|
||||||
base_guid, mix_guid, alpha_test))
|
base_guid, mix_guid, alpha_test))
|
||||||
|
|||||||
@@ -35,6 +35,13 @@ class TestTemplates(unittest.TestCase):
|
|||||||
self.assertIn("maxTextureSize: 2048", on)
|
self.assertIn("maxTextureSize: 2048", on)
|
||||||
self.assertIn("guid: " + "a" * 32, 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):
|
def test_material_yaml_refs_and_keyword(self):
|
||||||
y = ua.material_yaml("tong_wood", "s" * 32, "c" * 32, "d" * 32, alpha_test=True)
|
y = ua.material_yaml("tong_wood", "s" * 32, "c" * 32, "d" * 32, alpha_test=True)
|
||||||
self.assertIn("m_Name: tong_wood", y)
|
self.assertIn("m_Name: tong_wood", y)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ def safe_name(name):
|
|||||||
return re.sub(r"[^0-9A-Za-z_\-]", "_", name).strip("_") or "mat"
|
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
|
return """fileFormatVersion: 2
|
||||||
guid: {guid}
|
guid: {guid}
|
||||||
TextureImporter:
|
TextureImporter:
|
||||||
@@ -88,7 +88,7 @@ TextureImporter:
|
|||||||
spriteBorder: {{x: 0, y: 0, z: 0, w: 0}}
|
spriteBorder: {{x: 0, y: 0, z: 0, w: 0}}
|
||||||
spriteGenerateFallbackPhysicsShape: 1
|
spriteGenerateFallbackPhysicsShape: 1
|
||||||
alphaUsage: 1
|
alphaUsage: 1
|
||||||
alphaIsTransparency: 0
|
alphaIsTransparency: {ait}
|
||||||
spriteTessellationDetail: -1
|
spriteTessellationDetail: -1
|
||||||
textureType: 0
|
textureType: 0
|
||||||
textureShape: 1
|
textureShape: 1
|
||||||
@@ -135,7 +135,8 @@ TextureImporter:
|
|||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
assetBundleVariant:
|
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):
|
def material_yaml(name, shader_guid, base_tex_guid, mix_tex_guid, alpha_test):
|
||||||
|
|||||||
Reference in New Issue
Block a user