Fix proxy box color, mesh leak, and stale comment
The Mesh LOD proxy box rendered flat gray instead of the car's color. It was being given a shared material tinted via Material.color (the legacy _Color property), which URP ignores in favor of _BaseColor, and a single shared material cannot match each car anyway. Reuse the car's own material so the box matches its color again. Also destroy the proxy box mesh when tearing down or refreshing a car's LOD (the GameObject was destroyed but the Mesh leaked until scene unload), and prune dead weak-refs from the tracked-car list periodically so it cannot grow unbounded across a long session. Fix a stale comment in PhysicsTimer that still referenced PhysicsOverlayGUI after the overlay moved to the Profiler module.
This commit is contained in:
parent
4853015eff
commit
eb6699f23f
2 changed files with 18 additions and 25 deletions
|
|
@ -12,7 +12,6 @@ static class MeshLodInjector
|
||||||
{
|
{
|
||||||
static MeshLodSettings _settings = new();
|
static MeshLodSettings _settings = new();
|
||||||
static readonly List<WeakReference<Car>> _trackedCars = new();
|
static readonly List<WeakReference<Car>> _trackedCars = new();
|
||||||
static Material? _bboxMat;
|
|
||||||
|
|
||||||
// Debounced auto-refresh: set by MarkDirty, consumed by CheckAutoRefresh (called from Update).
|
// Debounced auto-refresh: set by MarkDirty, consumed by CheckAutoRefresh (called from Update).
|
||||||
static float _pendingRefreshAt = -1f;
|
static float _pendingRefreshAt = -1f;
|
||||||
|
|
@ -33,7 +32,6 @@ static class MeshLodInjector
|
||||||
{
|
{
|
||||||
_trackedCars.Clear();
|
_trackedCars.Clear();
|
||||||
_pendingRefreshAt = -1f;
|
_pendingRefreshAt = -1f;
|
||||||
if (_bboxMat != null) { UnityEngine.Object.Destroy(_bboxMat); _bboxMat = null; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (int total, int locos, int freight) GetTrackedCounts()
|
public static (int total, int locos, int freight) GetTrackedCounts()
|
||||||
|
|
@ -129,6 +127,11 @@ static class MeshLodInjector
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ApplyLods(car, renderers);
|
ApplyLods(car, renderers);
|
||||||
|
// Opportunistically drop dead weak-refs so the list can't grow unbounded over a
|
||||||
|
// long session of cars loading/unloading (RefreshAll also compacts, but only runs
|
||||||
|
// when a setting changes). Cheap: the modulo check runs once per car load.
|
||||||
|
if (_trackedCars.Count > 0 && _trackedCars.Count % 128 == 0)
|
||||||
|
_trackedCars.RemoveAll(wr => !wr.TryGetTarget(out _));
|
||||||
_trackedCars.Add(new WeakReference<Car>(car));
|
_trackedCars.Add(new WeakReference<Car>(car));
|
||||||
}
|
}
|
||||||
catch (Exception ex) { Log.Warn($"MeshLOD: apply failed for {car.DisplayName}: {ex.Message}"); }
|
catch (Exception ex) { Log.Warn($"MeshLOD: apply failed for {car.DisplayName}: {ex.Message}"); }
|
||||||
|
|
@ -208,9 +211,12 @@ static class MeshLodInjector
|
||||||
Renderer[] lod2Rend = sorted.Take(lod2Keep).Cast<Renderer>().ToArray();
|
Renderer[] lod2Rend = sorted.Take(lod2Keep).Cast<Renderer>().ToArray();
|
||||||
|
|
||||||
// LOD3: 12-triangle proxy box derived from the largest renderer's mesh-local AABB.
|
// LOD3: 12-triangle proxy box derived from the largest renderer's mesh-local AABB.
|
||||||
|
// Reuse the largest renderer's own material so the box matches the car's colour
|
||||||
|
// (a shared/tinted material can't match per-car, and Material.color sets the legacy
|
||||||
|
// _Color, not URP's _BaseColor — both reasons the previous matte material rendered gray).
|
||||||
Bounds localBounds = ComputeMeshLocalBounds(sorted[0], bodyRoot);
|
Bounds localBounds = ComputeMeshLocalBounds(sorted[0], bodyRoot);
|
||||||
MeshRenderer bboxMr = CreateBoundingBoxRenderer(bodyRoot, localBounds,
|
MeshRenderer bboxMr = CreateBoundingBoxRenderer(bodyRoot, localBounds,
|
||||||
GetOrCreateBBoxMat(sorted[0].sharedMaterial),
|
sorted[0].sharedMaterial,
|
||||||
sorted[0].gameObject.layer);
|
sorted[0].gameObject.layer);
|
||||||
Renderer[] lod3Rend = new[] { (Renderer)bboxMr };
|
Renderer[] lod3Rend = new[] { (Renderer)bboxMr };
|
||||||
|
|
||||||
|
|
@ -261,7 +267,14 @@ static class MeshLodInjector
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform? bbox = car.BodyTransform.Find("S3_BBox");
|
Transform? bbox = car.BodyTransform.Find("S3_BBox");
|
||||||
if (bbox != null) UnityEngine.Object.Destroy(bbox.gameObject);
|
if (bbox != null)
|
||||||
|
{
|
||||||
|
// Destroy the procedural box mesh too: destroying the GameObject alone leaves
|
||||||
|
// the Mesh asset alive until scene unload (a small leak on every refresh).
|
||||||
|
MeshFilter? bf = bbox.GetComponent<MeshFilter>();
|
||||||
|
if (bf != null && bf.sharedMesh != null) UnityEngine.Object.Destroy(bf.sharedMesh);
|
||||||
|
UnityEngine.Object.Destroy(bbox.gameObject);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Bounds helpers ────────────────────────────────────────────────────────
|
// ── Bounds helpers ────────────────────────────────────────────────────────
|
||||||
|
|
@ -316,26 +329,6 @@ static class MeshLodInjector
|
||||||
|
|
||||||
// ── Proxy box mesh ────────────────────────────────────────────────────────
|
// ── Proxy box mesh ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
// One matte material shared across all proxy boxes; tinted to the car body's
|
|
||||||
// albedo so it looks approximately correct under any lighting / post-processing.
|
|
||||||
// Tries URP first since Railroader uses the Universal Render Pipeline.
|
|
||||||
static Material GetOrCreateBBoxMat(Material? src)
|
|
||||||
{
|
|
||||||
if (_bboxMat != null) return _bboxMat;
|
|
||||||
var shader = Shader.Find("Universal Render Pipeline/Lit")
|
|
||||||
?? Shader.Find("Universal Render Pipeline/Simple Lit")
|
|
||||||
?? Shader.Find("Standard")
|
|
||||||
?? Shader.Find("Legacy Shaders/Diffuse");
|
|
||||||
_bboxMat = shader != null ? new Material(shader) : new Material(src);
|
|
||||||
_bboxMat.color = src != null && src.HasProperty("_Color")
|
|
||||||
? src.color
|
|
||||||
: new Color(0.45f, 0.45f, 0.45f);
|
|
||||||
if (_bboxMat.HasProperty("_Metallic")) _bboxMat.SetFloat("_Metallic", 0f);
|
|
||||||
if (_bboxMat.HasProperty("_Glossiness")) _bboxMat.SetFloat("_Glossiness", 0.1f); // built-in
|
|
||||||
if (_bboxMat.HasProperty("_Smoothness")) _bboxMat.SetFloat("_Smoothness", 0.1f); // URP
|
|
||||||
return _bboxMat;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MeshRenderer CreateBoundingBoxRenderer(Transform parent, Bounds localBounds,
|
static MeshRenderer CreateBoundingBoxRenderer(Transform parent, Bounds localBounds,
|
||||||
Material mat, int layer)
|
Material mat, int layer)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ public static class PhysicsTimer
|
||||||
_frames = 0;
|
_frames = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from PhysicsOverlayGUI.LateUpdate() to capture render frame time.
|
// Called from ProfilerOverlayGUI.LateUpdate() to capture render frame time.
|
||||||
public static void RecordRenderFrame(float deltaMs)
|
public static void RecordRenderFrame(float deltaMs)
|
||||||
{
|
{
|
||||||
_lastInstantRenderMs = deltaMs; // sampled into RingRender on the next RecordFrame call
|
_lastInstantRenderMs = deltaMs; // sampled into RingRender on the next RecordFrame call
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue