gpt4 book ai didi

javascript - 随时间褪色的 Canvas 绘画 |奇怪的阿尔法分层行为

转载 作者:数据小太阳 更新时间:2023-10-29 06:00:21 28 4
gpt4 key购买 nike

我正在绘制一个未被清除的 Canvas ,并使 Canvas 随着时间的推移逐渐变成纯色,或者在 alpha 中逐渐消失以显示后面的图层。

我的第一直觉是简单地用每帧的低 alpha 在绘图上填充一个矩形,这样填充颜色就会逐渐累积并淡出绘图。

但我发现了一些奇怪的行为(至少对我来说,我确信这是有原因的)。填充颜​​色永远不会完全累积。结果会根据油漆和填充颜色是否比彼此更亮/更暗而变化。

我发现这个问题有人和我做同样的事情:fade out lines after drawing canvas?

顶部的答案看起来不错,和我试过的一样。但它只适用于白底黑字。这是同一个 fiddle 的不同颜色的另一个版本,你会看到绘图永远不会消失,它留下了一个幽灵:http://jsfiddle.net/R4V97/92/

var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
painting = false,
lastX = 0,
lastY = 0;

canvas.width = canvas.height = 600;

canvas.onmousedown = function (e) {
if (!painting) {
painting = true;
} else {
painting = false;
}

lastX = e.pageX - this.offsetLeft;
lastY = e.pageY - this.offsetTop;
};

canvas.onmousemove = function (e) {
if (painting) {
mouseX = e.pageX - this.offsetLeft;
mouseY = e.pageY - this.offsetTop;

ctx.strokeStyle = "rgba(255,255,255,1)";
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(mouseX, mouseY);
ctx.stroke();

lastX = mouseX;
lastY = mouseY;
}
}

function fadeOut() {
ctx.fillStyle = "rgba(60,30,50,0.2)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
setTimeout(fadeOut,100);
}

fadeOut();

此外,如果您将填充不透明度更改为 0.01,并将时间更改为 20 毫秒,它甚至不会填充正确的颜色,而是保持灰色。

我尝试过的其他事情都存在同样的根本问题。我试过在两个 Canvas 之间弹跳,使用 Canvas A 并使用减少的 alpha 将其绘制到 Canvas B,然后再将 Canvas B 画回 Canvas A - 同样的问题,有一个阈值不会消失。

作为测试,我什至尝试了获取图像数据的超慢操作,遍历所有像素 alpha channel 并乘以 0.95,然后再将数据放回原处。它仍然留下了阴影,我必须在循环中做这样的事情(由于某种原因它甚至从未低于 10):

if (alpha<25) {
alpha = 0;
}

我在想我也许可以将 Canvas 分成一个网格或几行,并在每帧一个单元格中执行 imageData 操作,这在低淡入淡出时间时可能不会引人注意。

但是,如果有人知道更好的方法或者我没有得到的核心内容是什么,我将不胜感激!

  • 哦还应该注意,我让它在 Canvas 上栅格化,因为我正在用粒子/算法绘画,所以我不是在寻找意味着我不断刷新和重新绘制相同点的解决方案。谢谢!

最佳答案

RGB 和 8 位整数数学!

您需要避免接触 RGB channel ,因为当您对 8 位值进行数学运算时,结果会出现巨大错误。例如(8 位整数数学)14 * 0.1 = 1、8 * 0.1 = 1 因此,当您在现有像素上绘制时,您将得到一个舍入误差,该误差对于每个 channel 都不同,具体取决于您在顶部绘制的颜色。

没有完美的解决方案,但您可以通过使用全局复合操作“destination-out”来避免颜色 channel 并仅淡化 alpha channel 这将通过减少像素 alpha 来淡出渲染。

适用于低至 globalAlpha = 0.01 甚至更低一点的 0.006 的淡入淡出率,但低于该值可能会很麻烦。然后,如果您需要更慢的淡入淡出,只需每第 2 或第 3 帧进行一次淡入淡出。

ctx.globalAlpha = 0.01;           // fade rate
ctx.globalCompositeOperation = "destination-out" // fade out destination pixels
ctx.fillRect(0,0,w,h)
ctx.globalCompositeOperation = "source-over"
ctx.globalAlpha = 1; // reset alpha

请注意,这会将 Canvas 淡化为透明。如果您希望渐变朝着特定颜色发展,您需要将渐变 Canvas 保持为单独的屏幕外 Canvas ,并将其绘制在具有要渐变到的所需背景的 Canvas 上。

演示带有淡入淡出的彩色背景上的彩色粒子。

var canvas = document.createElement("canvas");
canvas.width = 1024;
canvas.height = 1024;
var ctx = canvas.getContext("2d");
var w = canvas.width;
var h = canvas.height;
document.body.appendChild(canvas);

var fadCan = document.createElement("canvas");
fadCan.width = canvas.width;
fadCan.height = canvas.height;
var fCtx = fadCan.getContext("2d");

var cw = w / 2; // center
var ch = h / 2;
var globalTime;

function randColour(){
return "hsl("+(Math.floor(Math.random()*360))+",100%,50%)";
}
var pps = [];
for(var i = 0; i < 100; i ++){
pps.push({
x : Math.random() * canvas.width,
y : Math.random() * canvas.height,
d : Math.random() * Math.PI * 2,
sp : Math.random() * 2 + 0.41,
col : randColour(),
s : Math.random() * 5 + 2,
t : (Math.random() * 6 -3)/10,

});
}
function doDots(){
for(var i = 0; i < 100; i ++){
var d = pps[i];
d.d += d.t * Math.sin(globalTime / (d.t+d.sp+d.s)*1000);
d.x += Math.cos(d.d) * d.sp;
d.y += Math.sin(d.d) * d.sp;
d.x = (d.x + w)%w;
d.y = (d.y + w)%w;
fCtx.fillStyle = d.col;
fCtx.beginPath();
fCtx.arc(d.x,d.y,d.s,0,Math.PI * 2);
fCtx.fill();

}
}


