MeshPainter: Rückseiten-Abweisung über Flächen-Normale bei großem Brush
Zusätzlich zum Kugel-Test wird die Oberflächen-Normale jedes Texels gegen die Brush-Normale geprüft (CPU/GPU/Preview). Neues Inspector-Feld "Brush Max Surface Angle" (90-180°, Default 120°). Bei fehlenden Mesh-Normalen Degradation zur reinen Kugel. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
9d17baee85
commit
cdd9fa9532
7 files changed
+68
-8
No files matched your search
@@ -266,6 +266,21 @@ public partial class MeshPainter : MonoBehaviour
|
||||
[Range(0.01f, 1f)]
|
||||
public float brushSizeScrollFactor = 0.15f;
|
||||
|
||||
[Tooltip("Max angle (deg) between a texel's surface normal and the clicked surface for the brush to " +
|
||||
"still paint it. Prevents a large brush from bleeding onto the opposite side of thin geometry " +
|
||||
"(that side faces ~180deg away). Lower = stricter separation; 180 = disabled (paint everything " +
|
||||
"inside the sphere, old behavior). ~120 keeps corners/rounded edges while cutting the back face.")]
|
||||
[Range(90f, 180f)]
|
||||
public float brushMaxSurfaceAngle = 120f;
|
||||
|
||||
/// <summary>
|
||||
/// cos(brushMaxSurfaceAngle): a texel is painted only if dot(texelNormal, brushNormal) >= this.
|
||||
/// At 180deg the cutoff is -1 (always true) -> the normal test is effectively disabled. Returns -1
|
||||
/// when the mesh has no normals (test not possible) so the brush degrades to the plain sphere.
|
||||
/// </summary>
|
||||
private float BrushNormalCutoff =>
|
||||
_normals != null ? Mathf.Cos(brushMaxSurfaceAngle * Mathf.Deg2Rad) : -1f;
|
||||
|
||||
/// <summary>
|
||||
/// Raised after Shift+wheel changes <see cref="brushSize"/> so the in-game HUD can re-sync its
|
||||
/// brush-size slider (the slider then re-clamps the value to its own configured range).
|
||||
@@ -372,6 +387,7 @@ public partial class MeshPainter : MonoBehaviour
|
||||
|
||||
// Mesh caches (in local/collider space).
|
||||
private Vector3[] _verts;
|
||||
private Vector3[] _normals; // per-vertex normals (brush back-face rejection); null if unavailable
|
||||
private int[] _tris;
|
||||
private Vector2[] _uvs;
|
||||
private Vector3[] _triCenter; // centroid per triangle (CPU culling)
|
||||
@@ -464,6 +480,7 @@ public partial class MeshPainter : MonoBehaviour
|
||||
private static readonly int BrushUId = Shader.PropertyToID("_BrushU");
|
||||
private static readonly int BrushVId = Shader.PropertyToID("_BrushV");
|
||||
private static readonly int BrushNormalId = Shader.PropertyToID("_BrushNormal");
|
||||
private static readonly int BrushNormalCutoffId = Shader.PropertyToID("_BrushNormalCutoff");
|
||||
private static readonly int MaskTexId = Shader.PropertyToID("_MaskTex");
|
||||
private static readonly int PadId = Shader.PropertyToID("_Pad");
|
||||
private static readonly int PreviewOpacityId = Shader.PropertyToID("_PreviewOpacity");
|
||||
@@ -773,6 +790,7 @@ public partial class MeshPainter : MonoBehaviour
|
||||
_previewMat.SetVector(BrushUId, u);
|
||||
_previewMat.SetVector(BrushVId, v);
|
||||
_previewMat.SetVector(BrushNormalId, n);
|
||||
_previewMat.SetFloat(BrushNormalCutoffId, BrushNormalCutoff);
|
||||
|
||||
// Re-draw the collider mesh; the shader clips it to the brush box. The collider mesh is in
|
||||
// the same local space as the raycast hit and valid for skinned (baked) and static meshes.
|
||||
|
||||
Reference in new issue
Block a user