# GMLscripts.com

Discuss and collaborate on GML scripts

You are not logged in.

## #1 2009-07-23 18:22:09

xot
Registered: 2007-08-18
Posts: 1,201

### Blend Modes

Game Maker Help wrote:

There are two more function that are not only useful for drawing textures. Normally primitives are blended with the background using the alpha value. You can actually indicate how this must happen. Besides the normal mode it is possible to indicate that the new color must be added to the existing color or subtracted from the existing color. This can be used to create e.g. spot lights or shadows. Also it is possible to sort of take the maximum of the new and existing color. This can avoid certain saturation effects that you can get with adding. Note that both subtracting and maximum do not take the alpha value fully into account. (DirectX does not allow this.) So you better make sure the outside area is black. There are two functions. The first one only gives you the four options described above. The second function gives you a lot more possibilities. You should experiment a bit with the settings. If used effectively they can be used to create e.g. interesting explosion or halo effects.

NOTE: Blend modes have no effect on the draw_clear or draw_clear_alpha functions. Saying that some modes "do not take the alpha value fully into account" seems a bit misleading. The ways in which alpha is taken into account simply may not be what the user desires or expects.

Standard Blending

Game Maker Help wrote:

draw_set_blend_mode(mode) Indicates what blend mode to use. The following values are possible: bm_normal (0), bm_add (1), bm_subtract (3), and bm_max (2). Don't forget to reset the mode to normal after use because otherwise other sprites and even the backgrounds are drawn with the new blend mode.

NOTE: The above four blending constants should only be use with this function. The values of the constants have been added.

Extended Blending

Game Maker Help wrote:

draw_set_blend_mode_ext(src,dest) Indicates what blend mode to use for both the source and destination color. The new color is some factor times the source and another factor times the destination. These factors are set with this function. To understand this, the source and destination both have a red, green, blue, and alpha component. So the source is (Rs, Gs, Bs, As) and the destination is (Rd, Gd, Bd, Ad). All are considered to lie between 0 and 1. The blend factors you can choose for source and destination are:

1. bm_zero:             Blend factor is (0, 0, 0, 0).

2. bm_one:              Blend factor is (1, 1, 1, 1).

3. bm_src_color:        Blend factor is (Rs, Gs, Bs, As).

4. bm_inv_src_color:    Blend factor is (1-Rs, 1-Gs, 1-Bs, 1-As).

5. bm_src_alpha:        Blend factor is (As, As, As, As).

6. bm_inv_src_alpha:    Blend factor is (1-As, 1-As, 1-As, 1-As).

7. bm_dest_alpha:       Blend factor is (Ad, Ad, Ad, Ad).

8. bm_inv_dest_alpha:   Blend factor is (1-Ad, 1-Ad, 1-Ad, 1-Ad).

9. bm_dest_color:       Blend factor is (Rd, Gd, Bd, Ad).

10. bm_inv_dest_color:   Blend factor is (1-Rd, 1-Gd, 1-Bd, 1-Ad).

11. bm_src_alpha_sat:    Blend factor is (f, f, f, 1); f = min(As, 1-Ad).

For example, the normal blending mode sets the source blending to bm_src_alpha and the destination blending to bm_inv_src_alpha. Don't forget to reset the mode to normal after use because otherwise also other sprites and even the backgrounds are drawn with the new blend mode.

NOTE: The above eleven blending constants should only be use with this function. The values of the constants have been added. Knowing these values is useful when fixing code that does not use the correct constants for a particular blend function.

Abusing forum power since 1986.

Offline

## #2 2009-07-23 20:08:29

xot
Registered: 2007-08-18
Posts: 1,201

### Re: Blend Modes

How Blend Modes Work

Extended blend modes are the source of more mystery than almost anything in the Game Maker arsenal. They are in fact completely logical and very straight-forward. Once you understand how they operate, you should have no trouble predicting what any particular blending mode will do.

It's all mathematical. The use of the term "factor" in the help file is the clue but it doesn't go into nearly enough detail.

Each extended blend mode has two factors, defined by the two arguments of the draw_set_blend_mode_ext function. The first factor is for the pixels being drawn (the source) and the second is for the existing pixels being drawn to (the destination). The source pixels can come from any drawing command, such as drawing sprites or primitives. The destination pixels can be the back buffer (the screen) or a targeted surface.

