You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Parent epic: #631
Depends on: Slice A (#632). Best-with: Paint v2 BrushEngine (#543 / #546).
Goal
Make every Paint v2 brush feature work for vertex paint: radius / strength / falloff / pressure / tilt / spacing / scatter / jitter / symmetry / line stabilizer / gradient ramps / textured stamps.
Today the legacy EditModeController vertex paint has only radius / strength / falloff / shape. The rest of Paint v2's BrushEngine shouldn't be duplicated — wire vertex paint into the same engine.
Scope
VertexPaintController consumes the same BrushEngine as Paint v2:
The brush's footprint produces a per-pixel weight at any 2D position.
For vertex paint, the projection step rasterises the footprint onto the mesh's screen-space vertex positions: each affected vertex receives a weight (0..1), then the brush colour is blended into that vertex's current colour with lerp(current, brush, weight * strength).
Gradient ramps (Paint v2 Slice A / Paint v2: Slice A — Gradient ramp brushes #544) — the brush colour varies along the stroke (linear) / across the brush footprint (radial / angular). For vertex paint, each affected vertex's colour comes from the ramp at its position in the brush.
Textured / stamp brushes (Paint v2 Slice B / Paint v2: Slice B — Textured / stamp brushes #545) — the stamp's alpha modulates the per-vertex weight; the stamp colour (or solid brush colour) is what gets written.
Channel routing: vertex paint has one channel (the vertex RGBA). No per-PBR-channel split like Paint v2's Paint v2: Slice D — Full PBR channel painting #547. But it does have per-channel mode: an optional sub-channel picker — Colour only / Alpha only / Red only / Green only / Blue only — so users can paint a single channel without disturbing the others. Useful for painting an AO mask into vertex alpha while the RGB stays clean.
The brush stamp computes a colour per affected vertex; the shading-mode resolver collapses to per-face if the face is Flat (using whichever corner the brush hits hardest), or writes per-vertex if Smooth.
This integration happens in VertexPaintController, not in BrushEngine — keep BrushEngine shading-mode-agnostic so it can be shared with texture paint cleanly.
Fallback: if Paint v2's BrushEngine hasn't shipped when this slice starts, prototype against the existing EditModeController brush params + a minimal local engine, and migrate when Paint v2 catches up.
Acceptance Criteria
Radius / strength / falloff / shape work identically to today.
Pressure modulates radius + strength on a tablet.
Symmetry mirrors strokes correctly (3 axes, world + local, topology-aware).
Line stabilizer smooths jittered strokes.
Linear / radial / angular gradient ramps colour vertices appropriately.
Stamp brushes (e.g. a "foliage cluster" stamp) modulate the per-vertex weight via the stamp's alpha.
Sub-channel picker (Colour / Alpha / R / G / B) writes only the chosen channel.
Brush respects the face shading-mode state from Slice A.
All operations undoable per-stroke as a single command.
Sentry breadcrumbs paint.vertex.brush.*.
Headless-CI test: stroke with each modifier (pressure, symmetry, gradient, stamp, channel restriction) on a fixture mesh.
Effort
~6 days, plus 2 buffer if Paint v2's BrushEngine extraction lags.
Parent epic: #631
Depends on: Slice A (#632). Best-with: Paint v2 BrushEngine (#543 / #546).
Goal
Make every Paint v2 brush feature work for vertex paint: radius / strength / falloff / pressure / tilt / spacing / scatter / jitter / symmetry / line stabilizer / gradient ramps / textured stamps.
Today the legacy
EditModeControllervertex paint has only radius / strength / falloff / shape. The rest of Paint v2'sBrushEngineshouldn't be duplicated — wire vertex paint into the same engine.Scope
VertexPaintControllerconsumes the sameBrushEngineas Paint v2:lerp(current, brush, weight * strength).VertexPaintController, not inBrushEngine— keepBrushEngineshading-mode-agnostic so it can be shared with texture paint cleanly.BrushEnginehasn't shipped when this slice starts, prototype against the existingEditModeControllerbrush params + a minimal local engine, and migrate when Paint v2 catches up.Acceptance Criteria
paint.vertex.brush.*.Effort
~6 days, plus 2 buffer if Paint v2's
BrushEngineextraction lags.