画布 - 在所有完全透明的区域填充矩形

jt7*_*t78 5 javascript html5 canvas clipping composite

我正在使用HTML5画布编写一个简单的2D游戏引擎.我来添加一个照明引擎.每个光源具有半径值和强度值(0-1,例如1将非常亮).还有一个环境光值,用于照亮世界上不靠近光源的所有其他物体(0-1,例如0.1将是月光).照明过程在主画布上方的单独画布上完成:

  1. 对于每个光源,在该位置绘制径向梯度,其半径与光源相同.渐变给出两个停止:中心是黑色,具有1的光强度的α,并且结束/边缘是黑色,具有1个环境光值的α.一切正常.
  2. 这是它出错的地方:/我需要用黑色和1个环境光值的alpha填充整个画布,此时我通过将context.globalCompositeOperation设置为source-out然后fillRecting整个画布来完成此操作.

我的代码是:

var amb = 'rgba(0,0,0,' + (1-f.ambientLight) + ')';
for(i in f.entities) {
    var e = f.entities[i], p = f.toScreenPoint(e.position.x, e.position.y), radius = e.light.radius;

    if(radius > 0) {
        var g = cxLighting.createRadialGradient(p.x, p.y, 0, p.x, p.y, radius);
        g.addColorStop(0, 'rgba(0,0,0,' + (1-e.light.intensity) + ')');
        g.addColorStop(1, amb);

        cxLighting.fillStyle = g;
        cxLighting.beginPath();
        cxLighting.arc(p.x, p.y, radius, 0, Math.PI*2, true);
        cxLighting.closePath();
        cxLighting.fill();
    }
}
//Ambient light
cxLighting.globalCompositeOperation = 'source-out';
cxLighting.fillStyle = amb;
cxLighting.fillRect(0, 0, f.width, f.height);
cxLighting.globalCompositeOperation = 'source-over';
Run Code Online (Sandbox Code Playgroud)

然而,我没有得到我不喜欢的引擎(左),而是得到了一种反向渐变(右).我认为这是因为当我使用source-out复合操作绘制矩形时,它会影响渐变本身的颜色,因为它们是半透明的.

理想的灯光效果 我明白了

有没有办法以不同或更好的方式做到这一点?可能会使用剪辑,或者先将矩形绘制在所有内容上?

此外,我修改了Mozila开发中心关于堆肥的示例,以复制我需要做的事情,并且没有任何复合模式似乎有效,请检查它是否有用.

非常感谢,任何答案都会很棒:)

Sim*_*ris 14

一个简单的方法是使用,imageData但这将是非常缓慢的.这是一个选项,但对游戏引擎来说不是一个好选择.

另一种方法是将环境光和光源视为一条路径.这样可以很容易地做到:

http://jsfiddle.net/HADky/

或者看一下背后的图片:http://jsfiddle.net/HADky/10/

你在这里利用的是这样一个事实,即画布上的路径的任何交集始终只是联合而且从不复合.因此,您使用单个渐变画笔绘制整个事物.

但如果有多个光源,它会比那更棘手.我不太确定如何以有效的方式覆盖它,特别是如果你计划两个光源相交.

你可能应该做的是设计一个alpha通道而不是这个重叠的东西,但我现在无法想到让它工作的好方法.如果我想到别的什么,我会重温这个.


编辑:嘿!所以我做了一些思考,想出了一个很好的解决方案.

您需要做的是绘制一种alpha通道,其中黑点标记您想要光的位置.所以如果你有三个光源,它看起来像这样:

在此输入图像描述

然后,您需要将填充样式设置为环境颜色,并将globalCompositeOperation设置为xor和xor整个事物.

ctx.fillStyle = amb;
ctx.globalCompositeOperation = 'xor';
ctx.fillRect(0,0,500,500);
Run Code Online (Sandbox Code Playgroud)

除了透明部分将正确环境外,这将留下"相反"的图像:

在此输入图像描述

这是代码的一个工作示例:

http://jsfiddle.net/a2Age/

额外优化:您可以实际实现效果,而无需使用任何路径,只需将完全相同的径向渐变绘制到rects而不是圆形路径:

http://jsfiddle.net/a2Age/2/ 希望有所帮助!