- Add hover preview (MeshPaintPreview.shader) with a Preview Mode enum (Off / Flat Decal / On Surface) sharing the paint placement path so size, mask, alignment and rotation match the actual stroke. - Preview Opacity now ranges up to 4.0 so faint/grey masks can be shown more strongly (saturates to full opacity before the hardware blend). - Add Paint On Move Only: stamp once on mouse-down, then only while the cursor moves (GPU and CPU paths alike). - Remove brushOpacity; brushColor.a is now the global opacity multiplier over the mask in both backends (the alpha channel was previously unused by the brush shader).
104 lines
4.1 KiB
Plaintext
104 lines
4.1 KiB
Plaintext
// Brush preview overlay: shows the brush footprint (size + mask) on the mesh
|
|
// WITHOUT painting. Two modes, selected via _PreviewMode:
|
|
//
|
|
// 0 = On-surface: the baked mesh is drawn again (object transform) and each
|
|
// fragment runs the SAME box + mask test as the paint shader, in local mesh
|
|
// space (_BrushCenter/_BrushU/_BrushV/_BrushNormal/_BrushRadius). So the
|
|
// preview wraps over curvature and across UV seams exactly like the paint
|
|
// would land. Depth test (LEqual) + a slight polygon offset keep it glued to
|
|
// the surface and correctly occluded by closer geometry.
|
|
//
|
|
// 1 = Flat decal quad: a single quad oriented in the tangent plane; the mask is
|
|
// sampled straight from the quad UVs (0..1 already spans the stamp, so it
|
|
// lines up 1:1 with the on-surface mapping). Flat - does not follow curvature.
|
|
//
|
|
// Unlit, transparent (SRPDefaultUnlit) so URP renders it via Graphics.DrawMesh. The
|
|
// mask drives the alpha (luma * alpha * _PreviewOpacity), tinted with _BrushColor.
|
|
Shader "Hidden/MeshPaintPreview"
|
|
{
|
|
Properties
|
|
{
|
|
_BrushColor ("Brush Color", Color) = (1,0,0,1)
|
|
_MaskTex ("Brush Mask", 2D) = "white" {}
|
|
}
|
|
SubShader
|
|
{
|
|
Tags { "RenderType" = "Transparent" "Queue" = "Transparent" "IgnoreProjector" = "True" }
|
|
Pass
|
|
{
|
|
ZWrite Off
|
|
ZTest LEqual
|
|
Cull Off
|
|
Offset -1, -1 // pull the overlay toward the camera so it wins over the painted surface
|
|
Blend SrcAlpha OneMinusSrcAlpha
|
|
|
|
CGPROGRAM
|
|
#pragma vertex vert
|
|
#pragma fragment frag
|
|
#include "UnityCG.cginc"
|
|
|
|
float4 _BrushColor;
|
|
float3 _BrushCenter; // brush center in local mesh space (on-surface mode)
|
|
float3 _BrushU; // stamp right axis (unit, local space)
|
|
float3 _BrushV; // stamp up axis (unit, local space)
|
|
float3 _BrushNormal; // surface normal at the hit (unit, local space)
|
|
float _BrushRadius; // stamp half-extent in local mesh space
|
|
float _PreviewOpacity; // overall preview alpha multiplier (>1 saturates to fully opaque)
|
|
float _PreviewMode; // 0 = on-surface (mesh), 1 = flat decal quad
|
|
sampler2D _MaskTex;
|
|
|
|
struct appdata
|
|
{
|
|
float4 vertex : POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
};
|
|
|
|
struct v2f
|
|
{
|
|
float4 pos : SV_POSITION;
|
|
float3 local : TEXCOORD0; // object-space position (on-surface box test)
|
|
float2 uv : TEXCOORD1; // quad uv (decal sampling)
|
|
};
|
|
|
|
v2f vert (appdata v)
|
|
{
|
|
v2f o;
|
|
o.pos = UnityObjectToClipPos(v.vertex);
|
|
o.local = v.vertex.xyz;
|
|
o.uv = v.uv;
|
|
return o;
|
|
}
|
|
|
|
fixed4 frag (v2f i) : SV_Target
|
|
{
|
|
float2 muv;
|
|
if (_PreviewMode < 0.5)
|
|
{
|
|
// On-surface: same square box test as the paint shader, in local space.
|
|
float3 d = i.local - _BrushCenter;
|
|
float du = dot(d, _BrushU);
|
|
float dv = dot(d, _BrushV);
|
|
float dn = dot(d, _BrushNormal);
|
|
clip(_BrushRadius - abs(du));
|
|
clip(_BrushRadius - abs(dv));
|
|
clip(_BrushRadius - abs(dn));
|
|
muv = float2(du, dv) / _BrushRadius * 0.5 + 0.5;
|
|
}
|
|
else
|
|
{
|
|
// Flat decal quad: uv already spans the stamp.
|
|
muv = i.uv;
|
|
}
|
|
|
|
fixed4 m = tex2D(_MaskTex, muv);
|
|
float luma = dot(m.rgb, fixed3(0.299, 0.587, 0.114));
|
|
float opacity = luma * m.a * _PreviewOpacity;
|
|
clip(opacity - 1e-4); // skip fully transparent texels
|
|
return fixed4(_BrushColor.rgb, opacity);
|
|
}
|
|
ENDCG
|
|
}
|
|
}
|
|
Fallback Off
|
|
}
|