目录

  • 前言
  • 一、 ellipse()函数的四种模式
  • 二、 Export输出应用程序
  • 三、 填充与描边
  • 四、vertex画多边形
  • 五、实用的dist()函数
  • 六、按键交互
  • 七、调入图片
  • 八、创建字体和绘制
  • 九、插件库安装的记录
  • 十、读入svg文件
  • 十一、map函数
  • 十二、constrain函数
  • 十三、使用millis函数触发计时器
  • 十四、Processing.js
  • 十五、平移变换
  • 十六、旋转和缩放
  • 十七、使用数组
  • 十八、三维坐标系
  • 十九、OPENGL的灯光
  • 二十、OPENGL的相机
  • 二十一、Processing与Arduino的交互,补充《爱上》
  • 二十二、使用Processing的原因
  • 二十三、无规则自由走
  • 二十四、random函数产生的是非常接近随机的伪随机数
  • 二十五、高斯分布
  • 二十六、在Processing里使用中文字体
  • 二十七、Perlin Noise柏林噪声
  • 二十八、一个形象的讲解map函数的图示
  • 二十九、Perlin Noise生成纹理
  • 三十、Vector向量的各种意思
  • 三十一、弹球的初步向量化
  • 三十二、向量的运算
  • 三十三、具有代表性的Mover类

前言

这个学习笔记的积累,是我自学Processing的产物。 如果没有其他的过大的影响,它应该会成为一个延续性的记录,我是 边学边记录的,而且有了系统的一本书、一本书的看下来的这种打算,是 我已经可以用Processing写一些细碎的小程序了。因此没有记录得很细致, 除非我对那些方面感兴趣。这些书,都是电子书,容易找的到,如果找不 到,可以找我要。 没有编程基础,可能看这个笔记会很别扭,这是正常的。


一、 ellipse()函数的四种模式

ellipse()是直接画圆和椭圆的函数,有4种模式。以下说明。

int w  =  600;
int h  =  400;
int  d  =  20;
int  len  =12;
int  sd  =  100;
void  setup()
{size(w,h);
}void  draw()
{ml();
//前两个参数是中心坐标,后两个参数是横竖半轴。这个是默认的。 ellipseMode(RADIUS);
ellipse(100,100,40,60);
//前两个参数是中心坐标,后两个参数是宽和高,即长轴和短轴 ellipseMode(CENTER);
ellipse(200,200,40,60);
//前两个参数是左上角坐标,后两个参数是宽和高,即长、短轴 ellipseMode(CORNER);
ellipse(300,300,40,60);
//前两个参数是左上角,后两个参数是右下角
ellipseMode(CORNERS);
ellipse(20,20,40,60);
}/*专用于画坐标刻度和网格*/
void ml()
{stroke(140);
for  (int  i  =  0;  i  ¡ w;  i  =  i+d) {line(i,  0,  i, h);
if  (i %  sd  ==  0)
{stroke(255,  10,  0);
strokeWeight(2);
line(i,0,i,len);
text(str(i),  i,  len);
stroke(140);
strokeWeight(1);
}}
stroke(140);
for  (int  j  =  0;  j¡h;  j  =  j+d){line(0,  j, w,  j);
if  (j %  sd  ==  0) {stroke(255,  10,  0);
strokeWeight(2);
line(0,j,len,j);
text(str(j),  0,  j);
stroke(140);
strokeWeight(1);
}
}
}

二、 Export输出应用程序

Processing可以输出成应用程序,for Windows/Mac/Linux的,也能输出 成Applet ,放在网页上。
以上的输出,在1.51上可以直接输出。在3.04和2.21上,需要一个插件。
在sf 上有个老外做的Tools,
直接扔目录里,就能用了:
使用方法。
⑴直接解压,把产生的AppletMaker目录扔到Processing“tools里面,那 里面的各种东西,都不要动;
⑵再复制一份Processing的整个副本,扔到当前用户的库/文档目录里,大
体结构,比如tools ,路径是C:“Users“mxx“Documents“Processing“tools“AppletMaker, 其它类似。实际上面查看的出错信息里面就有。
⑶打开Processing再输出,会告诉选择这个那个,就可以正常的像1.51里
面那样输出了。实际第2步也可以不那么麻烦,照着需要复制就行。
另外,Processing的Sketch可以放在JAVA GUI里面,这是另一个话题。

三、 填充与描边

size(480,320);
smooth();
fill(153);//填充
ellipse(132,82,200,200);
noFill();//不填充
ellipse(228,16,200,200);noStroke();
fill(153,0,0);//填充暗红色
//上面注释后,既没有填充,又不描边,就什么也不画了
ellipse(268,118,200,200);

