Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more

Tech

Explaining Blend Modes - Part 2

Posted by Mark Alexander on 27 June 2014

In the previous article that we published on blend modes, we covered the simple blend modes that you can use in your games, and gave an overview of how they work. However, to really get the most from blend modes you have step away from the general ones that GameMaker: Studio supports and start to use the extended blend modes.

draw_set_blend_mode_ext

In the previous article we concentrated on draw_set_blend_mode(), but this week we are going to look at draw_set_blend_mode_ext(). This is (as the name implies) an extended function to set custom blend modes, but how does this work? Let's just have a look at the dry technical answer first before we go any further:

draw_set_blend_mode_ext(src, dest) Indicates what blend mode to use for both the source and destination colour. The new colour 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 values are considered to lie between 0 and 1.

Now, while that text is correct and explains what blend modes do, it's not really intuitive so let's go into a bit more detail and explain what this is all about.

Source, Destination And Factors

When we talk about the source we are talking about the colour and alpha values of the pixel that is being drawn, and when we talk about the destination we are talking about the colour and alpha values of the pixel that it is being drawn over. To keep things easier we can write out the source colour as it's components, like this:

    (Rs, Gs, Bs, As) = the RGB and Alpha of the colour you are going to draw.

And the destination would be like this:

    (Rd, Gd, Bd, Ad) = the RGB and Alpha of the colour you are going to draw on.

 So when we draw something on the screen, our graphics processor is actually doing the following for every single pixel:

    (Rs,Gs,Bs,As) * source_blend_factor + (Rd,Gd,Bd,Ad) * destination_blend_factor

The blend factors mentioned above are defined in GameMaker: Studio by a number of constants, and each one represents a factor by which the source or destination R, G, B and A values should be multiplied by. The factors available are:

  • bm_zero: Blend factor is (0, 0, 0, 0).
  • bm_one: Blend factor is (1, 1, 1, 1). 
  • bm_src_color: Blend factor is (Rs, Gs, Bs, As). 
  • bm_inv_src_color: Blend factor is (1–Rs, 1–Gs, 1–Bs, 1–As). 
  • 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).
  • bm_dest_alpha: Blend factor is (Ad, Ad, Ad, Ad).
  • bm_inv_dest_alpha: Blend factor is (1–Ad, 1–Ad, 1–Ad, 1–Ad).
  • bm_dest_color: Blend factor is (Rd, Gd, Bd, Ad).
  • bm_inv_dest_color: Blend factor is (1–Rd, 1–Gd, 1–Bd, 1–Ad).
  • bm_src_alpha_sat: Blend factor is (f, f, f, 1); f = min(As, 1–Ad). 

The four "simple" blend modes that GameMaker: Studio has are actually composites of two of these blend factors.

Bm_normal

Time to look at a practical example of how this comes together for drawing in GameMaker: Studio. For this, we are going to look at bm_normal, which is really:

 draw_set_blend_mode_ext(bm_src_alpha, bm_inv_src_alpha);

One of the problems people have with blend modes is visualising the results, so to show the maths behind them, we'll use this blend mode as our test subject since it's the blend mode that everyone uses the most and we know exactly what to expect from it. Imagine we are drawing a rectangle with the colour (128, 255, 64, 255) over a background with tthe colour (64, 128, 255, 255).

So, our blend mode looks like this:

    Source: (128, 255, 64, 255) = (0.5, 1, 0.25, 1)
    Destination: (64, 128, 255, 255) = (0.25, 0.5, 1, 1)
    bm_src_alpha (As, As, As, As): (255, 255, 255, 255) = (1, 1, 1, 1)
    bm_inv_src_alpha (1–As, 1–As, 1–As, 1–As): (0, 0, 0, 0)

    (Rs,Gs,Bs,As) * bm_src_alpha + (Rd,Gd,Bd,Ad) * bm_inv_src_alpha
    (0.5, 1, 0.25, 1) * (1, 1, 1, 1) + (0.25, 0.5, 1, 1) * (0, 0, 0, 0)
    (0.5, 1, 0.25, 1)  + (0, 0, 0, 0) = (0.5, 1, 0.25, 1) = (128, 255, 64, 255)

