From 0d14980a76625f0a100221e4f3ed77b4662606ae Mon Sep 17 00:00:00 2001 From: MelekTaus Moribundus Date: Thu, 2 Jul 2026 16:23:37 +0200 Subject: [PATCH] Fix maps never binding due to partial-class static init order MapPropIds (in MeshPainter.Backend.cs) referenced the *Id fields from the MeshPainter.cs partial in its field initializer. Static field-initializer order across partial-class files is unspecified in C#; after the script reorg the composite array initialized before the *Id fields and captured 0 for every property id. HasProperty(0) is always false, so AssignMapTexture bound no maps at all -> the shader fell back to its white default textures, making every fresh avatar fully glossy (smoothness 1) and emissive. Build MapPropIds lazily on first access (runtime, after all static initializers) so the file order no longer matters. The per-stroke allocation savings are preserved; only a single null-check per call is added. Co-Authored-By: Claude Opus 4.8 --- .../Scripts/Components/MeshPainter/MeshPainter.Backend.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Assets/Scripts/Components/MeshPainter/MeshPainter.Backend.cs b/Assets/Scripts/Components/MeshPainter/MeshPainter.Backend.cs index 4de395b..74db91d 100644 --- a/Assets/Scripts/Components/MeshPainter/MeshPainter.Backend.cs +++ b/Assets/Scripts/Components/MeshPainter/MeshPainter.Backend.cs @@ -93,7 +93,12 @@ public partial class MeshPainter // Material slots per map, as pre-hashed IDs (this runs per stroke end - no per-call allocations). // MSO: one mask map drives three URP slots: _MetallicGlossMap (R/A) + _OcclusionMap (G) + // _ParallaxMap (G = occlusion reused as a 0.5-centred height for parallax/relief). - private static readonly int[][] MapPropIds = + // Built lazily on first use (runtime): the *Id fields live in the MeshPainter.cs partial and the + // static field-initializer order ACROSS partial files is unspecified - a plain field initializer + // here can run first and capture 0 for every id, so HasProperty(0) fails and no map ever binds + // (white defaults -> full-glossy + emissive). Deferring to first access sidesteps that ordering. + private static int[][] _mapPropIds; + private static int[][] MapPropIds => _mapPropIds ??= new[] { new[] { BaseMapId, MainTexId }, // MAP_ALBEDO new[] { MetallicGlossMapId, OcclusionMapId, ParallaxMapId }, // MAP_MSO