Difference between revisions of "BlendMode Formulas"
(12 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
− | + | Equations used when blending drawn content with the screen or active [[Canvas]]. | |
− | + | Color components are in the range of [0, 1]. Results are clamped to [0, 1] except when a [[Canvas]] is active that has a floating-point / HDR [[CanvasFormat|format]]. | |
− | + | Description: | |
+ | |||
+ | *'''dst''' - existing color in the screen. | ||
− | == | + | *'''src''' - the color of the drawn object (the color output by the pixel shader, or the global color multiplied by the texture's color – if any, if no shader is used.) |
+ | |||
+ | *'''res''' - resulting color. | ||
+ | |||
+ | Here are the [[BlendMode]] formulas for all 0.10.x and later versions: | ||
+ | |||
+ | == alpha == | ||
+ | |||
+ | === "alphamultiply" [[BlendAlphaMode|alpha mode]] === | ||
+ | |||
+ | res.r = dst.r * (1 - src.a) + src.r * src.a | ||
+ | res.g = dst.g * (1 - src.a) + src.g * src.a | ||
+ | res.b = dst.b * (1 - src.a) + src.b * src.a | ||
+ | res.a = dst.a * (1 - src.a) + src.a | ||
+ | |||
+ | === "premultiplied" [[BlendAlphaMode|alpha mode]] === | ||
+ | |||
+ | res.r = dst.r * (1 - src.a) + src.r | ||
+ | res.g = dst.g * (1 - src.a) + src.g | ||
+ | res.b = dst.b * (1 - src.a) + src.b | ||
+ | res.a = dst.a * (1 - src.a) + src.a | ||
+ | |||
+ | == add == | ||
+ | |||
+ | === "alphamultiply" [[BlendAlphaMode|alpha mode]] === | ||
res.r = dst.r + (src.r * src.a) | res.r = dst.r + (src.r * src.a) | ||
res.g = dst.g + (src.g * src.a) | res.g = dst.g + (src.g * src.a) | ||
res.b = dst.b + (src.b * src.a) | res.b = dst.b + (src.b * src.a) | ||
− | res.a = dst.a + (src.a * src.a) | + | res.a = dst.a |
+ | |||
+ | === "premultiplied" [[BlendAlphaMode|alpha mode]] === | ||
+ | |||
+ | res.r = dst.r + src.r | ||
+ | res.g = dst.g + src.g | ||
+ | res.b = dst.b + src.b | ||
+ | res.a = dst.a | ||
+ | |||
+ | == subtract == | ||
+ | |||
+ | === "alphamultiply" [[BlendAlphaMode|alpha mode]] === | ||
+ | |||
+ | res.r = dst.r - (src.r * src.a) | ||
+ | res.g = dst.g - (src.g * src.a) | ||
+ | res.b = dst.b - (src.b * src.a) | ||
+ | res.a = dst.a | ||
+ | |||
+ | === "premultiplied" [[BlendAlphaMode|alpha mode]] === | ||
+ | |||
+ | res.r = dst.r - src.r | ||
+ | res.g = dst.g - src.g | ||
+ | res.b = dst.b - src.b | ||
+ | res.a = dst.a | ||
+ | |||
+ | == replace == | ||
+ | |||
+ | === "alphamultiply" [[BlendAlphaMode|alpha mode]] === | ||
+ | |||
+ | res.r = src.r * src.a | ||
+ | res.g = src.g * src.a | ||
+ | res.b = src.b * src.a | ||
+ | res.a = src.a | ||
+ | |||
+ | === "premultiplied" [[BlendAlphaMode|alpha mode]] === | ||
+ | |||
+ | res.r = src.r | ||
+ | res.g = src.g | ||
+ | res.b = src.b | ||
+ | res.a = src.a | ||
+ | |||
+ | == multiply == | ||
+ | |||
+ | === "premultiplied" [[BlendAlphaMode|alpha mode]] === | ||
+ | |||
+ | res.r = src.r * dst.r | ||
+ | res.g = src.g * dst.g | ||
+ | res.b = src.b * dst.b | ||
+ | res.a = src.a * dst.a | ||
+ | |||
+ | Note: In 0.10.x, ''multiply'' with ''alphamultiply'' uses the same equations as with ''premultiplied''. In [[11.0]] and later versions, this variation is not supported. | ||
+ | |||
+ | == lighten == | ||
+ | |||
+ | === "premultiplied" [[BlendAlphaMode|alpha mode]] === | ||
+ | |||
+ | res.r = max(src.r, dst.r) | ||
+ | res.g = max(src.g, dst.g) | ||
+ | res.b = max(src.b, dst.b) | ||
+ | res.a = max(src.a, dst.a) | ||
+ | |||
+ | == darken == | ||
+ | |||
+ | === "premultiplied" [[BlendAlphaMode|alpha mode]] === | ||
+ | |||
+ | res.r = min(src.r, dst.r) | ||
+ | res.g = min(src.g, dst.g) | ||
+ | res.b = min(src.b, dst.b) | ||
+ | res.a = min(src.a, dst.a) | ||
+ | |||
+ | == screen == | ||
+ | |||
+ | Note: The math for this blend mode is not completely correct when using the "alphamultiply" alpha mode. Prefer the "premultiplied" variant (and be sure your content has its RGB multiplied by its alpha at some point before blending), when possible. | ||
+ | |||
+ | === "alphamultiply" [[BlendAlphaMode|alpha mode]] === | ||
+ | |||
+ | res.r = dst.r * (1 - src.r) + (src.r * src.a) | ||
+ | res.g = dst.g * (1 - src.g) + (src.g * src.a) | ||
+ | res.b = dst.b * (1 - src.b) + (src.b * src.a) | ||
+ | res.a = dst.a * (1 - src.a) + src.a | ||
+ | |||
+ | === "premultiplied" [[BlendAlphaMode|alpha mode]] === | ||
+ | |||
+ | res.r = dst.r * (1 - src.r) + src.r | ||
+ | res.g = dst.g * (1 - src.g) + src.g | ||
+ | res.b = dst.b * (1 - src.b) + src.b | ||
+ | res.a = dst.a * (1 - src.a) + src.a | ||
+ | |||
+ | == Older Versions == | ||
− | == alpha == | + | === alpha ([[0.9.0]], [[0.9.1]], and [[0.9.2]]) === |
res.r = dst.r * (1 - src.a) + src.r * src.a | res.r = dst.r * (1 - src.a) + src.r * src.a | ||
res.g = dst.g * (1 - src.a) + src.g * src.a | res.g = dst.g * (1 - src.a) + src.g * src.a | ||
res.b = dst.b * (1 - src.a) + src.b * src.a | res.b = dst.b * (1 - src.a) + src.b * src.a | ||
− | res.a = dst.a * (1 - src.a) + | + | res.a = dst.a * (1 - src.a) + src.a |
− | 0. | + | === alpha ([[0.8.0]] and older) === |
res.r = dst.r * (1 - src.a) + src.r * src.a | res.r = dst.r * (1 - src.a) + src.r * src.a | ||
res.g = dst.g * (1 - src.a) + src.g * src.a | res.g = dst.g * (1 - src.a) + src.g * src.a | ||
res.b = dst.b * (1 - src.a) + src.b * src.a | res.b = dst.b * (1 - src.a) + src.b * src.a | ||
+ | res.a = dst.a * (1 - src.a) + src.a * src.a | ||
+ | |||
+ | === premultiplied ([[0.9.2]] and older) === | ||
+ | |||
+ | res.r = dst.r * (1 - src.a) + src.r | ||
+ | res.g = dst.g * (1 - src.a) + src.g | ||
+ | res.b = dst.b * (1 - src.a) + src.b | ||
res.a = dst.a * (1 - src.a) + src.a | res.a = dst.a * (1 - src.a) + src.a | ||
− | == subtractive == | + | === screen ([[0.9.2]] and older) === |
+ | |||
+ | res.r = dst.r * (1 - src.r) + src.r | ||
+ | res.g = dst.g * (1 - src.g) + src.g | ||
+ | res.b = dst.b * (1 - src.b) + src.b | ||
+ | res.a = dst.a * (1 - src.a) + src.a | ||
+ | |||
+ | === additive ([[0.9.2]] and older) === | ||
+ | |||
+ | res.r = dst.r + (src.r * src.a) | ||
+ | res.g = dst.g + (src.g * src.a) | ||
+ | res.b = dst.b + (src.b * src.a) | ||
+ | res.a = dst.a + (src.a * src.a) | ||
+ | |||
+ | === subtractive ([[0.9.2]] and older) === | ||
res.r = dst.r - src.r * src.a | res.r = dst.r - src.r * src.a | ||
Line 33: | Line 168: | ||
res.a = dst.a - src.a * src.a | res.a = dst.a - src.a * src.a | ||
− | == multiplicative | + | === multiplicative ([[0.9.0]], [[0.9.1]], and [[0.9.2]]) === |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
res.r = src.r * dst.r | res.r = src.r * dst.r | ||
Line 47: | Line 175: | ||
res.a = src.a * dst.a | res.a = src.a * dst.a | ||
− | == | + | === multiplicative ([[0.8.0]] and older) === |
− | res.r = dst.r * (1 - src.a) + src.r | + | res.r = dst.r * (1 - src.a) + src.r * dst.r |
− | res.g = dst.g * (1 - src.a) + src.g | + | res.g = dst.g * (1 - src.a) + src.g * dst.g |
− | res.b = dst.b * (1 - src.a) + src.b | + | res.b = dst.b * (1 - src.a) + src.b * dst.b |
− | res.a = dst.a * (1 - src.a) + src.a | + | res.a = dst.a * (1 - src.a) + src.a * dst.a |
− | == replace == | + | === replace ([[0.9.2]] and older) === |
res.r = src.r | res.r = src.r | ||
Line 61: | Line 189: | ||
res.a = src.a | res.a = src.a | ||
− | == | + | == See Also == |
− | + | * [[BlendMode]] | |
+ | |||
+ | == Other Languages == | ||
+ | {{i18n|BlendMode Formulas}} |
Latest revision as of 16:20, 28 September 2024
Equations used when blending drawn content with the screen or active Canvas.
Color components are in the range of [0, 1]. Results are clamped to [0, 1] except when a Canvas is active that has a floating-point / HDR format.
Description:
- dst - existing color in the screen.
- src - the color of the drawn object (the color output by the pixel shader, or the global color multiplied by the texture's color – if any, if no shader is used.)
- res - resulting color.
Here are the BlendMode formulas for all 0.10.x and later versions:
Contents
- 1 alpha
- 2 add
- 3 subtract
- 4 replace
- 5 multiply
- 6 lighten
- 7 darken
- 8 screen
- 9 Older Versions
- 9.1 alpha (0.9.0, 0.9.1, and 0.9.2)
- 9.2 alpha (0.8.0 and older)
- 9.3 premultiplied (0.9.2 and older)
- 9.4 screen (0.9.2 and older)
- 9.5 additive (0.9.2 and older)
- 9.6 subtractive (0.9.2 and older)
- 9.7 multiplicative (0.9.0, 0.9.1, and 0.9.2)
- 9.8 multiplicative (0.8.0 and older)
- 9.9 replace (0.9.2 and older)
- 10 See Also
- 11 Other Languages
alpha
"alphamultiply" alpha mode
res.r = dst.r * (1 - src.a) + src.r * src.a res.g = dst.g * (1 - src.a) + src.g * src.a res.b = dst.b * (1 - src.a) + src.b * src.a res.a = dst.a * (1 - src.a) + src.a
"premultiplied" alpha mode
res.r = dst.r * (1 - src.a) + src.r res.g = dst.g * (1 - src.a) + src.g res.b = dst.b * (1 - src.a) + src.b res.a = dst.a * (1 - src.a) + src.a
add
"alphamultiply" alpha mode
res.r = dst.r + (src.r * src.a) res.g = dst.g + (src.g * src.a) res.b = dst.b + (src.b * src.a) res.a = dst.a
"premultiplied" alpha mode
res.r = dst.r + src.r res.g = dst.g + src.g res.b = dst.b + src.b res.a = dst.a
subtract
"alphamultiply" alpha mode
res.r = dst.r - (src.r * src.a) res.g = dst.g - (src.g * src.a) res.b = dst.b - (src.b * src.a) res.a = dst.a
"premultiplied" alpha mode
res.r = dst.r - src.r res.g = dst.g - src.g res.b = dst.b - src.b res.a = dst.a
replace
"alphamultiply" alpha mode
res.r = src.r * src.a res.g = src.g * src.a res.b = src.b * src.a res.a = src.a
"premultiplied" alpha mode
res.r = src.r res.g = src.g res.b = src.b res.a = src.a
multiply
"premultiplied" alpha mode
res.r = src.r * dst.r res.g = src.g * dst.g res.b = src.b * dst.b res.a = src.a * dst.a
Note: In 0.10.x, multiply with alphamultiply uses the same equations as with premultiplied. In 11.0 and later versions, this variation is not supported.
lighten
"premultiplied" alpha mode
res.r = max(src.r, dst.r) res.g = max(src.g, dst.g) res.b = max(src.b, dst.b) res.a = max(src.a, dst.a)
darken
"premultiplied" alpha mode
res.r = min(src.r, dst.r) res.g = min(src.g, dst.g) res.b = min(src.b, dst.b) res.a = min(src.a, dst.a)
screen
Note: The math for this blend mode is not completely correct when using the "alphamultiply" alpha mode. Prefer the "premultiplied" variant (and be sure your content has its RGB multiplied by its alpha at some point before blending), when possible.
"alphamultiply" alpha mode
res.r = dst.r * (1 - src.r) + (src.r * src.a) res.g = dst.g * (1 - src.g) + (src.g * src.a) res.b = dst.b * (1 - src.b) + (src.b * src.a) res.a = dst.a * (1 - src.a) + src.a
"premultiplied" alpha mode
res.r = dst.r * (1 - src.r) + src.r res.g = dst.g * (1 - src.g) + src.g res.b = dst.b * (1 - src.b) + src.b res.a = dst.a * (1 - src.a) + src.a
Older Versions
alpha (0.9.0, 0.9.1, and 0.9.2)
res.r = dst.r * (1 - src.a) + src.r * src.a res.g = dst.g * (1 - src.a) + src.g * src.a res.b = dst.b * (1 - src.a) + src.b * src.a res.a = dst.a * (1 - src.a) + src.a
alpha (0.8.0 and older)
res.r = dst.r * (1 - src.a) + src.r * src.a res.g = dst.g * (1 - src.a) + src.g * src.a res.b = dst.b * (1 - src.a) + src.b * src.a res.a = dst.a * (1 - src.a) + src.a * src.a
premultiplied (0.9.2 and older)
res.r = dst.r * (1 - src.a) + src.r res.g = dst.g * (1 - src.a) + src.g res.b = dst.b * (1 - src.a) + src.b res.a = dst.a * (1 - src.a) + src.a
screen (0.9.2 and older)
res.r = dst.r * (1 - src.r) + src.r res.g = dst.g * (1 - src.g) + src.g res.b = dst.b * (1 - src.b) + src.b res.a = dst.a * (1 - src.a) + src.a
additive (0.9.2 and older)
res.r = dst.r + (src.r * src.a) res.g = dst.g + (src.g * src.a) res.b = dst.b + (src.b * src.a) res.a = dst.a + (src.a * src.a)
subtractive (0.9.2 and older)
res.r = dst.r - src.r * src.a res.g = dst.g - src.g * src.a res.b = dst.b - src.b * src.a res.a = dst.a - src.a * src.a
multiplicative (0.9.0, 0.9.1, and 0.9.2)
res.r = src.r * dst.r res.g = src.g * dst.g res.b = src.b * dst.b res.a = src.a * dst.a
multiplicative (0.8.0 and older)
res.r = dst.r * (1 - src.a) + src.r * dst.r res.g = dst.g * (1 - src.a) + src.g * dst.g res.b = dst.b * (1 - src.a) + src.b * dst.b res.a = dst.a * (1 - src.a) + src.a * dst.a
replace (0.9.2 and older)
res.r = src.r res.g = src.g res.b = src.b res.a = src.a
See Also
Other Languages
Dansk –
Deutsch –
English –
Español –
Français –
Indonesia –
Italiano –
Lietuviškai –
Magyar –
Nederlands –
Polski –
Português –
Română –
Slovenský –
Suomi –
Svenska –
Türkçe –
Česky –
Ελληνικά –
Български –
Русский –
Српски –
Українська –
עברית –
ไทย –
日本語 –
正體中文 –
简体中文 –
Tiếng Việt –
한국어
More info