var frameCount = 0;
// main update function
function update(timer){
globalTime = timer;
frameCount += 1;
ctx.setTransform(1,0,0,1,0,0); // reset transform
ctx.globalAlpha = 1; // reset alpha
ctx.fillStyle = "hsl("+(Math.floor((timer/50000)*360))+",100%,50%)";
ctx.fillRect(0,0,w,h);
doDots();
if(frameCount%2){
fCtx.globalCompositeOperation = "destination-out";
fCtx.fillStyle = "black";
var r = Math.random() * 0.04
fCtx.globalAlpha = (frameCount & 2 ? 0.16:0.08)+r;
fCtx.fillRect(0,0,w,h);
fCtx.globalAlpha = 1;
fCtx.globalCompositeOperation = "source-over"
}
ctx.drawImage(fadCan,0,0)
requestAnimationFrame(update);
}
requestAnimationFrame(update);

在带淡入淡出的彩色背景上绘制演示。

点击拖动鼠标进行绘制。

var canvas = document.createElement("canvas");
canvas.width = 1024;
canvas.height = 1024;
var ctx = canvas.getContext("2d");
var w = canvas.width;
var h = canvas.height;
document.body.appendChild(canvas);

var fadCan = document.createElement("canvas");
fadCan.width = canvas.width;
fadCan.height = canvas.height;
var fCtx = fadCan.getContext("2d");

var cw = w / 2; // center
var ch = h / 2;
var globalTime;

function randColour(){
return "hsl("+(Math.floor(Math.random()*360))+",100%,50%)";
}



// main update function
function update(timer){
globalTime = timer;
ctx.setTransform(1,0,0,1,0,0); // reset transform
ctx.globalAlpha = 1; // reset alpha
ctx.fillStyle = "hsl("+(Math.floor((timer/150000)*360))+",100%,50%)";
ctx.fillRect(0,0,w,h);
if(mouse.buttonRaw === 1){
fCtx.strokeStyle = "White";
fCtx.lineWidth = 3;
fCtx.lineCap = "round";
fCtx.beginPath();
fCtx.moveTo(mouse.lx,mouse.ly);
fCtx.lineTo(mouse.x,mouse.y);
fCtx.stroke();
}


mouse.lx = mouse.x;
mouse.ly = mouse.y;
fCtx.globalCompositeOperation = "destination-out";
fCtx.fillStyle = "black";
fCtx.globalAlpha = 0.1;
fCtx.fillRect(0,0,w,h);
fCtx.globalAlpha = 1;
fCtx.globalCompositeOperation = "source-over"
ctx.drawImage(fadCan,0,0)
requestAnimationFrame(update);
}


var mouse = (function () {
function preventDefault(e) {
e.preventDefault();
}
var mouse = {
x : 0,
y : 0,
w : 0,
alt : false,
shift : false,
ctrl : false,
buttonRaw : 0,
over : false,
bm : [1, 2, 4, 6, 5, 3],
active : false,
bounds : null,
crashRecover : null,
mouseEvents : "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(",")
};
var m = mouse;
function mouseMove(e) {
var t = e.type;
m.bounds = m.element.getBoundingClientRect();
m.x = e.pageX - m.bounds.left + scrollX;
m.y = e.pageY - m.bounds.top + scrollY;
m.alt = e.altKey;
m.shift = e.shiftKey;
m.ctrl = e.ctrlKey;
if (t === "mousedown") {
m.buttonRaw |= m.bm[e.which - 1];
} else if (t === "mouseup") {
m.buttonRaw &= m.bm[e.which + 2];
} else if (t === "mouseout") {
m.buttonRaw = 0;
m.over = false;
} else if (t === "mouseover") {
m.over = true;
} else if (t === "mousewheel") {
m.w = e.wheelDelta;
} else if (t === "DOMMouseScroll") {
m.w = -e.detail;
}
if (m.callbacks) {
m.callbacks.forEach(c => c(e));
}
if ((m.buttonRaw & 2) && m.crashRecover !== null) {
if (typeof m.crashRecover === "function") {
setTimeout(m.crashRecover, 0);
}
}
e.preventDefault();
}
m.addCallback = function (callback) {
if (typeof callback === "function") {
if (m.callbacks === undefined) {
m.callbacks = [callback];
} else {
m.callbacks.push(callback);
}
}
}
m.start = function (element) {
if (m.element !== undefined) {
m.removeMouse();
}
m.element = element === undefined ? document : element;
m.mouseEvents.forEach(n => {
m.element.addEventListener(n, mouseMove);
});
m.element.addEventListener("contextmenu", preventDefault, false);
m.active = true;
}
m.remove = function () {
if (m.element !== undefined) {
m.mouseEvents.forEach(n => {
m.element.removeEventListener(n, mouseMove);
});
m.element.removeEventListener("contextmenu", preventDefault);
m.element = m.callbacks = undefined;
m.active = false;
}
}
return mouse;
})();

mouse.start(canvas);
requestAnimationFrame(update);

关于javascript - 随时间褪色的 Canvas 绘画 |奇怪的阿尔法分层行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41483806/

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