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()