圆圈上使用的HTML5 Canvas ctx.clip()方法在圆圈下留下一条线 [英] HTML5 Canvas ctx.clip() method used on a circle leaves a line underneath the circle

查看:849
本文介绍了圆圈上使用的HTML5 Canvas ctx.clip()方法在圆圈下留下一条线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个程序来生成行星精灵。我通过创建一个循环路径,运行 ctx.clip()来将所有以下图层保留在圆内,然后绘制黑色透明纹理图层,然后在整个画布上随机选择一个颜色的矩形,然后在它上面放上阴影并发光。 问题是裁剪后在圆圈下方还会出现一条彩色线,我不知道为什么。我需要这个删除。



这是一个小提琴。最后一行将代码设置为每半秒循环: https://jsfiddle.net/tzkwmzqu/4/

解决方案

我不确定我是否理解你的问题,但我会假设你正在谈论 anti-aliasing 问题。

目前,您在裁剪区域绘制了很多图像。

在每次抽奖时,新的抗锯齿工件将用于平滑最新绘图。最后,半透明像素应该是完全不透明的像素。

另一方面,使用 globalCompositeOperation 'destination-in',您只需要一个图形来进行合成(〜裁剪)。所以你不会积累文物。但即使你做到了,gCO也是全球性的,并且考虑到透明度,积累并不重要。

 

  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 +绘图方法产生透明的像素。



所以这里是所有上述内容的一个片段:

  / *加载图片* / var texture = new Image(); texture.src =http://i.imgur.com/0qMwa8p.png\"; var shadow = new Image(); shadow.src =http://i.imgur.com/pX3HVFY.png\";/*创建画布和上下文引用* / var canvas = document.getElementById(game); canvas。 canvas.style.height =(canvas.height = 512)+px; var ctx = canvas.getContext(2d); / * render * / function render(){/ *行星的大小* / var scale = Math.random()+ 1 //我们现在不需要保存/恢复画布状态,//只需记住将gCO设置回'资源在这个函数的末尾完成/ *清除画布以进行重绘* / ctx.clearRect(0,0,canvas.width,canvas.height); / *将纹理放置到星球* / 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)/ *给行星它的光芒和阴影* / 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 *比例尺)//代替裁剪,使用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>  

I've created a program to generate planet sprites. I'm doing that by creating a circular path, running ctx.clip() to keep all the following layers inside of the circle, then drawing a black and transparent texture layer, then a randomly colored rectangle over the full canvas, then a shadow and glow on top of it all. The issue is that a colored line also appears under the circle after clipping, and I'm not sure why. I need this removed.

Here is a fiddle. The last line sets the code to loop every half second: https://jsfiddle.net/tzkwmzqu/4/

解决方案

I am not sure I do understand your problem, but I will assume that you are talking about the anti-aliasing problem.

Currently, you are drawing a lot over your clipped area.
At each draw, new anti-aliasing artifacts will come to smooth the latest drawing. At the end, what should have been semi-transparent pixels are now fully opaque ones.
In the other hand, with globalCompositeOperation like 'destination-in', you need only one drawing to make the compositing (~clipping). So you don't accumulate artifacts. But even if you did, gCO is global and since it takes transparency into account, the accumulation would be less important.

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>

A few unrelated notes about your code :

closePath does not mark the end of your path declaration, only a new beginPath() call does. ctx.fillStyle = 'transparent'; ctx.fill() won't do anything. Only putImageData, clearRect methods and globalCompositeOperation + drawing method can produce transparent pixels.

So here is all the above in one snippet :

/* 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>

这篇关于圆圈上使用的HTML5 Canvas ctx.clip()方法在圆圈下留下一条线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