Processing绘制随风飘扬的名画
目录:
- 最终效果
- 参考示例
- 绘制原理
- 绘制过程
- 总结与体会
最终效果
参考示例
两个参考示例来自《代码本色》一书,另一个参考示例来自网站https://www.openprocessing.org,这个示例给出了关于风的参数。
示例一 2-1:
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
Mover m;
void setup() {
size(640,360);
m = new Mover();
}
void draw() {
background(255);
PVector wind = new PVector(0.01,0);
PVector gravity = new PVector(0,0.1);
m.applyForce(wind);//添加风力
m.applyForce(gravity);//添加重力
m.update();
m.display();
m.checkEdges();
}
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
class Mover {
PVector position;
PVector velocity;
PVector acceleration;
float mass;
Mover() {
position = new PVector(30,30);
velocity = new PVector(0,0);
acceleration = new PVector(0,0);
mass = 1;
}
void applyForce(PVector force) {
PVector f = PVector.div(force,mass);
acceleration.add(f);
}
void update() {
velocity.add(acceleration);
position.add(velocity);
acceleration.mult(0);
}
void display() {
stroke(0);
strokeWeight(2);
fill(127);
ellipse(position.x,position.y,48,48);
}
void checkEdges() {
if (position.x > width) {
position.x = width;
velocity.x *= -1;
} else if (position.x < 0) {
velocity.x *= -1;
position.x = 0;
}
if (position.y > height) {
velocity.y *= -1;
position.y = height;
}
}
}
示例运行效果:
本示例绘制了一个被风吹动的小球,同时小球还受到重力的作用下降,当小球撞到了画布边缘时做出判断,模拟出了弹力。
这提供给我一个想法:“风”,大自然的风可不是这么规律,自然界的风往往方向变化多端,要是风的吹向时刻在变化,那么,小球也就不是如此规律地左右循环了。为此,我修改了代码,让风的方向不变,但是大小随机变化得到下面的放飞的小球:
示例二 2-8:
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
Mover[] movers = new Mover[20];
float g = 0.4;
void setup() {
size(640,360);
for (int i = 0; i < movers.length; i++) {
movers[i] = new Mover(random(0.1,2),random(width),random(height));
}
}
void draw() {
background(255);
for (int i = 0; i < movers.length; i++) {
for (int j = 0; j < movers.length; j++) {
if (i != j) {
PVector force = movers[j].attract(movers[i]);
movers[i].applyForce(force);
}
}
movers[i].update();
movers[i].display();
}
}
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
class Mover {
PVector position;
PVector velocity;
PVector acceleration;
float mass;
Mover(float m, float x, float y) {
mass = m;
position = new PVector(x, y);
velocity = new PVector(0, 0);
acceleration = new PVector(0, 0);
}
void applyForce(PVector force) {
PVector f = PVector.div(force, mass);
acceleration.add(f);
}
void update() {
velocity.add(acceleration);
position.add(velocity);
acceleration.mult(0);
}
void display() {
stroke(0);
strokeWeight(2);
fill(0, 100);
ellipse(position.x, position.y, mass*24, mass*24);
}
PVector attract(Mover m) {
PVector force = PVector.sub(position, m.position); // Calculate direction of force
float distance = force.mag(); // Distance between objects
distance = constrain(distance, 5.0, 25.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects
force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction
float strength = (g * mass * m.mass) / (distance * distance); // Calculate gravitional force magnitude
force.mult(strength); // Get force vector --> magnitude * direction
return force;
}
}
运行效果:
参考这个示例并不是说用到了这个示例的技术,而是因为这个示例中“多个小球”汇聚在一起又离开,从而想到如果这个小球有特定的图像,赋予不同的贴图图片,比如贴上的是不同的人脸,那么这个示例就可以表现一些人员流动和人格魅力的吸引力。总之“吸引力”为这个群组里面的联系。
通过上面两个示例,拓展的目标定在了有运动联系的群组图元,并且受到不同风速的影响,由于一些原因,《代码本色》本章的拓展已经完成过一个,是关于粒子的运动,后来做到第四章的拓展时,发现已经做好的和第四章的示例太相似。不过本文的拓展灵感也因第四章的拓展而得到闪现:模拟图元构成的画被风吹动的效果。
绘制原理
主要思想:
1、读入目标绘画作品
2、规定固定的图元数量
3、使得每一个图元受力运动
这里模拟自然界风吹的时候用到了柏林噪声,用这个方法产生的力来模拟自然界的风力会非常的自然。这一点《代码本色》一书的第0章就提到过。柏林噪声能生成符合自然序列(“光滑”)的伪随机数。
processing里面的noise函数可以产生柏林噪声,可接收x,y,z三个坐标分量作为输入,并返回0.0~1.0的double值作为输出。由于输出归一化,程序中需要将数值扩大相应的倍数,而且为了使方向有正有负,最后还需要减去一个设定值。
模拟绘画作品时,为了使得绘制高效,避免出现非常卡顿的现象,不能一个像素一个像素地获取颜色,而是取一个像素点的颜色,绘制5像素或者更大像素的图元。
在用柏林噪声的时候遇到了参数盲目调节的问题,后来幸运地在https://www.openprocessing.org找到一篇用柏林噪声来模拟风的示例,使用到了示例中的参数,而后自行进行略为调整。得到以下绘制过程
绘制过程
读入jpg图片,获取作品的高度
img = loadImage("5.jpg");
imgX=img.width;
imgY=img.height;
绘制图元
for(int j=50;j<imgY;j+=4)
{
for(int i=20;i<imgX;i++)
{
float step = sin(a)*(sin((imgY-i)*PI/imgY));
float swing = j+step*(180.0*noise(a+i/300.0, a+j/300.0,a/10.0)-90);//计算风力
float dx = randomC()/2;
float dy = randomC()/2;
float x = i;
float y = swing+dy;//更新物体的坐标
strokeWeight(3);
stroke(255);
stroke(img.get(i,j));
point(x,y);//图元为点,这里也可以图元为矩形rect,效果有些不同
}
总结与体会
“用代码来画使得画动起来的画”十分好玩,也许真的有一天做出了各种各样变换的方式来使得“名画”动起来,我的电脑就是一个小型的数字名画展览器^ ^,毕竟到目前为止,我已经有两个关于如何使“名画”动起来的想法实现了。