混合模式使用指南

如果您使用 GameMaker 已有一段时间,那么您几乎肯定会遇到过 混合模式 ,甚至可能会在您的游戏中使用它们。混合模式是改变某些内容的绘制方式以提供有趣且特定的图形效果的好方法,但是您知道它们如何工作以及如何使用它们吗?这是一个可能令人困惑的主题,因此在本节中,我们希望消除有关混合模式的一些神秘面纱,并使您能够在游戏中充分利用它们。

概述

混合模式基本上告诉你的游戏将某些东西与事先已经绘制的其他东西混合起来。您绘制到屏幕上的所有内容均由四个组成部分组成 - 红色绿色蓝色Alpha- 默认情况下,它们使用混合绘制到屏幕上模式 bm_normal

此混合模式会绘制所有像素,其颜色和 Alpha 值基本保持不变 (不过,在本节后面您将看到这 完全 不正确 ...),但 GameMaker 有一个数字可以通过设置来改变此行为的 内置混合模式

事物是如何绘制的

GameMaker 开始绘制像素时,会存在一个 源颜色 ( 您要绘制的像素的颜色) 和一个 目标颜色 ( 我们已经存在于像素中的颜色) 重新绘制)。例如,如果您在同一像素绘制黄色后绘制粉红色,则粉红色是 ( 您正在绘制的内容),黄色是 目标 ( 因为它是已经在那了)。

在确定像素的最终颜色时,GameMaker 会根据 混合模式 组合源颜色和目标颜色 - 基本上是在问 " 我应该如何组合粉色和黄色?"。

计算最终颜色

源颜色和目标颜色均包含 RGBA( 红色绿色蓝色Alpha) 分量,每个分量都是 0 到 1 之间的浮点值。

像素的最终颜色是通过将源和目标的每个分量乘以一个 因子 ,然后根据设置的 方程 将它们组合在一起来计算的。

这意味着最终像素颜色的计算方式如下:( 源 * 因子 )+( 目标 * 因子 )

此处,两个值最终会 相加 ,因为默认方程为 bm_add,不过您可以更改该方程以进行减法或使用其他方程 (本页稍后介绍)。

基本混合模式

使用函数 gpu_set_blendmode 同时 应用一组混合因子和方程,作为 " 预设 " 混合模式。

您可以在 (例如) 绘制精灵之前调用此函数,然后在之后重置它,如下所示:

gpu_set_blendmode(bm_add);
draw_self();
gpu_set_blendmode(bm_normal);

该代码使用 加法 混合模式绘制实例精灵。加法混合模式使用可用的 GML 常量之一进行设置,其中有六个用于基本模式:

Blend Mode Constant
常量描述Extended Blend ModeBlend Equation
bm_normalNormal blending (the default blend mode).(bm_src_alpha, bm_inv_src_alpha)bm_eq_add
bm_addAdditive blending. Luminosity values of light areas are added.(bm_src_alpha, bm_one)bm_eq_add
bm_subtractSubtractive blending. Source is subtracted from the destination.(bm_src_alpha, bm_one)bm_eq_subtract
bm_reverse_subtractReverse subtractive blending. Destination is subtracted from the source.(bm_src_alpha, bm_one)bm_eq_reverse_subtract
bm_minSmaller value from source and destination is selected.(bm_one, bm_one)bm_eq_min
bm_maxMax blending. Similar to additive blending.(bm_src_alpha, bm_inv_src_colour)bm_eq_add

"扩展混合模式 " 列显示 (分别) 应用于源和目标的因子,"混合方程 " 列显示用于将这两个值结合在一起的方程。

现在让我们看看每种基本混合模式的工作原理。

注意 这些示例演示了使用绿色背景并在其上绘制蓝色方块的混合模式,这两种模式都算作目标。使用每种混合模式绘制一个灰色方块作为源。

bm_normalbm_normal

