From 60c83a3765c936865522c09f5f38ea335be88656 Mon Sep 17 00:00:00 2001 From: ud18010 Date: Wed, 15 Jul 2026 20:28:33 +0800 Subject: [PATCH] =?UTF-8?q?ModelTranslator:=20base=20=E8=B4=B4=E5=9B=BE?= =?UTF-8?q?=E5=86=99=20PNG=20=E5=89=8D=E5=81=9A=20linear->sRGB=20=E7=BC=96?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Blender Image.pixels 对 sRGB 贴图返回线性值,直接写 Non-Color PNG 会偏暗; 现按 Unity sRGB 导入预期编码 RGB,alpha(AO/透明)保持原值。附单元测试。 Co-Authored-By: Claude Opus 4.8 --- Tools/ModelTranslator/bl_convert.py | 16 ++++++++++++- .../ModelTranslator/tests/test_bl_convert.py | 23 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 Tools/ModelTranslator/tests/test_bl_convert.py diff --git a/Tools/ModelTranslator/bl_convert.py b/Tools/ModelTranslator/bl_convert.py index eeef91ff..8d0e8097 100644 --- a/Tools/ModelTranslator/bl_convert.py +++ b/Tools/ModelTranslator/bl_convert.py @@ -33,6 +33,20 @@ def decode_sphere_map(enc01): return np.concatenate([xy * 2.0, (l * 2.0 - 1.0)[..., None]], axis=-1) +def linear_to_srgb(c): + c = np.clip(c, 0.0, 1.0) + return np.where(c <= 0.0031308, c * 12.92, + 1.055 * np.power(c, 1.0 / 2.4) - 0.055) + + +def encode_base_texture_for_png(rgba): + """Base RGB is stored for Unity sRGB import; alpha keeps AO/opacity data.""" + out = np.array(rgba, dtype=np.float32, copy=True) + out[..., :3] = linear_to_srgb(out[..., :3]) + out[..., 3] = np.clip(out[..., 3], 0.0, 1.0) + return out + + # ---------------- 以下仅在 Blender 内执行 ---------------- @@ -316,7 +330,7 @@ def _convert_material(mat, model_name, outdir, max_size, used_snames, src_dir): stem = model_name if sname == model_name else "%s_%s" % (model_name, sname) base_png = os.path.abspath(os.path.join(outdir, "%s_base.png" % stem)) mix_png = os.path.abspath(os.path.join(outdir, "%s_mix.png" % stem)) - _save_png(base_png, base) + _save_png(base_png, encode_base_texture_for_png(base)) _save_png(mix_png, mix) return { diff --git a/Tools/ModelTranslator/tests/test_bl_convert.py b/Tools/ModelTranslator/tests/test_bl_convert.py new file mode 100644 index 00000000..ec737eb3 --- /dev/null +++ b/Tools/ModelTranslator/tests/test_bl_convert.py @@ -0,0 +1,23 @@ +import os +import sys +import unittest + +import numpy as np + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +import bl_convert as bc + + +class TestBaseTextureEncoding(unittest.TestCase): + def test_base_texture_rgb_is_encoded_as_srgb_and_alpha_is_preserved(self): + rgba = np.array([[[0.0, 0.18, 0.5, 0.37]]], dtype=np.float32) + + encoded = bc.encode_base_texture_for_png(rgba) + + expected_rgb = np.array([0.0, 0.461356, 0.735357], dtype=np.float32) + np.testing.assert_allclose(encoded[0, 0, :3], expected_rgb, rtol=0, atol=1e-5) + self.assertAlmostEqual(float(encoded[0, 0, 3]), 0.37, places=6) + + +if __name__ == "__main__": + unittest.main()