我试图使用粒子DepthBlur((代替"雪花"的不透明度 - 它位于步进函数内部,但它会产生不希望的频闪效果 - 为什么?考虑以下代码,
为澄清而编辑:
<canvas id="canvas"></canvas>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var num = 2000;
var canvas = document.getElementById("canvas");
var width = canvas.width = 960;
var height = canvas.height = 500;
var ctx = canvas.getContext("2d");
var particles = d3.range(num).map(function(i) {
return [Math.round(width*Math.random()), Math.round(height*Math.random())];
});
function particlesDepthBlur(){
return Math.random();
console.log(Math.random());
}
function particlesDepthSize(){
return Math.floor((Math.random()*4)+1);
}
d3.timer(step);
function step() {
ctx.shadowBlur=0;
ctx.shadowColor="";
ctx.fillStyle = "rgba(0,0,0,"+particlesDepthBlur()+")";
ctx.fillRect(0,0,width,height);
ctx.shadowBlur=particlesDepthSize();
ctx.shadowColor="white";
ctx.fillStyle = "rgba(255,255,255,1)";
particles.forEach(function(p) {
p[0] += Math.round(2*Math.random()-1);
p[1] += Math.round(2*Math.random()-1) + 2;
if (p[0] < 0) p[0] = width;
if (p[0] > width) p[0] = 0;
if (p[1] < 0) p[1] = height;
if (p[1] > height) p[1] = 0;
drawPoint(p);
});
};
function drawPoint(p) {
ctx.fillRect(p[0],p[1],1,1);
};
</script>
<style>
html, body { margin: 0; padding: 0; }
</style>
几件事:
首先,您在填充画布背景之前立即调用ctx.fillStyle = "rgba(0,0,0,"+particlesDepthBlur()+")";
。
其次,您每帧只计算一次模糊和不透明度,而不是每个粒子。
第三,如果你计算每个粒子(并继续使用Math.random()
(,那么它会使我的机器陷入每秒数千次操作的困境。
这是我的
小提琴!
~每帧我计算 10 个不透明度和 10 个大小,并迭代粒子,设置每个粒子~ <<这是一个旧版本;现在,在调用step()
之前,不透明度都已设置好,并且大小与不透明度成正比。
编辑:随机下降运动干得好!
edit2:调整以设置每个粒子的恒定不透明度和大小。这对我来说仍然运行得很慢,可能是因为你每帧运行 Math.random(( 4000 次。您可以考虑每帧计算几十个位置向量,并遍历所有粒子。这样,每 n 片雪花都会以相同的模式落下,从而减少所需的计算。
最后,也许可以考虑让"近"雪花(大而明亮(比"远"雪花落得更快。
<snip>
// Set up an opacity value for each particle, this will later be indexed with j
var particleOpacities = [];
particles.forEach(function(p){
particleOpacities.push(particlesDepthBlur());
});
d3.timer(step);
var j = 0;
// since j is used by both step and drawPoint, it has to be outside both functions
function step() {
ctx.shadowBlur=0;
ctx.shadowColor="";
ctx.fillStyle = "rgba(0,0,0,1)";
ctx.fillRect(0,0,width,height);
j = 0;
particles.forEach(function(p) {
p[0] += Math.round(2*Math.random()-1);
p[1] += Math.round(2*Math.random()-1) + 2;
if (p[0] < 0) p[0] = width;
if (p[0] > width) p[0] = 0;
if (p[1] < 0) p[1] = height;
if (p[1] > height) p[1] = 0;
drawPoint(p);
});
};
function drawPoint(p) {
j++; // iterate over points
var particleSize = particleOpacities[j] * 4;
ctx.shadowBlur=particleSize;
ctx.shadowColor="white";
ctx.fillStyle = "rgba(255,255,255," + particleOpacities[j] + ")";
ctx.fillRect(p[0],p[1],particleSize,particleSize);
};
ctx.fillStyle = "rgba(0,0,0,"+particlesDepthBlur()+")";
随机更改上一个画布的可见程度。它在整个画布上均匀地执行此操作。有时,如果用黑色完全填充屏幕,擦除过去的视图,有时它会让最后一个屏幕部分显示。当它允许看到以前的视图时,它可以使画布上的白色数量增加一倍,并且当随后是低不透明度时,白色的数量突然下降。
function particlesDepthBlur(){
return Math.random(0.5)+.5;
}
平滑了这个问题