Skip to content

Paint Groups brush: paint face groups with a stroke - #245

Merged
crisprintsstuff merged 3 commits into
mainfrom
paint-groups-brush
Nov 14, 2026
Merged

crisprintsstuff merged 3 commits into
mainfrom
paint-groups-brush

Conversation

@crisprintsstuff

Copy link
Copy Markdown
Owner

Adds a Paint Groups brush (requested by the maintainer): paint face groups directly instead of masking and then grouping.

Behaviour

  • In the brush shelf after Paint (no number key; the first ten are unchanged).
  • Each stroke makes a new group. Alt+stroke grows the group under the start of the stroke.
  • Paints whole triangles whose centre is inside the brush.
    • Follows symmetry, including radial, and Front faces only.
    • Leaves hidden faces alone and never moves the surface.
    • Fills dabs along the path, so fast strokes leave no gaps.
  • Turns the group colors on when you start painting, and says so in the status bar.
  • One undo step per stroke (a face edit). Escape mid-stroke puts the groups back.
  • The brush panel shows only what applies: Radius, Size mode, Pen pressure sets radius, and Front faces only.
  • Agents get a clear error for this brush instead of a stroke that does nothing.

How

  • Mesh::paint_group visits only chunks whose bounds meet the brush sphere.
  • It bumps the face version without recomputing per-vertex visibility, which stays valid because only groups change.
  • The stroke is app-driven (Drag::GroupPaint, crates/oxy-app/src/group_paint.rs), like Tube, not a dab kernel.
  • BrushKind::PaintGroups is added everywhere brush kinds are listed: preset and settings keys, icon (amber tint), description, and gravity exclusion.

Performance

Per dab on a 1,310,720-triangle sphere (release build, 4 cores, from a throwaway timing loop not in this PR):

Radius Time per dab
0.05 0.07 ms
0.2 0.21 ms

Sculpting brushes are untouched.

Verified

  • cargo fmt --check, clippy -D warnings, cargo test --workspace, check_corpus_ip.py.
  • New tests:
    • oxy-mesh: only the sphere is painted; front faces only.
    • Editor:
      • each stroke makes a new group and is one undo step;
      • Alt grows the group;
      • Escape cancels with nothing to undo;
      • X symmetry paints both sides;
      • hidden faces are skipped;
      • positions never change.
  • Headless screenshot (lavapipe): three strokes on the starting sphere make three groups, each mirrored across X. The brush panel is trimmed. The screenshot came from a temporary local hack that runs the strokes at start; it is not in this PR.

Not done / limitations

  • No "pick a group to paint with" eyedropper; Alt-grow covers extending one.
  • Triangles are painted whole, by their centre, so the stroke edge follows the mesh, not a smooth curve.
  • Not tested with a pen, on Windows or on macOS.

Generated by Claude Code

Making face groups meant masking first and then grouping from the mask
(Ctrl+W), two steps for something testers expect to paint directly.

Add a Paint Groups brush to the shelf after Paint. Each stroke makes a
new group, and Alt+stroke grows the group under the start of the stroke.
It paints whole triangles whose centre is within the brush radius,
mirrored by symmetry, honouring Front faces only, leaving hidden faces
alone and never moving the surface. Dabs are filled along the path, so
fast strokes leave no gaps. The whole stroke is one face-edit undo step,
and Escape puts the groups back.

The stroke is driven by the app, like Tube, rather than by the dab
kernels. Mesh::paint_group visits only the chunks the sphere touches and
bumps the face version without recomputing visibility: 0.07 to 0.2 ms
per dab on a 1.3M-triangle sphere. The brush panel hides the strength
and dab settings, which don't apply. Agents get a clear error rather
than a no-op stroke.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GEttLK8THCkZ7KHELbSp7g
Signed-off-by: Claude <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>

# Conflicts:
#	docs/ROADMAP.md
Signed-off-by: Claude <noreply@anthropic.com>

# Conflicts:
#	CHANGELOG.md
#	docs/ROADMAP.md
@crisprintsstuff
crisprintsstuff merged commit 27555ec into main Nov 14, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants