转载

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

CSDN移动将持续为您优选移动开发的精华内容,共同探讨移动开发的技术热点话题,涵盖移动应用、开发工具、移动游戏及引擎、智能硬件、物联网等方方面面。如果您想投稿、参与内容翻译工作,或寻求近匠报道,请发送邮件至tangxy#csdn.net(请把#改成@)。 

本文出自: WeheartSwift ,译文出自: 开发技术前线 ,译者: alier1226

介绍

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

着色程序代码如下:

void main() {  #define iterations 128  vec2 position = v_tex_coord; // gets the location of the current pixel in the intervals [0..1] [0..1]  vec3 color = vec3(0.0,0.0,0.0); // initialize color to black  vec2 z = position; // z.x is the real component z.y is the imaginary component  // Rescale the position to the intervals [-2,1] [-1,1]  z *= vec2(3.0,2.0);  z -= vec2(2.0,1.0);  vec2 c = z;   float it = 0.0; // Keep track of what iteration we reached  for (int i = 0;i < iterations; ++i) {   // zn = zn-1 ^ 2 + c   // (x + yi) ^ 2 = x ^ 2 - y ^ 2 + 2xyi   z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y);   z += c;   if (dot(z,z) > 4.0) { // dot(z,z) == length(z) ^ 2 only faster to compute    break;   }   it += 1.0;  }   if (it < float(iterations)) {   color.x = sin(it / 3.0);   color.y = cos(it / 6.0);   color.z = cos(it / 12.0 + 3.14 / 4.0);  }  gl_FragColor = vec4(color,1.0); } 

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

项目设置

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

  • Fractal.fsh 包含了上面着色程序的代码;
  • GameViewController.swift 包含了设置游戏场景的代码;
  • GameScene.swift 为空。

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

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

请注意纵横比固定为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。

class GameViewController: UIViewController, UIScrollViewDelegate  {       @IBOutlet weak var contentView: UIView!     @IBOutlet weak var scrollView: UIScrollView!     ... }

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

class GameViewController: UIViewController, UIScrollViewDelegate  {  ...  func scrollViewDidScroll(scrollView: UIScrollView) {   }  func scrollViewDidZoom(scrollView: UIScrollView) {  }  func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {   return contentView  }  ... } 

向着色程序发送数据

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

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

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

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

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

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

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

var textureValue: SKTexture! var floatValue: Float var floatVector2Value: GLKVector2 var floatVector3Value: GLKVector3 var floatVector4Value: GLKVector4 var floatMatrix2Value: GLKMatrix2 var floatMatrix3Value: GLKMatrix3 var floatMatrix4Value: GLKMatrix4

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

例子:将zoom的值设置成2

zoomUniform.floatValue = 2
正文到此结束
Loading...