美文网首页
用RealityKit实现简单Non-AR场景

用RealityKit实现简单Non-AR场景

作者: Xtuphe | 来源:发表于2023-02-06 09:36 被阅读0次

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

相关文章

网友评论

      本文标题:用RealityKit实现简单Non-AR场景

      本文链接:https://www.haomeiwen.com/subject/lqiahdtx.html