如何在Konva React画布中高效实现层级优先的战争迷雾系统?
问题
我想在Konva React画布中实现类似Roll20的“战争迷雾”系统:画布上的矩形分为两类——Hide(显示黑色区域)和Reveal(让黑色区域透明),要求后绘制的图形(或形状列表中靠后的元素)优先级更高。比如先绘制全屏Reveal区域,再在上方画Hide区域,该区域仍要保持黑色,但传统的XOR全局合成模式满足不了这种层级优先级需求。
我试过全局合成方案,下面的代码实现了理想逻辑,但逐像素处理的性能极差——哪怕是100x100的画布都要渲染10000个矩形,更大尺寸的画布性能问题更严重,请问怎么实现高效的计算方案?
const applyShapes = () => { // Initialize visibility to true const newPixelVisibility = Array(stageWidth * stageHeight).fill(true); // Apply hide shapes fowShapes.forEach((shape) => { if (shape.type === TOOL_ENUM.REVEAL) { for (let x = shape.x; x < shape.x + shape.width; x++) { for (let y = shape.y; y < shape.y + shape.height; y++) { if (x >= 0 && x < stageWidth && y >= 0 && y < stageHeight) { const index = y * stageWidth + x; newPixelVisibility[index] = shape.layer === FOW_ENUM.HIDE; } } } } }); setPixelVisibility(newPixelVisibility); }; return ( <> {pixelVisibility.map((visible, index) => ( <Rect key={index} x={index % stageWidth} y={Math.floor(index / stageWidth)} width={1} height={1} opacity={visible ? 1 : 0} fill={'black'} /> ))} </> );
高效实现方案
1. 利用Konva图层与自定义合成模式分层处理
抛弃逐像素生成矩形的思路,直接用Konva的globalCompositeOperation结合渲染顺序实现需求:
- 先绘制一个全屏黑色矩形作为初始迷雾(默认全隐藏状态)。
- 按形状列表的顺序逐个渲染Reveal/Hide矩形,通过合成模式控制显示逻辑:
- Reveal形状:使用
destination-out合成模式,绘制时会“挖空”下方的黑色迷雾,实现透明效果。 - Hide形状:使用
source-over合成模式,直接在当前画面上绘制黑色,覆盖之前的Reveal区域。
- Reveal形状:使用
- Konva会严格按照形状添加顺序渲染,后添加的形状自动拥有更高优先级,完全匹配你的需求。
示例代码思路:
// 初始全屏迷雾 <Rect x={0} y={0} width={stageWidth} height={stageHeight} fill="black" /> // 按顺序渲染所有迷雾形状 {fowShapes.map((shape, idx) => { const compositeOp = shape.type === TOOL_ENUM.REVEAL ? 'destination-out' : 'source-over'; return ( <Rect key={idx} x={shape.x} y={shape.y} width={shape.width} height={shape.height} fill="black" globalCompositeOperation={compositeOp} /> ); })}
2. 离屏Canvas预计算遮罩
如果需要支持更复杂的形状(非矩形)或批量处理,可通过离屏Canvas预生成完整遮罩,再作为单张图片渲染到Konva:
- 创建一个与Konva舞台尺寸一致的隐藏HTML Canvas。
- 在Canvas上先绘制全屏黑色,再按顺序处理每个形状:
- Reveal形状用
destination-out模式绘制,挖空黑色区域。 - Hide形状用
source-over模式绘制黑色,覆盖区域。
- Reveal形状用
- 将Canvas转换为图片,用Konva的
Image组件渲染到舞台,仅在形状变化时重新生成遮罩即可。
这种方式只需要渲染一张图片,性能远优于成千上万个小矩形。
3. 合并重叠形状减少绘制量
对形状列表做预处理,合并同类型的重叠/相邻形状:
- 比如多个相邻或重叠的Hide矩形可以合并为一个大矩形,大幅减少需要绘制的形状数量。
- 可使用扫描线算法等矩形合并逻辑批量处理形状列表,降低渲染时的绘制调用次数。
内容的提问来源于stack exchange,提问作者Ryan Malley
相关产品推荐
相关产品推荐

