Add painted-height HUD sliders for AO shift and relief intensity

Wire three material-backed look sliders (occlusion AO shift, relief normal
intensity, parallax intensity) through the paint HUD, its layout/state
persistence, the .paint slot format (bumped to v4), owner-authoritative
network sync and the runtime reset, mirroring the existing camo-knob path so
they save, restore, replicate and reset alongside the brush values.

Change the occlusion AO mapping from a division threshold to a linear shift:
AO fades from 1 down to (1 - shift) at the deepest painted hole, so a 0 shift
no longer leaves black spots. Enable _NORMALMAP alongside _PARALLAXMAP so URP
transforms the painted relief normal into world space (otherwise it discards
normalTS and the relief is invisible), and pin the added keyword in the build
keep-alive material.

Stop the pipette from picking the occlusion/height value and turn its toggle
off after a pick. Default the knobs to 0.2 shift / 1.4 normal / 1.0 parallax
across the shader, painter, network and HUD fallbacks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 4.8 committed 2026-07-01 07:07:39 +02:00
1 parent fdcb4f8d8a
commit 59939b3496
11 files changed
+216 -49

No files matched your search

+29
View File
@@ -94,6 +94,14 @@ public class PlayerPaintSync : NetworkBehaviour
new(new Vector3(0.5f, 0f, 0.1f), NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner);
private bool _camoApplyPending; // remote: apply _camo.Value to the material once IsReady / on change
// Painted-height knobs (x = occlusion AO threshold, y = relief normal intensity, z = parallax
// intensity). Same per-player material values as the camo knobs - not baked into the maps - so they
// ride their own owner-authoritative NetworkVariable and apply once the remote painter is ready. The
// default mirrors the PlayerCamoLit shader defaults (0.2 / 1.4 / 1).
private readonly NetworkVariable<Vector3> _height =
new(new Vector3(0.2f, 1.4f, 1f), NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner);
private bool _heightApplyPending; // remote: apply _height.Value to the material once IsReady / on change
// Monotonic message counter on the owner (one per stamp batch / checkpoint / restore); on every peer,
// the highest sequence accounted for (applied to a remote replica / sent by the owner). Used as the
// snapshot's cutoff marker so the join window neither loses nor double-applies events.
@@ -164,6 +172,10 @@ public class PlayerPaintSync : NetworkBehaviour
_camo.OnValueChanged += OnCamoChanged;
_camoApplyPending = true;
// Same deferred apply for the painted-height knobs.
_height.OnValueChanged += OnHeightChanged;
_heightApplyPending = true;
// The server (host) has been present since the start, so its replica already holds the full
// paint via the live stream; only a genuine late joiner needs the baseline pulled over.
if (!IsServer)
@@ -191,6 +203,7 @@ public class PlayerPaintSync : NetworkBehaviour
}
_emissionIntensity.OnValueChanged -= OnEmissionChanged;
_camo.OnValueChanged -= OnCamoChanged;
_height.OnValueChanged -= OnHeightChanged;
}
// Owner history events -> appended to the ordered outgoing FIFO, flushed in LateUpdate.
@@ -221,6 +234,7 @@ public class PlayerPaintSync : NetworkBehaviour
// Apply on the next LateUpdate once the material is ready (the camo setters are a no-op before that,
// and on a fresh spawn the OnValueChanged may arrive before the painter's Start has built the instance).
private void OnCamoChanged(Vector3 previous, Vector3 current) => _camoApplyPending = true;
private void OnHeightChanged(Vector3 previous, Vector3 current) => _heightApplyPending = true;
// ---- Live stamp stream (owner -> server -> remotes) ----
@@ -252,6 +266,16 @@ public class PlayerPaintSync : NetworkBehaviour
_camoApplyPending = false;
}
// Remote replica: apply the owner's painted-height knobs once the material exists / on change.
if (!IsOwner && _heightApplyPending && _painter && _painter.IsReady)
{
Vector3 h = _height.Value;
_painter.OcclusionThreshold = h.x;
_painter.HeightNormalIntensity = h.y;
_painter.ParallaxIntensity = h.z;
_heightApplyPending = false;
}
if (!IsOwner)
return;
@@ -282,6 +306,11 @@ public class PlayerPaintSync : NetworkBehaviour
var camo = new Vector3(_painter.CamoHalfLambert, _painter.CamoHalfLambertBrightness, _painter.CamoSpecularDampen);
if (_camo.Value != camo)
_camo.Value = camo;
// Publish the painted-height knobs the same way (delta-only, ready-gated).
var height = new Vector3(_painter.OcclusionThreshold, _painter.HeightNormalIntensity, _painter.ParallaxIntensity);
if (_height.Value != height)
_height.Value = height;
}
FlushOutgoing(unlimited: false);