一切从一个视频说起。在抖音上刷到一个交互装置的视频,正好之前有同学向我咨询一个相关问题,我觉得可以把这些内容串起来系统地讲一讲,正好能帮助大家梳理一下Processing的底层数据是如何存储的。
![5bd6b53703a8099a1ddb95ea424f24d4.png](https://i-blog.csdnimg.cn/blog_migrate/84ea8d6ef941819fb5c59955932ecee9.jpeg)
上面这个作品,我们先剥掉它华丽的外壳,人体触控感应装置估计是使用的雷达或者红外,这些硬件会告诉你当前屏幕上哪个位置正在被手触发,我们可以用鼠标来代替。另外,粒子的颜色是从梵高星空这张底图上相同位置取色,我们也剥掉,变成单色方便看清楚轨迹。
那现在的画面就是这个样子:
![07781f78d57a4c2346253a562f0d2485.png](https://i-blog.csdnimg.cn/blog_migrate/d3b9751d7352d0a3a086f375435624d0.png)
本质上就是很多很多粒子,沿着流场运动,然后拖动鼠标可以实时编辑流场。
(这里插播一段关于流场的介绍,了解的同学可以跳过)
下面三张图片摘自《The Nature of Code》Page 277~282,作者 Daniel Shiffman
![ce83068e9444376bb079c71103eb0869.png](https://i-blog.csdnimg.cn/blog_migrate/0ff97c3dd5d1af256461de8186ded033.jpeg)
什么是流场?想象有一张和窗口等大的图片,里面的每一个像素都包含一个速度信息(方向和速度大小)。注意这个箭头图只是一个示意图,箭头比较稀疏,实际上,每个像素都是一个箭头。
![9649f22ade541f19e0bfc3cd5aef9e9d.png](https://i-blog.csdnimg.cn/blog_migrate/e63e8804597784db02a6e73241287131.png)
有一辆小车在窗口内运动,小车当前位置的流场像素所包含的速度v,会作用于小车上,可以直接用v当做小车速度,也可以用v当做加速度影响小车的当前速度。换句话说,小车顺着流场移动。
简而言之,流场图就是一个小车运动的地图。当很多很多个小车在这个流场运动的时候,就是这个样子:
![1d6e283ac23873fe9c8941f1758b7674.png](https://i-blog.csdnimg.cn/blog_migrate/f4a30c6ca373cf466908e1796c744a53.jpeg)
在学习Perlin Noise 的时候,一个百分之百绕不过去的案例就是用noise 函数生成流场:
![cc587cd3593e2e2e79f1468605630304.gif](https://i-blog.csdnimg.cn/blog_migrate/fa8f68d2bde8e24ef15f3512a566c5ac.gif)
(流场介绍完成)
在noise 流场里,每个像素位置的速度值是每时每刻实时用 noise 计算出来的,带来的问题是:你可以用参数控制noise流场的大致形态,但是无法精确控制每一个像素位置的速度值。
如何精确控制每一个像素位置的速度值?
直接能想到的思路就是建立一个二维数组,直接按照像素阵列,把每个位置的速度都写到数组里面。
PVector[][]vels=new PVector[width][height];
这个思路是可行的,当拖动鼠标编辑流场的时候,把鼠标周围半径为R(笔刷半径)的圆范围内的所有数组元素的值都设定成流场速度,流场速度可以是鼠标移动的速度。
不过,我今天想讲的是另一个思路,那就是用图片像素直接存储速度数据。换句话说,把每个位置的速度都通过一个固定公式f 换算成颜色值,那么整个流场的速度信息就能保存为一张图片。当我们需要用到指定位置的速度的时候,就从图片里的这个位置取出像素颜色,然后通过 f 的反公式换算回速度。
这样做有这么几个好处:
- 速度更快。
- 方便进一步导入到GPU中做大规模并行运算。
如何把一个数据换算成颜色?
可能到这里你会有疑问:每个颜色本来就包含RGBA四个通道数值,不能直接写进去吗?答案是可以,但是每个通道0~255,只能表示256个数,