常量描述Extended Blend ModeBlend Equation
bm_normalNormal blending (the default blend mode).(bm_src_alpha, bm_inv_src_alpha)bm_add

bm_normal 是默认混合模式,它将源颜色与其 Alpha 相乘,并将目标颜色与源 Alpha 的 相乘 (为源颜色留出空间)。最后将两者相加 (因为等式为 bm_add):

bm_normal example

本示例中的背景颜色为 (50, 100, 0, 255)

bm_addbm_add

常量描述Extended Blend ModeBlend Equation
bm_addAdditive blending. Luminosity values of light areas are added.(bm_src_alpha, bm_one)bm_add

此混合模式将源颜色与其 Alpha 相乘,就像 bm_normal 一样,但它保持目标原样 (bm_one)。然后将两者加在一起,产生更浅的颜色。请注意,颜色值不能超过 255( 或低于 0),因此任何加起来超过该值的值都将被限制为 255。

bm_add example 此示例中的背景颜色为 (50, 100, 0, 255)

使用这种混合模式是获得 " 霓虹灯发光 " 外观的好方法,并且最常用于照明效果、激光或任何您想要发光或发光的东西。

 

bm_subtractbm_subtract

常量描述Extended Blend ModeBlend Equation
bm_subtractSubtractive blending. Source is subtracted from the destination.(bm_src_alpha, bm_one)bm_subtract

此模式使用与 bm_add 相同的因子,但它使用减法方程,以便从目标颜色中减去源颜色 (即从背景中移除前景)。

此示例中的背景颜色为 (50, 100, 0, 255)

这对于使用遮罩移除部分图像非常有用,如本页后面 " 混合方程 " 下的示例所示。

 

bm_reverse_subtractbm_reverse_subtract

常量描述Extended Blend ModeBlend Equation
bm_reverse_subtractReverse subtractive blending. Destination is subtracted from the source.(bm_src_alpha, bm_one)bm_reverse_subtract

这再次使用与 bm_addbm_subtract 相同的因子,但使用逆减方程,因此从源颜色中减去目标颜色 (即从前景中移除背景)。

此示例中的背景颜色为 (50, 100, 0, 255)

 

bm_minbm_min

常量描述Extended Blend ModeBlend Equation
bm_minSmaller value from source and destination is selected.(bm_one, bm_one)bm_min

这对源颜色和目标颜色都使用了 bm_one 因子,因此它们根本不会改变。然后它利用最小方程,以便源和目标 (对于 R、G、B 和 A 中的每一个) 之间较小的分量值用于最终像素。

此示例中的背景颜色为 (50, 100, 0, 255)

 

bm_maxbm_max

常量描述Extended Blend ModeBlend Equation
bm_maxMax blending. Similar to additive blending.(bm_src_alpha, bm_inv_src_colour)bm_eq_add

这种混合模式解释起来比较复杂,但它基本上是将源颜色乘以源 Alpha,然后将它们与目标颜色值乘以源颜色值的逆值相加。我们将在文章的第二部分介绍 bm_max( 以及其他混合模式) 背后的实际数学原理,但您需要知道的是,结果将是更 " 饱和 " 且更明亮的颜色,而不会导致达到与使用 bm_add 相同的纯白色亮度。

此示例中的背景颜色为 (50, 100, 0, 255)

 

 

现在您已经了解了在 GameMaker 中使用混合模式的基础知识。它获取源图像 (正在绘制的内容) 的 RGBA 值,然后将这些值与目标图像 (正在绘制的内容) 的 RGBA 值混合。

这种混合是通过将每个像素颜色和 Alpha 的各个分量乘以不同的量来完成的,具体取决于我们希望实现的效果,然后使用设置的方程计算两者的最终像素值。

有了这些知识,您就可以开始在游戏中使用混合模式来获得发光的激光、逼真的阴影或饱和的过渡效果,但这里还有更多东西需要学习!下面我们将了解 扩展混合模式 ( 因子),并探讨其背后的一些数学知识,以便您可以创建自己的混合效果,例如相乘或叠加。

