如何做一个iOS分形App
Posted 3行代码
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何做一个iOS分形App相关的知识,希望对你有一定的参考价值。
如何做一个iOS分形App
- 原文链接 : 如何做一个iOS分形App
- 原文作者 : Silviu Pop
- 译文出自 : 开发技术前线 www.devtf.cn
- 译者 : alier1226
- 校对者: MrLoong
- 状态 : 完成
介绍
在这个教程中,我们会做一个可以渲染Mandelbrot Set的应用程序,我们可以缩放和平铺它来看分形那令人惊叹的复杂之美。最终的结果如下:
着色程序的代码
你可以下载起始版本跟着教程一起做,也可以在本文结尾找到最终版本的代码。
项目设置
Gamescene.sks
文件里包含一个名为 fractal
的子画面,它填充了整个界面并且着色程序程序
Fractal.fsh
也附在它上。
Fractal.fsh
包含了上面着色程序的代码
GameViewController.swift
包含了设置游戏场景的代码
GameScene.swift
为空
如果你现在运行代码,你将会得到如下的结果:
请注意纵横比固定为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。
接下来我们去掉代理方法,并且实现 viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView?
这个方法
向着色程序发送数据
着色程序可以从你的swift代码里的uniform变量里获得数据。uniform变量可以在SpriteKit编辑器里声明。那现在我们来声明一下uniform变量。
打开 GameScene.sks
文件,选择 mandelbrote sprite。将insepctor拖到底部,在“Custom shader Uniforms”里添加两项:float
类型的
zoom
,值为1
, 以及 vec2
类型的offset
。我们将用这两项uniform变量储存scrollView的
contentOffset
以及 zoom
属性。
警告:Xcode 6.3的uniform变量有bug。它不能直接在编辑器里赋值初始化,你必须在代码里初始化它们。
我们可以通过shader属性来获取节点上(node)着色程序,用 theuniformedName()
方法来从着色程序得到uniform变量。以下是我们获取zoom uniform变量的例子:
Once we have a uniform we can change its value via one of of the properties
当我们有了uniform变量后,我们可以通过它的属性来改变它的值。
We’re only interested in using floatValue
and floatVector2Value
for this tutorial.
在本教程里,我们只对 floatValue
和floatVector2Value
感兴趣。
Ex: to set the zoom to 2 we use
例子:将zoom的值设置成2
Coordinate systems and mapping intervals
坐标系以及映射出区间
我们将在保持比例的基础上映射不同的坐标系。我们将用这个来转化scrollview的坐标到复平面。
让我们先看一下一维的情况:
将x从区间[0,a]映射到区间[0,1],我们只需要除以区间长度 x‘ = x / a
。
将x从区间[0,1]映射到区间[a,b],我们可以乘上区间长度,然后再加上区间起始值,x‘ = x * (b - a) + a
。
举个例子,比如iPhone4的x坐标,x坐标为0到480之间。映射 x
到[0,1]
, 我们用
x‘ = x / 480
。映射x‘
从 [0,1]
到[-2,2]
,我们用
x‘‘ = x‘ * 4 - 2
如果我们屏幕上有一点x,坐标值为120,那么对应到区间[0,1]
将成为 120 / 480 = 0.25
,以及在区间
[-2,2]
,如下所见它将成为 0.25 * 4 - 2 = -1
。
Mapping between the scrollview and the complex plane
scrollView及复平面互相映射
我们需要讲scrollView上的点转换到复平面。第一步,先将scrollView上的点转换到区间[0,1]
。通过将contentOffset
除以contentSize
可以将
contentOffset
转换到区间[0,1]
。
我们着色程序x,y坐标都有点在区间[0,1]
,所以我们要在scrollView的contentView里映射出这些店。
标准化过的contentView为 1.0 / zoom
,所以contentView里标准化过的点坐标讲在区间[contentOffset / contentSize,contentOffset / contentSize + 1.0 / zoom]
。
还有我们必须牢记的是,y轴的点在GLSL上,而点(0,0)在左下角,所以我们必须翻转y轴来对应我们的scrollView。
下面的GLSL代码转换scrollView的contentView里点的位置。
如下你可以看见蓝色的scrollView的contentView在标准化与未标准化过的边框。contentSize = (960,640)
,contentOffset = (240,160)
,zoom = 2.0
ScrollView
标准化过的ScrollView
最后我们将点映射到复平面。为了在mandelbrot里得到好看的效果,我们将希望映射区域[-1.5,0.5] x [-1,1]
复平面。
我们还想使纵横比正确。现在我们的x、y轴的比例一样,我们要乘以x和纵横比使得图片不会变形。
纵横比是什么
纵横比是屏幕宽度和高度的比例。
下面你可以看到我们scrollView的contentView映射到的平复面以及纠正过纵横比的结果。
为了整合上面所有代码,我们建了一个新的方法叫updateShader,它可以传一个contentView坐标到着色程序。我们所需要做的就是在scrollView的代理方法里调用updateShader方法。
同时也别忘了当view出现时调用updateShader方法,这样你才可以初始化uniform变量。