有人说,编程语言的选择更像是一场信仰之战。Processing是一种干净、纯粹的语言,是编程语言中的艺术家。
迭代之美,一蹴而就
使用编程基本语句之一,Iteration迭代,优雅的矢量绘图大体量图形
三角之美,周而复始
编写代码把时间转换成三角函数的弧度,运算结果化作图形的属性,制作出周而复始的Gif影像
噪声之美,时空转换
Perlin Noise算法把时间的变化转换在空间维度之上,计算出连续随机的坐标,用在静态动态图形之上,呈现数学信号上的噪声之美
自然之美,浮游天地
大规模群体活动,个体单位之间的互相行为,由flock算法来推演,编码用在动态图形上
背景简介:
红豆生南国,春来发几枝。愿君多采撷,此物最相思。
用processing来表现树木生长之美。
分生是植物人工繁殖方法,繁殖依花卉种类的不同,又可分为分株法和分球法。前者多用于丛生性强的花灌木和萌蘖力强的宿根花卉,后者则主要用于球根类花卉。
这是伟大 OpenProcessing 的馈赠。
【截图展示】(动画在演示视频里可观看)
【代码与技术分析】
《Nature of Code》即代码本色:用编程模拟自然系统 一书,是一本借助开源语言Processing 全面介绍如何用代码模拟自然世界的学习指南。
其中讲到了processing 中的向量PVector.
让我们来看看位置和速度背后的数据。在弹球例子中:
位置 x、y
速度 xspeed、yspeed
请注意我们如何存储位置和速度数据:用两个浮点数,一个浮点数代表x坐标,另一个浮点数代表y坐标。如果我们自己写个类来表示向量,那么可以这么开始:
class PVector {
float x;
float y;
PVector(float x_, float y_) {
x = x_;
y = y_;
}
}
在这里,PVector只是存储了两个变量(或者三维世界中的3个变量)的简单数据结构。
之前的初始化过程:
float x = 100;
float y = 100;
float xspeed = 1;
float yspeed = 3.3;
变成了:
PVector location = new PVector(100,100);
PVector velocity = new PVector(1,3.3);
既然我们已经有了位置和速度这两个向量对象,接下来就可以开始实现最基本的运动模拟:新位置 = 原位置 + 速度。 示例代码1-1没有用到向量,我们是这么做的:
x = x + xspeed; 将速度与当前位置相加
y = y + yspeed;
在理想情况下,我们希望用下面的代码完成同样的操作:
location = location + velocity; 将速度向量与位置向量相加
然而,在Processing语言中,加号(+)操作符是为原生数据类型(整数、浮点数等)预留的。Processing并不知道如何将两个PVector对象相加,就像它也不知道如何将两个PFont对象或PImage对象相加一样。但幸运的是,PVector类可以包含一些常用的数学操作函数。
【冬日之树】中向量PVector的运用
class PathFinder {
//结构体PathFinder 属性包括:位置、速度、直径
//其中位置和速度是向量,表示树枝生长的方向和速度
PVector location;
PVector velocity;
float diameter;
//构造方法一:主干的生长
PathFinder() {
location = new PVector(width/2, height);
velocity = new PVector(0, -2);
diameter = 40;
}
//构造方法二:树干分支的生长
PathFinder(PathFinder parent) {
location = parent.location.get();
velocity = parent.velocity.get();
float area = PI*sq(parent.diameter/2);
float newDiam = sqrt(area/2/PI)*2;
diameter = newDiam;
parent.diameter = newDiam;
}
void update() {
if (diameter>0.5) {
location.add(velocity);
//随机生长方向bump
PVector bump = new PVector(random(-1, 1), random(-1, 1));
bump.mult(0.1);
velocity.add(bump);
velocity.normalize();
//分枝的概率为0.025
if (random(0, 1)<0.025) {
paths = (PathFinder[]) append(paths, new PathFinder(this));
}
}
}
}
【processing中的色彩】
在Processing中,颜色的形式主要包括:灰阶、灰阶含透明度、彩色、彩色含透明度。其设置颜色的函数有:background()、fill()、stroke()。
相关语法:
background(rgb) //彩色
background(rgb, alpha) //彩色+透明度
background(gray) //灰阶
background(gray, alpha) //灰阶+透明度
background(v1, v2, v3) //彩色
background(v1, v2, v3, alpha) //彩色+透明度
fill(rgb)
fill(rgb, alpha)
fill(gray)
fill(gray, alpha)
fill(v1, v2, v3)
fill(v1, v2, v3, alpha)
stroke(rgb)
stroke(rgb, alpha)
stroke(gray)
stroke(gray, alpha)
stroke(v1, v2, v3)
stroke(v1, v2, v3, alpha)
【冬日之树】中色彩的运用
void draw() {
//冬树的显示
for (int j=0; j<8; j++) {
for (int i=0; i<paths.length; i++) {
PVector loc = paths[i].location;
float diam = paths[i].diameter;
ellipse(loc.x, loc.y, diam*2, diam*2);
paths[i].update();
}
}
}
void mousePressed() {
//鼠标点击 可随机变化树枝的颜色和星星点点花朵的颜色
float a = random(255,255);
float b = random(0,255);
float c = random(0,255);
//可设置r,g,b颜色的范围来改变冬树颜色的变化范围
fill(255,b,c);
}
————黄色小花点缀的冬树——————
————随性色彩的冬树——————
【键盘交互】 按字母 'R' 或 'r' 可重新生长,再生冬日树。
void keyPressed(){
if(key=='r'||key=='R'){
background(36);
fill(255);
paths = new PathFinder[1];
paths[0] = new PathFinder();
}
}
【processing中的数组】
Processing 3中对数组(Array)类型的操作函数,有复制,拼接,排序,编辑,取子序列,反转,延长等操作。
使用append(数组,同类型元素)将指定元素添加到数组末尾。
注意:对原数组无影响,是先复制再修改。其它数组有关函数同理。
使用splice(被插入数组,元素,位置)或者splice(被插入数组,待插入数组,位置)将元素或数组插入到指定位置。
【冬日之树中数组的运用】
//分枝概率为0.025
if (random(0, 1)<0.025) {
paths = (PathFinder[]) append(paths, new PathFinder(this));
}
append函数将新的分枝添加到冬树上,实现分枝的再生。
【参考链接】
https://blog.csdn.net/Hewes/article/details/76383246
https://blog.csdn.net/Hewes/article/details/82970909