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