Processing:数学(上)

1. “如果你不相信数学有多简单,是你还没有认识到生活有多复杂——John von Neumann”

2. 模数(Modulus):20 模(modulo,也就是除以,用百分号表示) 6 等于 2 或者写为 20 % 6 = 2。如果A = B % C,那么A永远不可能大于C(当然。。)。因此,模 可以用在你需要将一个计数器变量循环至0的情况。下列代码:
x = x + 1;
if (x >= limit){
x = 0;
}

可以被替换为:
x = (x + 1) % limit;
这在你想要每次一个的顺数数组中的元素时很有用,当你达到数组长度的时候总是返回0。一个例子:
// 4个随机数字
float[] randoms = new float[4];
int index = 0; // 我们正在使用的数字

void setup() {
size(200,200);
// 用随机值填充数组
for (int i = 0; i < randoms.length; i ++ ) {
randoms[i] = random(0,256);
}
frameRate(1);
}

void draw() {
// 我们每帧调用数组的一个元素
background(randoms[index]);
// 然后继续下一个
index = (index + 1) % randoms.length; // 使用模运算符(modulo operator)将计数器循环到0。
}

随机柱状图
随机柱状图

3. random()函数产出的随机值称为“统一(uniform)”分部,举例说明:如果我们要一个在0~9间的随机值,数字0~9出现的机率最高为10%。下例可证明此点:
// 一个记录随机数摘取频率的数组
float[] randomCounts;

void setup() {
size(200,200);
randomCounts = new float[20];
}

void draw() {
background(255);

// 选取一个随机数并增加计数
int index = int(random(randomCounts.length));
randomCounts[index] ++ ;

// 绘制直方图
stroke(0);
fill(175);
for (int x = 0; x < randomCounts.length; x ++ ) {
rect(x*10,0,9,randomCounts[x]);
}
}

通过一些小把戏,我们可以用random()产出非统一性分部的随机值,并且产出使特定事件发生的可能性。比如说,使一个sketch的背景色变黄的机率为10%而变蓝的机率为90%。

4. 可能性是什么?可能性就是某件事发生的可能性。比如投掷硬币,结果是正面与反面朝上的可能性各为50%。出现三次正面朝上的可能性为:
(1/2) * (1/2) * (1/2) = 1/8 (或者 0.125)
换句话说,每8次投掷硬币,正面朝上的情况可能会有3次。

5. Daniel出题,在一副扑克牌内抽中两张A的可能性是多少?答案为:0.00452488688。怎么算出来的?
一副扑克牌有52张牌,其中有4张A,因此抽中第一张A的可能性为:
4 / 52 = 0.0769230769
抽中第二张A的可能性为:
3(剩下的A) / 51(剩下的扑克牌) = 0.0588235294
因此抽中两张A的可能性为:
(4/52)*(3/51) = 0.00452488688

6. 我们可以用random()玩些小把戏:
int[] stuff = new int[5];

stuff[0] = 1;
stuff[1] = 1;
stuff[2] = 2;
stuff[3] = 3;
stuff[4] = 3;
int index = int(random(stuff.length));
if (stuff[index] == 1){
// 做爱做的事
}

如果运行上边这段代码,我们得到1和3的机率都将为40%,而得到2的机率则为20%。

7. 另一个策略是,要一个随机值,并且在我们指定的范围内才使用它:
float prob = 0.10; // 可能性为10%
float r = random(l); // 0~1间的随机浮点值

if (r < prob) { // 如果我们的随机值小于0.1
/*在此让事件发生*/
}

8. 同样的技术同样可用于多个输出:
Outcome A — 60% | Outcome B — 10% | Outcome C — 30%。
用代码实现这个,我们这么搞:
• 介于0.00~0.60间 (10%) → 输出 A.
• 介于0.60~0.70间 (60%) → 输出 B.
• 介于0.70~1.00间 (30%) → 输出 C .

三色可能性
三色可能性

接下来看例子:
void setup() {
size(200,200);
background(255);
smooth();
noStroke();
}

void draw() {

// 3种不同情况的可能性
// 它们加起来应当为100%!
float red_prob = 0.60; // 60%的机会红色
float green_prob = 0.10; // 10%的机会绿色
float blue_prob = 0.30; // 30%的机会蓝色

// 选取一个0~1间的随机值
float num = random(1);

// 如果随机值小于0.6
if (num < red_prob) {
fill(255,53,2,150);
// 如果随机数在0.6~0.7之间
} else if (num < green_prob + red_prob) {
fill(156,255,28,150);
// 所有其他的情况 (比如介于0.7~1.0)
} else {
fill(10,52,178,150);
}

// 绘制圆形
ellipse(random(width),random(height),64,64);
}

9. Perlin噪声,唧唧歪歪说了一堆,我只关注它可用于生成一系列有趣的效果,包括云、山水、大理石纹理等等。下图为Perlin噪声图(x轴代表时间;注意曲线有多么光滑)与纯随机数图的对比:

Perlin噪音  VS. 随机(random)
Perlin噪音 VS. 随机(random)

10. 如果你参考P5官网关于噪音(noise)的参考,你会发现噪音是基于若干“八度(octave)”计算出来的,你可以呼叫noiseDetail()改变八度的数量以及它们相关的重要性。这将改变噪音函数的行为。你可以在这里阅读更多Ken Perlin与噪音协作的东西。

11. 你可以使用函数 noise( )在P5内调用Perlin噪音算法。引数为三个,分别代表一、二、三维,这里只讲一维,剩下两维请参阅P5官网。一维的Perlin噪音反复制造一个值的线性序列。例如:0.364, 0.363, 0.363, 0.364, 0.365

12. Perlin噪音在P5中的使用:a. 呼叫函数noise();b. 传递当前的“时间”为其引数:
float t = 0.0;
float noisevalue = noise(t); // 从时间0开始噪音

我们可以在draw()内使其循环:
float t = 0.0;
void draw() {
float noisevalue = noise(t);
println(noisevalue);
}

但你也许会发现,输出的总是同样的值,那是因为时间没有变化,如果我们让时间增加的话:
float t = 0.0;
void draw() {
float noisevalue = noise(t);
println(noisevalue);
t + = 0.01;
}

输出的值将开始平滑变化。时间变化的快慢决定了噪声曲线的平滑度,越快则越不平滑。

13. 你也许会发现,noise()返回的值总是介于0.0~1.0之间的浮点值,这是不可变的,但如果我们需要更大的值,那么用乘法即可,这个例子阐述了这一关点,请注意球的缩放多么舒服和平滑。

Be Sociable, Share!

发表评论

电子邮件地址不会被公开。 必填项已用*标注