我正在使用HTML5画布编写一个简单的2D游戏引擎。我来添加一个照明引擎。每个光源具有半径值和强度值(0-1,例如1将非常亮)。还有一个环境光值,用于照亮世界上不靠近光源的所有其他物体(0-1,例如0.1将是月光)。照明过程在主画布上方的单独画布上完成:
我的代码是:
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';
然而,我得到了一种颠倒的渐变(右),而不是得到我不喜欢的引擎(左)。我认为这是因为当我使用source-out
复合操作绘制矩形时,它会影响渐变本身的颜色,因为它们是半透明的。
有没有办法以不同或更好的方式做到这一点?可能会使用剪辑,或者先将矩形绘制在所有内容上?
另外,我修改了Mozila开发中心的example关于堆肥以复制我需要做的事情,并且没有任何复合模式似乎有效,check that out如果有帮助的话。
非常感谢,任何答案都会很棒:)
答案 0 :(得分:14)
一个简单的方法是使用imageData
,但这会非常缓慢。这是一个选项,但不适合游戏引擎。
另一种方法是将环境光和光源视为一条路径。这样做很容易:
或者看一下背后的图片:http://jsfiddle.net/HADky/10/
你在这里利用的是这样一个事实,即画布上的路径的任何交集始终只是联合而且从不复合。所以你使用一个渐变画笔绘制整个画面。
但如果有多个光源,它会比那更棘手。我不太清楚如何以有效的方式覆盖它,特别是如果你计划两个光源交叉。
你可能应该做的是设计一个alpha通道而不是这个重叠的东西,但我现在无法想到让它工作的好方法。如果我想到别的什么,我会重温这个。
编辑:嘿!所以我已经做了一些思考并提出了一个很好的解决方案。
你需要做的是绘制一种alpha通道,其中黑点标记你想要光的位置。所以,如果你有三个光源,它将是这样的:
然后你想要将填充样式设置为环境颜色,并将globalCompositeOperation设置为xor和xor整个事物。
ctx.fillStyle = amb;
ctx.globalCompositeOperation = 'xor';
ctx.fillRect(0,0,500,500);
除了透明部分是正确的环境外,这将留下“相反”的图像:
以下是代码的工作示例:
额外优化:您可以实际实现效果,而无需使用任何路径,只需将完全相同的径向渐变绘制到rects而不是圆形路径:
http://jsfiddle.net/a2Age/2/ 希望有所帮助!
答案 1 :(得分:0)
只是一个想法,但是因为你从梯度中获得了相反的效果,你是否尝试过逆转渐变?