You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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区域。
  • 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模式绘制黑色,覆盖区域。
  • 将Canvas转换为图片,用Konva的Image组件渲染到舞台,仅在形状变化时重新生成遮罩即可。

这种方式只需要渲染一张图片,性能远优于成千上万个小矩形。

3. 合并重叠形状减少绘制量

对形状列表做预处理,合并同类型的重叠/相邻形状:

  • 比如多个相邻或重叠的Hide矩形可以合并为一个大矩形,大幅减少需要绘制的形状数量。
  • 可使用扫描线算法等矩形合并逻辑批量处理形状列表,降低渲染时的绘制调用次数。

内容的提问来源于stack exchange,提问作者Ryan Malley

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 13:22:10