Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Layer Blend Mode Property #3932

Open
Paperdomo101 opened this issue Apr 19, 2024 · 15 comments · May be fixed by #4140
Open

Layer Blend Mode Property #3932

Paperdomo101 opened this issue Apr 19, 2024 · 15 comments · May be fixed by #4140
Labels
feature It's a feature, not a bug.

Comments

@Paperdomo101
Copy link

Images intended to be rendered with blend modes other than alpha blend don't display accurately in Tiled.

It would be great if layers had a blend mode property, choices would include additive, multiplied, subtractive, and default alpha blend.

Currently, I just a custom property to set the blend mode in my engine, but obviously this doesn't fix it rendering inaccurately in Tiled.

Demo:
gui
side_by_side

@Paperdomo101 Paperdomo101 added the feature It's a feature, not a bug. label Apr 19, 2024
@eishiya
Copy link
Contributor

eishiya commented Apr 19, 2024

This is not currently possible in Tiled without a massive performance hit, AFAIK. There is already a plan to write a different renderer that would allow blending modes and even custom shaders: https://github.com/mapeditor/tiled/wiki/New-Hardware-Renderer

@Paperdomo101
Copy link
Author

Ok, thanks for letting me know.

@AxiomVerge
Copy link

Is there a way to do paid bounties with tiled?

@bjorn
Copy link
Member

bjorn commented Sep 26, 2024

Is there a way to do paid bounties with tiled?

Starting at the $20/month sponsorship tier there is already 1h of time I will guarantee to look into a certain issue. It will take a little more time to implement this, but if one of the composition modes supported by QPainter suits your needs, then there is no need to first implement a new renderer.

For testing, I've done a quick minimal patch (fb0289b) that just added a composition mode layer property (no undo or serialization yet). It's a little hard to see the difference, but "Plus" might be the "additive" mode @Paperdomo101 is after:

image

