diff --git a/Assets/Scripts/ConcealmentMeter.cs b/Assets/Scripts/ConcealmentMeter.cs index 61cf7f2..0efd26f 100644 --- a/Assets/Scripts/ConcealmentMeter.cs +++ b/Assets/Scripts/ConcealmentMeter.cs @@ -10,8 +10,10 @@ using UnityEngine; /// its complement. /// /// Pipeline: -/// 1. -> mesh in the renderer's LOCAL space -/// (same convention MeshPainter uses for its collider; world = transform.localToWorldMatrix). +/// 1. -> mesh in the renderer's LOCAL space, then the +/// player's world scale is divided back out (BakeMesh bakes that scale IN; see PlayerScaler) so the +/// convention world = transform.localToWorldMatrix holds at ANY size — the same fixup SkinnedColliderBaker +/// applies, and the unit-scale mesh MeshPainter borrows from it. /// 2. Column ray-stabbing in local space: each (x,z) grid column collects the Y where the mesh /// surface crosses it; parity (odd # of crossings below a voxel center) marks interior voxels. /// This is the same XZ triangle rasterization MeshPainter.GetIslandMask uses for UV islands. @@ -74,6 +76,7 @@ public class ConcealmentMeter : MonoBehaviour private Vector3[] _verts; private int[] _tris; private float _timer; + private readonly List _vbuf = new List(); // reused scale-fixup scratch; nothing allocated per eval // Per-column Y crossings (index = iz * nx + ix). Reused across evals; sizes grow as needed. private List[] _columns; @@ -122,6 +125,17 @@ public class ConcealmentMeter : MonoBehaviour if (!targetRenderer) return; targetRenderer.BakeMesh(_baked); + + // BakeMesh freezes the bone deformation — which already carries the player's world scale (PlayerScaler) + // — into the mesh. Everything below treats the bake as unit-scale LOCAL geometry and raises it to world + // via targetRenderer.localToWorldMatrix, which re-applies that same scale. Divide it back out first, + // else a scaled player is measured at scale² (voxel world positions, broadphase box AND gizmos), which + // also corrupts EmbeddedPercent. No-op at scale 1; the uniform divide is rotation-independent, which the + // player's uniform scale guarantees. Mirrors SkinnedColliderBaker's identical fixup. + Vector3 ls = targetRenderer.transform.lossyScale; + if (ls.x != 1f || ls.y != 1f || ls.z != 1f) + RescaleBakedToUnitScale(ls); + _verts = _baked.vertices; _tris = _baked.triangles; if (_verts.Length == 0 || _tris.Length < 3) return; @@ -199,6 +213,24 @@ public class ConcealmentMeter : MonoBehaviour HasResult = true; } + /// Divides the player's world scale back out of the freshly baked mesh so it is true unit-scale + /// local geometry (the space this class raises to world with). Reuses — no per-eval alloc. + private void RescaleBakedToUnitScale(Vector3 lossyScale) + { + float ix = lossyScale.x != 0f ? 1f / lossyScale.x : 0f; + float iy = lossyScale.y != 0f ? 1f / lossyScale.y : 0f; + float iz = lossyScale.z != 0f ? 1f / lossyScale.z : 0f; + _baked.GetVertices(_vbuf); + for (int i = 0; i < _vbuf.Count; i++) + { + Vector3 v = _vbuf[i]; + v.x *= ix; v.y *= iy; v.z *= iz; + _vbuf[i] = v; + } + _baked.SetVertices(_vbuf); + _baked.RecalculateBounds(); + } + /// /// Rasterizes every triangle into the XZ column grid; each column accumulates the Y values /// where the surface crosses it (one per triangle whose XZ projection covers the column center).