Difference between revisions of "BlendMode Formulas"

m (Prettier titles)
 
(14 intermediate revisions by 6 users not shown)
Line 1: Line 1:
Copied from: [http://www.love2d.org/forums/viewtopic.php?f=4&t=10268&p=62157&hilit=blend+formula#p62171 Forum Post]
+
Equations used when blending drawn content with the screen or active [[Canvas]].
  
LÖVE currently uses OpenGL and exposes some of the blend equations and functions of it.
+
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]].
  
Here's a list where the numbers are in the interval [0,1]; dst is the existing color in the buffer; src is the global color, texture color, or both of them mixed together (depending on the color mode); and res is the resulting color.
+
Description:
 +
 +
*'''dst''' - existing color in the screen.
  
== additive ==
+
*'''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) + src.a * src.a
+
     res.a = dst.a * (1 - src.a) + src.a
  
0.9.0 changes it to this:
+
=== 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 (up to and including 0.8.0) ==
+
=== 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.r = dst.r * (1 - src.a) + src.r * dst.r
Line 40: Line 182:
 
     res.a = dst.a * (1 - src.a) + src.a * dst.a
 
     res.a = dst.a * (1 - src.a) + src.a * dst.a
  
0.9.0 changes it to this:
+
=== replace ([[0.9.2]] and older) ===
 
 
    res.r = src.r * dst.r
 
    res.g = src.g * dst.g
 
    res.b = src.b * dst.b
 
    res.a = src.a * dst.a
 
  
== premultiplied ==
+
    res.r = src.r
 +
    res.g = src.g
 +
    res.b = src.b
 +
    res.a = src.a
  
    res.r = dst.r * (1 - src.a) + src.r
+
== See Also ==
    res.g = dst.g * (1 - src.a) + src.g
+
* [[BlendMode]]
    res.b = dst.b * (1 - src.a) + src.b
 
    res.a = dst.a * (1 - src.a) + src.a
 
  
== Notes ==
+
== Other Languages ==
OpenGL clamps to [0,1] (by default) in case you're wondering if subtractive could have had negative values.
+
{{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:

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