Canvas - Fill a rectangle in all areas that are fully transparent

前端 未结 2 1342
予麋鹿
予麋鹿 2020-12-09 07:03

I\'m writing a simple 2D game engine using the HTML5 canvas. I\'ve come to adding a lighting engine. Each light source has a radius value and an intensity value (0-1, eg 1 w

2条回答
  •  有刺的猬
    2020-12-09 07:48

    One trivial way would be to use imageData but that would be painfully slow. It's an option, but not a good one for a game engine.

    Another way would be to think of the ambient light and the light-source as if they were one path. That would make it very easy to do:

    http://jsfiddle.net/HADky/

    Or see it with an image behind: http://jsfiddle.net/HADky/10/

    The thing you're taking advantage of here is the fact that any intersection of a path on canvas is always only unioned and never compounded. So you're using a single gradient brush to draw the whole thing.

    But it gets a bit trickier than that if there's more than one light-source. I'm not too sure how to cover that in an efficient way, especially if you plan for two light-sources to intersect.

    What you should probably do instead is devise an alpha channel instead of this overlay thing, but I can't currently think of a good way to get it to work. I'll revisit this if I think of anything else.


    EDIT: Hey! So I've done a bit of thinking and came up with a good solution.

    What you need to do is draw a sort of alpha channel, where the dark spots mark the places where you want light to be. So if you had three light sources it would look like this:

    enter image description here

    Then you want to set the fill style to your ambient color and set the globalCompositeOperation to xor and xor the whole thing.

    ctx.fillStyle = amb;
    ctx.globalCompositeOperation = 'xor';
    ctx.fillRect(0,0,500,500);
    

    That will leave you with the "opposite" image except the transparent parts will be correctly ambient:

    enter image description here

    Here's a working example of the code:

    http://jsfiddle.net/a2Age/

    Extra optimization: You can actually achieve the effect without using any paths at all, by simply drawing the exact same radial gradients onto rects instead of circular paths:

    http://jsfiddle.net/a2Age/2/ Hope that helps!

提交回复
热议问题