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:
1 parent
fdcb4f8d8a
commit
59939b3496
11 files changed
+216
-49
No files matched your search
@@ -60,6 +60,12 @@ public partial class PaintHud
|
||||
private bool _hasPendingCamo;
|
||||
private bool _camoEverReady;
|
||||
|
||||
// Painted-height knobs (occlusion threshold, normal intensity, parallax intensity) ride the exact same
|
||||
// material-ready deferral as the camo knobs above: they become writable only after the painter's Start,
|
||||
// so a restored/carried value waits here and is applied in the LateUpdate ready-gate (shared timing).
|
||||
private Vector3 _pendingHeight;
|
||||
private bool _hasPendingHeight;
|
||||
|
||||
// Authored defaults for the runtime reset (= "as if the saved layout file had been deleted"): the
|
||||
// prefab's panel positions, captured before any saved layout is restored over them, and the painter's
|
||||
// prefab/material default brush values, captured before carry/restore mutate the live painter. Camo is
|
||||
@@ -95,6 +101,7 @@ public partial class PaintHud
|
||||
public int version = HudFileVersion;
|
||||
public bool hasValues; // false = no painter was bound when saved -> restore positions only
|
||||
public bool hasCamoValues; // false = pre-camo save file -> keep the material's authored camo (no clobber)
|
||||
public bool hasHeightValues; // false = pre-height save file -> keep the material's authored height knobs (no clobber)
|
||||
public List<PanelPos> panels = new List<PanelPos>();
|
||||
public HudValues values = new HudValues();
|
||||
}
|
||||
@@ -120,6 +127,7 @@ public partial class PaintHud
|
||||
public int sprayDots;
|
||||
public float sprayDotSizeMin, sprayDotSizeMax, sprayDotAlphaMin, sprayDotAlphaMax;
|
||||
public float camoHalfLambert, camoHalfLambertBrightness, camoSpecularDampen; // PlayerCamoLit material knobs
|
||||
public float occlusionThreshold, heightNormalIntensity, parallaxIntensity; // painted-height knobs (material-backed)
|
||||
}
|
||||
|
||||
/// <summary>A draggable panel was dropped -> persist the layout immediately.</summary>
|
||||
@@ -146,6 +154,7 @@ public partial class PaintHud
|
||||
CopyValues(painter, state.values);
|
||||
state.hasValues = true;
|
||||
state.hasCamoValues = painter.IsReady; // only claim camo when it was actually readable
|
||||
state.hasHeightValues = painter.IsReady; // height knobs share the camo readiness
|
||||
}
|
||||
else if (_hasCarry)
|
||||
{
|
||||
@@ -153,6 +162,7 @@ public partial class PaintHud
|
||||
state.values = _carry;
|
||||
state.hasValues = true;
|
||||
state.hasCamoValues = _camoEverReady; // _carry holds valid camo only after a ready painter
|
||||
state.hasHeightValues = _camoEverReady;
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(HudSaveDir);
|
||||
@@ -198,6 +208,16 @@ public partial class PaintHud
|
||||
_hasPendingCamo = true;
|
||||
}
|
||||
|
||||
// Same deferral for the painted-height knobs; hasHeightValues guards pre-height save files so they
|
||||
// keep the material's authored defaults instead of being slammed to a 0 threshold/flat relief.
|
||||
if (state.hasHeightValues && state.values != null)
|
||||
{
|
||||
_pendingHeight = new Vector3(state.values.occlusionThreshold,
|
||||
state.values.heightNormalIntensity,
|
||||
state.values.parallaxIntensity);
|
||||
_hasPendingHeight = true;
|
||||
}
|
||||
|
||||
// Point-anchored panels: anchoredPosition is resolution-independent under the canvas'
|
||||
// ScaleWithScreenSize scaler, so the raw saved value places them identically next session.
|
||||
var root = _panel.transform;
|
||||
@@ -229,6 +249,9 @@ public partial class PaintHud
|
||||
_defaults.camoHalfLambert = painter.CamoHalfLambert;
|
||||
_defaults.camoHalfLambertBrightness = painter.CamoHalfLambertBrightness;
|
||||
_defaults.camoSpecularDampen = painter.CamoSpecularDampen;
|
||||
_defaults.occlusionThreshold = painter.OcclusionThreshold;
|
||||
_defaults.heightNormalIntensity = painter.HeightNormalIntensity;
|
||||
_defaults.parallaxIntensity = painter.ParallaxIntensity;
|
||||
_hasDefaultCamo = true;
|
||||
}
|
||||
|
||||
@@ -239,11 +262,21 @@ public partial class PaintHud
|
||||
painter.CamoSpecularDampen = _pendingCamo.z;
|
||||
_hasPendingCamo = false;
|
||||
}
|
||||
if (_hasPendingHeight)
|
||||
{
|
||||
painter.OcclusionThreshold = _pendingHeight.x;
|
||||
painter.HeightNormalIntensity = _pendingHeight.y;
|
||||
painter.ParallaxIntensity = _pendingHeight.z;
|
||||
_hasPendingHeight = false;
|
||||
}
|
||||
SyncCamoSliders();
|
||||
|
||||
_savedValues.camoHalfLambert = _lastSeenValues.camoHalfLambert = painter.CamoHalfLambert;
|
||||
_savedValues.camoHalfLambertBrightness = _lastSeenValues.camoHalfLambertBrightness = painter.CamoHalfLambertBrightness;
|
||||
_savedValues.camoSpecularDampen = _lastSeenValues.camoSpecularDampen = painter.CamoSpecularDampen;
|
||||
_savedValues.occlusionThreshold = _lastSeenValues.occlusionThreshold = painter.OcclusionThreshold;
|
||||
_savedValues.heightNormalIntensity = _lastSeenValues.heightNormalIntensity = painter.HeightNormalIntensity;
|
||||
_savedValues.parallaxIntensity = _lastSeenValues.parallaxIntensity = painter.ParallaxIntensity;
|
||||
|
||||
_camoEverReady = true;
|
||||
_camoSynced = true;
|
||||
@@ -312,7 +345,10 @@ public partial class PaintHud
|
||||
&& p.sprayDotAlphaMax == v.sprayDotAlphaMax
|
||||
&& p.CamoHalfLambert == v.camoHalfLambert
|
||||
&& p.CamoHalfLambertBrightness == v.camoHalfLambertBrightness
|
||||
&& p.CamoSpecularDampen == v.camoSpecularDampen;
|
||||
&& p.CamoSpecularDampen == v.camoSpecularDampen
|
||||
&& p.OcclusionThreshold == v.occlusionThreshold
|
||||
&& p.HeightNormalIntensity == v.heightNormalIntensity
|
||||
&& p.ParallaxIntensity == v.parallaxIntensity;
|
||||
}
|
||||
|
||||
/// <summary>Snapshots the bound painter's brush values into the in-memory mirror.</summary>
|
||||
@@ -338,6 +374,10 @@ public partial class PaintHud
|
||||
_carry.camoHalfLambertBrightness,
|
||||
_carry.camoSpecularDampen);
|
||||
_hasPendingCamo = true;
|
||||
_pendingHeight = new Vector3(_carry.occlusionThreshold,
|
||||
_carry.heightNormalIntensity,
|
||||
_carry.parallaxIntensity);
|
||||
_hasPendingHeight = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,6 +412,9 @@ public partial class PaintHud
|
||||
v.camoHalfLambert = from.CamoHalfLambert;
|
||||
v.camoHalfLambertBrightness = from.CamoHalfLambertBrightness;
|
||||
v.camoSpecularDampen = from.CamoSpecularDampen;
|
||||
v.occlusionThreshold = from.OcclusionThreshold;
|
||||
v.heightNormalIntensity = from.HeightNormalIntensity;
|
||||
v.parallaxIntensity = from.ParallaxIntensity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,11 +441,14 @@ public partial class PaintHud
|
||||
to.sprayDotAlphaMin = v.sprayDotAlphaMin;
|
||||
to.sprayDotAlphaMax = v.sprayDotAlphaMax;
|
||||
|
||||
// Camo setters are a no-op until the material exists; the guaranteed deferred apply runs from the
|
||||
// LateUpdate ready-gate via _pendingCamo. Writing here too keeps Copy/Apply/Equal symmetric.
|
||||
// Camo + height setters are a no-op until the material exists; the guaranteed deferred apply runs
|
||||
// from the LateUpdate ready-gate via _pendingCamo/_pendingHeight. Writing here too keeps Copy/Apply/Equal symmetric.
|
||||
to.CamoHalfLambert = v.camoHalfLambert;
|
||||
to.CamoHalfLambertBrightness = v.camoHalfLambertBrightness;
|
||||
to.CamoSpecularDampen = v.camoSpecularDampen;
|
||||
to.OcclusionThreshold = v.occlusionThreshold;
|
||||
to.HeightNormalIntensity = v.heightNormalIntensity;
|
||||
to.ParallaxIntensity = v.parallaxIntensity;
|
||||
}
|
||||
|
||||
private HudState LoadHudState()
|
||||
@@ -482,15 +528,19 @@ public partial class PaintHud
|
||||
_defaults.camoHalfLambert = painter.CamoHalfLambert;
|
||||
_defaults.camoHalfLambertBrightness = painter.CamoHalfLambertBrightness;
|
||||
_defaults.camoSpecularDampen = painter.CamoSpecularDampen;
|
||||
_defaults.occlusionThreshold = painter.OcclusionThreshold;
|
||||
_defaults.heightNormalIntensity = painter.HeightNormalIntensity;
|
||||
_defaults.parallaxIntensity = painter.ParallaxIntensity;
|
||||
}
|
||||
|
||||
ApplyValues(painter, _defaults);
|
||||
SyncFromPainter();
|
||||
SyncCamoSliders();
|
||||
|
||||
// ApplyValues wrote the camo straight to the material (painter is ready at a runtime reset), so
|
||||
// drop any still-pending restored camo the ready-gate would otherwise re-apply over the default.
|
||||
// ApplyValues wrote the camo + height knobs straight to the material (painter is ready at a
|
||||
// runtime reset), so drop any still-pending restored values the ready-gate would re-apply over the default.
|
||||
_hasPendingCamo = false;
|
||||
_hasPendingHeight = false;
|
||||
|
||||
CaptureCarry(); // a later respawn now carries the defaults, not the pre-reset values
|
||||
SnapshotSavedBaseline(); // values match the (now deleted) save -> the reset itself triggers no auto-save
|
||||
|
||||
Reference in new issue
Block a user