Julia使用WebGL for Elm设置可视化

用榆树制作精美的分形动画

介绍

分形对我来说一直很美丽。 借助WebGL for Elm,我们可以在浏览器中以功能和静态类型化的语言可视化分形。 由于WebGL着色器在GPU上运行,因此Julia集的可视化效果非常好。 如果您不熟悉基本的WebGL概念,请查看

GitHub – Elm-community / webgl:在Elm中使用WebGL进行Function.al渲染。
webgl – Elm中使用WebGL进行功能渲染。 github.com

在下面的内容中,我们将处理由两个三角形组成的二次网格M ,两个三角形的顶点分别为(-1,-1),(-1,1),(1,1)和(-1,-1),(1 ,1),(1,-1)。 我们首先说明如何可视化M上的 Julia集

朱莉娅集可视化

Julia集是由某些复数值函数生成的。 在本文中,我们将重点介绍二次映射

网格M上的f的Julia集是该系列的点集的边界

不会趋于无穷大。 对于可视化算法,这意味着我们必须为(1)指定最大迭代次数N ,并确定策略(1)是否对网格中的点z发散。 决定散度的一种可能性是假设(1)趋于无穷大

对于一些n≤N和正C。 然后,通过以下步骤确定每个像素的颜色:

  1. 选择一个数字N和一个常数C。
  2. 对于网格中的每个像素,我们计算(1)直到达到N或满足条件(2)。
  3. 如果我们达到N,像素将被涂成黑色。 如果对于n≤N满足(2) 则将像素渲染为取决于n的颜色(出于这个原因,我们稍后将使用WebGL纹理)。

榆木实施

可以在elm-julia-set-visualization.herokuapp.com上找到实时演示,并且代码可以在github.com/fl9/elm-julia-set-visualization中找到。

让我们在部分代码上添加一些解释。 我们的网格是由两个三角形生成的

 输入别名Vertex = 
{位置:Vec2}
  mesh:网格顶点 
网格=
WebGL.triangles
[((顶点(vec2 -1 -1))
,(顶点(vec2 -1 1))
,(顶点(vec2 1 1))

,((顶点(vec2 1 -1))
,(顶点(vec2 -1 -1))
,(顶点(vec2 1 1))

]

仅存储每个顶点的位置。 通过更改上一节中定义的函数f的参数c ,AnimationFrame用于呈现不同的Julia集。 在这里,我们使用经过的时间在-1和1之间改变 c的实部cX和虚部cY

 信息类型 
=动画浮动| ...
 订阅:型号-> Sub Msg 
订阅模式=
AnimationFrame.diffs动画
 更新:消息->模型->(模型,Cmd消息) 
更新味精模型=
例味精
动画值->

timeElapsed = model.timeElapsed +值
  cX = 
sin(0.0006 *(getX model.c + timeElapsed))
  cY = 
sin(0.0002 *(getY model.c + timeElapsed))

{型号| c = vec2 cX cY,timeElapsed = timeElapsed}! []

有趣的部分发生在片段着色器中。 在这里,我们需要执行上一部分中描述的步骤。 我们选择N = 80作为最大迭代数,选择C = 800作为上限。 模型参数c (请参见上文)也声明为统一变量,以在片段着色器中进一步使用。 此外,我们提供纹理以及视图的宽度和高度。 纹理用于将我们需要满足的迭代次数映射到纹理内的一种颜色上的(2)(或最大迭代次数)。 片段着色器的内容如下

  fragmentShader:着色器{}制服{} 
fragmentShader =
[glsl |
精密中型浮子;
统一的vec2 c;
均匀的sampler2D纹理;
统一的int screenWidth;
统一的int screenHeight;
  const int max_iterations = 80; 
  vec2 complex_square(vec2 v){ 
返回vec2(
vx * vx-vy * vy,
vx * vy * 2.0
);
}
  vec2 julia_function(vec2 z,vec2 c){ 
返回c + complex_square(z);
}
 浮动float_count_to_texture_position(int count){ 
if(count == max_iterations){
返回0.0;
}其他{
返回float(count)/ float(max_iterations);
}
}
  void main(){ 
vec2 z = 3.5 * vec2((gl_FragCoord.x-0.5 * float(screenWidth))/ float(screenWidth),(gl_FragCoord.y-0.5 * float(screenHeight))/ float(screenHeight));
  int count = max_iterations; 
  for(int i = 0; i <max_iterations; i ++){ 
z = julia_function(z,c);
  if(dot(z,z)> 800.0){ 
计数=我;
打破;
}
}
  gl_FragColor = texture2D(纹理, 
vec2(iteration_count_to_texture_position(count),0.0));
}
|]

结论

与WebGL for Elm一起工作真是有趣! 我期待学习更多有关WebGL的知识,并希望将所获得的知识用于以后的文章。