3

I'm looking at all of the different types of global composite operations here:

https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation

None of them do exactly what I want to do. Is there a way to define a custom globalCompositeOperation? It would be perfect if I could create a shader and then have it be used everytime I draw something with a CanvasRenderingContext2D.draw method.

Specifically, on a per pixel basis, I want the following (psuedo code) operation to be used by the CanvasRenderingContext2D.draw methods:

if the existing canvas color alpha is 0.0, 
    then draw the new shape's color and set alpha to 0.1
if the existing canvas color is the same as the new shape's color
    then increase the alpha, by 0.1
if the existing canvas color is different from the the new shape's color
    then decrease the alpha by 0.1

Am I even thinking about this correctly? I'm sensing that I should be using WebGLRenderingContext somehow, but I'm a little shaky on how it all fits together.

  • 1
    Short answer : no you can"t (or without too much work). You should search on the net, there's a variety of project that does image processing with webgl, that you could modify easily to fit your need. Don't forget both FF and Chrome offer now great webgl debugging tools. – GameAlchemist Jan 02 '16 at 10:52
  • You can refactor your code for webGL and get the benefit of shaders. But don't try to extend CanvasRenderingContext2D -- no need for that. But you can easily create your own custom image filter function using the existing canvas plus another in-memory canvas. The in-memory canvas will hold the new drawings. Then `getImageData` on both canvases and compare + manipulate + replace each pixel on the existing canvas based on your custom blending operation. Note: This is fairly resource & cpu intensive because compositing using getImageData cannot be offloaded to the gpu. – markE Jan 02 '16 at 19:18

1 Answers1

2

The answer is mostly no.

There is no way to define your own globalCompositeOperation with Canvas2D.

2 solutions off the top of my head

  1. Use 2 canvases, a 2d one and WebGL one

    for each shape
       clear the 2d canvas
       draw the shape into the 2d canvas
       upload the canvas to a webgl texture
       composite that texture with the previous results using a custom shader.
    

    The problem with this solution is it will be slow because uploading your canvas to a texture is a relatively slow operation. But, it means you can use all of the canvas functions like stroke and arc and gradients etc to build it shape.

  2. Switch entirely to WebGL

    The problem here is you won't have access to all the features of the 2D API and reproducing ALL of them is a lot of work.

    On the other hand, if you are only using a limited set of them then it may not be too much work. For example if you are only using drawImage, fillRect, clear, and maybe moveTo and lineTo, fill and stroke then it would be relatively easy to reproduce in WebGL. If you are using lots of the features like masking, bezier curves, gradients, or patterns it starts to become much more work.

As a starter here's a tutorial that presents a certain kind of compositing or image processing which is the basic technique for globalCompositeOperation in WebGL. Both of the solutions above would require this basic type of solution to composite the results after each shape.

gman
  • 100,619
  • 31
  • 269
  • 393
  • "reproducing [all context2D] features is a lot of work" : true, but using an API that does such (or have enough features for the O.P.) is still possible. I know of pixi.js, maybe some others does that too. – GameAlchemist Jan 02 '16 at 17:46
  • Pixi doesn't reproduce the canvas API. It basically provides 1 and only 1 function, `drawImage` on top of which it creates a scene graph. Which was kind of my point above, if you're only using a few basic features of the canvas 2d api then it's not hard to repo. I don't know any JS libraries that come close to reproducing the canvas 2d api in WebGL. If you know of some please post them below. The only one I know if is [this one](https://github.com/gameclosure/webgl-2d) and it's 5 years abandoned and missing tons of features. – gman Jan 02 '16 at 18:41
  • Maybe you're talking of the first version of Pixi. Now it has line, bezier, polygons... Maybe not what you're after, but still a lot more than drawImage. (http://www.goodboydigital.com/pixijs/docs/classes/Graphics.html). And sorry, i don't know about any other choice. – GameAlchemist Jan 02 '16 at 19:03
  • Oh, nice! I hadn't been paying attention. – gman Jan 02 '16 at 19:34
  • Thanks for the awesome answer @gman. I just marked this as the answer. Your explanation of the two options is super helpful. I am, in fact, using quite a bit of the drawing api including bezier curves, so I actually have been using the dual canvas method you suggest as the first solution (with limited success, cuz I'm super new to webgl and haven't worked out all the bugs yet). – vaporizationator Jan 03 '16 at 16:37
  • However, I'm already using the phaser.js library which is built on pixi.js so the second solution coupled with pixi's drawing libraries may be the optimal solution. – vaporizationator Jan 03 '16 at 16:45