Xamarin.iOS 中的 SceneKit

SceneKit 是一个 3D 场景图 API,可简化 3D 图形的使用。 它首次是在 OS X 10.8 中引入,现已引入 iOS 8。 使用 SceneKit 创建沉浸式 3D 可视化和休闲 3D 游戏不需要 OpenGL 专业知识。 SceneKit 以常见的场景图概念为基础,抽象化了 OpenGL 和 OpenGL ES 的复杂性,使得向应用程序添加 3D 内容变得非常容易。 但是,如果你是 OpenGL 专家,SceneKit 也可以很好地支持直接与 OpenGL 结合。 它还包括许多补充 3D 图形的功能(例如物理),并能与其他几个 Apple 框架(例如 Core Animation、Core Image 和 Sprite Kit)很好地集成。

SceneKit 非常易于使用。 它是一个声明性 API,负责呈现。 只需设置场景、向其添加属性,SceneKit 就会处理场景的呈现。

若要使用 SceneKit,请使用 SCNScene 类创建场景图。 场景包含节点的层次结构,由 SCNNode 实例表示,定义 3D 空间中的位置。 每个节点都有影响其外观的属性,如几何图形、光照和材质,如下图所示:

The SceneKit hierarchy

创建场景

若要在屏幕上显示场景,可以通过将其分配给视图的 Scene 属性将其添加到 SCNView 中。 此外,如果对场景进行任何更改,SCNView 将自动更新以显示这些更改。

scene = SCNScene.Create ();
sceneView = new SCNView (View.Frame);
sceneView.Scene = scene;

场景可以从通过 3d 建模工具导出的文件填充,也可以从几何基元以编程方式进行填充。 例如,下面介绍了如何创建球体并将其添加到场景:

sphere = SCNSphere.Create (10.0f);
sphereNode = SCNNode.FromGeometry (sphere);
sphereNode.Position = new SCNVector3 (0, 0, 0);
scene.RootNode.AddChildNode (sphereNode);

添加光

此时球体不会显示任何内容,因为场景中没有光。 在 SceneKit 中,将 SCNLight 实例附加到节点可创建光。 有几种类型的光,从各种形式的定向光照到环境光照。 例如,下面的代码在球体一侧创建了一个全向光:

// omnidirectional light
var light = SCNLight.Create ();
var lightNode = SCNNode.Create ();
light.LightType = SCNLightType.Omni;
light.Color = UIColor.Blue;
lightNode.Light = light;
lightNode.Position = new SCNVector3 (-40, 40, 60);
scene.RootNode.AddChildNode (lightNode);

全向光照会产生漫反射,使得光照均匀,就像照亮手电筒一样。 创造环境光是类似的过程,但是它没有方向,因为它会均匀地照亮所有方向。 想想它就像氛围光照 :)

// ambient light
ambientLight = SCNLight.Create ();
ambientLightNode = SCNNode.Create ();
ambientLight.LightType = SCNLightType.Ambient;
ambientLight.Color = UIColor.Purple;
ambientLightNode.Light = ambientLight;
scene.RootNode.AddChildNode (ambientLightNode);

设置光后,球体现在在场景中就清晰可见了。

The sphere is visible in the scene when lit

添加相机

向场景中添加相机 (SCNCamera) 会更改视角。 添加相机的模式类似。 创建相机,将其附加到节点,并将节点添加到场景中。

// camera
camera = new SCNCamera {
    XFov = 80,
    YFov = 80
};
cameraNode = new SCNNode {
    Camera = camera,
    Position = new SCNVector3 (0, 0, 40)
};
scene.RootNode.AddChildNode (cameraNode);

如上面的代码所示,可以使用构造函数或使用 Create 工厂方法来创建 SceneKit 对象。 前者允许使用 C# 初始化表达式语法,但使用哪一种语法主要取决于个人喜好。

相机放置在合适位置时,用户可以看到整个球体:

The entire sphere is visible to the user

还可以向场景添加其他光。 下面是添加了一些其他全向光后的效果:

The sphere with a few more omnidirectional lights

此外,通过设置 sceneView.AllowsCameraControl = true,用户还可以使用触摸手势更改视角。

材质

材质是使用 SCNMaterial 类创建的。 例如,若要将图像添加到球体表面,请将图像设置为材质的漫射内容

material = SCNMaterial.Create ();
material.Diffuse.Contents = UIImage.FromFile ("monkey.png");
sphere.Materials = new SCNMaterial[] { material };

这会将图像分层放置到节点上,如下所示:

Layering the image onto the sphere

材质也可以设置为响应其他类型的光照。 例如,可以将物体照亮,并且将其镜面反射内容设置为显示镜面反射,从而在表面上产生一个亮点,如下所示:

The object made shiny with specular reflection, resulting in a bright spot on the surface

材料非常灵活,可以通过很少的代码实现很多效果。 例如,不要将图像设置为漫射内容,而是将其设置为反射内容。

material.Reflective.Contents = UIImage.FromFile ("monkey.png");

现在,视觉上看起来猴子似乎坐在球体内,不受视角影响。

动画

SceneKit 旨在很好地与动画配合使用。 可以同时创建隐式或显式动画,甚至可以从 Core Animation 层树呈现场景。 创建隐式动画时,SceneKit 提供自己的过渡类 SCNTransaction

下面是旋转球体的示例:

SCNTransaction.Begin ();
SCNTransaction.AnimationDuration = 2.0;
sphereNode.Rotation = new SCNVector4 (0, 1, 0, (float)Math.PI * 4);
SCNTransaction.Commit ();

不过,除了旋转,还可以制作更多的动画。 SceneKit 的许多属性都是可进行动画处理的。 例如,下面的代码对材料的 Shininess 进行了动画处理以增加镜面反射。

SCNTransaction.Begin ();
SCNTransaction.AnimationDuration = 2.0;
material.Shininess = 0.1f;
SCNTransaction.Commit ();

SceneKit 非常易于使用。 它提供了大量附加功能,包括约束、物理、声明性操作、3D 文本、景深支持、Sprite Kit 集成和 Core Image 集成等等。