As you can see, we multiply the destination values by 0, which gives them a value of 0 too, meaning that the source colours are unchanged. You can see how the inclusion of alpha affects this value too:

    Source: (128, 255, 64, 128) = (0.5, 1, 0.25, 0.5)
    Destination: (64, 128, 255, 255) = (0.25, 0.5, 1, 1)
    bm_src_alpha (As, As, As, As): (128, 128, 128, 128) = (0.5, 0.5, 0.5, 0.5)
    bm_inv_src_alpha (1–As, 1–As, 1–As, 1–As): (0.5, 0.5, 0.5, 0.5)

    (Rs,Gs,Bs,As) * bm_src_alpha + (Rd,Gd,Bd,Ad) * bm_inv_src_alpha
    (0.5, 1, 0.25, 0.5) * (0.5, 0.5, 0.5, 0.5) + (0.25, 0.5, 1, 1) * (0.5, 0.5, 0.5, 0.5)
    (0.25, 0.5, 0.125, 0.25) + (0.125, 0.25, 0.5, 0.5) = (0.375, 0.75, 0.625, 0.75) = (96, 192, 159, 192)

This will give an image like that shown below:

Hopefully you can see clearly now what the blend mode factors do, and how combining them can change what is drawn to create some interesting effects. We will now look at a practical example of how to combine these factors to create your own custom blend modes.

Creating Your Own Blend Modes

Using the different factors available, you can create your own blend modes to achieve blending options that are not available to you normally. In this example, we are going to create a multiply effect like that used in Photoshop. We can simulate this blend mode using two of our blend mode factors like this:

draw_set_blend_mode_ext(bm_dest_color, bm_zero);

Before we actually draw something using this blend mode, let's have a look at how it should look in Photoshop:

Using our extended blend mode we get the following:

    (Rs,Gs,Bs,As)*(Rd,Gd,Bd,Ad)+(Rd,Gd,Bd,Ad)*(0,0,0,0) = (Rs,Gs,Bs,As)*(Rd,Gd,Bd,Ad)
    Source color * dest color + dest color * zero = source color * dest color

The blend factor bm_zero effectively removes the destination colour from the equation (as zero times anything is zero), so we are left with the source colour multiplied by the blend factor of the destination colour, hence the name bm_multiply. To use this in GameMaker: Studio, you would simply have something like this in your Draw Event:

draw_set_blend_mode_ext(bm_dest_color, bm_zero);
draw_self();
draw_set_blend_mode(bm_normal);

The next image was taken from a test project using this exact code:

Spot the difference? Probably not! There will be some deviation between the two due to differences between the render tools used, but it's almost exactly as you would expect. Note though that not all the blend modes used by art programs are available to you within GameMaker: Studio due to the fact some of them can actually force the colour values to go over 255 and so create special effects, but that doesn't mean you can't create passable imitations of these effects, or even brand new effects, using them.

Surfaces And Alpha

One final thing is worth noting about blend modes, and that is how they affect the alpha component of a colour. When simply drawing to the application surface or the back buffer, you don't really need to take into consideration the destination alpha value as it will always be one. However surfaces are different, since you can clear a surface to have any value from zero to one that you wish. This leads to some interesting effects that are contrary to what most people would expect.

To illustrate this, we are going to look at drawing using the basic default bm_normal. Most people think that having a surface cleared to alpha 0, and then drawing something with an alpha of 0.5 will give a resulting alpha value 0.5 too... but this is not the case and is something that many people think is a "bug" in how GameMaker: Studio draws things. However, as you will see, it's not!

Say you have surface with every pixel at alpha 0, then you draw a circle on it with alpha 0.5 using the bm_normal blend mode. The entire surface is still going to be alpha 0, but in the circle the alpha will be 0.25, since:

    0.5 * 0.5 + 0 * 0.5 = 0.5 * 0.5 = 0.25

If you then proceed to draw another circle in the existing circle, also with an alpha of 0.5, the alpha outside the circles would be 0, in between the circles 0.25, and in the smaller circle it would be 0.375.

    0.5 * 0.5 + 0.25 * 0.5 = 0.25 + 0.125 = 0.375

Anyway, were you to draw a number of 0.5 alpha circles to asurface, then draw this surface to the room, you would be able to clearly see this:

If you are still a bit confused about the alpha, try to picture it as just another colour. It behaves like a colour and all calculations on it are done in a similar manner. It’s just not really visible, although the effect it has on other colours is. Which brings us to the final thing to note when using surfaces and blend modes...

Even if the alpha of the surface is 0, the colour components are still there and exist and will influence in all blending operations. So drawing to a zero alpha cleared surface that has been cleared using the colour red (for example) will blend the source colours with the destination colours and give different effects to that which may think. The above image was created on a surface cleared to black over a black background, but if we clear the surface to red, we get this:

Hopefully you can now work out why this happens for yourself using the formulas I've outlined above and applying the approriate figures for bm_normal. 

You can find part one of this article from the following link: Explaining Blend Modes - Part 1

Back to Top