Scene Kit (翻译)

前言

Scene Kit(SK)是WWDC12推出OS X平台的属于Cocoa类的3D渲染引擎框架。初版已经有不错了而且后续又增长了一些强大的功能好比着色修改,限制。当苹果推出新系统Mavericks时又增长了骨架动画。今年,SK变得更增强大了,新增支持粒子效果,物理模拟,脚本事件,多程渲染,最重要得是支持iOS平台。node

从一开始,我就发现SK最强大与区别是它与其余图形处理框架的整合,好比CI,CA还有SK。这意味着除了游戏工程师外一些有兴趣游戏开发的Cocoa开发也能对SK立刻上手。swift

SK基础

SK以OpenGL为基石,对外开放高级API,你能够用OC或者swift建立出光,几何图形,物质,还有摄像机对象。若是你用过OpenGL早先没有着色器的版本,那估计会让你想起那段关于被系统限制而不能方便配置的很差的记忆。幸运的是,如今不会在这样了。高级配置对于大部分通常得任务已经足够了-甚至是更高级的东西好比动态着色还有层次效果。数组

甚至,SK还可让你调用低级接口去调用OpenGL着色代码去进行渲染(GLSL)。框架

结点

除去光,几何体,物质还有相机,SK使用了节点层级来组织自身的内容。每一个节点都包含位置,旋转度,还有相对父节点的缩放度,反过来也关联自身的父节点,如此特性递归到根节点。为了给其余对象中的某个一个3D坐标,每一个节点被链接到节点群的某一个节点上。节点层级用以下的方法管理:ide

addChildNode(_:)
insertChildNode(_: atIndex:)
removeFromParentNode()

如同iOS以及OS X中管理视图层级的方式同样。测试

几何学对象

SK提出内置简单形状几何学对象好比像箱子,球体,飞机,圆锥体,对于游戏来讲,大部分你要作的就是从一个文件中载入3D模型。你能够导入或者导出COLLADA文件采起关联文件名的方式引用文件:动画

let chessPieces = SCNScene(named: "chess pieces") // SCNScene?

若文件所包含得场景须要被彻底展现,那它能够做为整个场景视图的场景。若是场景包含许多对象,而且这些对象只有部分是须要展现在屏幕上的,那么他们能够经过名字索引找到,能够将他们加入场景而且在场景视图中进行渲染。编码

if let knight = chessPieces.rootNode.childNodeWithName("Knight", recursively: true) {
    sceneView.scene?.rootNode.addChildNode(knight)
}

在导入文件的原始结点和包含着其余任一或者全部得子结点,包括附带了几何体对象,光,摄像机。搜寻一样名字的子结点会指向一个相对的对象。人工智能

这里有图。。spa

当一个场景有多个模型拷贝的时候,好比,为了展现两个其实在国际象棋的棋盘上,你会拷贝结点或者克隆(递归拷贝)它。这样这份结点的拷贝引用了同一个物质几何体对象。凉粉拷贝都指向了同一个几何体对象。因此改变一个物质,这个几何体对象将也不得不被拷贝而且拥有一个新的物质依附在它身上。拷贝一个几何体对象比较迅速而且代价较小,由于拷贝仍是指向了同一份顶点数据。

根据操纵骨动画集合体对象导入的结点有一个皮肤对象用来提供访问骨架结点层级喝用来管理骨头喝几何体对象的关系。个别的骨头能够被移动和旋转;可是,更复杂的动画会改变多个骨头-举个栗子, a character’s walk cycle - 更多是从一个文件加载并加到对象中去。

SK中的光是彻底动态的。这使得他们更容易被获取而且更易于使用,可是一样意味着SK提供的光源跟一个完整功能的游戏引擎比起来不够先进。这里有四种不一样的光:周围光,指向性光,点光,聚光。

在不少状况下,特定一个旋转坐标系和一个角度并非最感知的方法去识别一个物体上的光。在这些状况下,这个给出光得结点的位置喝朝向可以经过另一个结点进行限制。添加一个“look at”-约束一位置这束光线将会一直指向这个结点,及时结点移动了。

let spot = SCNLight()
spot.type = SCNLightTypeSpot
spot.castsShadow = true

let spotNode = SCNNode()
spotNode.light = spot
spotNode.position = SCNVector3(x: 4, y: 7, z: 6)

let lookAt = SCNLookAtConstraint(target: knight)
spotNode.constraints = [lookAt]

动画

SK中任意对象任意属性都是可动画的。就想Cocoa,这意味着你须要建立一个CAAnimation关键路径(哪怕是“position.x”)并添加到动画对象。相似的,你能够改变你动画相关得值在SCNTransaction动做“begin”与“commit”。上述两种方式十分相同,毫无二致。

let move = CABasicAnimation(keyPath: "position.x")
move.byValue  = 10
move.duration = 1.0
knight.addAnimation(move, forKey: "slide right")

SK一样支持Sprite Kit动做方式的动画API。这就容许你去建立一串动画而后调用自定义的block代码与其余动画同时运行,这些动做做为游戏循环的一部分,而且每一帧都进行更新数据层值,而不只仅是表象层结点。