For the purposes of blending, color channels (Red, Green, and Blue) are thought of as holding values from 0.0 to 1.0, rather than from 0 to 255.

Let's start with normal blending, the default blend mode of Game Maker:

draw_set_blend_mode_ext(bm_src_alpha, bm_inv_src_alpha);

Looking at the chart above:

• bm_src_alpha:           Blend factor is (As, As, As, As).

• bm_inv_src_alpha:    Blend factor is (1-As, 1-As, 1-As, 1-As).

The chart says the blend factor of bm_src_alpha is (As, As, As, As). What does this mean? Each of those four values ("As") represent factors for the four color channels (Red, Green, Blue, Alpha). The factor "As" means the Alpha of the Source pixels. The first letter refers to the color channel, and the second letter refers to the source or destination pixels. By "factor" we mean multiply; we are going to multiply each color channel of each of the source pixels by this factor.

Likewise, we are going to do the same sort of operation to the destination pixels, only using the bm_inv_src_alpha (1-As) factor instead. When a blend factor has "inv" (inverse) in the name, it means it subtracts the indicated channel from 1.0 (thus light becomes dark, and dark becomes light).

The results of these two operations are then added together to form the final image.

Here's the entire normal blending operation expressed mathematically:
Source          Destination       ResultingPixels            Pixels           Pixels   [Rs] * [As]  +  [Rd] * [1-As]  =  new Red[Gs] * [As]  +  [Gd] * [1-As]  =  new Green[Bs] * [As]  +  [Bd] * [1-As]  =  new Blue[As] * [As]  +  [Ad] * [1-As]  =  new Alpha

... and visually:

What's going on here is the alpha mask of the sprite is being used to (1) erase the background of the Mario sprite, and (2) erase the area in the existing image where Mario will appear. Now when these images are combined, there will be no interaction between the two. The isolated elements will fit together perfectly. This is obviously a very useful blend mode for games, which is why it's the default. Here's an example of the math in action. Let's say the pixel we are drawing is Mario's red shirt (#F84070) against a brown background (#C89858). Since this is part of Mario, we know the alpha is 100% for this pixel. The background is also fully opaque.
Source              Destination           ResultingPixels                Pixels               Pixels   [0xF8] * [1.00]  +  [0xC8] * [1-1.00]  =  new Red[0x40] * [1.00]  +  [0x98] * [1-1.00]  =  new Green[0x70] * [1.00]  +  [0x58] * [1-1.00]  =  new Blue[1.00] * [1.00]  +  [1.00] * [1-1.00]  =  new Alpha

