emilk / emilk/egui

Painting with opacity

Open
#7,623 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
30.6k
Forks
2.1k
Avg merge
1d 9h
Merged PRs (30d)
72

Description

I'm trying to work out how to do replicate egui's painting demo with a highlighter-like stroke.

That is, a thick stroke (32.0 width or higher) with a half-transparent color.

With the simple demo and naively giving the stroke color transparency, it looks all wrong because the different shapes overlap at the seams:
Image

I have tried a few things to fix this, none of them have worked all that well.

  • combining all egui::Shape::LineSegment into a single egui::Shape::Vec changed nothing
  • using a different library like lyon to first create a mesh and then using egui::Shape::Mesh, same result
    • although lyon had the additional benefit of supporting line caps and line joins, those would be nice to haves in egui as well
    • both vertex colors and using a texture had the same result
    • I guess lyon also generates overlaps in the mesh
  • using ui.set_opacity before painting, no difference

My understanding is that egui paints the shapes as they come in, meaning a "paint shapes, then apply opacity globally" isn't really a thing egui can do currently. In Qt, I can use a Canvas to draw things and then apply opacity to the whole canvas, but I believe that would require some kind of multi-pass rendering and thus isn't doable with egui?

Shape::Path, Shape::Mesh and Shape::Vec could have some way to set a global opacity to the whole shape. I assume this would require significant changes to how these are handled though.

Another option is the ability to do the painting into a separate texture and just display that as an image. Then I can draw opaque shapes into the texture and apply one global opacity to the whole image. It would be impossible to use different opacities in a single drawing, but it's more than enough for my use case. This seems related to #4432, just that my usecase isn't for testing and so egui_kittest::Harness isn't really the right tool here. I tried getting this done manually with egui_glow, but I don't understand the rendering well enough and didn't really get anywhere.

I did a little test using tiny_skia. It's very unperformant because it doesn't use the GPU, but rendering out an image with skia and then displaying that with a global opacity did work. skia also looked correct even if I just gave the stroke itself opacity, so tiny_skia already deals with this itself it seems.

Lastly, maybe there is a way to create a mask of the previous shapes to prevent drawing of overlapping areas?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No source file or test is named. Start by reviewing how egui handles Shape::Path, Shape::Mesh, Shape::Vec, and rendering through egui_glow; use #4432 and the egui_kittest Harness as related context. Done means a thick, semi-transparent stroke can be rendered without darker overlaps at seams, or a separate texture can receive one global opacity.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
computer-graphics
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.