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:
adminandClaude Opus 4.8 committed 2026-07-14 22:26:35 +02:00
1 parent 9d17baee85
commit cdd9fa9532
7 files changed
+68 -8

No files matched your search

@@ -167,6 +167,11 @@ public partial class MeshPainter
float invR = 1f / radiusLocal;
float r2 = radiusLocal * radiusLocal;
// Back-face rejection: skip texels whose surface normal faces away from the clicked
// surface (the opposite side of thin geometry faces ~180deg away). cos(maxAngle); at
// 180deg it is -1 -> test disabled. n is unit, so dot(normalize(texelN), n) >= cutoff.
float nCutoff = BrushNormalCutoff;
bool doNormalTest = _normals != null && nCutoff > -0.9999f;
int triCount = _tris.Length / 3;
float ts = textureSize;
@@ -226,6 +231,18 @@ public partial class MeshPainter
// bleed across a seam / around a corner. Also guarantees |du|,|dv| <= r -> mu,mv in [0,1].
if (du * du + dv * dv + dn * dn > r2) continue;
// Reject the opposite side of thin geometry (interpolated texel normal vs. brush normal).
if (doNormalTest)
{
Vector3 tn0 = _normals[i0], tn1 = _normals[i1], tn2 = _normals[i2];
float nx = a * tn0.x + b * tn1.x + c * tn2.x;
float ny = a * tn0.y + b * tn1.y + c * tn2.y;
float nz = a * tn0.z + b * tn1.z + c * tn2.z;
float nl = nx * n.x + ny * n.y + nz * n.z;
float nmag = Mathf.Sqrt(nx * nx + ny * ny + nz * nz);
if (nmag > 1e-6f && nl < nCutoff * nmag) continue;
}
float mu = du * invR * 0.5f + 0.5f;
float mv = dv * invR * 0.5f + 0.5f;
float maskOp = SampleMaskOpacity(mu, mv);