Processing带有颜色选择器,在tools菜单下,比如绿色,复制之后,就可 以到代码区粘贴,比如fill(#1EF50C)。
fill和stroke可以带第4个参数,也是0-255之间,控制的是透明度。

四、vertex画多边形

在2D平面上直接绘图,以这些点连成多边形。但不一定是封闭的。需 要指定。

void  setup(){size(480,320);
//这句调整帧率,调不调没什么区别
//frameRate(0.1);
}void  draw(){for  (int  i=0;i¡480;i++){beginShape();
vertex(i/10+180,80);
vertex(i/10+200,30);
vertex(i/10+210,160);
endShape(CLOSE);
//关闭画线,注释掉,就不关闭了
//endShape();
}}也可以指定只画点。
//注意size()第3个参数以3D绘图
size(200,  200, P3D);
//画成点,可以指定点的大小
strokeWeight(25);
beginShape(POINTS);
vertex(30,  20,  -50);
vertex(85,  20,  -50);
vertex(85,  75,  -150);
vertex(30,  75,  -50);
endShape();

还可以纹理填充。

size(480,  320, P3D);
PImage  img  =  loadImage(”2.jpg”);
noStroke();
beginShape();
texture(img);
//下面使用vertex(x,y,u,v)格式画纹理
//u和v保证从横向和纵向贴图
vertex(10,  20,  0,  0);
vertex(480,  5,  100,  0);
vertex(95,  290,  100,  100);
vertex(340,  295,  0,  100);
endShape();

五、实用的dist()函数

int x  =  120;
int y  =  60;
int radius  =  12;void  setup(){size(240,240);
smooth();
ellipseMode(RADIUS);
}
void  draw(){background(204);
float  d  =  dist(mouseX,mouseY,x,y);
if  (d  ¡ radius){radius++;
fill(0);
˝  else  {fill(255);
radius  =  12;
ellipse(x,y,radius,radius);
}ellipse(x,y,radius,radius);
}鼠标放上去,圆就变黑,还变大。拿走,就复原了。

六、按键交互

鼠标和按键的交互,都不难,帮助里面说得很清楚。下面是个键盘交
互,判断后,显示文字,或者让一个小方块上下左右移动。

int x  =  120;
int y  =  120;
void  setup()  {size(240,  240);
smooth();
textSize(64);
}
void  draw()  {background(204);
if  (keyPressed)  {//直接判断的,都是常用键
if  (key  ==  ’a’)  {//不创建字体,汉字是不显示的
text(”dsfdsf”,  100,  100);
˝  else  {text(key,  60,  80);
}if  (key  ==  CODED)  {//那些特殊键,CTRL/SHIFT/ALT之类 if  (keyCode  ==  LEFT)  {x--;
˝  else  if  (keyCode  == RIGHT)  {x++;
˝  else  if  (keyCode  == UP)  {y--;
˝  else  if  (keyCode  == DOWN)  {y++;
}//rect(x, y,  50,  50);//写这儿一闪就没了
}//rect(x, y,  50,  50);//写这儿也没
}
rect(x, y,  50,  50);//行了
}

七、调入图片

Processing支持的图片格式有jpg、gif、png和svg ,gif和png的Alpha通道 信息也是能读入的。如下:

PImage  img;
void  setup(){size(600,400);
img  =  loadImage(”1.png”);
}
void  draw(){background(204);
image(img,0,0);
image(img,0,mouseY  *  -1);
}

透明的部分,会显示出窗口的底色,或者背后的内容。svg格式的文件,已 经有很多软件支持了,一个小巧而强大的软件,叫PhotoLine ,仿佛Linux下 的GIMP 那样。

八、创建字体和绘制

默认字体以外的字体,需要转换成VLW格式。这样就可以使用特定的
命令来修改字体大小和使用一些特殊字体了。下面是大体的例子。

PFont  font;
void  setup(){size(480,320);
smooth();
font  =  loadFont(”a.vlw”);
textFont(font);
}
void  draw(){background(204);
textSize(36);
text(”afafgfg”,0,0);
textSize(18);
text(”shgg”,9,200);
}

九、插件库安装的记录

P5的插件安装,一般就是这样三个可能性:

  1. 一个是,把提供的zip包下载回来,放在

C:“Users“miracle“Desktop“processing-2.2.1-windows32“processing-2.2.1 “modes“java“libraries“dxf

  1. 一个是,下载回来的包,直接放在

C:“Users“miracle“Documents“Processing“libraries“papaya

  1. 最麻烦的,是只能安装,到IDE里面找到Add Labrary ,然后找到,等 待。

十、读入svg文件

svg矢量文件的读入。

PShape network;void  setup(){size(480,320);
smooth();
network  =  loadShape(”a.svg”);
}
void  draw(){background(204);
shape(network,30,10);
shape(network,180,10,280,280);
}

十一、map函数

map函数在这个例子里用到,但是书上没解释。

PShape network;
void  setup(){size(240,120);
smooth();
shapeMode(CENTER);
network  =  loadShape(”n.svg”);
}
void  draw(){background(0);
float  diameter  = map(mouseX,0,width,10,800);
shape(network,120,60,diameter,diameter);
}map是做什么的呢? map函数用于数值映射 , 比如要把鼠标的mouseX值 从0到width映射到0到PI就可以用map写成map(mouseX,0,width,0,PI) ,最简单 的,比如
float  a  =  1;
float m = map(a,  1,  10,  2,  20);
println(m);   // Prints  ”2.0”

上面a = 1 ,所以输出2.0 ,如果让a = 2 ,输出就是4.0 。实际就相当于比例缩 放。帮助文件里面有例外的用法,可用于特殊用途。

十二、constrain函数

constrain函数限制一个变量总在一个区间内,省掉不少判断。下面这个 例子,只有在特定区域,小方块才跟随鼠标。

void  setup(){size(320,240);
}void  draw()
{background(204);
float mx  =  constrain(mouseX, float my  =  constrain(mouseY, rect(mx, my,  20,  20);

十三、使用millis函数触发计时器

int  t1  =  2000;
int  t2  =  4000;
float x  =  0;
void  setup(){size(480,240);
smooth();
}void  draw()
{int  currentTime  = millis();
background(204);
if  (currentTime  ¿  t2)  {println(”4000ms”);
x  -=  0.5;
˝  else  if  (currentTime  ¿  t1)  {println(”2000ms”);
x  +=  2;
}ellipse(x,60,90,90);
}

十四、Processing.js

发现了一个Processing的js变体,网址在http://processingjs.org/ ,直接嵌 入到网页里,非常不错的表现层。

十五、平移变换

平移变换是translate ,结合pushMatrix()和popMatrix()可以实现变换的独 立性。

void  setup(){size(120,120);
}
void  draw(){background(200);
//平移变换
translate(mouseX,mouseY);rectMode(CENTER);
rect(0,0,50,50);
//如果再次translate ,坐标以新的原点再次平移
//新原点在(mouseX+35,mouseY+15)
translate(35,15);
rect(0,0,15,15);}使变换独立:
void  setup(){size(120,120);
}
void  draw(){background(200);
pushMatrix();//暂存坐标原点
//平移变换
translate(mouseX,mouseY);rectMode(CENTER);
rect(0,0,50,50);
popMatrix();//弹出坐标原点
//这时再translate ,坐标以最初最初的原点平移
//新原点在(0+35,0+15)
translate(35,15);
rect(0,0,15,15);
}

特别特别注意的问题是,如果只push ,不pop ,会提示说,push的次数不能 超过200次,然后程序就死掉了。

十六、旋转和缩放

rotate()是旋转函数,实施旋转,需先设置旋转中心,如果不设置,旋 转中心就是(0,0)点,通过平移变换translate() 可以把中心变换到指定的位 置。
旋转变换的例子。

float  angle  =  0.0;
void  setup(){size(120,120);
smooth();
}
void  draw(){background(200);
translate(mouseX,mouseY);
rotate(angle);
rect(-15,-15,30,30);angle  +=  0.1;
}scale()缩放,下面的例子中,注意到了画笔的宽度。
float  angle  =  0.0;
void  setup(){frameRate(5);
size(120,120);
smooth();
}
void  draw(){background(200);
translate(mouseX,mouseY);
float  s  =  sin(angle)+1;
rotate(angle);
scale(s);
//这一步使画笔宽度总与缩放比保持一致
//不会变得很粗或者很细
strokeWeight(1.0/s);
rect(-15,-15,30,30);
angle  +=  0.1;
}

十七、使用数组

float  [] x  = new  float[3000];void  setup(){size(240,120);
smooth();
noStroke();
fill(255,200);
for  (int  i  =  0;  i¡x.length;i++){x[i]  = random(-1000,1000);
}}
void  draw(){background(0);
for  (int  i  =  0;  i¡x.length;i++){x[i]+=0.5;
float y  =  i*0.4;arc(x[i],y,12,12,0.52,5.76);
}}数组的使用,创建,赋值等,和其他语言里面是类似。
int[] x;//声明数组
int[] y  = new  int[2];//declare
int[]  z  =  {99,34567˝;//declare  and  set value
void  setup(){size(200,200);
x  = new  int[2];//创建
x[0]  =  12;//赋值
x[1]  =  2;
println(x[0]);y[0]  =  44;//set  a value
y[1]  =  55;
println(y[1]);println(str(z[1])+”混球!”);
}对象也可以使用数组,形成对象数组。
int numFrames  =  12;//帧数
PImage[]  images  = new PImage[numFrames];
int  currentFrame  =1;void  setup(){size(160,120);
for(int  i  =  1;i¡images.length;i++){String  imageName  =  ”frame-”  + nf(i,4)  +”.png”;
images[i]  =  loadImage(imageName);
}frameRate(3);
}
void  draw(){background(0);
image(images[currentFrame],0,0);
currentFrame++;
if  (currentFrame¿=images.length){currentFrame  =  1;
}}

frame{0001.png等小文件,是从3DMAX里面渲染静态图片序列生成的。特 别多的图形图像软件里可以输出这种图像序列。

十八、三维坐标系

P5里面的三维,支持JAVA3D和OPENGL两种模式,几乎所有的JAVA2D的 函数,都支持三维的三个参量。三维坐标系统如图。

十九、OPENGL的灯光

P5里的OPENGL很神奇的是默认的,也就是在libraries目录里,是找不 到的,这样,import的时候,就只能手动敲代码输入了。这个例子是灯光。 灯光总要设定在draw的起始处。lights()函数会自动创建一个环境和默认的灯 光,看样子特别像是标准场景的三点灯。
灯的参数有很多,看帮助比直接记忆要好的多。

import processing.opengl.*;
void  setup()  {size(420,  220, OPENGL);
noStroke();
fill(255);
}
void  draw()  {lights();//ambientLight(102,  102,  102);
//directionalLight(255,  255,  255,
//-1,  0,  0);
pointLight(255,  255,  255,
mouseX,  110,  50);
//spotLight(255,  255,  255,
//mouseX,  0,  200,
//0,  0,  -1,
//PI,  2);rotateY(PI/24);
background(0);
translate(width/2, height/2,  -20);
int  dim =  18;
for  (int  i  =  -height/2;  i¡height/2;  i+=dim*1.4)  {      for  (int  j  =  -height/2;  j  ¡height/2;  j+=dim*1.4)  {pushMatrix();
translate(i,  j,  -j);
box(dim,  dim,  dim);
popMatrix();
}
}
}

二十、OPENGL的相机

import processing.opengl.*;
void  setup()  {size(420,  220, OPENGL);
noStroke();
}
void  draw()  {lights();
background(0);float  camZ  =  (height/2.0)/tan(PI*60/360.0);camera(mouseX,mouseY,camZ,        width/2.0,height/2.0,0, 0,1,0);//相机位置
//相机目标
//相机方向translate(width/2, height/2,  -20);
int  dim =  18;
for  (int  i  =  -height/2;  i¡height/2;  i+=dim*1.4)  {for  (int  j  =  -height/2;  j  ¡height/2;  j+=dim*1.4)  {pushMatrix();
translate(i,  j,  -j);
box(dim,  dim,  dim);
popMatrix();
}}}

二十一、Processing与Arduino的交互,补充《爱上》

这一节是《爱上Processing》 的最后一章 。 当时对Arduino一 点儿不 懂。因此没有记录笔记。后来研究了一下,发现Processing和Arduino是绝 配 ,Arduino给予了计算机用户最朴素 、最简单 、最直接的互动途径 , 而且在程序结构和思想上,Arduino与Processing类似,有着简单易学的语 言。Arduino注重数据的采集。因此,一个用来人机交互和沟通,一个用来 人机表达和展现,这也正是为什么老外选择Arduino和Processing开创了“数 字互动媒体艺术”这样一种课程的原因。
《爱上Processing》这本书里给出了二者通过串 口通信的例子。实际, 如果有条件,也可以使用WiFi和BlueTooth 实现Arduino、Processing和PC间 的交流与互动,但无疑串口是最容易被接受的。因为Arduino本身就带USB模 拟的串口。
下面这个例子不是《爱上》 原书里的,但原理相同。它实现的是一个 电位器把3.3V电压加到电位器两个针脚时,从分压部分取出来的电压信号 送给Arduino的A5针脚。然后板子一方面把它送给串 口,一方面间隔0.1s判 断,看送过来的信号是不是超过300 。如果超过,就表示过载了,板子上自 带的13号引脚处的LED会亮起。
代码中的注释,是解释的功能。虽然Arduino和Processing的程序语言很
像,但是Arduino承袭自C ,而Procssing近亲则是JAVA ,虽同属C系,但是变 异已经比较大了。
Arduino程序:

//注意没分号,A5针脚
#define ADpin A5
//直接使用板子上的LED
#define  LED  13//模拟信号的Buffer
int ADBuffer  =  0;void  setup()
{pinMode(LED,OUTPUT);
Serial.begin(9600);
}
void  loop()
{ADBuffer  =  analogRead(ADpin);
//ADBuffer在0-1023之间
//使用write函数,不用print ,原因参看帮助
Serial.write(ADBuffer/4);
//这个数据可以提前用串口监视器查看
if(ADBuffer  ¿  300)
{//点亮LED
digitalWrite(LED,HIGH);
}else
{//低电平送给LED ,熄灭
digitalWrite(LED,LOW);
}//延迟100毫秒
delay(100);
}编译,并写入Arduino UNO里。
注意把Arduino的串口监视器关了,否则在Processing里打不开串口,会 提示错误。
Processing里:
//引入串口支持库
import processing.serial.*;
//定义串口接收的数据
int p˙data;
//定义串口句柄
Serial myPort;void  setup()  {size(300,300);
myPort  = new  Serial(this,  ”COM3”,  9600);
}
void  draw()  {//读串口数据
p˙data  = myPort.read();
//在console里查看,也可以注释掉
println(p˙data);
//如果读到数据,则大于0
//没有读到数据时,p˙data为-1
if  (p˙data  ¿  0)  {background(255);
fill(255,0,0);
//根据串口送过来的数据确定圆心位置
ellipse(p˙data*3+50,  100,  50,  50);
}}

此时,在电位器两侧分别接地和3.3V输入,中间脚输出到A5 ,旋转电位 器,红色圆就产生互动效果了,也就是位置的移动。更复杂的互动,取决 于创意,与计算机本身无关。
总结了一点儿小小的经验如下:
∙ 在Arduino里面使用Serial.write(ADBuer)把信号写到串口时,0{1023这 个数据范围是可以保证的,因为这个范围是0{3.3V供电时的analogRead()返 回值 ,但是 , 串 口写入 时 ,范 围 只有0{255 。 当然 ,如果范 围超
过BYTE时,作除法,或者取模当然是可以的,但是我发现一些时 候是不超出,那计算之后,读回来的值就没必要再计算了。
∙ 怎么能知道范围超出了没有呢? 投机取巧的办法,尝试了一下,通 过。loop里面先for一次delay(100)的极快循环,把最大值和最小值存储 起来,for之后的loop就不再进入for了,以后的计算,全由前面取出来 的值去map ,一下子把数据拉开了。
∙ processing里取出的串口数据,经过同样的map ,就展开在全屏幕上面
去,因为取回来的数据肯定在0{255之间,处理起来比Arduino里面容 易得多。

二十二、使用Processing的原因

∙ Processing的语言和环境令人愉快。
∙ 自由、开源,适合初学者,并且有一个活跃的社区。
∙ 其他语言能够实现,但Processing可以得到支持。
源码下载的位置:
http://github.com/shiffman/The-Nature-of-Code-Examples

二十三、无规则自由走

初版,只有前后左右四个方向,而且Walker类写在了主体程序的里面。

class Walker  {int x;
int y;
Walker()  {x  = width/2;
y=height/2;
}void  display()  {stroke(2);
point(x, y);
}void  step()  {int  choice  =  int(random(4));
if  (choice  ==0)  {x++;
˝  else  if  (choice==1)  {x--;
˝  else  if  (choice  ==2)  {y++;˝  else  {y--;
}}}
Walker w;void  setup()  {size(600,  360);
w=new Walker();
background(255);
}
void  draw()  {w.step();
w.display();
}前面的step()函数只能实现上、下、左、右四个方向,现在修改成可以左 上 、左下 、右上 、右下的方向 。再增加浮点数的行走 ,不限于只是整 数。step()函数写成了3个形式。
class Walker  {int x;
int y;
Walker()  {x  = width/2;
y=height/2;
}void  display()  {stroke(2);
point(x, y);
}//上下左右,只有4个方向
void  step1()  {int  choice  =  int(random(4));//0,1,2,3
if  (choice  ==0)  {x++;
˝  else  if  (choice==1)  {x--;
˝  else  if  (choice  ==2)  {y++;
˝  else  {y--;}}//相邻八个格子的方向
void  step2()  {//实现-1到1的整数
int  stepx  =  int(random(3))-1;
int  stepy  =  int(random(3))-1;
x  +=  stepx;
y  +=  stepy;
}void  step3()  {float  stepx  = random(-1,  1);
float  stepy  = random(-1,  1);
x  +=  stepx;
y  +=  stepy;
}}
Walker w;void  setup()  {size(600,  360);
w=new Walker();
background(255);
}
void  draw()  {w.step1();
w.display();
}

在上面的step3()里面,由于random(− 1; 1)产生的是浮点数,而x和y在声明的 时候,是int ,所以在计算+ = stepx和+ = stepy的时候,点子一直向左上方 运动,然后保持在最顶边。这说明程序并没有把random(− 1; 1)看作是浮点 数,而是取整了。因为random(a,b)产生的值,包括a ,但不包括b 。原书中并 没有注意到这个不同,至少在P5的2.x版上是这样的。
如果让step3()与前两个函数效果一致,只需把类变量x和y在声明时改写 成float x和float y就行了。也许1.51版能正常?

二十四、random函数产生的是非常接近随机的伪随机数

原文如此,可对照帮助 。正态分布以及随机种子的计算,可参看帮 助。

The random numbers we get from the random() function are not truly random; therefore they are known as “pseudo{random(伪随机数).”They are the result of a mathematical function that simulates randomness. This function would yield a pattern over time, but that time period is so long that for us, it’s just as good as pure randomness.

二十五、高斯分布

高斯分布这个名称,很有一段故事。最早要推到棣莫佛,然后是勒让 德、高斯和拉普拉斯的研究。实际他们对此都有贡献,但是高斯对正态分 布的研究和应用太过巨大,所以德国人称之为“高斯分布” ,而法国人则 称之为“拉普拉斯分布” ,所以就一直有争论,直到后来统计学家皮尔森 主张将其称为“正态分布” ,这样就中立了。
正态分布,在Processing里是有特定的函数的,但是也可以用JAVA标准 库里面的函数。这是原版中的例子。

//下面这个包引用于JAVA标准库
//http://docs.oracle.com/javase/6/docs/api/java/util/Random.html //这个代码,作者新提供的已经改写了
import  java.util.Random;
Random  generator;
void  setup(){size(640,360);
generator  = new Random();
}
void  draw(){float num =(float)generator.nextGaussian();
float  sd  =  60;
float means  =  320;float x  =  sd  * num + means;noStroke();
fill(255,10);
ellipse(x,180,16,16);
}现在作者提供的是:
// The Nature  of Code
// Daniel  Shiffman
// http://natureofcode.comvoid  setup()  {size(640,  360);
background(255);
}
void  draw()  {// Get  a  gaussian random number
//w/ mean  of 0  and  standard  deviation  of  1.0
float xloc  = randomGaussian();float  sd  =  60;
// Define  a  standard  deviation
float mean  = width/2;
// Define  a mean value  (middle  of  the  screen  along  the x-axis) xloc  =  ( xloc  *  sd  )  + mean;
//  Scale  the  gaussian random number by  standard  deviation  and meanfill(0,  10);
noStroke();
ellipse(xloc, height/2,  16,  16);
// Draw  an  ellipse  at  our  ”normal” random  location
}

二十六、在Processing里使用中文字体

IDE里使用中文注释 ,即使是在2.x以后的版本里 ,也不是那么舒服 的, 目前所知道的是,小鸭五笔输入法不可以输入中文,使用微软拼音输 入法和微软五笔输入法都能正常输入中文。实际上,小鸭五笔是非常非常 好的一款输入法。
而在窗口里面输入中文汉字,更需要注意。下面是例子。

/*在P5里面使用中文字体
不要使用Tools里面的Create  Fonts工具
它产生的字体是位图格式的,据说还很慢
把系统里自带的字体文件如simhei.ttf复制到
pde文件所在的data文件夹里,然后createFont就行了
*/
PFont myFont;//声明void  setup(){size(200,200);
myFont  =  createFont(”simhei.ttf”,40);//创建
textFont(myFont);//指定字体
textSize(40);
text(”汉字”,100,100);
}

二十七、Perlin Noise柏林噪声

Perlin Noise是一种自然噪声的生成算法,是在一系列的随机值里通过 倍频叠加计算产生柔化的随机值的算法。Noise()与noiseDetail()结合,可以
得到Perlin噪声。
示例,以随机的数值作为左上角坐标,画一系列的圆:

float  t1  =  1;
float  t2  =  100;
//Typically we would  start  at  time  =  0,
//though  this  is  arbitrary.
void  setup()  {size(200,  200);
}void  draw()  {float n  = noise(t1);
float x  = map(n,  0,  1,  0, width);
float m = noise(t2);float y  = map(m, ellipse(x, y,  6, //println(n);      t1  +=  0.01;          t2  +=  0.02;0,  1,  0, height);
6);// Now, we move  forward  in  time!
}

二十八、一个形象的讲解map函数的图示

二十九、Perlin Noise生成纹理

以下的代码,用二维柏林噪声生成黑白云状纹理。取自所附源码。行 间注释部分解释了一下。

float  increment  =  0.02;void  setup()  {size(640,  360);
//重复与否没必要,因为种子数不变时,随机数是相同的。
noLoop();
}
void  draw()  {background(0);// Optional:  adjust noise  detail here
// noiseDetail(8,0.65f);
loadPixels();//下面解释float xoff =  0.0; //  Start xoff  at  0//  For  every x,y  coordinate  in  a  2D  space,
//calculate  a noise value  and produce  a brightness value
for  (int x  =  0; x  ¡ width; x++)  {xoff +=  increment;     //  Increment xoff
float yoff =  0.0;     //  For  every xoff,  start yoff  at  0
for  (int y  =  0; y  ¡ height; y++)  {yoff +=  increment; //  Increment yoff//  Calculate noise  and  scale by  255
float bright  = noise(xoff, yoff)*255;// Try using  this  line  instead
//下面这个随机数替换后,就没有云雾效果了
//float bright  = random(0,255);
//原书上的语句,效果一致
//float bright  = map(noise(xoff,yoff),0,1,0,255);//  Set  each pixel  onscreen  to  a  grayscale value
pixels[x+y*width]  =  color(bright);
}}updatePixels();
}

效果如下图:

上例中有几个函数,需要做些解释。
∙ loadPixels()函数 。把显示窗 口的像素数据调入到pixels[]数组里 。此 函数必须在从pixels[]数组读 、 向数组里写数据之前调用 。当要操 纵pixels[]数组数据时 ,必须首先调用loadPixels() ,数据改变后 ,再 调用updatePixels()。
∙ updatePixels()函数 。与loadPixels()函数配合实现以像素数据更新屏
幕。如果只读像素数据,就用不到这个函数了。
∙ pixels[]函数 。显示窗 口所有像素的值的数组 ,颜色数据 。例如 , 如果图像是100100像素 ,pixels数组就有10000 个值; 200300 ,数组 就有60000个值 。索引值是位置 。例如color b = pixels[230] ,就是把 数组的颜色值赋予b 。此函数之前 ,需使用loadPixels() ,否则会提 示NullPointerException异常。
两个示例,是Processing帮助里带的,已经经过修改了。

PImage myImage  =  loadImage(”C:““2.jpg”);void  setup()  {size(200,  200);
noLoop();
}
void  draw()  {int halfImage  = width*height/2;
image(myImage,  0,  0);loadPixels();
for  (int  i  =  0;  i  ¡ halfImage;  i++)  {pixels[i+halfImage]  = pixels[i];
}updatePixels();
}void  setup()  {size(200,  200);
frameRate(12);
//noLoop();
}
void  draw()  {color p  =  color(random(0,255), random(0,255), random(0,255)); loadPixels();
for  (int  i  =  0;  i  ¡  (width*height/2)-width/2;  i++)  {pixels[i]  = p;
}updatePixels();
}

三十、Vector向量的各种意思

老外这种写书的风格很有意思。向量这个词考究下去,确实有多个含
义,但是,除了真正数学意义上的向量之外,其他的,我们一直没太总结 过。
Vector is the name of a New Wave(新浪潮,上世纪七十年代、朋友摇 滚之后兴起的新音乐风格,但有时,也模糊为朋友摇滚本身。专门在网 上查阅的。) rock band formed in Sacramento, CA in the early 1980s. It’s the name of a breakfast cereal(早餐麦片) manufactured by Kellogg’s Canada. In the field of epidemiology(传染病学), a vector is used to describe an organism that transmits infection from one host to another. In the C++ programming language, a vector (std::vector) is an implementation of a dynamically resizable array data structure(其实R语言里面的才更能表现这个特点! ).

三十一、弹球的初步向量化

弹球游戏的向量化,便于以类来管理代码,也将在代码大型化之后, 起到简化的作用。起初,只是用了简单变量。

float x=100;
float y=100;
float xspeed=1;
float yspeed=3.3;
//这里面定义了4个简单变量
void  setup()  {size(200,  200);
smooth();
background(255);
}
void  draw()  {background(255);
x=x+xspeed;
y=y+yspeed;if  ((x¿width)——(x¡0))  {xspeed=xspeed*-1;
}if  ((y¿height)——(y¡0))  {yspeed=yspeed*-1;
}
stroke(0);
fill(175);
ellipse(x, y,  6,  6);
}下面使用向量,定义了一个PVector类,如下代码:
class PVector  {float x;
float y;
PVector(float x˙,  float y˙)  {x  = x˙;
y  = y˙;
}//定义矢量加法
void  add(PVector v){x=x+v.x;
y=y+v.y;
}}事实上,上面这段代码是Processing里面自带的PVector数学向量类,即使我 们不重写,也是可以直接调用的。经过改造,代码如下。
/*实际这个类注释掉之后,代码仍可正常运行,PVector是自带的类 class PVector  {
float x;
float y;
PVector(float x˙,  float y˙)  {
x  = x˙;
y  = y˙;
}//定义矢量加法
void  add(PVector v)  {
x=x+v.x;
y=y+v.y;
}}*/
PVector  location  =new PVector(100,  100);
PVector velocity  =new PVector(1,  3.3);void  setup()  {size(200,  200);
smooth();
background(255);
}
void  draw()  {background(255);
location.add(velocity);if  ((location.x¿width)——(location.x¡0))  {velocity.x=velocity.x*-1;
}if  ((location.y¿height)——(location.y¡0))  {velocity.y=velocity.y*-1;
}
stroke(0);
fill(175);
ellipse(location.x,  location.y,  6,  6);
}

三十二、向量的运算

几个向量的运算,这些运算函数, 同样包括在processing的PVector类
中,但是,为了说明原理,一样地,也都使用了重写的办法。
class PVector {
float x;
float y;
PVector(float x˙, float y˙) {
x = x˙;
y = y˙;
}//定义矢量加法
void add(PVector v) {
x=x+v.x;
y=y+v.y;
}//定义减法
void sub(PVector v) {
x=x-v.x;
y=y-v.y;
}//定义数乘
void mult(float n) {
x=xn;
y=y
n;
}//定义数除?
void div(float n) {
x=x/n;
y=y/n;
}//求模
float mag() {
return sqrt(xx+yy);
}//标准化归一

void normalize() {
float m=mag();
if (m != 0 ) {
div(m);
}}}这些运算,包括add()、sub()、mult()数乘、div()、mag()计算模、setMag()设
置模、normalize()把向量标准化为1个单位长度、limit()限定向量的大小、heading2D()用 角表示向量的方向、rotate()、lerp()线性插入到另一向量、dist()距离、angleBetween()成
角、dot()点积、cross()叉积、random2D() 二维随机阵、random3D()三维随机 阵。减法和数乘演示:

/*可以把上面的class PVector放在这里,也可以不放*/
void  setup()  {size(200,  200);
}void  draw()  {background(255);
PVector mouse  = new PVector(mouseX, mouseY);
PVector  center  = new PVector(width/2, height/2);
mouse.sub(center);//减法
mouse.mult(0.5);//数乘
float m = mouse.mag();
fill(0);
rect(0,0,m,10);//用一个黑矩形显示模
mouse.normalize();//标准化,归一
mouse.mult(50);//增长50倍,使长度总为50
translate(width/2, height/2);
line(0,  0, mouse.x, mouse.y);
}

另: 原书42页第5行有一处笔误(以下其中v为向量):The distributive rule with 2 scalars, 1 vector: (n *m) *v= n v+ mv ,应为(n *m) *v= n v + mv , 这里讲的是分配律,但显然作者有了笔误。

三十三、具有代表性的Mover类

可以很清晰的理解和把握类的结构,里面的代码已经被我改过好几次 了。

Mover mover;
void  setup()  {size(200,  200);
smooth();
mover  = new Mover();
}void  draw()  {background(255);
mover.update();
mover.checkEdges();
mover.display();
}*/Mover[] movers  = new Mover[20];
void  setup()  {size(200,  200);
smooth();
background(255);
for  (int  i  =  0;  i  ¡ movers.length;  i++)  {movers[i]  = new Mover();
}}void  draw()  {background(255);
for  (int  i  =  0;  i  ¡ movers.length;  i++)  {movers[i].update();
movers[i].checkEdges();
movers[i].display();
}}
class Mover  {PVector  location;
PVector velocity;
PVector  acceleration;
float  topspeed;
Mover()  {location  = new PVector(random(width), random(height)); //location  = new PVector(width/2, height/2);
velocity  = new PVector(0,  0);
//acceleration  = new PVector(-0.001,  0.01);
topspeed  =  4;
}void update()  {PVector mouse  = new PVector(mouseX, mouseY);
PVector  dir  = PVector.sub(mouse,  location);
dir.normalize();
dir.mult(0.5);
//acceleration  = PVector.random2D();
acceleration  =  dir;
//acceleration.mult(random(2));
velocity.add(acceleration);
velocity.limit(topspeed);
location.add(velocity);
}void  display()  {stroke(0);
fill(175);
ellipse(location.x,  location.y,  16,  16);
}void  checkEdges()  {if  (location.x  ¿ width)  {location.x  =  0;
˝  else  if  (location.x  ¡  0)  {location.x  = width;
}if  (location.y  ¿ height)  {location.y  =  0;
˝  else  if  (location.y  ¡  0)  {location.y  = height;
}}}

Processing学习笔记 巨细无比相关推荐

  1. 【Processing学习笔记】安装与入门

    Porcessing 是一款用于交互艺术和创意编程的工具.最早基于java开发,几年来同时推出了JavaScript版本p5.js,以及python版本processing.py.同时对于安卓机和树莓 ...

  2. Digital Image Processing 学习笔记3

    第三章 灰度变换与空间滤波 3.1 背景知识 3.1.1 灰度变换和空间滤波基础 本章节所讨论的图像处理技术都是在空间域进行的.可以表示为下式: $$g(x, y) = T[f(x,y)]$$ 其中$ ...

  3. 【笔记】Polygon mesh processing 学习笔记(7)

    多边形网格处理(7) 7. Repairing Definetion Problem statement Model repair, removing artifacts from a geometr ...

  4. TOPOGRAPHIC LASER RANGING AND SCANNING Principles and Processing学习笔记

    Laser altimeter 激光高度计 Laser profiler 激光断面仪 Attitude 姿态 Custom-built 定制的 Bathymetric 海洋测深的 2.3.1 LiDA ...

  5. 【笔记】Polygon mesh processing 学习笔记(10)

    Spherical parametrizations 定义 把genus-0的网格映射到球面上 球面参数化,要求网格是亏格为0,封闭的 应用 对应,correspondence 变形,morphing ...

  6. B站台湾大学郭彦甫|MATLAB 学习笔记|08 图像处理I Image Processing

    MATLAB学习笔记(08 图像处理I Image Processing) 如果想获得更好浏览体验的朋友可以转到下面链接 08 1. 基本操作 读取图像 imread() 展示图像 imshow() ...

  7. B站台湾大学郭彦甫|MATLAB 学习笔记|09 图像处理II Image Processing

    MATLAB学习笔记(09 图像处理II Image Processing) 如果想获得更好浏览体验的朋友可以转到下面链接 09 1. 提出问题 题目:如何找出图片中的米粒,并且确定他们的大小? 老师 ...

  8. Guava学习笔记(转)

    Guava(瓜娃)学习笔记 Guava工程包含了若干被google的java项目广泛依赖的核心库,例如:集合 [collections] .缓存 [caching] .原生类型支持 [primitiv ...

  9. Dynamic CRM 2013学习笔记(四十三)流程6 - 自定义流程活动

    当我们在流程里添加步骤时,有一些默认的步骤,像创建.更新.发邮件等,但如果你想加一个里面没有的步骤,比如发SMS消息,或者调用一个外部的web service,怎么办?这时就只能自定义一个流程活动了. ...

  10. 爬虫学习笔记(十)—— Scrapy框架(五):下载中间件、用户/IP代理池、settings文件

    一.下载中间件 下载中间件是一个用来hooks进Scrapy的request/response处理过程的框架. 它是一个轻量级的底层系统,用来全局修改scrapy的request和response. ...

最新文章

  1. FCN与U-Net语义分割算法
  2. js中内置对象Math()常用方法笔记
  3. windows : Jmeter自动化测试-eclipse+maven+jmeter
  4. 第四话 想不到办法,就研究规律 ver1.0
  5. 百度联盟广告如何理解按父容器宽度
  6. 动态dp模板题(树剖+dp+线段树)
  7. 如何成功构建大规模 Web 搜索引擎架构?
  8. post多个参数_如何使用Arjun v1.3挖掘HTTP参数
  9. 【Flink】FLink SQL TableException: Table sink doesn‘t support consuming update changes which is
  10. el-tree 拖拽互换位置_那些我们与UI交互的动作(三·拖拽)
  11. 无任何网络提供程序接受指定的网络路径
  12. KVM 介绍(7):使用 libvirt 做 QEMU/KVM 快照和 Nova 实例的快照 (Nova Instances Snapshot Libvirt)
  13. 51单片机+ESP8266-01WIFI模块实现数据传输
  14. 圣诞老人python代码_用Python画圣诞老人的N种方法
  15. Win10双系统选择系统界面黑白或彩色问题
  16. js 判断手势_JS触摸与手势事件详解
  17. 世界上最流行的开放源代码冲锋枪AK-47
  18. 郭霖的LitePal版本历程
  19. ZJNU——1695(分栗子)
  20. 常见的信息安全相关SCI期刊

热门文章

  1. chm文件显示“已取消网页导航”的解决办法
  2. 终于懂得孤独是躲不开的单行道
  3. android扫一扫 二维码显示结果中文乱码
  4. wordpress 安装教程
  5. 中国矿业大学(北京)第二届ACM程序设计公开赛(决赛)
  6. html表单界面设计,ui界面表单设计的三个方面
  7. 解密Zynga:专注 流水线 数据控
  8. 处理行内元素行内块元素中间空隙
  9. QT如何去掉布局(Layout)内控件之间的空隙
  10. 测试小兵成长记:新兵营