Paint-Partikel beim Malen: Emission pro Stamp, Scale = Brush-Radius, Farbe = Brush-Albedo mit Helligkeits-Streuung
- MeshPainter: Paint Particles Prefab, lazy Instanz, Play/Stop am Stroke, MinMaxGradient (Albedo +-25%/15% dunkel/hell) - PaintSplatter.prefab + Paint Particle Material/Textur, Wiring am Player.prefab - FurShellRenderer: Kill-Switch-Destroy nur im Play-Mode (Edit-Mode-Error beim Prefab-Load) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a5438cf5a0
commit
094cf3a493
9 files changed
+5169
-3
No files matched your search
@@ -153,7 +153,9 @@ namespace Chameleon.Components
|
||||
return;
|
||||
}
|
||||
|
||||
Destroy(this);
|
||||
// Play mode only: in the editor Awake also runs on edit-mode loads (LoadPrefabContents,
|
||||
// [ExecuteAlways]) where Destroy is illegal - there OnEnable's disable path handles it.
|
||||
if (Application.isPlaying) Destroy(this);
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
|
||||
@@ -328,6 +328,14 @@ public partial class MeshPainter : MonoBehaviour
|
||||
[Range(0f, 4f)]
|
||||
public float previewOpacity = 0.5f;
|
||||
|
||||
[Header("Paint particles")]
|
||||
[Tooltip("Optional particle effect played at the brush while a stroke deposits paint. Instantiated " +
|
||||
"once on first use. Author the system for brush world-radius 1 with scaling mode Hierarchy: " +
|
||||
"the instance is scaled to the brush's world radius and tinted with the brush albedo color " +
|
||||
"(Start Color is overwritten). +Z of the instance points along the surface normal.")]
|
||||
public ParticleSystem paintParticlesPrefab;
|
||||
private ParticleSystem _paintParticles;
|
||||
|
||||
[Header("Canvas")]
|
||||
[Tooltip("Resolution of the paint textures (square).")]
|
||||
public int textureSize = 1024;
|
||||
@@ -829,6 +837,7 @@ public partial class MeshPainter : MonoBehaviour
|
||||
if (!PaintingEnabled)
|
||||
{
|
||||
EndStrokeIfActive(); // finalize an in-progress stroke if the mode was left mid-paint
|
||||
StopPaintParticles();
|
||||
_hasLastScreen = false;
|
||||
return;
|
||||
}
|
||||
@@ -859,6 +868,7 @@ public partial class MeshPainter : MonoBehaviour
|
||||
if (!TryGetMouse(out bool pressed, out Vector2 screenPos))
|
||||
{
|
||||
StrokeInProgress = false;
|
||||
StopPaintParticles();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -869,6 +879,7 @@ public partial class MeshPainter : MonoBehaviour
|
||||
// While the button is held on the paint path the hardware cursor is hidden entirely
|
||||
// (CursorController); the preview decal itself stays visible during the stroke.
|
||||
StrokeInProgress = pressed && !pipette;
|
||||
if (!StrokeInProgress) StopPaintParticles();
|
||||
|
||||
// Brush preview at the hover point.
|
||||
if (previewMode != BrushPreviewMode.Off && _previewMat && paintCamera)
|
||||
@@ -975,11 +986,46 @@ public partial class MeshPainter : MonoBehaviour
|
||||
else UseResolvedStampMask();
|
||||
|
||||
DrawBackendStamp(pLocal, radiusLocal, u, v, nLocal);
|
||||
UpdatePaintParticles(pLocal, radiusLocal, nLocal);
|
||||
|
||||
EmitStamp(pLocal, radiusLocal, u, v, nLocal);
|
||||
MarkStrokePainted(); // a stamp landed -> this stroke is undoable
|
||||
}
|
||||
|
||||
/// <summary>Moves/scales/tints the stroke particle effect at a landed stamp and keeps it playing.
|
||||
/// Scale = brush world radius (author the prefab for radius 1, scaling mode Hierarchy), tint =
|
||||
/// brush albedo color with a small per-particle random offset (alpha forced opaque - the brush
|
||||
/// alpha is paint opacity, not particle fade).</summary>
|
||||
private void UpdatePaintParticles(Vector3 pLocal, float radiusLocal, Vector3 nLocal)
|
||||
{
|
||||
if (!paintParticlesPrefab) return;
|
||||
if (!_paintParticles)
|
||||
_paintParticles = Instantiate(paintParticlesPrefab);
|
||||
|
||||
Transform t = _paintParticles.transform;
|
||||
t.SetPositionAndRotation(transform.TransformPoint(pLocal),
|
||||
Quaternion.LookRotation(transform.TransformDirection(nLocal)));
|
||||
t.localScale = Vector3.one * transform.TransformVector(nLocal * radiusLocal).magnitude;
|
||||
|
||||
var main = _paintParticles.main;
|
||||
Color c = brushColor;
|
||||
c.a = 1f;
|
||||
// Per-particle random tint offset around the albedo (darker <-> lighter).
|
||||
Color dark = Color.Lerp(c, Color.black, 0.13f);
|
||||
Color light = Color.Lerp(c, Color.white, 0.09f);
|
||||
dark.a = light.a = 1f;
|
||||
main.startColor = new ParticleSystem.MinMaxGradient(dark, light);
|
||||
|
||||
if (!_paintParticles.isPlaying) _paintParticles.Play();
|
||||
}
|
||||
|
||||
/// <summary>Stops emitting stroke particles (already-spawned ones live out their lifetime).</summary>
|
||||
private void StopPaintParticles()
|
||||
{
|
||||
if (_paintParticles && _paintParticles.isPlaying)
|
||||
_paintParticles.Stop();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if a brush dab at this placement would wrap excessively around a corner: more than
|
||||
/// <see cref="cornerGuardMaxFraction"/> of its footprint sits on surface whose face normal
|
||||
@@ -1235,6 +1281,7 @@ public partial class MeshPainter : MonoBehaviour
|
||||
if (_proceduralMask) Destroy(_proceduralMask);
|
||||
if (_previewMat) Destroy(_previewMat);
|
||||
if (_previewQuad) Destroy(_previewQuad);
|
||||
if (_paintParticles) Destroy(_paintParticles.gameObject);
|
||||
TeardownSpray();
|
||||
TeardownCpu();
|
||||
TeardownGpu();
|
||||
|
||||
Reference in new issue
Block a user