Fur: Albedo-gekoppelte Länge, Toggle-Gate, Soft-Edge, World-Gravity, Pipette & FP-Hide

- Fur-Map trägt nur noch R = Länge (linearer Datenkanal); Farbe kommt per-texel
  aus der Live-Albedo-RT (an _BaseMap des Shell-Shaders gebunden)
- Toggle_Fur als echtes Gate (IsChannelActive = fur), Default aus, furLength 0.5
- Weicher Alpha-Übergang (radial/tip/length coverage) statt Hard-Clip; Transparent-
  Pass mit Depth-Bias (Offset -1,-1) gegen Body-Durchflimmern
- Root dunkler / Tip heller aus gemalter Farbe abgeleitet (kein Fix-Tint)
- Gravity/Curl in World-Space nach Transform (unabhängig von Mesh-Rotation)
- Pipette aktiviert Fur-Toggle immer; liest R-Kanal als Länge
- First-Person blendet FurShellRenderer mit aus
- Netzwerk (FlagFur), Undo, Persistence (fur.png R=Länge) mitgezogen

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 4.8 committed 2026-07-03 23:40:58 +02:00
1 parent 7536e8ec8b
commit 1b783a39be
15 files changed
+254 -306

No files matched your search

@@ -20,7 +20,9 @@ public partial class PaintHud
"defaults every session.")]
public bool persistHud = true;
private const int HudFileVersion = 1;
// v2: HudValues gained fur (toggle) + furLength. Bumping discards pre-v2 saves so the new fur fields
// fall back to the painter's prefab defaults instead of deserializing as 0/false.
private const int HudFileVersion = 2;
// Auto-save bookkeeping. Brush edits are debounced (sliders fire every frame while dragged): the due
// time is pushed forward and written once they settle.
@@ -83,11 +85,12 @@ public partial class PaintHud
[Serializable]
private class HudValues
{
public bool paintAlbedo, paintMetallicSmoothness, paintOcclusion, paintEmission, spray;
public bool paintAlbedo, paintMetallicSmoothness, paintOcclusion, paintEmission, spray, fur;
public Color brushColor;
public float metallic, smoothness, metallicSmoothnessOpacity, occlusion, occlusionOpacity;
public Color emissionColor;
public float emissionIntensity;
public float furLength;
public int brushSize;
public int activeBrushIndex;
public int sprayDots;
@@ -275,6 +278,8 @@ public partial class PaintHud
&& p.paintOcclusion == v.paintOcclusion
&& p.paintEmission == v.paintEmission
&& p.spray == v.spray
&& p.fur == v.fur
&& p.furLength == v.furLength
&& p.brushColor == v.brushColor
&& p.metallic == v.metallic
&& p.smoothness == v.smoothness
@@ -335,6 +340,8 @@ public partial class PaintHud
v.paintOcclusion = from.paintOcclusion;
v.paintEmission = from.paintEmission;
v.spray = from.spray;
v.fur = from.fur;
v.furLength = from.furLength;
v.brushColor = from.brushColor;
v.metallic = from.metallic;
v.smoothness = from.smoothness;
@@ -371,6 +378,8 @@ public partial class PaintHud
to.paintOcclusion = v.paintOcclusion;
to.paintEmission = v.paintEmission;
to.spray = v.spray;
to.fur = v.fur;
to.furLength = v.furLength;
to.brushColor = v.brushColor;
to.metallic = v.metallic;
to.smoothness = v.smoothness;
@@ -44,7 +44,6 @@ public partial class PaintHud : MonoBehaviour
private const string ToggleFur = "Toggle_Fur";
private const string PickerAlbedo = "Picker_Albedo";
private const string PickerEmission = "Picker_Emission";
private const string PickerFur = "Picker_Fur";
private const string SliderAlbedoAlpha = "Slider_AlbedoAlpha";
private const string SliderEmissionAlpha = "Slider_EmissionAlpha";
private const string SliderMetallic = "Slider_Metallic";
@@ -65,8 +64,7 @@ public partial class PaintHud : MonoBehaviour
private const string SliderOcclusionThreshold = "Slider_OcclusionThreshold";
private const string SliderNormalIntensity = "Slider_NormalIntensity";
private const string SliderParallaxIntensity = "Slider_ParallaxIntensity";
private const string SliderFurAlpha = "Slider_FurAlpha";
private const string SliderFurOpacity = "Slider_FurOpacity";
private const string SliderFurLength = "Slider_FurLength";
private const string MaskSelector = "MaskSelector";
private const string MaskSwatchPrefix = "MaskSwatch_";
@@ -263,12 +261,10 @@ public partial class PaintHud : MonoBehaviour
WireSlider(panel, SliderNormalIntensity, painter ? painter.HeightNormalIntensity : 1.4f, v => { if (painter) painter.HeightNormalIntensity = v; });
WireSlider(panel, SliderParallaxIntensity, painter ? painter.ParallaxIntensity : 1f, v => { if (painter) painter.ParallaxIntensity = v; });
WirePicker(panel, PickerFur, painter ? painter.furColor : Color.blue,
c => { if (painter) painter.furColor = WithRgb(painter.furColor, c); });
WireSlider(panel, SliderFurAlpha, painter ? painter.furColor.a : .6f,
v => { if (painter) painter.furColor = WithAlpha(painter.furColor, v); });
WireSlider(panel, SliderFurOpacity, painter ? painter.furOpacity : 1f,
v => { if (painter) painter.furOpacity = v; });
// Fur has its own Toggle_Fur gate (wired above); the colour comes from the albedo map and the deposit
// weight from the brush alpha, so the only extra fur control is the target length.
WireSlider(panel, SliderFurLength, painter ? painter.furLength : 0.5f,
v => { if (painter) painter.furLength = v; });
foreach (var name in DraggablePanels)
MakeDraggable(panel, name);
@@ -295,11 +291,9 @@ public partial class PaintHud : MonoBehaviour
SetPicker(panel, PickerAlbedo, painter.brushColor);
SetPicker(panel, PickerEmission, painter.emissionColor);
SetPicker(panel, PickerFur, painter.furColor);
SetSlider(panel, SliderAlbedoAlpha, painter.brushColor.a);
SetSlider(panel, SliderEmissionAlpha, painter.emissionColor.a);
SetSlider(panel, SliderFurAlpha, painter.furColor.a);
SetSlider(panel, SliderFurOpacity, painter.furOpacity);
SetSlider(panel, SliderFurLength, painter.furLength);
SetSlider(panel, SliderMetallic, painter.metallic);
SetSlider(panel, SliderSmoothness, painter.smoothness);