
本文介绍如何通过 globalCompositeOperation 配合 createRadialGradient,在 HTML5 Canvas 中正确渲染可透光的径向渐变,使光照区域(白→透明)保留底层图形可见性,而阴影区域(黑)自然遮蔽内容。
本文介绍如何通过 `globalcompositeoperation` 配合 `createradialgradient`,在 html5 canvas 中正确渲染可透光的径向渐变,使光照区域(白→透明)保留底层图形可见性,而阴影区域(黑)自然遮蔽内容。
在使用 Canvas 实现光线投射(ray casting)式动态光照(如迷宫中的手电筒效果)时,一个常见误区是:仅依赖颜色渐变(如 "white" → "black")却忽略透明度通道与混合模式,导致渐变覆盖而非叠加——结果就是所有线条被不透明的白色“糊住”,完全看不到底层绘制的墙壁或路径。
关键问题在于:"white" 和 "black" 默认是不透明色(即 #FFFFFF 和 #000000),即使你希望“白色代表光”、“黑色代表暗”,若未启用透明度或合理混合,Canvas 会直接用纯色填充,遮挡一切。
✅ 正确解法:组合使用透明色 + 混合模式
-
定义带 Alpha 的渐变色
将colorStop0改为半透明白色(如"rgba(255, 255, 255, 0.8)"),colorStop1改为全透明黑色(如"rgba(0, 0, 0, 0)"),而非不透明黑。这样渐变本身具备从“亮而微透”到“完全不可见”的过渡:
gradient.addColorStop(0, "rgba(255, 255, 255, 0.8)"); // 亮区:透光 gradient.addColorStop(1, "rgba(0, 0, 0, 0)"); // 暗区:完全透明,不遮挡
-
设置混合模式(核心步骤)
在绘制渐变前,将globalCompositeOperation设为"lighter"(叠加发光)或"screen"(更柔和的提亮),但针对「光照遮罩」需求,推荐使用:
ctx.globalCompositeOperation = "destination-out"; // ✅ 推荐:用渐变“擦除”黑暗区域 // 或 ctx.globalCompositeOperation = "overlay"; // 需配合预设背景色
⚠️ 但最契合你场景(1000 条射线组成圆形光晕,需让光区透出、暗区隐去)的是:
// 步骤一:先绘制所有迷宫线条(墙壁等)
drawWalls(); // ctx.stroke() 多次
// 步骤二:开启“遮罩擦除”模式 —— 黑色区域将清除已有像素,白色区域保留
ctx.globalCompositeOperation = "destination-out";
// 步骤三:用径向渐变(中心白→边缘全透明黑)“挖空”黑暗区
for (let i = 0; i <p>? 更稳健的生产级方案(推荐):</p><pre class="brush:php;toolbar:false;">// 1. 绘制所有场景(墙壁、角色等)
drawScene();
// 2. 创建临时离屏 canvas(lightCanvas)用于光照层
const lightCtx = lightCanvas.getContext("2d");
lightCtx.clearRect(0, 0, w, h);
// 3. 在光照层上绘制 1000 条渐变射线(每条:中心透明白 → 边缘透明黑)
for (let i = 0; i <p>? 注意事项:</p>
- 避免在循环中频繁修改
globalCompositeOperation,性能开销大;优先用离屏 canvas 分层处理; -
"screen"混合模式天然支持透光叠加:白色增强亮度,黑色无影响,灰阶部分提亮,完美模拟光源; - 若需“黑暗中仅照亮局部”,可先用全黑矩形
fillRect()覆盖画布,再用"lighter"或"screen"绘制透明渐变光斑; - 测试时用
rgba(255,0,0,0.3)等高对比色调试渐变范围,确认透明过渡是否生效。
总结:透明径向渐变 ≠ 仅改颜色字符串,而是透明度(alpha)+ 混合模式(composite)+ 分层策略三位一体。用好 globalCompositeOperation = "screen" 或 "lighter",配合 rgba() 渐变色,即可让千条射线真正成为“可穿透的光”,而非“不透明的面纱”。











