Mag*_*dal 6 javascript canvas effects
我想在我正在制作的游戏的背景上放置一些光源,这对于一个光源非常有效,如下所示:
这是通过将.png图像放置在对中心更加透明的其他所有内容上来实现的,如下所示:
适用于一个光源,但我需要另一种方法,我可以添加更多光源并移动光源.
我已经考虑为每个帧逐个像素地绘制类似的"阴影层",并根据到每个光源的距离计算透明度.但是,这可能会非常缓慢,我相信这个问题有更好的解决方案.
图像只是示例,每个帧将有更多的内容可以使用requestAnimationFrame移动和更新.
是否有轻量级和简单的方法来实现这一目标?提前致谢!
编辑
在ViliusL的帮助下,我想出了这个屏蔽解决方案:
// Create canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = 300;
canvas.height = 300;
document.body.appendChild(canvas);
// Draw background
var img=document.getElementById("cat");
ctx.drawImage(img,0,0);
// Create shadow canvas
var shadowCanvas = document.createElement('canvas');
var shadowCtx = shadowCanvas.getContext('2d');
shadowCanvas.width = canvas.width;
shadowCanvas.height = canvas.height;
document.body.appendChild(shadowCanvas);
// Make it black
shadowCtx.fillStyle= '#000';
shadowCtx.fillRect(0,0,canvas.width,canvas.height);
// Turn canvas into mask
shadowCtx.globalCompositeOperation = "destination-out";
// RadialGradient as light source #1
gradient = shadowCtx.createRadialGradient(80, 150, 0, 80, 150, 50);
gradient.addColorStop(0, "rgba(255, 255, 255, 1.0)");
gradient.addColorStop(1, "rgba(255, 255, 255, .1)");
shadowCtx.fillStyle = gradient;
shadowCtx.fillRect(0, 0, canvas.width, canvas.height);
// RadialGradient as light source #2
gradient = shadowCtx.createRadialGradient(220, 150, 0, 220, 150, 50);
gradient.addColorStop(0, "rgba(255, 255, 255, 1.0)");
gradient.addColorStop(1, "rgba(255, 255, 255, .1)");
shadowCtx.fillStyle = gradient;
shadowCtx.fillRect(0, 0, canvas.width, canvas.height);
Run Code Online (Sandbox Code Playgroud)
使用light的另一种方法是使用globalCompositeOperation模式'ligther'来连接事物,并使用globalAlpha来暗示事物.
首先是一个图像,左边是卡通闪电,右边是更逼真的闪电,但你更喜欢看小提琴,因为它是动画的:http:
//jsfiddle.net/gamealchemist/ABfVj/
那我是怎么做的:
变暗:
- 选择变暗的颜色(很可能是黑色,但您可以选择红色或其他颜色来模糊结果).
- 选择不透明度(0.3似乎是一个很好的起始值).
- fillRect您想要变暗的区域.
function darken(x, y, w, h, darkenColor, amount) {
ctx.fillStyle = darkenColor;
ctx.globalAlpha = amount;
ctx.fillRect(x, y, w, h);
ctx.globalAlpha = 1;
}
Run Code Online (Sandbox Code Playgroud)
减轻:
- 选择淡淡的颜色.请注意,此颜色的r,g,b将被添加到前一个点的r,g,b:如果使用较高的值,则颜色会被烧焦.
- 将globalCompositeOperation更改为"更轻"
- 您也可以更改不透明度,以便更好地控制闪电.
- fillRect或arc想要减轻的区域.
如果在较亮模式下绘制多个圆圈,结果将相加,因此您可以选择一个非常低的值并绘制几个圆圈.
function ligthen(x, y, radius, color) {
ctx.save();
var rnd = 0.03 * Math.sin(1.1 * Date.now() / 1000);
radius = radius * (1 + rnd);
ctx.globalCompositeOperation = 'lighter';
ctx.fillStyle = '#0B0B00';
ctx.beginPath();
ctx.arc(x, y, radius, 0, 2 * ?);
ctx.fill();
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(x, y, radius * 0.90+rnd, 0, 2 * ?);
ctx.fill();
ctx.beginPath();
ctx.arc(x, y, radius * 0.4+rnd, 0, 2 * ?);
ctx.fill();
ctx.restore();
}
Run Code Online (Sandbox Code Playgroud)
请注意,我添加了一个正弦变化,使光线更加生动.
Ligthen:另一种方式:
你也可以在仍然使用'ligther'模式的同时使用渐变来获得更平滑的效果(第一个更像卡通,除非你绘制很多圆圈.).
function ligthenGradient(x, y, radius) {
ctx.save();
ctx.globalCompositeOperation = 'lighter';
var rnd = 0.05 * Math.sin(1.1 * Date.now() / 1000);
radius = radius * (1 + rnd);
var radialGradient = ctx.createRadialGradient(x, y, 0, x, y, radius);
radialGradient.addColorStop(0.0, '#BB9');
radialGradient.addColorStop(0.2 + rnd, '#AA8');
radialGradient.addColorStop(0.7 + rnd, '#330');
radialGradient.addColorStop(0.90, '#110');
radialGradient.addColorStop(1, '#000');
ctx.fillStyle = radialGradient;
ctx.beginPath();
ctx.arc(x, y, radius, 0, 2 * ?);
ctx.fill();
ctx.restore();
}
Run Code Online (Sandbox Code Playgroud)
我还在这里添加了一个罪恶变异.
Rq:在每次绘制时创建渐变将创建垃圾:如果使用单个渐变,则存储渐变;如果要为渐变设置动画,则将它们存储在数组中.
如果在多个位置使用相同的灯光,则构建一个渐变,以(0,0)为中心,并在绘制之前使用此单个渐变来平移画布.
Rq 2:你可以使用裁剪来防止屏幕的某些部分被照亮(如果有障碍物).我在我的例子中添加了蓝色圆圈来表明这一点.
因此,您可能希望直接将场景与这些效果相关联,或者单独创建一个光照层,在您在屏幕上绘制它之前,您可以根据需要变暗/变亮.
有太多的场景来讨论它们(光动画与否,剪裁与否,预先计算光层或不...,但就速度而言,对于Safari和iOS safari,使用rect的解决方案)/arc draw -either with gradient或solid fill-将比绘制图像/画布更快.
在Chrome上它将完全相反:绘制图像比在几何计数增加时绘制每个几何图形更快.
Firefox与此非常相似.
归档时间: |
|
查看次数: |
3244 次 |
最近记录: |