扩展混合模式 (因子)

上面我们讨论了函数 gpu_set_blendmode,但现在我们要看看 gpu_set_blendmode_ext

我们看到每种内置混合模式都会将 因子 应用于 目标 颜色。例如,bm_add 将源与其 Alpha 相乘,并将目标与 1 相乘。

通过 gpu_set_blendmode_ext,您可以分别为源颜色和目标颜色 手动设置系数 。这为您提供了更多绘制像素的选项,因为您现在可以手动选择源乘什么,然后选择目标乘什么。

表示组件

如您所知,源颜色和目标颜色都具有 RGBA 分量。每个分量的值都在 0 到 1 之间。

我们将源 RGBA 表示为 (Rs, Gs, Bs, As),将目标 RGBA 表示为 (Rd, Gd, Bd, Ad)

了解这些将帮助您了解每个因素的工作原理,因为一个因素可能会使用例如 Rs 值 (源红色),但另一个可能使用 Rd( 目标红色),依此类推。

计算最终像素

当你去画东西时,GPU 会得到以下信息:

然后它对每个像素执行以下操作:

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

正如您所看到的,它将源 RGBA 和目标 RGBA 与其设定因子相乘。然后,它根据默认 方程 将它们加在一起。

混合因子在 GameMaker 中由许多 GML 常量定义。每个常量都是可用于源或目标 (或两者) 的因子。可以考虑以下因素:

混合模式因子常量
常量混合因子(红色、绿色、蓝色、透明度)
bm_zero(0, 0, 0, 0)
bm_one(1, 1, 1, 1)
bm_src_colour(Rs, Gs, Bs, As)
bm_inv_src_colour(1-Rs, 1-Gs, 1-Bs, 1-As)
bm_src_alpha(As, As, As, As)
bm_inv_src_alpha(1-As, 1-As, 1-As, 1-As)
bm_dest_alpha(Ad, Ad, Ad, Ad)
bm_inv_dest_alpha(1-Ad, 1-Ad, 1-Ad, 1-Ad)
bm_dest_colour(Rd, Gd, Bd, Ad)
bm_inv_dest_colour(1-Rd, 1-Gd, 1-Bd, 1-Ad)
bm_src_alpha_sat(f, f, f, 1) where f = min(As, 1-Ad)

第二列显示使用该因子时,R、G、B、A 各分量乘以的值。

bm_normal 工作原理示例 bm_normal 工作原理示例

现在我们来看看一个实际示例,了解如何将其结合起来在 GameMaker 中进行绘图。为此,我们将了解 bm_normal 混合模式,它很简单:

gpu_set_blendmode_ext(bm_src_alpha, bm_inv_src_alpha);
gpu_set_blendequation(bm_add);

人们在使用混合模式时遇到的问题之一是可视化结果,因此为了展示其背后的数学原理,我们将使用此混合模式作为我们的测试对象,因为它是每个人使用最多的混合模式,并且我们确切地知道会发生什么从中。假设我们在颜色为 (64, 128, 255, 255) 的背景上绘制一个颜色为 (128, 255, 64, 255) 的矩形:

Example of bm_normal 因此,我们的混合计算如下所示:

Colours:
Source: (128, 255, 64, 255) = (0.5, 1, 0.25, 1)
Destination: (64, 128, 255, 255) = (0.25, 0.5, 1, 1)

Factors:
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)

Formula:
(Rs,Gs,Bs,As) * bm_src_alpha + (Rd,Gd,Bd,Ad) * bm_inv_src_alpha

Apply factors:
(0.5, 1, 0.25, 1) * (1, 1, 1, 1) + (0.25, 0.5, 1, 1) * (0, 0, 0, 0)

Apply equation:
(0.5, 1, 0.25, 1) + (0, 0, 0, 0)

Final pixel:
(0.5, 1, 0.25, 1) = (128, 255, 64, 255)

如您所见,我们将目标值乘以 0,这也使它们的值也为 0,这意味着源颜色保持不变,因此我们的最终颜色值为 (128, 255, 64, 255)

您可以看到包含较低的 alpha 如何影响此计算:

Colours:
Source (128, 255, 64, 128) = (0.5, 1, 0.25, 0.5)
Destination: (64, 128, 255, 255) = (0.25, 0.5, 1, 1)

Factors:
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)

Formula:
(Rs,Gs,Bs,As) * bm_src_alpha + (Rd,Gd,Bd,Ad) * bm_inv_src_alpha

Apply factors:
(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)

Apply equation:
(0.25, 0.5, 0.125, 0.25) + (0.125, 0.25, 0.5, 0.5)

Final pixel:
(0.375, 0.75, 0.625, 0.75) = (96, 192, 159, 192)

这将给出最终像素颜色 (96, 192, 159, 192),并给出如下所示的图像:

Example Of bm_normal With Alpha

希望您现在可以清楚地了解混合模式因素的作用,以及将它们组合起来如何改变绘制的内容以创建一些有趣的效果。

现在,我们将看一个实际示例,了解如何结合这些因素来创建您自己的自定义混合模式。

创建您自己的混合模式

使用不同的可用因子,您可以创建自己的混合模式,以实现通常不可用的混合选项。在这个例子中,我们将创建一个类似于Photoshop中使用的效果。我们可以使用上面提到的两个混合模式因子常量来模拟这种混合模式,如下所示:

gpu_set_blendmode_ext(bm_dest_colour, bm_zero);

在我们实际使用这种混合模式绘制东西之前,让我们看看它在Photoshop中应该是什么样子:

The "Multiply" Blend Mode In Photoshop使用我们的扩展混合模式,我们得到以下结果:

(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 colour * dest colour + dest colour * zero = source colour * dest colour

混合因子bm_zero有效地将目标颜色从等式中移除(因为零乘以任何东西都是零),所以我们剩下的是源颜色乘以目标颜色的混合因子,因此该模式的名称为"乘"。要在GameMaker中使用此模式,您只需在Draw Event中设置如下内容:

gpu_set_blendmode_ext(bm_dest_colour, bm_zero);
draw_self();
gpu_set_blendmode(bm_normal);

下一张图片是使用以下代码从GameMaker的测试项目中拍摄的:

The "Multiply" Blend Mode In GameMaker 您看得出来差别吗?可能不会!然而,由于使用的渲染工具之间的差异,两者之间会存在一些偏差,但它几乎与您所期望的完全一样。

请注意,尽管并非艺术程序使用的所有混合模式都可以在 GameMaker 中使用,因为其中一些混合模式实际上可以强制颜色值超过 255,从而创建特殊效果,但这并不意味着这意味着您无法使用它们创建这些效果的合格模仿,甚至无法创建全新的效果。

值得一提的是,通过 GameMaker,您可以使用函数 gpu_set_blendmode_ext_sepalpha 更进一步。这允许您分离出不同混合模式因子的 Alpha 分量,并单独使用它们来创建更多可能的组合。我们不会在这里介绍这个功能,因为它已经在手册中进行了深入解释,但值得一提,以便您知道它可以使用。

混合方程

通过阅读本指南,您应该已经对什么是混合方程有了基本的了解。它控制应用因素后源颜色和目标颜色如何混合在一起。

默认情况下,源值和目标值都会 相加 在一起,因为默认方程为 bm_eq_add

GameMaker 中提供了以下方程,可以使用 gpu_set_blendequation 设置:

Blend Mode Equation Constant
常量描述方程
bm_eq_addAdd both together (the default equation).source + destination
bm_eq_subtractSubtract source from destination.destination - source
bm_eq_reverse_subtractSubtract destination from source.source - destination
bm_eq_minUse whichever value is smaller.min(source, destination)
bm_eq_maxUse whichever value is larger.max(source, destination)

重要 当使用 bm_eq_minbm_eq_max 作为混合方程时,不会应用 混合因子 ,这与使用 bm_one 作为混合方程实际上相同的因素。

您还可以使用 gpu_set_blendequation_sepalpha 分别设置用于 RGB 和 Alpha 的方程。

使用方程式

您可以使用 bm_eq_subtract 方程来实现以下效果:

在这里,我们将精灵绘制到 表面 ,然后绘制一个圆圈,减去表面中的所有内容。然后将表面绘制到屏幕上。

这可以通过以下 CreateDraw 事件代码来实现:

Create Event

surf = surface_create(128, 128);
surf_x = 175;
surf_y = 90;

Draw Event

if (!surface_exists(surf))
{
    surf = surface_create(128, 128);
}

// Draw to surface
surface_set_target(surf);
    
draw_sprite(spr_box, 0, 0, 0);
    
gpu_set_blendequation(bm_eq_subtract);
draw_circle(mouse_x - surf_x, mouse_y - surf_y, 32, 0);
gpu_set_blendequation(bm_add);
    
surface_reset_target();
    
// Draw surface to screen
draw_surface(surf, surf_x, surf_y);

首先,我们创建一个表面并定义其房间位置。然后在 Draw 事件中,我们检查表面是否不存在,然后重新创建它。

然后我们在该表面上绘制以下内容:

圆将从表面已有的任何内容中减去其 alpha 值,使我们能够看穿它。

然后在房间中的定义位置绘制表面。

表面 和 透明度

关于混合模式,最后一件事值得注意,那就是它们如何影响颜色的 Alpha 分量。 当仅绘制到应用程序表面显示缓冲区时,您实际上不需要考虑目标 Alpha 值,因为它始终为 1。 然而,您自己制作的表面是不同的,因为您可以清除表面以使其具有您希望的从零到一的任何 alpha 值。 这会导致一些有趣的效果,与大多数人的预期相反。

为了说明这一点,我们将使用基本的默认值bm_normal进行绘制。大多数人认为将表面清除为alpha 0,然后绘制alpha为0.5的东西将给予结果alpha值也为0.5.但事实并非如此,许多人认为这是GameMaker渲染事物的"错误"。然而,正如你所看到的,这根本不是一个bug!

假设你有一个表面,每个像素的alpha都是0,然后你用bm_normal混合模式在上面画一个alpha为0.5的圆。整个表面仍然是alpha 0,但是在圆中alpha实际上是0.25,因为:

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

如果你在现有的圆上再画一个alpha值为0.5的圆,那么在圆外的alpha值为0,在圆间的alpha值为0.25,在较小的圆内的alpha值为0.375:

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

如果你继续在一个alpha值为0的曲面上画一些alpha值为0.5的圆,然后把这个曲面画到房间上,你可以清楚地看到:

Surface Alpha Illustration如果您对 Alpha 仍然有点困惑,请尝试将其想象为另一种颜色。 它的行为就像一种颜色,所有关于它的计算都以类似的方式完成。 它只是不太明显,尽管它对其他颜色的影响是可见的。 这就是我们在使用曲面和混合模式(甚至是 bm_normal)时需要注意的最后一点...

即使表面的 Alpha 为 0, 颜色分量仍然存在并且会影响所有混合操作 。因此,绘制到已使用红色 (例如) 清除的零 alpha 清除表面会将源颜色与目标颜色混合,并给出您可能想到的不同效果。上面的图像是在清除为黑色的表面上创建的,但是如果我们将表面清除为红色,我们会得到以下结果:

希望您现在可以使用我们上面概述的公式并应用适当的 bm_normal 数字来弄清楚为什么会发生这种情况。