如何在实时画布中使用“乘法混合模式”?

3
2016年修改说明: "multiply"值已经在globalCompositeOperation中实现。该性能足够支持实时图形。
基本上,我有两个画布(一个是用于绘制的隐藏画布),我想使用乘法混合模式将隐藏画布混合到可见画布上。 Context.globalCompositeOperation 不包括乘法(尽管在我看来应该包括),使用 imageData 手动混合画布太慢了(我需要以60fps进行操作)。
有没有更快的方法可以用来混合画布?我相信可以使用 WebGL 来完成,但我没有使用它的经验。
1个回答

5
WebGL的混合模式不包括乘法(源和目标的乘积)。不过,你可以利用WebGL的渲染到纹理功能来高效地执行乘法操作。
  1. Let your visible canvas be a WebGL canvas.
  2. Create two textures; call them "source" and "destination".
  3. Render your invisible-canvas content to the "source" texture; this can be done either using WebGL drawing operations directly (using no extra canvas) or by uploading your 2D invisible canvas's contents to the texture (this is a built-in operation):

    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. Render the other content to be multiplied to the "destination" texture.

  5. Finally, targeting the actual visible canvas, use a fragment shader to multiply the "source" and "destination" textures. The techniques here are those used for post-processing effects — I recommend looking up such a tutorial or simple example. Briefly, to apply a fragment shader to the entire canvas, you draw a full-screen quad - geometry that covers the entire viewport. The vertex shader is trivial, and the fragment shader would be like:

    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)的事情。但是,我不确定要使用哪种类型。此外,我也不知道如何处理着色器部分。提前感谢您的帮助。 - nondefault
1
@user1175802,我已经添加了一些具体的示例代码来回答你的问题。总的来说,我建议你查找一个关于后处理效果的WebGL教程(因为大部分代码都是相似的),然后根据你的需求进行调整。 - Kevin Reid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接