gpt4 book ai didi

javascript - 如何避免 drawImage() 星爆伪影?

转载 作者:行者123 更新时间:2023-11-29 21:34:46 25 4
gpt4 key购买 nike

1。原始问题:

我正在制作 Canvas 动画“缩放”效果,该效果会产生一些烦人的视觉伪像。这个简化示例显示了 255 帧后的输出。在每一帧中,都会发生两件事:(1) drawArc() 在 Canvas 中心制作一个彩色(灰色)圆盘; (2) imageDraw() 以稍微放大的比例重新绘制 Canvas 。我希望看到一个平滑的径向渐变从中心向外扩展。相反,这是我所看到的:

zzz

让我感到困扰的是 (a) 沿垂直和水平轴(以及在较小程度上,在对 Angular 线上)的明亮“星爆”和 (b) 模糊的菱形图案。

我认为这是 drawImage() 缩放算法的某种产物。我已经尝试调整所有参数(deltastrokeWidth、圆弧半径),但总有一些版本的这种星爆效果。关于如何避免或至少减少这种影响的任何建议?

这是我的代码:

var cv = document.getElementById("testCanvas");
var ctx = cv.getContext('2d');
var cvHeight = cv.height;
var cvWidth = cv.width;
for (var j=0;j<255;j++) {
var delta = 4;

// redraw the canvas, enlarged by delta pixels
ctx.drawImage(cv, 0, 0, cvWidth, cvHeight,
-delta/2, -delta/2, cvWidth+delta, cvHeight+delta);

// draw a new circle at the center, in a different color
ctx.beginPath();
ctx.strokeStyle = "rgb("+ j + "," + j + "," + j +")";
ctx.strokeWidth = 10;
ctx.arc(cvWidth/2, cvHeight/2, 10, 0, Math.PI*2.0);
ctx.stroke();
}

这是 the JSFiddle .

2。进一步阐述

正如@Igor Raush 恰如其分地观察到的那样,我给出的示例图像可以使用 createRadialGradient() 渲染得更好(无星暴)。但我的示例代码过于简单且容易引起误解:我的目标不是生成径向颜色渐变,而是通过连续调用 imageDraw() 来放大 Canvas 来创建缩放动画效果。在上面的例子中,一个静态的白色圆盘被放置在 Canvas 的中心。在我的实际应用程序中,新图像被放置在每一帧 Canvas 的中心。问题在于,无论 Canvas 中央原本放着什么样的图像,都会或多或少地出现那些烦人的星爆图案。

这是一个使用随机数据和真实动画的更好示例。 (为了简单起见,我在这里使用随机数据。我的应用程序中的实际数据不是随机的,但效果是相同的。)在每一帧中,一个随机的环(ctx.arc())彩色点绘制在 Canvas 的中心; imageDraw() 然后稍微扩展 Canvas 。

这是 JS Fiddle ,这是代码:

var cv = document.getElementById("testCanvas");
var ctx = cv.getContext('2d');
var cvHeight = cv.height;
var cvWidth = cv.width;
var delta = 10; // higher = faster "expansion" of the canvas
var data = new Array(100);

setInterval( function() {
FetchNewData(data); // fill the array with new data
DrawTheRing(cv,data); // draw the data around a ring, as shades of gray, centered on the canvas
ctx.drawImage(cv, 0, 0, cvWidth, cvHeight, -delta/2, -delta/2, cvWidth+delta, cvHeight+delta); // expand the canvas
} , 10);


// Load up the array with random data
function FetchNewData(data) {
var nSamples = data.length;
for (var k=0; k< nSamples; k++) {
data[k] = Math.floor((Math.random() * 255));
}
}

// draw a ring, centered on the canvas, containing the grayscale data
function DrawTheRing(cv,data) {
var radius = 10;
var thickness = 10;
var ctx = cv.getContext('2d');
var angle = 0;
var dAngle = Math.PI*2.0/data.length;
for ( var k = 0; k < data.length; k++) {
var value = data[k];
ctx.beginPath();
ctx.lineWidth = thickness;
ctx.strokeStyle = "rgb("+ value + "," + value + "," + value +")"; // a shade of gray
ctx.arc(cvWidth/2, cvHeight/2, radius, angle, angle+dAngle);
ctx.stroke();
angle += dAngle;
}
}

下面是它的运行快照: zoooming with random data

关于如何避免垂直和水平轴以及对 Angular 线上那些虚假的锐线有什么想法吗?有没有更好的方法来实现这种缩放效果?

最佳答案

缺陷确实是由于缩放造成的。一旦在 Canvas 上绘制路径,路径信息就会丢失,因此您正在调整图像的光栅化版本的大小。这就是为什么您的圆圈最终看起来像多边形的原因。

您可以改为使用 ctx.createRadialGradient ,为色标设置动画,并在每一帧重新绘制 Canvas 。

var s = 0.99;
var x = cvWidth / 2,
y = cvHeight / 2,
r = cvWidth / 2;

// generate gradient
var gradient = ctx.createRadialGradient(x, y, r, x, y, 0);
gradient.addColorStop(0, 'black');
gradient.addColorStop(s, 'black');
gradient.addColorStop(1, 'white');

Here是一个例子 fiddle 。您可以使用内圆半径和控制颜色停止的计时功能来实现您想要的结果。

关于javascript - 如何避免 drawImage() 星爆伪影?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35138002/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com