Skip to content

Epic: Paint v2 — Gradients, textured brushes, layers, full PBR painting #543

Description

@fernandotonon

Overview

The Paint Tools MVP (epic #313, closed) shipped a solid foundation: TexturePaintController with Paint / Erase / Fill / ColorPicker / Smudge / SmartSelect tools, round/square brushes with radius / strength / falloff, vertex-and-texture targets, undo-wired strokes, paint-buffer image provider for live QML preview, vertex-color baking, and seam dilation.

This epic is Paint v2: build on that foundation to bring QtMeshEditor's painting up to the level users expect from Blender Texture Paint, Substance Painter (the parts that fit a single-binary indie editor), Krita, and 3D-Coat's "paint" workflow. The two features the user explicitly asked for — gradient brushes and textured (stamp / tiling) brushes — anchor the work, plus the rest of the modern-paint feature set the MVP doesn't yet cover.

GUI + CLI + MCP parity (where painting maps to scriptable operations), undo through UndoManager, Sentry breadcrumbs (paint.*), and the slice-PR cadence used by every recent epic.

Why

  • Plain solid color is the v1 limit. Real surface authoring needs gradient ramps (sunset, gold→rust, hue ramp), textured brushes (a leaf shape, a metal-scratch stamp), and tiling pattern brushes (wood grain, brick, fabric).
  • One target slot (BaseColor) leaves the PBR story half-done. Painters need to paint into normal, roughness, metallic, AO, emissive, height.
  • No layers means destructive painting. Every major painter has layered, blendable, maskable, reorderable layers; QtMeshEditor's MVP composites directly into the texture.
  • No symmetry, no projection painting, no stencils — table-stakes 3D-paint features missing today.
  • Pairs with finished epics: HDR/IBL (Epic: HDR — HDR lighting, IBL, and tone mapping #466) — painted PBR maps need IBL; UV editor (Epic: UV — UV Map editing #458) — Paint v2 should let users fix seams visible in the UV panel; AI (AI: Mesh-aware texture generation (depth-conditioned sd.cpp) #403, AI: PBR map synthesis from albedo (DeepBump-style, ONNX) #404) — generated maps land into the new layer stack rather than overwriting a flat texture.

Architecture

Builds on what's already merged, doesn't replace it:

  • PaintLayerStack — per-material ordered list of PaintLayer { name, type, blendMode, opacity, visible, mask, buffer }. The MVP's single TexturePaintBuffer becomes one layer ("Background") on a new stack; existing strokes route to the active layer.
  • BrushEngine — extracted from TexturePaintController's stamp loop:
    • Footprint: round / square / textured stamp image / tiling source texture sampler.
    • Color source: solid / gradient ramp / picker from texture / cavity / curvature / AO mask.
    • Modifiers: jitter, spacing, scatter, rotation (fixed / pen tilt / direction-of-stroke), pressure→size / pressure→opacity, line stabilizer.
  • PaintChannelRouter — routes the active brush onto BaseColor / Normal / Roughness / Metallic / AO / Emissive / Height with channel-aware presets.
  • SymmetryEngine — mirror painting across X/Y/Z (world or local) and topology-aware mirror for asymmetric meshes.
  • ProjectionPainter — paint from the active viewport camera (stencil / projection); paint from a 2D image projected through a placed plane (decals).

Reuses every MVP component: TexturePaintBuffer becomes per-layer; PaintSelectionMask extends to layer masks; PaintBufferImageProvider becomes layer-aware; VertexColorBaker becomes "Bake vertex layer to texture layer"; existing undo commands gain a layerIndex field.

Cross-cutting integration: UV editor (#458) overlap/stretch overlays surface in paint mode; HDR/IBL (#466) renders painted PBR correctly; AI generators (#403, #404) land into a new layer instead of overwriting.

Child Issues

Slices A–D are the user's directly requested features plus the missing-must-haves; E–H cover the rest of the modern-paint table-stakes; I closes the loop into engine deliverables; J brings everything to project conventions.

Acceptance Criteria (epic-level)

  • User can paint with a gradient ramp (linear / radial / angular), at least 6 bundled ramps, and author/save custom ones.
  • User can paint with textured / stamp brushes — choosing a stamp image or tiling source — with jitter / scatter / spacing.
  • Painting is non-destructive via a layer stack with at least 8 blend modes (Normal, Multiply, Screen, Overlay, Add, Subtract, Soft Light, Hue/Sat/Color/Luminosity).
  • Layers have per-layer masks, opacity, visibility, reorder, rename, duplicate, merge.
  • User can paint directly into normal / roughness / metallic / AO / emissive / height — not just BaseColor.
  • Symmetry painting works across world/local X/Y/Z plus a topology-aware mode.
  • Projection painting from the active viewport camera and from a placed image plane both work.
  • Cavity / curvature / AO masks auto-generate from the mesh and feed brush color or layer masks.
  • Tablet pressure modulates size and opacity (Wacom + Apple Pencil).
  • Brush preset library and color swatches/palettes ship.
  • Bake-up: vertex → layer, layer stack → flat PBR set, layer stack → engine-specific texture pack.
  • Every stroke is undoable; layer ops are undoable.
  • Sentry breadcrumbs paint.* for every user-visible paint action.
  • CLAUDE.md "Paint" section updated.

Dependencies & related issues

Out of scope

  • Full Substance-Painter-style smart materials with chained procedural generators.
  • Sculpting / displacement painting beyond a height layer.
  • 2D-only image editing tools (curves/levels/filters).
  • Network / collaborative painting.
  • Multi-tile UDIM painting beyond display (single 0..1 UV target for v2).

Notes for implementers

  • The MVP's TexturePaintBuffer, PaintSelectionMask, PaintBufferImageProvider, and VertexColorBaker are tested production code — wrap, don't rewrite.
  • Every brush stamp must run through BrushEngine so modifiers compose without re-touching every tool.
  • Layer composition runs on paint commit; live preview keeps composing the current stroke against the visible-below stack.
  • Painting into normal maps must convert from screen/object-space height to tangent-space normals correctly — coordinate with AI: PBR map synthesis from albedo (DeepBump-style, ONNX) #404's DeepBump path.
  • Tablet input: QTabletEvent is portable; no platform-specific code needed.
  • Slice cadence + screenshots + Xvfb-safe tests, per project convention.

Metadata

Metadata

Assignees

No one assigned

    Labels

    editorenhancementNew feature or requestpaintPaint tools (vertex, texture, projection, layers, brushes)qtmesh-roadmap

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions