【问题标题】:How can I use the multiply blend mode on a canvas in real time?如何在画布上实时使用多重混合模式?
【发布时间】:2024-04-25 19:20:02
【问题描述】:

自 2016 年起编辑:为 globalCompositeOperation 实现了“乘”值。对于实时图形,性能绰绰有余。


基本上,我有两个画布(一个是用于绘图的不可见画布),我想使用多重混合模式将不可见画布混合到可见画布上。

Context.globalCompositeOperation 不包括乘法(尽管在我看来应该如此)并且使用imageData 手动混合画布太慢(我需要能够以 60fps 的速度进行此操作)。

有什么更快的方法可以用来混合画布吗?我相信这可以使用 WebGL 来完成,但我没有使用它的经验。

【问题讨论】:

    标签: javascript html canvas webgl


    【解决方案1】:

    WebGL 的混合模式也不包括(源和目标的)乘法。但是,您可以使用 WebGL 的渲染到纹理功能有效地执行乘法运算:

    1. 让您的可见画布成为 WebGL 画布。
    2. 创建两个纹理;称它们为“源”和“目的地”。
    3. 将不可见的画布内容渲染到“源”纹理;这可以通过直接使用 WebGL 绘图操作(不使用额外的画布)或通过将 2D 不可见画布的内容上传到纹理来完成(这是一个内置操作):

      var sourceTexture = gl.createTexture()
      gl.bindTexture(gl.TEXTURE_2D, sourceTexture)
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, sourceCanvas)
      // ...also set texture filters — see any WebGL tutorial...
      
    4. 渲染要乘以“目标”纹理的其他内容。

    5. 最后,针对实际可见的画布,使用片段着色器将“源”和“目标”纹理相乘。这里的技术是那些用于后期处理效果的技术——我建议查找such a tutorial 或简单示例。简而言之,要将片段着色器应用于整个画布,您需要绘制一个全屏四边形 - 覆盖整个视口的几何体。顶点着色器是微不足道的,片段着色器是这样的:

      varying vec2 texCoord;
      uniform sampler2D sourceTexture;
      uniform sampler2D destTexture;
      void main(void) {
        gl_FragColor = texture2D(sourceTexture, texCoord) * texture2D(destTexture, texCoord);
      }
      

    如果你想在每帧中进行多个重叠乘法混合,那么如果不超过 8 个,你可以扩展上述过程来乘以多个纹理;如果有很多,您将需要执行多个阶段,将两个纹理相乘,同时渲染到第三个,然后交换角色。

    如果您想要更具体的答案,请扩展您的问题,详细说明您要相乘的图形数量和类型。

    【讨论】:

    • 感谢您的回答。我对 WebGL 非常陌生,需要一些代码帮助。我做了一些研究,发现 gl.texSubImage2D 可用于将画布内容复制到 webGL 纹理中。我正在考虑做类似 gl.texSubImage2D(GL_TEXTURE_2D,0,0,0,640,480,GL_COLOR_INDEX,type,imageData) 的事情。但是,我不确定要使用哪种类型。另外,我不知道如何处理着色器部分。提前致谢。
    • @user1175802 我添加了一些特定的示例代码来回答您的问题。总的来说,我建议查找有关后处理效果的 WebGL 教程(因为大多数代码都相似),然后根据您的需要进行调整。