[0.97] * [1.00]  +  [0.78] * [0.00]    =  0.97[0.25] * [1.00]  +  [0.60] * [0.00]    =  0.25    (#F84070)[0.44] * [1.00]  +  [0.35] * [0.00]    =  0.44[1.00] * [1.00]  +  [1.00] * [0.00]    =  1.00

The resulting pixel is the color of the shirt. Not surprising, I know, but the math shows us why. Now, what happens when Mario is not fully opaque? Let's try his blue overalls (#408098) at 60% alpha against the same background.
[0.25] * [0.60]  +  [0.78] * [0.40]    =  0.46[0.50] * [0.60]  +  [0.60] * [0.40]    =  0.54    (#75897F)[0.60] * [0.60]  +  [0.35] * [0.40]    =  0.50[0.60] * [0.60]  +  [1.00] * [0.40]    =  0.76

As expected, we have a blend of the two colors, a sort greenish-gray. Take special notice of the resulting Alpha: 0.76. Normally, when drawing to the back buffer, this is ignored. The game window is always 100% opaque, after all. However, when drawing to a surface this becomes extremely important. If we were to repeat the last operation on a surface, the resulting pixels, wherever we drew a transparent Mario, would in fact become partially transparent themselves. Although this effect can appear to be a weird graphical glitch, it is perfect normal. It can be corrected with additional blending operations. We will do that next with some "additive" blending.

Our drawing destination is a surface, the result of the preceeding operation. As noted, some of the pixels have become transparent. To restore them to full opacity, we are going to draw over them with black. Because the blend mode we will use simply adds two color channels together, and because black has a value of 0 for Red, Green, and Blue, it will not alter the destination RGB colors at all (n + 0 = n). The alpha, however, is set to 1.0, fully opaque. Adding this to the existing alpha will guarantee that the result will be at least 1.0. Values above 1.0 (or below 0.0) are clamped. The blend factor we are going to be using is called bm_one which, as you might guess, is equal to 1.0 in the blending equation. We will use it for both the source and destination pixels. The basic bm_add blend mode works similarly (but not identically).
Source               Destination        ResultingPixels                 Pixels            Pixels   [0.00] * [1.00]  +  [0.46] * [1.00]    =  0.46[0.00] * [1.00]  +  [0.54] * [1.00]    =  0.54    (#75897F)[0.00] * [1.00]  +  [0.50] * [1.00]    =  0.50[1.00] * [1.00]  +  [0.76] * [1.00]    =  1.00 (clamped from 1.76)

The color remains the same but now the pixel is fully opaque.

So far all of the blend modes shown have factors that are the same for all color channels. This is not necessarily so. The blend factors with the word "color" in them have different factors for each channel. A common use for these is in lighting engines, the so called "multiplicative" lighting/texture pass. The idea is to draw the shading first, then the textures for the shaded objects second with a multiplicative blend. The colors in the source will be multiplied by the colors in the destination. White shaded areas will show the texture normally, color shaded areas will tint the texture, black areas will remain black. You can see exactly the same effect when you use the image_blend variable to change the color of an instance. The blend factors we will use are bm_dest_color and bm_zero.
Source               Destination        ResultingPixels                 Pixels            Pixels   [Rs]  *  [Rd]   +   [Rd]  *  [0.00]  =  new Red[Gs]  *  [Gd]   +   [Gd]  *  [0.00]  =  new Green[Bs]  *  [Bd]   +   [Bd]  *  [0.00]  =  new Blue[As]  *  [Ad]   +   [Ad]  *  [0.00]  =  new Alpha

If the source texture is lilac (#C8A2C8) and the shaded destination pixels are deep saffron (#FF9933):
[0.90] * [1.00]  +  [1.00] * [0.00]  =  0.90[0.64] * [0.60]  +  [0.60] * [0.00]  =  0.38     (#E6602E)[0.90] * [0.20]  +  [0.20] * [0.00]  =  0.18[1.00] * [1.00]  +  [1.00] * [0.00]  =  1.00

... the result is a darker, coppery color. Observant readers will have noticed that blend mode (bm_dest_color, bm_zero) is exactly the same as (bm_zero, bm_src_color).

Abusing forum power since 1986.

Offline

## #3 2010-02-25 18:44:49

brac37
Member
Registered: 2010-02-12
Posts: 18

### Re: Blend Modes

There are two other issues. Normal blending does not set the z-buffer when the alpha of the source is zero. You can use blend mode (bm_zero, bm_one) if your only purpose is to change the z-buffer. Are there other blendings that do not set the z-buffer with alpha = 0?

Another issue is blend mode 13. Is it really something different as 1 to 11? Or is it only a tale?

Offline

## #4 2010-02-25 21:03:34

xot
Registered: 2007-08-18
Posts: 1,201

### Re: Blend Modes

Good observation about the z-buffer. I ran across that working on my old d3d shadow engine. I suspected that (bm_zero,bm_one) would behave as you describe but never tried it. Glad to know it would work.

I've never really spent much time exploring any out-of-spec blend modes. To me they just appeared to duplicate existing modes but I knew a lot less about blend modes when I was looking at them. Because I've always assumed they would be platform dependent if they did anything different, I never felt compelled to use them.

Abusing forum power since 1986.

Offline

## #5 2010-02-27 19:47:24

icuurd12b42
Member
Registered: 2008-12-11
Posts: 303

### Re: Blend Modes

Thanks..
The help should state from the start that the result is a matrix calculation...
r = red
g = green
b = blue
a = alpha
s = source
d = destination
bm = blendmode matrix (0,1,2,3; r,g,b,a)

set_blend_mode_ext(bms,bmd);
=

Before you explained it, it made no sence to me how it worked... How would drawing all As merged with (1-As) result in a transparent draw

Last edited by icuurd12b42 (2010-02-27 19:50:01)

Offline

## #6 2010-02-27 21:46:09

icuurd12b42
Member
Registered: 2008-12-11
Posts: 303

### Re: Blend Modes

[1.00] * [1.00]  +  [0.76] * [1.00]    =  1.00 (clamped from 1.76)

Ah! This is where the problem lies when you try to roll back effects from the image...

Offline

## #7 2010-05-09 11:42:41

vdweller
Member
Registered: 2010-05-09
Posts: 2

### Re: Blend Modes

Greetings,

I have the following question: I am trying to alter the alpha of a surface in real-time, so that the player is able to see behind tall buildings. For this, I draw the building sprite on a surface, and I apply an alpha mask which makes the area of the buiding obscuring the player's vision fade.

this is the closest method I've found:
draw_set_blend_mode_ext(bm_inv_dest_alpha,bm_src_alpha);
(draw the alpha mask surface at the desired height)
draw_set_blend_mode(bm_normal);

The problem is that the alpha mask messes with the building's shadow, which is semi-transparent, making it darker:

My question is: Is there a combination of blend modes capable of reducing the alpha of the target surface, without actually making transparent areas more opaque??

EDIT: draw_set_blend_mode_ext(bm_zero,bm_src_alpha) seems to get rid of the shadow problem, but I think it also gradually darkens the area of smooth fading of the building. The mask I'm using is this:
http://i114.photobucket.com/albums/n251 … yo84/6.png

Last edited by vdweller (2010-05-09 11:59:06)

Offline

## #8 2010-05-09 16:16:31

xot
Registered: 2007-08-18
Posts: 1,201

### Re: Blend Modes

Kind of hard to answer without the project file. Also, becauce I'm not at my normal computer, I'm not sure what that png looks like. If it is white with an alpha channel you might try (bm_zero, bm_src_color). Otherwise, post an example for me to look at, or email xot at this domain.

Abusing forum power since 1986.

Offline

## #9 2010-05-19 21:50:47

xot
Registered: 2007-08-18
Posts: 1,201

### Re: Blend Modes

GearGOD just posted a great topic on GMC about using "premultiplied" textures in order to get surfaces to handle the alpha channel in a more intuitive way (ie. like the backbuffer does). Good stuff.

http://gmc.yoyogames.com/index.php?showtopic=474273

Abusing forum power since 1986.

Offline

## #10 2010-07-02 03:30:00

Earthrise1993
Member
Registered: 2010-07-02
Posts: 1

### Re: Blend Modes

I am trying to get the player sprite look like there is a light attached to the front, however, I do not know how to use this command (draw_set_blend_mode_ext(src,dest)) to do so. Any ideas? Am I even looking at the right command?

Offline

## #11 2010-07-02 15:57:28

xot
Registered: 2007-08-18
Posts: 1,201

### Re: Blend Modes

Normally with light effects you want to use additive blending when you draw the light. The two most common settings for this are:

draw_set_blend_mode(bm_add)

draw_set_blend_mode_ext(bm_one, bm_one)

Try one of those.

Abusing forum power since 1986.

Offline

## #12 2010-07-12 00:55:33

xDanielx
Member
Registered: 2009-01-02
Posts: 38

### Re: Blend Modes

Another issue is blend mode 13. Is it really something different as 1 to 11? Or is it only a tale?

Yeah, 12 and 13 have been obsolete for a long time. I suppose if we were interacting with the D3D API directly, we could save a line of code by calling

d->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_BOTHSRCALPHA);

d->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
d->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

But presumably GM sets the source mode and then the destination mode in response to draw_set_blend_mode_ext, so mode 13 should have the same effect as bm_src_alpha. (Unless it's used illegally as the destination mode. I think it would be ignored in that case.)

Last edited by xDanielx (2010-07-12 00:57:24)

Offline

## #13 2010-07-12 10:55:58

xot
Registered: 2007-08-18
Posts: 1,201

### Re: Blend Modes

Thanks for that link, xDanielx. It clears some things up.

Abusing forum power since 1986.

Offline

## #14 2011-03-29 12:06:19

xot
Registered: 2007-08-18
Posts: 1,201

### Re: Blend Modes

As I posted in another topic, a GMC member recently questioned me for many details about blend modes. Although slightly out of context, I'll post here some of what I learned in answering his questions.

Regarding bm_add:

As I said before, bm_add is meant to add colors together, which I also said was the simplest kind of blend mode. The truly simplest blend mode is the extended blend mode (bm_one, bm_one), which is what I would characterize as a truly additive process. What it means is: multiply the colors and alpha of the source pixels by 1.0, multiply the colors and alpha of the destination pixels by 1.0, then add these colors and alphas together and draw them to the destination. For speed, the multiplication can be skipped by the GPU and no other values need to be read from memory to compute the result. This is what makes it the simplest and fastest blend mode.

Blend mode bm_add doesn't do this exactly. It uses blend factors (bm_src_alpha, bm_one) which means: multiply the source pixel colors and alpha by the alpha value of the source pixels, multiply the destination pixel colors and alpha by 1.0, then add these colors and alphas together. If the source pixels are completely opaque (alpha = 1.0), then the output is identical to (bm_one, bm_one), although it would take slightly longer for the GPU to compute. The lower the source alpha, the less the source colors will affect the destination. This usually produces the result the user desires.

Regarding the simple blend modes and their extended blend mode equivalents:

Blend mode bm_add is equivalent to (bm_src_alpha, bm_one), which I discuss above.

Blend mode bm_subtract does not really do what its name suggests. If you'll recall, all blending operations are based on the multiplication and addition of color values that are always integers between 0 and 255 (conceptually, the range is 0.0 to 1.0). There is no blend mode that can perform subtraction except in a very specific sense. Blend mode bm_subtact is (bm_zero, bm_inv_src_color), which in simple terms means multiply the destination by the inverse of the source. Inverse here means subtracting the value from the maximum possible value. For example, if the source is 0.7 and the destination is 0.8, the result is 0.8 * (1.0 - 0.7) = 0.24, rather than (0.8 - 0.7) = 0.1 as you might expect. It is possible to perform a true subtraction using multiple blending operations. If you can figure out how, you'll have a good understanding of blend modes.

Blend mode bm_max is (bm_src_alpha, bm_inv_src_color). I only arrived at this conclusion through exhaustive automated testing. It's a strange blend mode and I don't know for what purpose it is intended. Perhaps Mark Overmars thought it looked nice.

You did not ask, but for completion I'll add that blend mode bm_normal is (bm_src_alpha, bm_inv_src_alpha). I cover this in detail in my forum post.

Abusing forum power since 1986.

Offline

## #15 2012-09-29 22:08:50

xot
Registered: 2007-08-18
Posts: 1,201

### Re: Blend Modes

So what is the method to produce a true subtractive blend? As I said in the previous post, there is no way to perform subtraction using a combination of addition and multiplication, the mathematical basis for all blend modes ... except in a very specific sense. I was referring to the bm_inv_* factors. They subtract a channel from 1.0 and are the only kind of subtraction we have at our disposal. Fortunately, it's all we need.

True subtraction can be emulated with a multistep process. Let's say we wanted to subtract 0.2 from a channel with a value of 0.75. What we expect is:

0.75 - 0.2 = 0.55

What we actually get with bm_subtract is (bm_zero, bm_inv_src_color):

0.2 * 0.0 + 0.75 * (1 - 0.2) = 0.6

Close, but no cigar. We need a different approach. By using the concept of inversion (our special case of subtraction) we can make addition look like subtraction. First we invert the destination, second we add what we want to subtract to the destination, and third we re-invert the destination.

Step 1: (bm_inv_dest_color, bm_zero), drawing white (1.0)
1.0 * (1 - 0.75) + 0.75 * 0.0 = 0.25

Step 2: (bm_one, bm_one), drawing the color value we wish to subtract (0.2)
1.0 * 0.2 + 1.0 * 0.25 = 0.45

Step 3: (bm_inv_dest_color, bm_zero), drawing white (1.0)
1.0 * (1 - 0.45) + 0.45 * 0.0 = 0.55

And there it is, 0.55, the answer we want.

Abusing forum power since 1986.

Offline