When adding this I wonder about a few things:

  • Should we be selective about which composition modes are supported, or just support all of those modes that QPainter supports? (I've left out its "RasterOp" modes already because they have quite a few restrictions according to the docs).
  • If one would try to implement lighting using a "Multiply" mode, then one would probably want to first render all lights "additive" to an intermediate layer and then multiply the result with the destination. Supporting this would go way beyond a simple patch, however.

@bjorn
Copy link
Member

bjorn commented Sep 26, 2024

I see SVG supports all these composition operations as well, so they appear to be quite standard. Hence I see no real reason to limit them to a subset.

SVG also uses the same names, so I wonder if we should just go with those. On the other hand, both GIMP and Krita call it "Blend mode: Addition" rather than "Composition mode: Plus", so some adjustment to more common vocabulary could be useful.

Regarding group layers, I feel like child layers should inherit the composition mode from the parent layer, so there should probably be an "Inherit" (SVG) or "Normal" (GIMP, Krita) entry in the list that is selected by default.

@eishiya
Copy link
Contributor

eishiya commented Sep 26, 2024

If one would try to implement lighting using a "Multiply" mode, then one would probably want to first render all lights "additive" to an intermediate layer and then multiply the result with the destination. Supporting this would go way beyond a simple patch, however.

In Photoshop, this sort of thing is done with groups: You'd group a "Normal" layer (standard alpha blending) with a Add layer with your lights, and then set the group to Multiply. The default blending mode for groups in PS is "pass through", i.e. blend each child as if the group wasn't there, but all the standard blending modes are also available, which treat the "output" of the group as its own independent layer. Perhaps the same approach could work for Tiled? It'd still take extra work since with blending modes other than "pass through" would require compositing each group's contents separately before compositing them with the other layers.

The "sourceIn" composition mode would allow creating essentially clipping masks, but as these are often combined with other blending modes, they'd probably also need to be used with groups as suggested above to get their full effect.

I see SVG supports all these composition operations as well, so they appear to be quite standard. Hence I see no real reason to limit them to a subset.

Nice :D
IME the blending modes provided out of the box in engines are usually pretty limited - typically just add, multiply, alpha blend, sometimes not even that. But all these modes can be implemented with shaders or blend equations (in engines that provide an interface for that, e.g. Unity).
If added to Tiled, I think they should be given more common names where appropriate, and the calculations should be documented in the Tiled docs. In Qt, they're implemented with OpenGL blend functions, and each one is pretty simple: https://github.com/qt/qtbase/blob/a0f53ec9708dd8032b466b868883f8118ab7c7ef/src/opengl/qopenglpaintengine.cpp#L514-L613
Perhaps we could simply include these, since most engines/frameworks provide some equivalent to these, or expose them directly. We could also link to OpenGL's blendFunc documentation, which explains the actual calculations.

@bjorn
Copy link
Member

bjorn commented Sep 26, 2024

In Photoshop, this sort of thing is done with groups

I agree the group layers could be a good base for the intermediate layer logic, though the same might already be expected from a plain object layer where lights are placed. However, for such a change I think we should first rewrite the renderer in general. Qt Quick does support rendering to intermediate textures through the ShaderEffectSource.

In Qt, they're implemented with OpenGL blend functions, and each one is pretty simple:

Of course, that is only when enabling OpenGL. By default Tiled uses software rendering, in which case the composition functions at https://github.com/qt/qtbase/blob/a0f53ec9708dd8032b466b868883f8118ab7c7ef/src/gui/painting/qcompositionfunctions.cpp are used. Either way I think the SVG docs are pretty good at explaining each operation, so I'd suggest we link to those (or those and the OpenGL ones...).

(hmm, I did notice the SVG doc is a working draft from 2011 that is about features that don't appear to be supported by latest Firefox nor Chromium today)

@eishiya
Copy link
Contributor

eishiya commented Sep 26, 2024

I figured proper group blending support would have to wait for the bigger change. To avoid having more functional changes in the future, perhaps for now, groups should not have blending modes at all, and always behave as "pass through"? Then when the new renderer is implemented, a blending mode could be added to groups that would blend the combined output of the group according to the group's blending mode, if it's not "pass through".

FWIW, given how objects are typically rendered in games, I think objects inheriting their layer's blending mode, rather than blending the whole layer after rendering all objects, would be fine. It's normal for multiple fog objects to all add together in games, for example. So, if only groups add an intermediate rendering step to apply their blending modes, then switching from the current renderer + CompositionModes to the new renderer should result only in feature additions, and no changes to "older" functionality.

Of course, that is only when enabling OpenGL. By default Tiled uses software rendering, in which case the composition functions at https://github.com/qt/qtbase/blob/a0f53ec9708dd8032b466b868883f8118ab7c7ef/src/gui/painting/qcompositionfunctions.cpp are used. Either way I think the SVG docs are pretty good at explaining each operation, so I'd suggest we link to those.

I think there's value in both linking to the SVG page for the calculations and showing the OpenGL blendFunc equivalents, since most people are probably not doing software rendering in their games. The calculations are useful for hardware rendering if one is implementing the blending modes as shaders, but often that is overkill, as many engines/libraries provide some way to specify the blend functions more directly. SFML, Unity, and Monogame all provide ways to define blending modes similarly to OpenGL, for example.

@AxiomVerge
Copy link

Since it's up to the game to interpret it, I don't think it would hurt to have the software rendering modes listed; I would just ignore them at runtime. Maybe just put a * next to the ones that would need a special shader.

@eishiya
Copy link
Contributor

eishiya commented Sep 26, 2024

Since it's up to the game to interpret it, I don't think it would hurt to have the software rendering modes listed; I would just ignore them at runtime. Maybe just put a * next to the ones that would need a special shader.

All of these modes are implementable without shaders (as seen by the fact that Qt provides such implementations), so it's just a question of which ones have easy-to-use named aliases in your engine, and which ones might require some extra code. In addition, some frameworks have no support for additional blending modes at all, while some require all blending modes to be implemented with shaders. So, there's no way to provide a useful distinction within Tiled, it'll have to be up to each user to be aware of what they can and can't do in their game. #2794 should perhaps allow disabling not only blending modes entirely, but also specific modes, to make it easier to avoid selecting modes which aren't supported in one's game.

@bjorn
Copy link
Member

bjorn commented Dec 2, 2024

I've pushed an updated patch for the layer Composition Mode property: 8ec53b3. It now supports undo/redo and updates the view when the mode is changed. Serialization in the various supported formats still needs to be added.

@bjorn bjorn linked a pull request Jan 12, 2025 that will close this issue
5 tasks
@bjorn
Copy link
Member

bjorn commented Jan 17, 2025

There are now Tiled builds available at https://github.com/mapeditor/tiled/actions/runs/12833517585 which have this feature mostly implemented, as per #4140. The only remaining tasks are to update the documentation and to make the property accessible through the scripting API, but otherwise it should be fully working.

image

@AxiomVerge and @Paperdomo101, please let me know whether this suits your needs or whether you're still missing something for this feature to be useful to you.

@AxiomVerge
Copy link

There are now Tiled builds available at https://github.com/mapeditor/tiled/actions/runs/12833517585 which have this feature mostly implemented, as per #4140. The only remaining tasks are to update the documentation and to make the property accessible through the scripting API, but otherwise it should be fully working.

image

@AxiomVerge and @Paperdomo101, please let me know whether this suits your needs or whether you're still missing something for this feature to be useful to you.

It certainly looks like exactly what I'd want. Is there a binary? I'm not sure where to find it on github.

@eishiya
Copy link
Contributor

eishiya commented Jan 17, 2025

Scroll down to Artifacts in the link bjorn posted for binaries.

@AxiomVerge
Copy link

D'oh, my mouse was over the wrong part of the screen and it disabled scrolling :)

This is PERFECT. Thank you SO MUCH!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature It's a feature, not a bug.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants