02 混合模式是什么,如何选择
前置知识:第 01 章的源颜色、目标颜色与 Alpha。
本章示例:四种混合模式同屏对照 · 完整源码。
预期画面:普通混合形成彩色薄雾,加法形成明亮火光,乘法与减色使背景变暗。
学完本章能做什么
你将能读懂混合方程里的源、目标与因子,知道 Three.js r174 四种常用模式的实际 RGB 规则,并能为烟雾、发光火焰和局部变暗效果选择起点。你还会知道为什么同一个 opacity 滑块对不同模式反应不同。
先看现象
打开示例。四格使用两枚部分重叠的软圆,中心色和分布相同。普通混合的圆像半透明烟雾;加法重叠处变亮甚至发白;乘法与减色在背景上形成暗色。把 opacity 从 0.65 向 0 拖:上面两格明显变淡,下面两格的中心强度却没有按同样方式变化。
这不是滑块失灵,而是 r174 内置混合模式所用的 RGB 因子不同。示例为乘法和减色准备了中性的边缘颜色;否则,单凭一张“RGB 不变、只有 Alpha 渐变”的贴图,可能看到整块矩形。示例还使用不向浏览器暴露 Alpha 的 WebGL 画布,避免浏览器把画布 Alpha 再与网页背景合成,干扰对 RGB 混合公式的观察。
1. 混合方程的两个乘数
一般形式是:
C结果 = 运算( F源 × C源, F目标 × C目标 )
F源 和 F目标 是混合因子,可以取 0、1、源 Alpha、1 − 源 Alpha、源颜色等。通常的“运算”是相加。RGB 和 Alpha 通道可设置不同因子;下表只讨论最容易观察的 RGB。设源颜色为 S,目标颜色为 D,源 Alpha 为 a,均按当前混合步骤中的数值理解。
r174 模式,默认 premultipliedAlpha: false |
RGB 结果 | 视觉特征与常见用途 |
|---|---|---|
NoBlending |
S,直接替换 |
不做源与目标颜色混合;适合确实要覆盖结果的特殊通道 |
NormalBlending |
aS + (1−a)D |
半透明薄雾、烟、雪的软边 |
AdditiveBlending |
aS + D |
火光、星光、魔法光点;重叠越多越亮 |
MultiplyBlending |
D × S |
染色、局部变暗;RGB 因子没有源 Alpha |
SubtractiveBlending |
D × (1−S) |
特殊暗化效果;在 r174 中不是简单的 D−S |
最后两行尤其容易被名字误导。r174 的非预乘 MultiplyBlending 使用目标颜色乘源颜色;SubtractiveBlending 使用目标颜色乘 1−源颜色。例如某一通道 D=0.8、S=0.3,两者分别得到 0.24 和 0.56。S=0 对减色是中性值,S=1 对乘法是中性值。具体 GPU 因子可在本仓库的 WebGLState.js 中看到。
这些表达式说明默认非预乘材质的 RGB 行为。启用
premultipliedAlpha、使用自定义混合、改变渲染目标或后处理后,要重新核对实际因子;不能把这张表机械套到所有状态。
2. 烟、火、阴影为什么选得不同
烟雾的目标通常是让背景仍可辨认,同时叠加自身颜色,因此先试 NormalBlending。每层烟都会占据一部分视觉权重;交叠很多层时颜色会累积,顺序也更重要。
发光火焰、火花和星光通常先试 AdditiveBlending。它保留目标颜色再加源颜色,所以光斑交叠更亮。代价是亮背景上容易失去对比,重叠过多会饱和成一片白;纯黑的源 RGB 不会贡献亮度。加法混合缓和了许多透明排序问题,但并不保证在任何构图下都完全无关顺序。
乘法与减色适合需要压暗或改变已有颜色的效果。它们的“透明边缘”不能只指望 opacity:在 r174 的上述因子里,RGB 没有乘上源 Alpha。乘法贴图在不想改变背景的区域应输出白色 RGB;减色贴图应输出黑色 RGB。示例在圆外这样编码。把整体 opacity 拖到 0,下方两格的 RGB 效果仍然可见;需要淡出时必须改变参与混合的 RGB 或改用合适的自定义方案。
这四种模式只是起点。实际火焰常结合普通混合的暗烟与加法混合的火芯;阴影是否适合乘法,还要看光照模型、背景内容与颜色管理。
3. 在 Three.js 中设置
两枚软圆各是一张平面贴图。普通烟雾材质的关键设置是:
const smokeMaterial = new THREE.MeshBasicMaterial( {
map: smokeTexture,
transparent: true,
opacity: 0.65,
blending: THREE.NormalBlending,
depthWrite: false
} );
把 blending 改成 THREE.AdditiveBlending 就得到发光叠加。这里关闭 depthWrite,是为了让示例中的两个半透明圆都能参与显示;这并非所有透明物体的固定配方。为什么透明粒子常这样设置,第 05 章会通过深度缓冲实验解释。
当需要精确控制因子时,使用 CustomBlending。下面的设置分别指定 RGB 与 Alpha 因子,重建非预乘普通混合的核心行为:
const material = new THREE.MeshBasicMaterial( {
transparent: true,
blending: THREE.CustomBlending,
blendEquation: THREE.AddEquation,
blendSrc: THREE.SrcAlphaFactor,
blendDst: THREE.OneMinusSrcAlphaFactor,
blendEquationAlpha: THREE.AddEquation,
blendSrcAlpha: THREE.OneFactor,
blendDstAlpha: THREE.OneMinusSrcAlphaFactor
} );
只有选择 CustomBlending 时,自定义的源/目标因子和方程才会按这些参数应用。RGB 公式与 Alpha 公式不能混为一谈。刚入门时先用内置模式,只有明确需要某个公式再自定义。
4. 对照实验怎么读
先保持中灰蓝背景,观察四格中心和两圆交叠处。然后切为深背景:加法火光更突出,乘法效果变得更难辨认。切为浅背景:减色和乘法的暗化更显眼,加法更容易洗白。
最后调 opacity,尤其观察下方两格。因为它们的 RGB 公式没有源 Alpha,不能把 opacity 理解成对所有混合模式通用的“可见程度”。若真的需要可调强度,可在生成的 RGB 里向中性值插值,或编写自定义片元/混合方案:乘法向白色插值,减色向黑色插值。对应练习会实现前一种做法。
常见问题
为什么我的乘法贴图显示出矩形边框? 透明像素若仍携带会改变目标的 RGB,内置乘法的 RGB 因子并不会因 Alpha 为 0 而自动变中性。检查透明区域的 RGB、纹理过滤及是否需要裁切,不能只看 Alpha 通道。
为什么“减色”不是直接相减? 混合模式名称是用途提示;在 r174 的 WebGL 实现中,它采用目标乘 1−源颜色 的因子。要实现另一个数学式,应明确选用 CustomBlending 并核对 GPU 支持的方程与因子。
为什么加法火花看上去太白? 减少每粒 Alpha、粒子尺寸或重叠层数,并观察背景亮度。单纯把贴图换成更暗的边缘,不一定解决中心的过度累积。
下一章会解释为何一张 Alpha 看似正确的贴图,边缘仍可能发黑。完成第 02 章练习。