事实上,若是你曾经使用过Sprite Kit,那你对SK将有似曾相识的感受,不一样的是此次是3D世界。在iOS8和OS X 10.10,上述两个框架能够一块儿协做。在使用Sprite Kit的时候,2D能够混杂3D模型一块儿使用。在使用SK开发的时候,Sprite Kit的场景以及纹理能够被用做SK的纹理,而且Sprite Kit场景能够被用做一种2D覆盖在SK场景之上。

使用SK写游戏

动做跟纹理并非Scene KitSprite Kit惟一共同的东西。当使用SK进行游戏编码的时候,这种感受与2D框架是很是类似的。在上述两种开发框架下,游戏轮回有以下同样的步骤,同样的代理回调。

  1. 更新场景
  2. 运行动画/动做
  3. 仿真物理
  4. 执行约束
  5. 渲染

请看轮回方向 ->
图片描述
每一帧都有一个回调而且用来执行游戏运行相关的逻辑好比像输入源句柄,人工智能,或者是游戏剧本。

输入源句柄

SK使用相同的输入机制,例如键盘事件,鼠标事件,点击事件,还有Cocoa与Cocoa Touch产品中手势识别,主要的不一样是这里只有一个视图那就是场景视图。对于键盘事件或者缩放,快滑,旋转手势,它可能仅仅是知道这些事件发生了,可是好比点击或者长按拖动,此类事件则须要更多的信息。

对于这些状况,场景视图须要使用-hitTest(_: options:)来进行点击测试。与一般视图以及图层不一样的是(只返回点击的子视图或者子图层),SK中返回的是有交点几何体对象以及摄像机穿过该点的射线的数组。每个点击结果包含着点击几何体归属结点,还有交点的详细信息(点击坐标,纹理坐标)。大多数情形,这些信息足够知道了所触碰的第一个结点是:

if let firstHit = sceneView.hitTest(tapLocation, options: nil)?.first as? SCNHitTestResult {
    let hitNode = firstHit.node
    // do something with the node that was hit...
}

默认渲染扩展

光,材质配置,虽然容易协同工做,可是也只能让你走这么远(限制你)。若是你已经用上了OpenGL的着色器,你能够用其进行渲染来配置材质,进而作到彻底的自定义。而后,若是你只是想修改默认的渲染,SK剔除四点能够将着色器代码片断(GLSL)注入到默认的渲染代码中。在不一样的切入点,SK提供了数据入口例如变换矩阵,几何体数据,纹理示例,还有渲染颜色输出。

举个栗子,在入口点的数行着色器代码片断能够被用来扭曲几何体对象X轴方向全部的点。能够经过定义一个方程去建立一个渲染变换并把这个变换应用到这些X轴点和几何体的正常化。一样也能够定义一个“不变”变量来决定物体的扭曲度:

// a function that creates a rotation transform matrix around X
mat4 rotationAroundX(float angle)
{
    return mat4(1.0,    0.0,         0.0,        0.0,
                0.0,    cos(angle), -sin(angle), 0.0,
                0.0,    sin(angle),  cos(angle), 0.0,
                0.0,    0.0,         0.0,        1.0);
}

#pragma body

uniform float twistFactor = 1.0;
float rotationAngle = _geometry.position.x * twistFactor;
mat4 rotationMatrix = rotationAroundX(rotationAngle);

// position is a vec4
_geometry.position *= rotationMatrix;

// normal is a vec3
vec4 twistedNormal = vec4(_geometry.normal, 1.0) * rotationMatrix;
_geometry.normal   = twistedNormal.xyz;

着色修改器能够被依附到任意个几何体对象上或是其下的人一个材质上。上述两个类都是支持KVC,这意味着你能够为任意的Keys设置值。在着色修改器中已经声明了“扭曲因子”使SK观察Key和重绑定的不变值任什么时候候只要值发生变化。便可以使用KVC进行简单得改变属性值:

torus.setValue(5.0, forKey: "twistFactor")

一样能够靠建立一个CAAnimation来获取关键路径:

let twist = CABasicAnimation(keyPath: "twistFactor")
twist.fromValue = 5
twist.toValue   = 0
twist.duration  = 2.0

torus.addAnimation(twist, forKey: "Twist the torus")

图片描述

延迟着色

有些图形效果不能在一次的渲染过程当中达成,即便是纯OpenGL。解决方案是序列化不一样的着色器操做来进行预处理操做或者延迟着色。SK在这种处理技术上使用的是SCNTechnique类。它建立一个字典来定义绘画过程,输入输出,着色文件,符号等等。

第一步一般是SK默认渲染,输出源是颜色和场景的层级深度。若是你不想颜色被着色,材质能够被设置常量光模型,或者场景中的全部光能够被替代成单一周围光。

举个栗子,经过SK初始值传参以及二次传参的天然值获取深度,同时在第三次传参的时候对两者进行边缘探测,你能够在沿着大纲略图和边缘画出清晰的轮廓:

图片描述

相关文章
相关标签/搜索