用RealityKit实现简单Non-AR场景

参考:Quick RealityKit Tutorial 1: Programmatic non-AR Setup

可以说,SceneKit 正在被 RealityKit 取代。 为什么? 在过去的两年里,没有添加任何新功能,没有修复严重的错误,也没有在 WWDC 上提到 SceneKit。

另一方面,RealityKit 一直走在前列。 它具有巨大的潜力,但文档很少,并且缺少一些重要的功能。 就目前而言,无法设置自定义几何体,也不支持着色器。

Apple 工程师积极鼓励开发人员开始使用 RealityKit 而不是 SceneKit。 不仅适用于 ARKit 应用程序,还适用于使用“常规”3D 渲染的应用程序。

所以是时候开始研究 RealityKit 了。 大多数示例都使用 AR 和 Reality Composer,但也有需要用代码实现非AR的需求, 但是关于此的文档并不多。 我在这里和那里找到了一些片段,并决定在这个快速教程中将它们放在一起。

本示例要实现的内容:

将 HDR 贴图用于环境照明和场景背景。
以代码方式创建反射材料并将其附加到球体。
为相机创建一个动画循环,使其围绕球体旋转。

听起来很简单,但也得琢磨好一阵子。

1. 创建AR项目


在ViewController中添加

arView.cameraMode = .nonAR

这样arView就不会调用相机

2. HDR

可以从 HDRI Haven下载 HDR 图像 。 在 SceneKit 中设置 .hdr 或 .exr 图像非常简单:

scene.lightingEnvironment.contents = "myhdrimage.hdr"

但 RealityKit 中有点不同。 首先,您必须创建一个文件夹(在 Finder 中),其名称和后缀为 .skybox。 例如 /aerodynamics_workshop.skybox 。 然后将 .hdr 或 .exr 文件放入其中,并将文件夹拖到 Xcode 中的项目导航器中。 选择“Create folder references”并"Copy items if needed"。 Xcode 会将图像编译为环境资源。

此资源现在可用于环境照明和场景背景。 可以使用不带扩展名的文件名来引用资源:

let skyboxName = "room_hdr" // The .exr or .hdr file
let skyboxResource = try! EnvironmentResource.load(named: skyboxName)
arView.environment.lighting.resource = skyboxResource
arView.background = .skybox(skyboxResource)

请注意与 SceneKit 的 SCNMaterialProperty 的区别:在这里您将以更一致的方式设置环境:

scene.lightingEnvironment.contents = "myhdrimage.hdr"
scene.background.contents = "myhdrimage.hdr"

3.创建一个球体

现在我们要在场景中添加一个反射球体。 首先我们将创建一个材质:

var sphereMaterial = SimpleMaterial()
sphereMaterial.metallic = MaterialScalarParameter(floatLiteral: 1)
sphereMaterial.roughness = MaterialScalarParameter(floatLiteral: 0)

现在我们可以使用 MeshResource 的静态方法之一来创建我们的球体基元并分配我们刚刚创建的材质:

let sphereEntity = ModelEntity(mesh: .generateSphere(radius: 1),
                               materials: [sphereMaterial])

现在我们需要创建一个 AnchorEntity ,将它放在场景的中心,添加 sphereEntity 作为child,然后将锚点实体添加到场景中:

let sphereAnchor = AnchorEntity(world: .zero)
sphereAnchor.addChild(sphereEntity)
arView.scene.addAnchor(sphereAnchor)

4.创建和动画相机

最后一件事是添加透视相机, 在观察球体中心的同时为其制作一个圆圈的动画。

创建和添加相机很简单:

let cameraEntity = PerspectiveCamera()
cameraEntity.camera.fieldOfViewInDegrees = 60
let cameraAnchor = AnchorEntity(world: .zero)
cameraAnchor.addChild(cameraEntity)
arView.scene.addAnchor(cameraAnchor)

创建自定义动画需要在 RealityKit 中做更多工作。 如果实体实现了 HasTransform 协议,则它们可以被动画化。 该协议定义了几个 .move() 方法。 可以将转换以及持续时间和动画计时函数传递给这些方法。 这对于简单的动画来说很好,但要完成一些不同的事情,我们必须hook到渲染循环中。

在 SceneKit 中,可以使用delegate hook到渲染循环的不同阶段,以在 SceneKit 渲染线程中执行代码。 在 RealityKit 中,我们可以通过subscribe SceneEvents.update 来做同样的事情。

首先我们必须导入 Combine 框架。 Combine 通过组合事件处理运算符来定制异步事件的处理。

import Combine

接下来我们需要创建一个实例变量,该变量将保存对 Cancellable 对象的强引用。 如果这是一个方法变量,它就不会工作,因为它会立即被释放。

private var sceneEventsUpdateSubscription: Cancellable!

现在我们可以订阅每帧间隔触发一次的 SceneEvents.Update:

sceneEventsUpdateSubscription = arView.scene.subscribe(to: SceneEvents.Update.self) { _ in
    // do stuff 
}

现在我们可以使用它来创建我们的自定义相机动画:

let cameraDistance: Float = 3
var currentCameraRotation: Float = 0
let cameraRotationSpeed: Float = 0.01
sceneEventsUpdateSubscription = arView.scene.subscribe(to: SceneEvents.Update.self) { _ in
    let x = sin(currentCameraRotation) * cameraDistance
    let z = cos(currentCameraRotation) * cameraDistance
    let cameraTranslation = SIMD3<Float>(x, 0, z)
    let cameraTransform = Transform(scale: .one,
                                    rotation: simd_quatf(),
                                    translation: cameraTranslation)
    cameraEntity.transform = cameraTransform
    cameraEntity.look(at: .zero, from: cameraTranslation, relativeTo: nil)
    currentCameraRotation += cameraRotationSpeed
}

在这里,我们通过使用 sin 和 cos 来计算相机的位置来建立圆周运动。 我们直接设置相机的变换,并确保相机看向球体所在的场景中心 (.zero)。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容