
本文介绍通过Canvas的globalCompositeOperation属性配合径向渐变,实现可穿透显示底层线条的动态光源效果,解决纯色遮盖导致无法看见迷宫轮廓的问题。
本文介绍通过canvas的globalcompositeoperation属性配合径向渐变,实现可穿透显示底层线条的动态光源效果,解决纯色遮盖导致无法看见迷宫轮廓的问题。
在基于射线投射(ray casting)的2D光照系统中,常见的误区是仅依赖createRadialGradient()生成从白到黑的渐变,却忽略了Canvas默认的“覆盖式”绘制模式——即无论渐变中是否含透明度,只要未显式设置alpha通道或混合模式,所有绘制内容都会不透明地覆盖已有像素。你当前代码中colorStop0 = "white"和colorStop1 = "black"均为不透明色值(等价于"#FFFFFF"和"#000000"),因此即使视觉上呈现“由亮到暗”,实际每个像素的alpha值均为1,完全遮挡下方的迷宫墙壁线条。
要实现“光区内可见墙壁、暗区不可见”的真实感光照,关键不是让渐变自身变透明,而是改变绘制时的像素合成逻辑。推荐使用 ctx.globalCompositeOperation = "darken":
// 在绘制光照渐变前设置混合模式 this.ctx.globalCompositeOperation = "darken"; // 创建并应用径向渐变(颜色仍可用纯白/纯黑) const gradient = this.ctx.createRadialGradient(x, y, 0, x, y, radius); gradient.addColorStop(0, "white"); // #FFFFFF → alpha=1,但"darken"会保留下方更暗的像素 gradient.addColorStop(1, "black"); // #000000 → 完全覆盖为黑,隐藏该区域内容 this.ctx.beginPath(); this.ctx.arc(x, y, radius, 0, Math.PI * 2); this.ctx.fillStyle = gradient; this.ctx.fill();
✅ 原理说明:"darken" 模式对每个目标像素执行 result = min(source, destination) 的RGB分量比较。白色(255,255,255)与任何颜色比较均取后者,因此光心区域“透出”底层线条;黑色(0,0,0)则强制覆盖为黑,形成有效遮蔽。这恰好符合“亮处见墙、暗处隐匿”的光照语义。
⚠️ 重要注意事项:
- 必须在每次绘制光照前重置
globalCompositeOperation,否则会影响后续所有绘制(如UI、文字)。建议绘制后恢复默认值:this.ctx.globalCompositeOperation = "source-over"; - 若需更精细控制(如半透明衰减),可改用带alpha的颜色(如
"rgba(255,255,255,0.3)")配合"source-over"模式,但性能略低且需多层叠加; - 1000条射线无需逐条绘制渐变圆——应统一绘制一个覆盖全部射线范围的大渐变圆盘,大幅提升渲染效率。
最终效果:玩家鼠标所在位置呈现明亮光晕,可清晰辨识迷宫结构;远离光心的区域逐渐沉入黑暗,墙壁线条自然隐去,真正实现动态、可交互的2D光照体验。











