Split mesh painter into partials and add occlusion via combined mask map
- Split MeshPainter into partial classes (Setup/Backend/Gpu/Cpu) for maintainability - Add ambient occlusion painting, packed with metallic/smoothness into one MSO mask map (R=metallic, G=occlusion, A=smoothness) bound to both _MetallicGlossMap and _OcclusionMap, kept independently paintable via per-channel ColorMask - Gate painting from a single IsChannelActive source so AO-only strokes work - Blend albedo/emission in linear space on CPU to match the GPU framebuffer - Pre-compensate data-channel writes for sRGB->linear so GPU matches CPU - Harden GPU shader fallback to reflect real backend state Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
86c0a33687
commit
c7ec12e6d9
11 files changed
+927
-776
No files matched your search
@@ -20,6 +20,7 @@ Shader "Hidden/MeshPaintBrush"
|
||||
{
|
||||
_BrushColor ("Brush Color", Color) = (1,0,0,1)
|
||||
_MaskTex ("Brush Mask", 2D) = "white" {}
|
||||
_ColorWriteMask ("Color Write Mask", Float) = 15
|
||||
}
|
||||
SubShader
|
||||
{
|
||||
@@ -29,6 +30,11 @@ Shader "Hidden/MeshPaintBrush"
|
||||
ZTest Always
|
||||
ZWrite Off
|
||||
Cull Off
|
||||
// Per-channel write mask: lets the shared mask map (R=metallic, G=smoothness,
|
||||
// B=occlusion) be painted by metallic/smoothness and occlusion independently.
|
||||
// ColorWriteMask bits: R=8, G=4, B=2, A=1 (15 = all). Alpha (coverage) is always
|
||||
// written so the dilation pass still sees the freshly painted texels.
|
||||
ColorMask [_ColorWriteMask]
|
||||
// Source-over for color; alpha accumulates coverage toward 1 (painted marker
|
||||
// for the dilation pass). Soft edges keep partial alpha.
|
||||
Blend SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
// Packs the metallic-smoothness WORK layout into the URP _MetallicGlossMap layout.
|
||||
// Packs the mask-map WORK layout into the URP mask-map layout.
|
||||
//
|
||||
// While painting, the metallic-smoothness map is kept in a "work" RenderTexture as
|
||||
// R = metallic, G = smoothness, A = coverage (painted marker for the dilation pass).
|
||||
// While painting, the mask map is kept in a "work" RenderTexture as
|
||||
// R = metallic, G = smoothness, B = occlusion, A = coverage (painted marker for dilation).
|
||||
// This lets the same brush + dilate shaders (which use alpha as the coverage marker)
|
||||
// drive it exactly like the albedo map. But URP's _MetallicGlossMap expects
|
||||
// R = metallic, A = smoothness.
|
||||
// This pass converts work -> final after each stroke: out = (work.r, 0, 0, work.g).
|
||||
// drive it exactly like the albedo map. The packed result is one texture bound to BOTH
|
||||
// _MetallicGlossMap (URP reads R = metallic, A = smoothness) and
|
||||
// _OcclusionMap (URP reads G = occlusion).
|
||||
// This pass converts work -> final after each stroke: out = (work.r, work.b, 0, work.g)
|
||||
// = (metallic, occlusion, 0, smoothness).
|
||||
//
|
||||
// Both work and final are linear RenderTextures (metallic/smoothness are data, not
|
||||
// color), so no gamma conversion happens.
|
||||
// Both work and final are linear RenderTextures (these are data, not color), so no gamma
|
||||
// conversion happens.
|
||||
Shader "Hidden/MeshPaintPackMS"
|
||||
{
|
||||
Properties
|
||||
@@ -35,7 +37,8 @@ Shader "Hidden/MeshPaintPackMS"
|
||||
fixed4 frag (v2f_img i) : SV_Target
|
||||
{
|
||||
fixed4 c = tex2D(_MainTex, i.uv);
|
||||
return fixed4(c.r, 0.0, 0.0, c.g); // R = metallic, A = smoothness
|
||||
// work (R=metallic, G=smoothness, B=occlusion) -> (metallic, occlusion, 0, smoothness)
|
||||
return fixed4(c.r, c.b, 0.0, c.g);
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user