【问题标题】:Filling shape with particles canvas用粒子画布填充形状
【发布时间】:2014-12-27 17:45:12
【问题描述】:

只是想知道是否有人可以为我指出一个好的方向,即我可以用粒子填充不规则形状,成行,然后可以动画化。

这是我能找到的最接近的例子 - http://www.wkams.com/#!/work/detail/coca-cola-music-vis

我认为可行的两种方法是计算出我想要的密度,绘制出每行需要多少粒子,并相应地定位。这种方式似乎很及时,但不是很健壮。

第二种方法,我似乎不知道该怎么做,是在画布中绘制形状,然后用粒子生成地填充形状,使它们保持在形状的约束中。

任何关于如何做到这一点的一般概念将不胜感激。

如果没有意义,请告诉我。

干杯

【问题讨论】:

  • 你想要什么类型的粒子?喜欢下雪还是下雨?还是随机浮动?它们会从边缘反弹吗?
  • 一个相当刚性的粒子网格,可以应用动力学,非常类似于可乐瓶的例子。想象一下,如果白色的圆形颗粒没有在瓶子周围设置动画并且只是成排排列。那有意义吗?抱歉,对这一切都不陌生。

标签: javascript html canvas particle-system particles


【解决方案1】:

您可以使用合成将粒子限制在不规则形状内

对于动画的每个循环:

  • 清除画布。

  • 在画布上画出不规则的形状。

  • 将合成设置为“source-atop”。这将导致任何新的绘图出现只有当任何新绘制的像素超过现有的不透明像素时。这是将粒子限制为仅在不规则形状内绘制的秘诀。

  • 画出你的粒子行。所有粒子只会出现在形状内部。

这是示例代码和演示。我的示例只是为每个粒子行的大小设置动画。您可以应用您的设计要求来更改每行的大小和位置。

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
//
ctx.fillStyle='skyblue';

var PI2=Math.PI*2;
//
var w=132;
var h=479;
//
var x1=29;
var x2=177;
var x3=327;
//
var nextTime=0;
var delay=16*2;
var isFading=true;
var isComplete=false;
var opacity=100;

var imgCount=2;
var img=new Image();img.onload=start;img.src="https://dl.dropboxusercontent.com/u/139992952/multple/coke.png";
var label=new Image();label.onload=start;label.src="https://dl.dropboxusercontent.com/u/139992952/multple/label.png";
function start(){
  console.log(imgCount);
  if(--imgCount>0){return;}

  requestAnimationFrame(animate);

  $('#again').click(function(){
    nextTime=0;
    delay=16*2;
    opacity=100;
    isFading=true;
  });
}

function overlay(clipX,x,alpha){
  ctx.globalAlpha=alpha;
  ctx.drawImage(img,clipX,0,w,h,x,0,w,h);
}

function fillParticles(radius,margin){
  var rr=radius*2+margin;
  ctx.save();
  ctx.clearRect(0,0,cw,ch);
  overlay(x3,50,1.00);   
  ctx.globalCompositeOperation='source-atop';
  ctx.beginPath();
  var rows=parseInt(ch/(rr))-2;
  var cols=parseInt(cw/rr);
  for(var r=0;r<rows;r++){
    for(var c=0;c<cols;c++){
      ctx.arc(c*rr,h-(r*rr),radius,0,PI2);
      ctx.closePath();
    }}
  ctx.fill();
  ctx.restore();
  overlay(x2,50,1.00);
}

function animate(time){

  if(!isComplete){ requestAnimationFrame(animate); }

  if(time<nextTime){return;}

  if(isFading){
    if(--opacity>0){
      ctx.clearRect(0,0,cw,ch);
      overlay(x1,50,opacity/100);
      overlay(x2,50,1.00);
    }else{
      isFading=false;
      overlay(x2,50,1.00);
      ctx.drawImage(label,70,210);            
      nextTime=time+1000;
    }
  }else{
    delay=1000;
    fillParticles(parseInt(Math.random()*8)+2,3);         
    ctx.drawImage(label,70,210);            
    nextTime=time+delay;
  }

}
body{ background-color:white; padding:10px; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id=again>Again</button>
<br>
<canvas id="canvas" width=250 height=500></canvas>

【讨论】:

  • 太好了!比我的回答好多了,我不知道source-atop 存在!
【解决方案2】:

如果我要解决这个问题,我会这样处理:

  1. 创建一个可用于“创建”粒子的对象。
  2. 为所需的密度创建尽可能多的该对象的新实例。

因此,基本上,所有工作都由一个函数构造函数/对象完成。

您希望此对象提供将自己绘制到画布上的方法,存储其 x 和 y 坐标、速度和方向。

然后您可以使用 new 关键字创建此对象的实例,并设置它们的 x 和 y 坐标以将它们分布在网格中。

【讨论】:

  • 太棒了。谢谢你。我认为我已经完成了粒子创建和定位。这只是我似乎无法解决的到行中对象的映射。正如我所提到的,我可以手动定位这个我想象的 - 比如说它是一个三角形,第一行是一个粒子,第二行是两个粒子,第三行是三个粒子 - 例如。但是有没有一种方法可以让粒子填充一个我已经绘制的形状,自主地 - 从左上角开始,并检测边缘以打破新行。我是不是想多了?
  • @user3244169 你是如何绘制你的多边形的?如果是通过海龟,您可以让海龟在某些点保存其坐标,这样您就知道粒子可以使用这些坐标保持在形状的范围内。或者,如果你知道顶点,那也不会很困难:你只需要确保你的粒子坐标在顶点所包围的区域内,你可以使用形状的顶点来创建不等式来定义区域被它包围。
  • @user3244169 检查 source-atop 以仅在下方已经存在不透明像素时进行绘制。
猜你喜欢
  • 1970-01-01
  • 2013-11-20
  • 2012-05-02
  • 2014-06-21
  • 2014-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多