HTML5 Canvas ctx.clip() 方法用在圆上,在圆下面留下一条线
HTML5 Canvas ctx.clip() method used on a circle leaves a line underneath the circle
我创建了一个生成行星精灵的程序。我这样做是通过创建一个圆形路径,运行 ctx.clip()
将所有以下图层保留在圆圈内,然后绘制一个黑色和透明的纹理层,然后在整个 canvas,然后是阴影和光晕。 问题是在裁剪后圆下也出现了彩色线条,我不知道为什么。我需要删除它。
这里是fiddle。最后一行将代码设置为每半秒循环一次:https://jsfiddle.net/tzkwmzqu/4/
我不确定我是否理解你的问题,但我假设你在谈论 anti-aliasing 问题。
目前,您在裁剪区域上画了很多。
在每次绘制时,新的抗锯齿工件都会使最新的绘图变得平滑。最后,本来应该是半透明的像素现在完全不透明了。
另一方面,使用 globalCompositeOperation
和 'destination-in'
一样,您只需要一张绘图即可进行合成(~剪裁)。所以你不会积累人工制品。但即使你这样做了,gCO 是全球性的,因为它考虑了透明度,所以积累就不那么重要了。
var ctx1 = clip.getContext('2d');
var ctx2 = gCO.getContext('2d');
var ctx3 = gCO2.getContext('2d');
ctx1.beginPath();
ctx1.arc(150, 150, 150, 0, Math.PI*2)
ctx1.clip();
// drawing multiple times on this clipped area will increase artifacts
ctx1.fillRect(0,0,300, 150);
ctx1.fillRect(0,0,300, 150);
ctx1.fillRect(0,0,300, 150);
ctx1.fillRect(0,0,300, 150);
ctx2.beginPath();
ctx2.arc(150, 150, 150, 0, Math.PI*2)
ctx2.fillRect(0,0,300, 150);
ctx2.globalCompositeOperation = 'destination-in';
//With gCO you only draw once, but even if you did draw multiple times, there would still be less artifacts
ctx2.fill();
ctx2.fill();
ctx2.fill();
ctx2.fill();
ctx2.globalCompositeOperation = 'source-over';
ctx3.beginPath();
ctx3.arc(150, 150, 150, 0, Math.PI*2)
ctx3.fillRect(0,0,300, 150);
ctx3.globalCompositeOperation = 'destination-in';
// only one drawing needed:
ctx3.fill();
ctx3.globalCompositeOperation = 'source-over';
ctx1.fillStyle = ctx2.fillStyle = ctx3.fillStyle = "white";
ctx1.fillText('clipping', 120, 100);
ctx2.fillText('compositing', 120, 100);
ctx3.fillText('single compositing', 120, 100);
canvas{
border: 1px solid;
}
<canvas id="clip"></canvas><canvas id="gCO"></canvas><canvas id="gCO2"></canvas>
关于您的代码的一些不相关的注释:
closePath
不标记路径声明的结尾,只有新的 beginPath()
调用才标记。 ctx.fillStyle = 'transparent'; ctx.fill()
不会做任何事情。只有putImageData
、clearRect
方法和globalCompositeOperation
+绘图方法可以产生透明像素。
以上所有内容都集中在一个片段中:
/* Load images */
var texture = new Image();
texture.src = "http://i.imgur.com/0qMwa8p.png";
var shadow = new Image();
shadow.src = "http://i.imgur.com/pX3HVFY.png";
/* Create the canvas and context references */
var canvas = document.getElementById("game");
canvas.style.width = (canvas.width = 512) + "px";
canvas.style.height = (canvas.height = 512) + "px";
var ctx = canvas.getContext("2d");
/* render */
function render() {
/* Size of planets */
var scale = Math.random() + 1
// We don't need to save/restore the canvas state now,
// simply remember to set the gCO back to 'source-over'
// here it done at the end of the function
/* Clear canvas for redraw */
ctx.clearRect(0, 0, canvas.width, canvas.height);
/* Place texture onto planet */
ctx.globalAlpha = Math.random() * .5 + .5;
ctx.drawImage(texture, (Math.round(Math.random() * 256) - 128 * scale), (Math.round(Math.random() * 256) - 128 * scale), texture.naturalWidth * scale, texture.naturalHeight * scale)
/* Color Planet */
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = "multiply";
var color = "hsl(" + Math.random() * 256 + ", 100%, 50%)"
ctx.fillStyle = color;
ctx.fillRect(0, 0, canvas.width, canvas.height)
/* Give planet its shine and shadow */
ctx.globalCompositeOperation = "source-over";
ctx.drawImage(shadow, Math.round(Math.random() * 200 - 128 * scale), Math.round(Math.random() * 200 - 128 * scale), shadow.naturalWidth * scale, shadow.naturalHeight * scale)
// instead of clipping, use gCO
ctx.globalCompositeOperation = 'destination-in';
ctx.beginPath();
ctx.arc(256, 256, 128 * scale, 0, 2 * Math.PI);
ctx.fill();
// reset gCO
ctx.globalCompositeOperation = 'source-over';
}
render()
window.interval = setInterval(render, 500)
#game {
border: 1px solid black;
background-color: black;
}
<canvas id="game"></canvas>
我创建了一个生成行星精灵的程序。我这样做是通过创建一个圆形路径,运行 ctx.clip()
将所有以下图层保留在圆圈内,然后绘制一个黑色和透明的纹理层,然后在整个 canvas,然后是阴影和光晕。 问题是在裁剪后圆下也出现了彩色线条,我不知道为什么。我需要删除它。
这里是fiddle。最后一行将代码设置为每半秒循环一次:https://jsfiddle.net/tzkwmzqu/4/
我不确定我是否理解你的问题,但我假设你在谈论 anti-aliasing 问题。
目前,您在裁剪区域上画了很多。
在每次绘制时,新的抗锯齿工件都会使最新的绘图变得平滑。最后,本来应该是半透明的像素现在完全不透明了。
另一方面,使用 globalCompositeOperation
和 'destination-in'
一样,您只需要一张绘图即可进行合成(~剪裁)。所以你不会积累人工制品。但即使你这样做了,gCO 是全球性的,因为它考虑了透明度,所以积累就不那么重要了。
var ctx1 = clip.getContext('2d');
var ctx2 = gCO.getContext('2d');
var ctx3 = gCO2.getContext('2d');
ctx1.beginPath();
ctx1.arc(150, 150, 150, 0, Math.PI*2)
ctx1.clip();
// drawing multiple times on this clipped area will increase artifacts
ctx1.fillRect(0,0,300, 150);
ctx1.fillRect(0,0,300, 150);
ctx1.fillRect(0,0,300, 150);
ctx1.fillRect(0,0,300, 150);
ctx2.beginPath();
ctx2.arc(150, 150, 150, 0, Math.PI*2)
ctx2.fillRect(0,0,300, 150);
ctx2.globalCompositeOperation = 'destination-in';
//With gCO you only draw once, but even if you did draw multiple times, there would still be less artifacts
ctx2.fill();
ctx2.fill();
ctx2.fill();
ctx2.fill();
ctx2.globalCompositeOperation = 'source-over';
ctx3.beginPath();
ctx3.arc(150, 150, 150, 0, Math.PI*2)
ctx3.fillRect(0,0,300, 150);
ctx3.globalCompositeOperation = 'destination-in';
// only one drawing needed:
ctx3.fill();
ctx3.globalCompositeOperation = 'source-over';
ctx1.fillStyle = ctx2.fillStyle = ctx3.fillStyle = "white";
ctx1.fillText('clipping', 120, 100);
ctx2.fillText('compositing', 120, 100);
ctx3.fillText('single compositing', 120, 100);
canvas{
border: 1px solid;
}
<canvas id="clip"></canvas><canvas id="gCO"></canvas><canvas id="gCO2"></canvas>
关于您的代码的一些不相关的注释:
closePath
不标记路径声明的结尾,只有新的 beginPath()
调用才标记。 ctx.fillStyle = 'transparent'; ctx.fill()
不会做任何事情。只有putImageData
、clearRect
方法和globalCompositeOperation
+绘图方法可以产生透明像素。
以上所有内容都集中在一个片段中:
/* Load images */
var texture = new Image();
texture.src = "http://i.imgur.com/0qMwa8p.png";
var shadow = new Image();
shadow.src = "http://i.imgur.com/pX3HVFY.png";
/* Create the canvas and context references */
var canvas = document.getElementById("game");
canvas.style.width = (canvas.width = 512) + "px";
canvas.style.height = (canvas.height = 512) + "px";
var ctx = canvas.getContext("2d");
/* render */
function render() {
/* Size of planets */
var scale = Math.random() + 1
// We don't need to save/restore the canvas state now,
// simply remember to set the gCO back to 'source-over'
// here it done at the end of the function
/* Clear canvas for redraw */
ctx.clearRect(0, 0, canvas.width, canvas.height);
/* Place texture onto planet */
ctx.globalAlpha = Math.random() * .5 + .5;
ctx.drawImage(texture, (Math.round(Math.random() * 256) - 128 * scale), (Math.round(Math.random() * 256) - 128 * scale), texture.naturalWidth * scale, texture.naturalHeight * scale)
/* Color Planet */
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = "multiply";
var color = "hsl(" + Math.random() * 256 + ", 100%, 50%)"
ctx.fillStyle = color;
ctx.fillRect(0, 0, canvas.width, canvas.height)
/* Give planet its shine and shadow */
ctx.globalCompositeOperation = "source-over";
ctx.drawImage(shadow, Math.round(Math.random() * 200 - 128 * scale), Math.round(Math.random() * 200 - 128 * scale), shadow.naturalWidth * scale, shadow.naturalHeight * scale)
// instead of clipping, use gCO
ctx.globalCompositeOperation = 'destination-in';
ctx.beginPath();
ctx.arc(256, 256, 128 * scale, 0, 2 * Math.PI);
ctx.fill();
// reset gCO
ctx.globalCompositeOperation = 'source-over';
}
render()
window.interval = setInterval(render, 500)
#game {
border: 1px solid black;
background-color: black;
}
<canvas id="game"></canvas>