This is the 8th day of my participation in the August More Text Challenge
rendering
In fact, the core idea of the effect is to combine multiple “layers” of heart-shaped cigarettes. First of all, we define the implementation code of one “layer” of heart-shaped cigarettes.
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 points
OpenSimplexNoise noise = new OpenSimplexNoise(); ///< noise, used to disturb the heart
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.3 f;
int per = 2;
float xx = rf*xh(theta) + pow(p,3.0 f)*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.0 f)*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); }}}Copy the code
The key code (shown below) represents the formula to draw the heart (divide 360° into m parts, then place a point in each position, as long as the partition is fine enough, it can look like a full ♥)
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));
}
Copy the code
The schematic diagram of corresponding functions after simplification is shown below
We can then simulate the effect of soot by superimposing a random perturbation of Simplex noise.
Heartsmoke.pde (Main entrance)
From there, we then construct multiple layers (250 in this case) of heart-shaped smoke and paint them layer by layer
float t, c;
int samplesPerFrame = 5;
int numFrames = 100;
float shutterAngle = 6.;
int n = 250; / / / < 250 layer has
Heart[] array = new Heart[n];
void setup(a){
size(600.600,P3D);
for(int i=0; i<n; i++){ array[i] =newHeart(); }}void show(a){
background(0);
push();
translate(width/2,height/2);
for(int i=0; i<n; i++){ array[i].show(t); } pop(); }void draw(a) {
t = mouseX*1.0/width;
c = mouseY*1.0/height;
if (mousePressed)
println(c);
frameCount = 0;
show();
/// @note save sequence GIF, later use gifsicle synthesis of real GIF
// saveFrame("fr###.gif");
}
void keyPressed(a){
if(key == 'r' || key == 'R'){ recording = ! recording; println("recording:"+ recording); }}Copy the code
The last part is OpenSimplexnoise.pde (because the code is too long to read, so I upload it to Baidu web site). For a detailed explanation of noise, you can see my previous article ShaderJoy — The Beauty of Noise, Let’s make noise together.
Link: pan.baidu.com/s/1uKqedakx… Extraction code: U8RU
How to compose GIF
Gifsicle download link: www.lcdf.org/gifsicle/
After the download and installation is complete, open the command line tool and run the following command (the default naming mode for each frame is FR *.gif) to generate anim.gif. The delay for each frame is 10/100 s
gifsicle --delay=10 --loop fr*.gif > anim.gif
Copy the code
Gifsicle supports more complex command lines in its official manual