3

I'm drawing semitransparent paths with QGraphicsPathItems but I have an issue when two paths overlap, they become more opaque, but I would like them to keep the same level of transparency, no matter how many paths overlap.

On the left side two separate paths, become more opaque. On the right, single path crossing over itself, same level of transparency, this is the effect I would like to achieve with several paths.

Overlapping paths

Is it possible to achieve something like that?

Damir Porobic
  • 681
  • 1
  • 8
  • 21
  • I think it's impossible. Each item simply draws itself on top of everything else. It is not aware of what item is drawn underneath it. Besides, what you want contradicts the idea of semi-transparency - if the item underneath is completely covered by the top item, them the top item effectively hides it, which is counter to the idea of semi-transparency. Just make your items opaque. – sashoalm Sep 02 '16 at 05:33
  • Actually, can you make the items children of some other item? The items themselves are fully opaque, but the parent item plane on which they are drawn is semi-transparent. I don't know you can have that, though. This is what you really want, right? – sashoalm Sep 02 '16 at 05:37
  • 2
    Also see https://stackoverflow.com/questions/31403383/qt-overlapping-semitransparent-qgraphicsitem – sashoalm Sep 02 '16 at 05:45
  • Thanks @sashoalm for the replies. I have tried creating custom QGraphicsItems which draw it's own path but the effect is the same like above, even with setting the CompositionMode like explained on the link that you have shared, tried also different other composition mode too but the effect is totally strange (changing the color of the background and similar). I was thinking about checking if paths overlap, if yes, add the new path as sub-path to the already existing, don't know if this could work. Also, I need to be able to erase paths separately, not sure if it will work with sub-paths. – Damir Porobic Sep 02 '16 at 06:21
  • What about my second comment? Is it possible to make them fully opaque but children to a semi-transparent parent layer item? – sashoalm Sep 02 '16 at 06:23
  • Interesting idea, haven't thought of that. Need to check how it would work with other drawing options as I have also some kind of pen drawing which is totally opaque, so eventually would need to go with two layers that have different transparency setting. This will eventually make me unable to reach stuff below the top layer in case I need to erase it. – Damir Porobic Sep 02 '16 at 07:26
  • I've fallen back to using `painter->setCompositionMode`, it looks like the `CompositionMode_ColorBurn` could work though it's a little bit dark on dark background but very nice on brighter backgrounds like white. Guess I've missed this one when I tested this solution in the first place. http://i.imgur.com/FlZSELk.png – Damir Porobic Sep 03 '16 at 16:05

2 Answers2

0

I searched a bit about whether Qt has true layering for opacity, and found a post in Qt Blog by Andreas Aardal Hanssen:

https://blog.qt.io/blog/2009/04/23/layered-rendering-part-2-it-helps-solve-many-problems/

He says the only way to do it is using off-screen rendering.

By rendering the “green sub-tree” into a separate layer, we can combine all items and apply one uniform opacity as part of composing these items together. In my last blog I wrote about off-screen rendering. This work has progressed and is in quite a usable state (although the code is really ugly). It works! The rendering output for the same application as the above looks like this.

The link to the off-screen rendering solution is https://blog.qt.io/blog/2009/02/27/braindump-graphics-view-and-the-joys-of-off-screen-rendering.

I think the idea is that you render each layer separately to a pixmap. The items in that layer are opaque relative to each other. Then you render the layers themselves with transparency relative to each other.

Items in the same layer are opaque relative to each other, but transparent relative to items in the other layers.

The link talks about some prototype project that uses DeepItemCoordinateCache, which renders an item and its children to an offscreen buffer, then renders that buffer. This would achieve the desired effect.

Collapsing a subtree into a single offscreen buffer is possible. I’ve spent two days this week researching it, wrote some code, and ended up with a prototype that’s so ugly I don’t want to share it just yet. But I’ve seen that it’s perfectly possible without messing up QGV’s internals. I dubbed two new cache modes:

DeepItemCoordinateCache – caches the item and “all” children, no repaints for “any” child if the parent is transformed DeepDeviceCoordinateCache – save for DeviceCoordinateCache

Unfortunately, I don't know if his prototype code is available anywhere. He implies it's inside the Embedded Dialogs example at https://doc.qt.io/qt-5/qtwidgets-graphicsview-embeddeddialogs-example.html, so maybe you should search there.

Community
  • 1
  • 1
sashoalm
  • 75,001
  • 122
  • 434
  • 781
  • Thanks again @sashoalm for looking into this further. I'm fine with using the composition mode solution in the paint function for now, it's not perfect but good enough. I have tested some other solutions too, like adding new paths all to a single item in form of sub-paths, it worked but it's such an ugly solution that I've stepped away from it. – Damir Porobic Sep 05 '16 at 09:25
0

Coming back to this question after long time, the final solution for me was using indeed CompositionMode, precisly QPainter::CompositionMode_Multiply but the error that I wealier had was was that I had alpha in the used colors. With the mentioned CompositionMode and no alpha in the color I get exactly the result I was looking for.

Damir Porobic
  • 681
  • 1
  • 8
  • 21