在这个教程中,我们会做一个可以渲染Mandelbrot Set的应用程序,我们可以缩放和平铺它来看分形那令人惊叹的复杂之美。终的结果可点击链接查看小视频。
着色程序代码如下:
[cpp] view plaincopy
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
为空。
如果你现在运行代码,你将会得到如下的结果:
请注意纵横比固定为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
class GameViewController: UIViewController, UIScrollViewDelegate {
@IBOutlet weak var contentView: UIView!
@IBOutlet weak var scrollView: UIScrollView!
...
}
接下来我们去掉代理方法,并且实现viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView?
这个方法
[cpp] view plaincopy
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
属性。
注意:Xcode 6.3的uniform变量有bug。它不能直接在编辑器里赋值初始化,你必须在代码里初始化它们。
我们可以通过shader属性来获取节点上(node)着色程序,用 theuniformedName()
方法来从着色程序得到uniform变量。以下是我们获取zoom uniform变量的例子:
[cpp] view plaincopy
let zoomUniform = node.shader!.uniformNamed("zoom")!
当我们有了uniform变量后,我们可以通过它的属性来改变它的值。
[cpp] view plaincopy
var textureValue: SKTexture!
var floatValue: Float
var floatVector2Value: GLKVector2
var floatVector3Value: GLKVector3
var floatVector4Value: GLKVector4
var floatMatrix2Value: GLKMatrix2
var floatMatrix3Value: GLKMatrix3
var floatMatrix4Value: GLKMatrix4
在本教程里,我们只对 floatValue
和floatVector2Value
感兴趣。
例子:将zoom的值设置成2
[cpp] view plaincopy
zoomUniform.floatValue = 2
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是一个个人学习交流的平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽,造成漏登,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。