perf(paint): stronger X-ray hit flash + kill spawn/respawn freeze
X-ray hit flash: drive a dedicated flash mode instead of the normal reveal - pulse off (steady), intensity boost (xrayFlashBoost, default 3x), snap-on, then restore authored color/pulse exactly. Fixes the weak/dark flicker where the 0.35s hit window often caught only the pulse's near-off plateau. Spawn/respawn freeze: pool GPU RenderTextures across despawn->respawn (TeardownGpu recycles, CreateRT pops) so a hider->hunter conversion no longer churns ~70MB of RT alloc/free on every observer; reuse staging textures to cut per-map GC. Defer the blank base-seed on reveal-gated remote replicas (DeferInitialSeed) - the real pixels arrive with the snapshot apply anyway; gate the FurShellRenderer alongside the body so a deferred replica never shows the pooled RT's stale fur; EnsureBackendSeeded + TryCaptureSnapshot guard against capture-before-reseed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
4ceaf85c8f
commit
48975c0f20
9 files changed
+196
-24
No files matched your search
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
using Chameleon.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Per-avatar network glue on the spawned player. The local owner binds the scene singletons
|
||||
@@ -102,6 +103,7 @@ public class NetworkPlayerSetup : NetworkBehaviour
|
||||
public void MarkConversionSpawn(Vector3 worldPos) => _conversionSpawnPos = worldPos;
|
||||
|
||||
private Renderer[] _bodyRenderers; // skinned body mesh(es), toggled by the per-client visibility pass
|
||||
private FurShellRenderer[] _furRenderers; // fur draws via a custom GPU-instanced pass (NOT a Renderer); gated with the body so the avatar reveals atomically and never shows stale pooled fur
|
||||
private bool _visibilityApplied;
|
||||
private bool _lastVisible = true;
|
||||
private bool _renderGate; // conversion: body force-hidden until the fresh hunter has settled into place
|
||||
@@ -113,6 +115,7 @@ public class NetworkPlayerSetup : NetworkBehaviour
|
||||
private PlayerCharacterController _controller; // sibling, cached (the freeze re-asserts per frame)
|
||||
private bool _xrayApplied;
|
||||
private bool _lastXRay;
|
||||
private bool _lastFlash;
|
||||
private bool _frozenApplied;
|
||||
private bool _lastFrozen;
|
||||
private float _xrayFlashUntil; // Time.time deadline for the just-shot X-ray flash (local per client)
|
||||
@@ -122,6 +125,7 @@ public class NetworkPlayerSetup : NetworkBehaviour
|
||||
{
|
||||
_active.Add(this); // scoreboard registry (paired with OnNetworkDespawn)
|
||||
_bodyRenderers = GetComponentsInChildren<SkinnedMeshRenderer>(true);
|
||||
_furRenderers = GetComponentsInChildren<FurShellRenderer>(true);
|
||||
_painter = GetComponentInChildren<MeshPainter>(true);
|
||||
_paintSync = GetComponentInChildren<PlayerPaintSync>(true);
|
||||
_concealment = GetComponentInChildren<ConcealmentMeter>(true);
|
||||
@@ -297,6 +301,12 @@ public class NetworkPlayerSetup : NetworkBehaviour
|
||||
if (_bodyRenderers != null)
|
||||
foreach (var r in _bodyRenderers)
|
||||
if (r) r.enabled = visible;
|
||||
// Fur is drawn by a custom GPU-instanced pass, NOT a Renderer, so the skinned-mesh toggle above
|
||||
// misses it; gate it too (enabled=false unsubscribes its camera hook), or a deferred/reveal-gated
|
||||
// body would show stale pooled fur strands while its own mesh is hidden.
|
||||
if (_furRenderers != null)
|
||||
foreach (var f in _furRenderers)
|
||||
if (f) f.enabled = visible;
|
||||
_lastVisible = visible;
|
||||
_visibilityApplied = true;
|
||||
}
|
||||
@@ -353,20 +363,21 @@ public class NetworkPlayerSetup : NetworkBehaviour
|
||||
private void UpdateXRayReveal()
|
||||
{
|
||||
if (!_painter) return;
|
||||
bool reveal = ComputeXRay();
|
||||
if (_xrayApplied && reveal == _lastXRay) return;
|
||||
_painter.XRayRevealed = reveal;
|
||||
// Just-shot flash: a hunter's hit lights this hider up for a brief window (server-broadcast). It drives
|
||||
// a distinct, much stronger flash mode (steady + boosted), so it is tracked apart from the normal reveal.
|
||||
bool flash = Time.time < _xrayFlashUntil;
|
||||
bool reveal = flash || ComputeXRay();
|
||||
if (_xrayApplied && reveal == _lastXRay && flash == _lastFlash) return;
|
||||
_painter.SetXRayReveal(reveal, flash);
|
||||
_lastXRay = reveal;
|
||||
_lastFlash = flash;
|
||||
_xrayApplied = true;
|
||||
}
|
||||
|
||||
// The X-ray reveal predicate for this avatar on the local machine.
|
||||
// The normal (non-flash) X-ray reveal predicate for this avatar on the local machine. The just-shot flash
|
||||
// is OR-combined by the caller so it can select the stronger flash mode.
|
||||
private bool ComputeXRay()
|
||||
{
|
||||
// Just-shot flash: a hunter's hit lights this hider up for a brief window (server-broadcast), on top
|
||||
// of the normal reveal triggers, so the moment of the hit reads before the hider leaves play.
|
||||
if (Time.time < _xrayFlashUntil) return true;
|
||||
|
||||
// Buried-hider reveal: already gated to hider + running match on the owner before it is published.
|
||||
if (_embeddedReveal.Value) return true;
|
||||
|
||||
|
||||
Reference in new issue
Block a user