参考: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)。