Introduction在尝试可视化数学函数时,发现了一个有趣的库FieldPlay,并对README中的说明做了部分翻译记录,初步了解一下。来源我的GitHub什么的?让我们为网格上的每个点分配一个向量(1,0)。这意味着我们有一个指向右边的箭头:假设这些向量代表速度。如果我们将一千个粒子扔到这个网格上会怎样?他们将如何行动?当我们为空白空间上的每个点分配一个向量时,我们创建了一个称为向量场的数学结构。让我们创建一个更有趣的矢量场:y坐标为偶数的点得到一个矢量(1,0);y坐标为奇数的点得到相反的向量(-1,0);我们再次放下几千个粒子,看看会发生什么:上面可以用公式表示:v.x=-2.0*mod(floor(y),2.0)+1.0;v.y=0.0;y/2除以整数后的余数可能是1或0。然后我们对余数进行变换,使最终向量为(-1,0)或(1,0)。到目前为止,我们只使用了速度矢量的一个分量v.x,粒子只水平移动。让我们尝试设置两个组件,看看会发生什么v.x=-2.0*mod(floor(y),2.0)+1.0;v.y=-2.0*mod(floor(x),2.0)+1.0;哇!两个简单的操作和最终的动画看起来像一件艺术品!事实证明,矢量场是非常灵活的生成框架。这个项目如何运作?该项目的灵感来自VladimirAgafonkin的文章:我如何使用WebGL构建风图。Vladimir演示了如何以每秒60帧的速度完全在GPU上渲染多达100万个粒子。我使用了几乎相同的技术,但做了一些修改:向量场是在着色器语言GLSL代码中定义的,因此可以自由表达数学。使用四阶Runge-Kutta方法在GPU上计算粒子位置。每个维度X和Y都是独立计算的,因此我们可以更准确地存储位置。使用panzoom库添加了平移/缩放功能。矢量字段定义使用查询状态库保存在URL中。这样您就可以轻松地为您的矢量场添加书签/共享。基于WebGL计算的Floatpacking核心思想很简单。GPU可以非常快速地渲染图像。每个图像都是像素的集合。每个像素只是代表一种颜色的数字,通常以32位(RGBA格式)书写。但是谁说每像素32位就必须代表一种颜色呢?为什么我们不能计算一些数字并将它们存储为32位?这个数字可能是,例如,一个粒子沿着某个速度矢量的位置......如果我们这样做,GPU仍然会将这些数字视为颜色:幸运的是,我们不必让用户看到这些看似随机的图像。WebGL允许在称为帧缓冲区的“虚拟”屏幕上呈现内容。这些虚拟屏幕只是显存中的图像(纹理)。有了两个纹理,我们就可以利用GPU来解决数学问题。在每一帧上,算法的工作方式如下:告诉GPU从“背景”纹理中读取数据;告诉GPU使用帧缓冲区将数据写入“屏幕”纹理;将“背景”替换为“屏幕”;从理论上讲,这应该可以正常工作。其实是有问题的。WebGL不允许将浮点数写入纹理。所以我们需要将一个浮点数转换为每通道8位的RGBA格式。在Vladimir的文章中,使用了以下编码/解码模式://decodeparticleposition(x,y)frompixelRGBAcolorvec2pos=vec2(color.r/255.0+color.b,color.g/255.0+color.a);...//移动位置//将位置编码回RGBAgl_FragColor=vec4(fract(pos*255.0),floor(pos*255.0)/255.0);这里,粒子的X和Y坐标都存储在一个32位数字中。我从一开始就使用这种方法,它在台式机和Android手机上运行良好。然而,当我在iPhone上打开一个网站时,一个不愉快的惊喜等待着我。没有任何明显原因就会出现严重的瑕疵。比较在桌面(左)和iPhone(右)上运行的相同代码更糟糕的是,虽然矢量场是静态的(到处都是速度0),但在iPhone上粒子一直在移动:我检查了请求的浮点数是否将点分辨率设置为最高可用(highp)。然而,这些缺陷仍然很明显。我们如何解决这个问题?我不想使用最简单的启用浮点纹理的解决方法。它们没有像我希望的那样得到广泛支持。相反,我做了多年的非GPU编程告诉我不要做的事情。我决定解决数千个常微分方程,而不是每帧一个。但是每个维度一次。我将向着色器传递一个属性,告诉它需要将哪个维度写入此“绘制”调用的输出:if(u_out_coordinate==0)gl_FragColor=encodeFloatRGBA(pos.x);elseif(u_out_coordinate==1)gl_FragColor=encodeFloatRGBA(pos.y);在伪代码中,它看起来像这样:第1帧:第1步:嘿,WebGL,将u_out_coordinate设置为0,并将所有内容渲染到texture_x中;第2步:嘿,WebGL,将u_out_coordinate设置为1,然后再次将所有内容渲染到texture_y中;我们解决了同样的问题,除了解决方案中的x组件,我们扔掉了所有东西。然后对y重复。这对我来说似乎很疯狂,因为我认为这会影响性能。但是使用这种方法,即使是我的低端安卓手机也没有问题。encodeFloatRGBA()使用全部32位将浮点数编码为RGBA向量。我在stackoverflow的某个地方找到了它的一个应用程序,但我不确定这是否是解决它的最佳方法(如果您更了解,请告诉我)。好消息是瑕疵没有了:参考fieldplaygithub
