Fix frozen rim pixels via GPU coverage stamp; add brush masks
Replace the CPU island-mask dilation guard on the GPU backend with a coverage pass rendered through the same brush rasterizer, so sub-pixel rim texels that the GPU brush can never reach fall into the gutter and stay paintable (no more frozen loaded pixels at island edges). Also includes user content: additional brush masks (dirt) with an expanded mask selector in the HUD prefab, and CharacterController / wall-climb inspector tuning. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
c14525a2c8
commit
fa7082817e
8 files changed
+986
-16
No files matched your search
@@ -78,18 +78,46 @@ public partial class MeshPainter
|
||||
if (mi == MAP_MSO)
|
||||
{
|
||||
// Canonical (R=metallic, G=occlusion, A=smoothness) -> work layout
|
||||
// (R=metallic, G=smoothness, B=occlusion); UploadColorsToRT fills A = island coverage.
|
||||
// (R=metallic, G=smoothness, B=occlusion). Alpha = coverage, stamped below.
|
||||
var work = new Color32[src.Length];
|
||||
for (int i = 0; i < src.Length; i++) work[i] = new Color32(src[i].r, src[i].a, src[i].g, 0);
|
||||
UploadColorsToRT(work, gm.display, linear: true);
|
||||
StampCoverage(gm.display);
|
||||
PackMs(gm); // build the final mask RT once so the material shows the seeded values
|
||||
}
|
||||
else
|
||||
{
|
||||
UploadColorsToRT((Color32[])src.Clone(), gm.display, linear: gm.sRGB == false);
|
||||
StampCoverage(gm.display);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stamps the dilation coverage guard into a map's alpha: rasterizes the mesh with the brush
|
||||
/// shader's coverage pass (pass 1), writing alpha = 1 on exactly the texels the GPU brush can
|
||||
/// paint. This replaces the CPU island-mask approximation, whose generous edge tolerance marked
|
||||
/// sub-pixel island borders as protected even though the brush never reaches them - so they
|
||||
/// could never be overpainted (stayed frozen at their seeded value) while the dilation guarded
|
||||
/// them. With a GPU-accurate guard those border texels fall in the gutter (alpha 0) and dilation
|
||||
/// overpaints them normally. Texels stay alpha 0 until reached, identical to the brush.
|
||||
/// </summary>
|
||||
private void StampCoverage(RenderTexture rt)
|
||||
{
|
||||
if (!_brushMat || !_bakedMesh) return;
|
||||
var prev = RenderTexture.active;
|
||||
Graphics.SetRenderTarget(rt);
|
||||
if (_brushMat.SetPass(1))
|
||||
{
|
||||
int sub = _bakedMesh.subMeshCount;
|
||||
for (int i = 0; i < sub; i++) Graphics.DrawMeshNow(_bakedMesh, Matrix4x4.identity, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[MeshPainter] Brush coverage pass (pass 1) missing - dilation guard not seeded.", this);
|
||||
}
|
||||
RenderTexture.active = prev;
|
||||
}
|
||||
|
||||
private void TeardownGpu()
|
||||
{
|
||||
if (_gpu != null)
|
||||
@@ -124,16 +152,13 @@ public partial class MeshPainter
|
||||
return rt;
|
||||
}
|
||||
|
||||
/// <summary>Writes Color32 data into a RenderTexture via a temporary texture.</summary>
|
||||
/// <summary>Writes Color32 RGB into a RenderTexture via a temporary texture. Alpha (the
|
||||
/// dilation coverage marker) is cleared to 0 here and stamped afterwards by StampCoverage,
|
||||
/// so the guard matches the GPU rasterizer exactly (see SeedGpuMap).</summary>
|
||||
private void UploadColorsToRT(Color32[] colors, RenderTexture rt, bool linear)
|
||||
{
|
||||
var tmp = new Texture2D(textureSize, textureSize, TextureFormat.RGBA32, false, linear);
|
||||
// Alpha is the dilation coverage marker: island texels (real content) = 255 so the
|
||||
// dilate pass keeps them; the gutter = 0 so it stays paddable. Driving this from the UV
|
||||
// islands (not a flat "unpainted") protects seeded content from the first stroke's bleed.
|
||||
var island = GetIslandMask();
|
||||
bool useMask = island.Length == colors.Length;
|
||||
for (int i = 0; i < colors.Length; i++) colors[i].a = (useMask && island[i]) ? (byte)255 : (byte)0;
|
||||
for (int i = 0; i < colors.Length; i++) colors[i].a = 0;
|
||||
tmp.SetPixels32(colors);
|
||||
tmp.Apply(false);
|
||||
|
||||
|
||||
Reference in new issue
Block a user