这是我参与8月更文挑战的第8天,活动详情查看: 8月更文挑战
效果图
该效果其实核心思想是将多“层”的心形烟进行组合,首先我们来定义其中一 “层” 的心形烟的实现代码。
Heart.pde
class Heart{
float seed = random(10,1000);
float offset = random(TWO_PI);
float ff = random(0.5,2.5);
float sw = random(0.8,1.8);
float part = 0.1+0.5*pow(random(1),2.0);
float rf = random(0.5,1.15);
float d = random(10,120);
int m = 500; ///< 500 个点
OpenSimplexNoise noise = new OpenSimplexNoise(); ///< 噪声,用于扰动心形
float R = 150;
float xh(float p){
return R/15.0*16*pow(sin(p),3);
}
float yh(float p){
return R/15.0*(-13*cos(p) +5*cos(2*p) + 2*cos(3*p) + cos(4*p));
}
void show(float q){
for(int i=0;i<m;i++){
float p = 1.0*i/m;
float theta = offset + part*TWO_PI*i/m;
float rad = 1.3f;
int per = 2;
float xx = rf*xh(theta) + pow(p,3.0f)*d*(float)noise.eval(seed + rad*cos(TWO_PI*(per*p-q)),rad*sin(TWO_PI*(per*p-q)));
float yy = rf*yh(theta) + pow(p,3.0f)*d*(float)noise.eval(2*seed + rad*cos(TWO_PI*(per*p-q)),rad*sin(TWO_PI*(per*p-q)));
strokeWeight(sw);
stroke(255,ff*18*sin(PI*p));
point(xx,yy);
}
}
}
其中关键的代码(如下所示)代表的公式可以绘制出心形(将 360° 分成了 m 份,然后每个位置放置一个点,只要划分的足够细,就可以看起来像是一个完整的 ♥)
float R = 150;
float xh(float p){
return R/15.0*16*pow(sin(p),3);
}
float yh(float p){
return R/15.0*(-13*cos(p) +5*cos(2*p) + 2*cos(3*p) + cos(4*p));
}
简化后对应函数示意图如下所示
然后通过叠加 Simplex 噪声的随机扰动,我们就可以模拟出烟尘的效果。
HeartSmoke.pde(主入口)
自此基础上,接着我们构造多层(本例为 250 层)的心形烟尘,并将它们叠加起来一层一层绘制
float t, c;
int samplesPerFrame = 5;
int numFrames = 100;
float shutterAngle = .6;
int n = 250; ///< 250 层 ♥
Heart[] array = new Heart[n];
void setup(){
size(600,600,P3D);
for(int i=0;i<n;i++){
array[i] = new Heart();
}
}
void show(){
background(0);
push();
translate(width/2,height/2);
for(int i=0;i<n;i++){
array[i].show(t);
}
pop();
}
void draw() {
t = mouseX*1.0/width;
c = mouseY*1.0/height;
if (mousePressed)
println(c);
frameCount = 0;
show();
/// @note 保存序列 gif,后期可用 gifsicle 合成真正的 gif
// saveFrame("fr###.gif");
}
void keyPressed(){
if(key == 'r' || key == 'R'){
recording = !recording;
println("recording:" + recording);
}
}
最后附上 OpenSimplexNoise.pde(由于代码过长,为了不影响阅读,所以上传到百度网盘),关于噪声的详解可以看我之前写的一篇ShaderJoy —— 噪声之美,大家一起 “噪” 起来 【GLSL】
链接:pan.baidu.com/s/1uKqedakx…
提取码:u8ru
如何合成 GIF
gifsicle 下载链接:www.lcdf.org/gifsicle/
下载安装完成之后,打开命令行工具,执行以下命令(默认各帧的命名模式为 fr*.gif) ,最终生成 anim.gif,各帧的延迟为 10 / 100 s
gifsicle --delay=10 --loop fr*.gif > anim.gif
gifsicle 支持的更加复杂的命令行请参见其官方手册