Layer Blend Mode Property
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:
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
Ok, thanks for letting me know.
Is there a way to do paid bounties with tiled?
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 (fb0289b63fddf70c7f5e8a9360a8bc81e2767425) 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:
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.
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.
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.
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)
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.
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.
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.