令人惊叹的复杂之美:如何做一个iOS分形App?

更新时间:2015-09-06 10:49:39点击次数:2514次

介绍


在这个教程中,我们会做一个可以渲染Mandelbrot Set的应用程序,我们可以缩放和平铺它来看分形那令人惊叹的复杂之美。终的结果可点击链接查看小视频。

着色程序代码如下:


[cpp] view plaincopy

  1. void main() {  

  2.     #define iterations 128  

  3.     vec2 position = v_tex_coord; // gets the location of the current pixel in the intervals [0..1] [0..1]  

  4.     vec3 color = vec3(0.0,0.0,0.0); // initialize color to black  

  5.     vec2 z = position; // z.x is the real component z.y is the imaginary component  

  6.     // Rescale the position to the intervals [-2,1] [-1,1]  

  7.     z *= vec2(3.0,2.0);  

  8.     z -= vec2(2.0,1.0);  

  9.     vec2 c = z;   

  10.     float it = 0.0; // Keep track of what iteration we reached  

  11.     for (int i = 0;i < iterations; ++i) {  

  12.         // zn = zn-1 ^ 2 + c  

  13.         // (x + yi) ^ 2 = x ^ 2 - y ^ 2 + 2xyi  

  14.         z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y);  

  15.         z += c;  

  16.         if (dot(z,z) > 4.0) { // dot(z,z) == length(z) ^ 2 only faster to compute  

  17.             break;  

  18.         }  

  19.         it += 1.0;  

  20.     }   

  21.     if (it < float(iterations)) {  

  22.         color.x = sin(it / 3.0);  

  23.         color.y = cos(it / 6.0);  

  24.         color.z = cos(it / 12.0 + 3.14 / 4.0);  

  25.     }  

  26.     gl_FragColor = vec4(color,1.0);  

  27. }  



你可以下载 起始版本跟着教程一起做,也可以在本文结尾找到终版本的代码。


项目设置


Gamescene.sks文件里包含一个名为fractal的子画面,它填充了整个界面并且着色程序程序Fractal.fsh也附在它上。


  • Fractal.fsh包含了上面着色程序的代码;

  • GameViewController.swift包含了设置游戏场景的代码;

  • GameScene.swift为空。


如果你现在运行代码,你将会得到如下的结果:

Starter 
起始

请注意纵横比固定为3/2,我们需要先根据屏幕大小调节它。同时,由于画面是静态的,所以你不可能与它有任何方式的交互。


设置界面


我们将用一个透明的scrollview来处理平铺缩放。scrollview将自动跟踪我们的位置以及我们在分形中的缩放程度。

打开'Main.storyboard'文件,拖进去一个scrollview。将scrollview设置成fill the view,并对它的宽度,到顶部距离,到底部距离设置限制。

将scrollview的大缩放程度设置为100000,意味着我们将可以把分享放大到十万倍!我们不能再放大更多了因为已经接近了`float`类型的准确限。

拖一个view(画面)到scrollview里,它将用作处理缩放。这个view本身不会展示任何东西,我们将用到它的contentOffset和scrollView的zoom属性来更新我们的着色程序。要确保这个画面可以填满scrollView,并且设定好宽度,到顶部底部左右距离的限制。将画面的背景色设置为 Clear Color (透明色)。

接下来我们将连接我们所需要的outlet和scrollView的代理。给scrollView和scrollView的contentView拖进outlet。


[cpp] view plaincopy

  1. class GameViewController: UIViewController, UIScrollViewDelegate  {  

  2.    

  3.     @IBOutlet weak var contentView: UIView!  

  4.     @IBOutlet weak var scrollView: UIScrollView!  

  5.     ...  

  6. }  



接下来我们去掉代理方法,并且实现viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? 这个方法


[cpp] view plaincopy

  1. class GameViewController: UIViewController, UIScrollViewDelegate  {  

  2.     ...  

  3.     func scrollViewDidScroll(scrollView: UIScrollView) {   

  4.     }  

  5.     func scrollViewDidZoom(scrollView: UIScrollView) {  

  6.     }  

  7.     func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {  

  8.         return contentView  

  9.     }  

  10.     ...  

  11. }  




向着色程序发送数据


着色程序可以从你的swift代码里的uniform变量里获得数据。uniform变量可以在SpriteKit编辑器里声明。那现在我们来声明一下uniform变量。

打开GameScene.sks文件,选择mandelbrote sprite。将insepctor拖到底部,在“Custom shader Uniforms”里添加两项:float类型的zoom ,值为1, 以及vec2类型的offset。我们将用这两项uniform变量储存scrollView的 contentOffset 以及zoom 属性。

Uniforms

注意:Xcode 6.3的uniform变量有bug。它不能直接在编辑器里赋值初始化,你必须在代码里初始化它们。

我们可以通过shader属性来获取节点上(node)着色程序,用 theuniformedName()方法来从着色程序得到uniform变量。以下是我们获取zoom uniform变量的例子:


[cpp] view plaincopy

  1. let zoomUniform = node.shader!.uniformNamed("zoom")!  


当我们有了uniform变量后,我们可以通过它的属性来改变它的值。


[cpp] view plaincopy

  1. var textureValue: SKTexture!  

  2. var floatValue: Float  

  3. var floatVector2Value: GLKVector2  

  4. var floatVector3Value: GLKVector3  

  5. var floatVector4Value: GLKVector4  

  6. var floatMatrix2Value: GLKMatrix2  

  7. var floatMatrix3Value: GLKMatrix3  

  8. var floatMatrix4Value: GLKMatrix4  


在本教程里,我们只对 floatValuefloatVector2Value感兴趣。

例子:将zoom的值设置成2


[cpp] view plaincopy

  1. zoomUniform.floatValue = 2  


本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是一个个人学习交流的平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽,造成漏登,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

  • 项目经理 点击这里给我发消息
  • 项目经理 点击这里给我发消息
  • 项目经理 点击这里给我发消息
  • 项目经理 点击这里给我发消息