diff --git a/Assets/Scripts/Components/Concealment/ConcealmentVolume.cs b/Assets/Scripts/Components/Concealment/ConcealmentVolume.cs index 820fe4f..e694129 100644 --- a/Assets/Scripts/Components/Concealment/ConcealmentVolume.cs +++ b/Assets/Scripts/Components/Concealment/ConcealmentVolume.cs @@ -18,6 +18,8 @@ using UnityEngine; [DisallowMultipleComponent] public class ConcealmentVolume : MonoBehaviour { + static readonly Color gizmoColor = new(0.2f, 0.6f, 1f, 0.35f); + public enum BakeMethod { WindingNumberOrFloodFill, WindingNumberOnly, FloodFillOnly } [Header("Bake settings")] @@ -30,10 +32,6 @@ public class ConcealmentVolume : MonoBehaviour [SerializeField] private BakeMethod method = BakeMethod.WindingNumberOrFloodFill; - [Header("Debug")] - [SerializeField] private bool drawBakedGizmos; - [SerializeField] private Color gizmoColor = new Color(0.2f, 0.6f, 1f, 0.35f); - // --- Baked data (local space) --- [SerializeField, HideInInspector] private Vector3 origin; // local min corner of the grid [SerializeField, HideInInspector] private float voxelSize; @@ -242,7 +240,7 @@ public class ConcealmentVolume : MonoBehaviour private void OnDrawGizmosSelected() { - if (!drawBakedGizmos || !HasBake) return; + if (!HasBake || UnityEditor.Selection.activeTransform != transform) return; Gizmos.color = gizmoColor; Gizmos.matrix = transform.localToWorldMatrix; Vector3 cube = Vector3.one * (voxelSize * 0.9f); diff --git a/Assets/Scripts/Components/MeshPainter/MeshPainter.Pick.cs b/Assets/Scripts/Components/MeshPainter/MeshPainter.Pick.cs index b2e28c2..c8a1f22 100644 --- a/Assets/Scripts/Components/MeshPainter/MeshPainter.Pick.cs +++ b/Assets/Scripts/Components/MeshPainter/MeshPainter.Pick.cs @@ -1,5 +1,6 @@ using System; using UnityEngine; +using UnityEngine.Rendering; public partial class MeshPainter { @@ -206,38 +207,63 @@ public partial class MeshPainter // Base map but no UV resolvable: defer to the on-screen pixel (which at least reflects the // texture) rather than silently picking the flat _BaseColor. - if (!hasUv && GetTexProp(mat, "_BaseMap", "_MainTex")) return false; + if (!hasUv && GetTexProp(mat, "_BaseMap", "_MainTex", "_Albedo")) return false; // --- Albedo: BaseMap (sRGB) * BaseColor --- - Color baseCol = GetColorProp(mat, "_BaseColor", "_Color", Color.white); - Texture baseTex = GetTexProp(mat, "_BaseMap", "_MainTex"); + // AVP/* shaders name the map "_Albedo" and the tint "_AlbedoColor" (Glass tints via "_Color"). + Color baseCol = GetColorProp(mat, Color.white, "_BaseColor", "_AlbedoColor", "_Color"); + Texture baseTex = GetTexProp(mat, "_BaseMap", "_MainTex", "_Albedo"); Color albedo = baseCol; if (hasUv && baseTex) - albedo = SampleTexel(baseTex, ApplyST(mat, "_BaseMap", "_MainTex", uv), true) * baseCol; + albedo = SampleTexel(baseTex, ApplyST(mat, uv, "_BaseMap", "_MainTex", "_Albedo"), true) * baseCol; AdoptAlbedo(albedo); - // --- Metallic / Smoothness: MetallicGloss map (linear) --- - // URP/Lit: metallic = map.r ; smoothness = map.a * _Smoothness (or _Metallic/_Glossiness scalars). - float metallicVal = GetFloatProp(mat, "_Metallic", null, 0f); - float smoothVal = GetFloatProp(mat, "_Smoothness", "_Glossiness", 0.5f); - Texture mgTex = GetTexProp(mat, "_MetallicGlossMap", null); - if (hasUv && mgTex) - { - Color mg = SampleTexel(mgTex, ApplyST(mat, "_MetallicGlossMap", null, uv), false); - metallicVal = mg.r; - smoothVal = mg.a * smoothVal; - } + // --- Metallic: mask map .r * power, else flat scalar (linear) --- + // URP/Lit: _MetallicGlossMap.r (or the flat _Metallic scalar when no map). AVP name the mask + // "_Metallic" (a TEXTURE) and POM multiplies it by "_Metallic_Power"; Glass' "_Metallic" is a + // flat FLOAT. The type-checked reads resolve the "_Metallic" texture-vs-float collision per shader. + Texture metTex = GetTexProp(mat, "_MetallicGlossMap", "_Metallic"); + float metallicVal; + if (hasUv && metTex) + metallicVal = SampleTexel(metTex, ApplyST(mat, uv, "_MetallicGlossMap", "_Metallic"), false).r + * GetFloatProp(mat, 1f, "_Metallic_Power"); // POM power; neutral 1 for URP/Velvet + else + metallicVal = GetFloatProp(mat, 0f, "_Metallic"); // URP/Glass flat scalar metallic = Mathf.Clamp01(metallicVal); + + // --- Smoothness: mask map .a * scalar (linear) --- + // Alpha source: URP _MetallicGlossMap, AVP POM/Velvet/Curtains the "_Metallic" mask, Glass a + // dedicated "_Smoothness" TEXTURE. Scalar: _Smoothness/_Glossiness (URP/Velvet) or _SmoothnessPower + // (POM); Glass has none -> neutral 1 so smoothness = map.a. ("_Smoothness" is a float in Velvet but + // a texture in Glass - both handled by the type-checked reads.) + Texture smTex = GetTexProp(mat, "_MetallicGlossMap", "_Metallic", "_Smoothness"); + float smoothVal; + if (hasUv && smTex) + smoothVal = SampleTexel(smTex, ApplyST(mat, uv, "_MetallicGlossMap", "_Metallic", "_Smoothness"), false).a + * GetFloatProp(mat, 1f, "_Smoothness", "_Glossiness", "_SmoothnessPower"); + else + smoothVal = GetFloatProp(mat, 0.5f, "_Smoothness", "_Glossiness", "_SmoothnessPower"); smoothness = Mathf.Clamp01(smoothVal); // Occlusion is deliberately NOT sampled (that channel drives painted height now, see FinalizePick). - // --- Emission: EmissionMap (sRGB) * EmissionColor --- - Color emColor = GetColorProp(mat, "_EmissionColor", null, Color.black); - Texture emTex = GetTexProp(mat, "_EmissionMap", null); - Color emCol = emColor; - if (hasUv && emTex) - emCol = SampleTexel(emTex, ApplyST(mat, "_EmissionMap", null, uv), true) * emColor; + // --- Emission: EmissionMap (sRGB) * tint/intensity --- + // URP/Standard: _EmissionMap * _EmissionColor. AVP Velvet/Curtains: "_Emission" TEXTURE * + // "_Emission_Power" (a scalar intensity, no colour tint). POM/Glass have no emission. + Texture emTex = GetTexProp(mat, "_EmissionMap", "_Emission"); + float emPower = GetFloatProp(mat, -1f, "_Emission_Power"); // >=0 marks the AVP intensity path + Color emCol; + if (emPower >= 0f) + emCol = (hasUv && emTex) + ? SampleTexel(emTex, ApplyST(mat, uv, "_EmissionMap", "_Emission"), true) * emPower + : Color.black; + else + { + Color emColor = GetColorProp(mat, Color.black, "_EmissionColor"); + emCol = (hasUv && emTex) + ? SampleTexel(emTex, ApplyST(mat, uv, "_EmissionMap", "_Emission"), true) * emColor + : emColor; + } emissionColor = new Color(Mathf.Clamp01(emCol.r), Mathf.Clamp01(emCol.g), Mathf.Clamp01(emCol.b), emissionColor.a); return true; @@ -397,30 +423,49 @@ public partial class MeshPainter // --- Material read helpers (name-tolerant: URP and legacy Standard) --- - private static Color GetColorProp(Material m, string nameA, string nameB, Color fallback) + // A name can collide across types (e.g. AVP names "_Metallic"/"_Smoothness" as a TEXTURE while + // URP/Lit uses them as floats). HasProperty ignores type, so GetFloat/GetColor on the wrong-typed + // property spams a Unity error every hover frame - match the expected type before reading. + private static bool HasProp(Material m, string n, ShaderPropertyType type) { - if (m.HasProperty(nameA)) return m.GetColor(nameA); - if (nameB != null && m.HasProperty(nameB)) return m.GetColor(nameB); + if (n == null) return false; + Shader s = m.shader; + int i = s.FindPropertyIndex(n); + if (i < 0) return false; + ShaderPropertyType t = s.GetPropertyType(i); + return type == ShaderPropertyType.Float ? (t == ShaderPropertyType.Float || t == ShaderPropertyType.Range) + : type == ShaderPropertyType.Color ? (t == ShaderPropertyType.Color || t == ShaderPropertyType.Vector) + : t == type; + } + + // Names are tried in order; first match of the right type wins. Covers URP/Lit, legacy Standard + // AND the bespoke AVP/* naming (_Albedo / _AlbedoColor) from one call site. + private static Color GetColorProp(Material m, Color fallback, params string[] names) + { + foreach (string n in names) + if (HasProp(m, n, ShaderPropertyType.Color)) return m.GetColor(n); return fallback; } - private static float GetFloatProp(Material m, string nameA, string nameB, float fallback) + private static float GetFloatProp(Material m, float fallback, params string[] names) { - if (m.HasProperty(nameA)) return m.GetFloat(nameA); - if (nameB != null && m.HasProperty(nameB)) return m.GetFloat(nameB); + foreach (string n in names) + if (HasProp(m, n, ShaderPropertyType.Float)) return m.GetFloat(n); return fallback; } - private static Texture GetTexProp(Material m, string nameA, string nameB) + private static Texture GetTexProp(Material m, params string[] names) { - if (m.HasProperty(nameA)) { Texture t = m.GetTexture(nameA); if (t) return t; } - if (nameB != null && m.HasProperty(nameB)) { Texture t = m.GetTexture(nameB); if (t) return t; } + foreach (string n in names) + if (HasProp(m, n, ShaderPropertyType.Texture)) { Texture t = m.GetTexture(n); if (t) return t; } return null; } - private static Vector2 ApplyST(Material m, string nameA, string nameB, Vector2 uv) + private static Vector2 ApplyST(Material m, Vector2 uv, params string[] names) { - string prop = m.HasProperty(nameA) ? nameA : (nameB != null && m.HasProperty(nameB) ? nameB : null); + string prop = null; + foreach (string n in names) + if (HasProp(m, n, ShaderPropertyType.Texture)) { prop = n; break; } if (prop == null) return uv; Vector2 s = m.GetTextureScale(prop); Vector2 o = m.GetTextureOffset(prop);