2

我正在尝试使用particleDepthBlur() 代替“雪花”的不透明度 - 它位于步进函数内部,但是它会产生不希望的频闪效果 - 为什么?考虑以下代码,

为澄清而编辑:

<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>
4

2 回答 2

2

几件事:
首先,您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);
};
于 2013-10-09T23:57:14.113 回答
2

ctx.fillStyle = "rgba(0,0,0,"+particlesDepthBlur()+")";随机改变前一个画布的可见程度。它在整个画布上均匀地执行此操作。有时,如果用黑色完全填满屏幕,抹掉过去的视图,有时它会让最后一个屏幕部分显示。当它让以前的视图被看到时,它可以使画布上的白色数量增加一倍,而当不透明度紧随其后时,白色的数量会突然下降。

function particlesDepthBlur(){ 
   return Math.random(0.5)+.5;
}

解决这个问题

于 2013-10-09T23:53:25.610 回答