为您的visionOS应用程序添加深度和维度,并发现如何将应用程序的内容整合到人们的环境中。
概述
带有立体显示的设备让人们以更真实的方式体验3D内容。内容似乎有真正的深度,人们可以从不同的角度观看它,让它看起来像是在他们面前。
在为visionOS构建应用程序时,请考虑如何为应用程序的界面增加深度。该系统提供了多种方式来显示3D内容,包括在现有窗口、卷和沉浸式空间中。选择最适合您的应用程序和您提供的内容的选项。



为传统的2D窗口添加深度
Windows是应用程序界面的重要组成部分。使用visionOS,应用程序会自动获取具有visionOS外观和感觉的材料,具有完全可调整大小的窗口,其间距为眼睛和手的输入进行了调整,并可以访问自定义控件的突出显示调整。

根据需要将深度效果整合到自定义视图中,并使用3D布局选项在窗口中排列视图。
• Apply a shadow(color:radius:x:y:) or visualEffect(_:) modifier to the view.
• Lift or highlight the view when someone looks at it using a hoverEffect(_:isEnabled:) modifier.
• Lay out views using a ZStack.
• Animate view-related changes with transform3DEffect(_:).
• Rotate the view using a rotation3DEffect(_:axis:anchor:anchorZ:perspective:) modifier.
除了提供更深入的2D视图外,您还可以将静态3D模型添加到2D窗口中。Model3D视图加载USDZ文件或其他资产类型,并在您的窗口中按其内在大小显示。在应用程序中已经拥有模型数据的地方使用它,或者可以从网络下载它。例如,购物应用程序可能会使用这种类型的视图来显示产品的3D版本。
使用RealityKit显示动态3D场景
RealityKit是苹果用于构建3D模型和场景的技术,您可以在屏幕上动态更新。在visionOS中,同时使用RealityKit和SwiftUI将应用程序的2D和3D内容无缝耦合。加载现有的USDZ资产或在Reality Composer Pro中创建场景,其中包含动画、物理、灯光、声音和内容的自定义行为。要在应用程序中使用Reality Composer Pro项目,请将Swift软件包添加到Xcode项目中,并在Swift文件中导入其模块。有关更多信息,请参阅在Xcode项目中管理文件和文件夹。

当您准备在界面中显示3D内容时,请使用RealityView。此SwiftUI视图作为RealityKit内容的容器,并允许您使用熟悉的SwiftUI技术更新该内容。
以下示例显示了使用RealityView显示3D球体的视图。视图闭包中的代码为球体创建一个RealityKit实体,将纹理应用于球体的表面,并将球体添加到视图的内容中。
struct SphereView: View {
var body: some View {
RealityView { content in
let model = ModelEntity(
mesh: .generateSphere(radius: 0.1),
materials: [SimpleMaterial(color: .white, isMetallic: true)])
content.add(model)
}
}
}
当SwiftUI显示您的RealityView时,它会执行一次您的代码以创建实体和其他内容。由于创建实体相对昂贵,视图只运行一次您的创建代码。当您想更新实体的状态时,请更改视图的状态,并使用更新闭包将这些更改应用于您的内容。当缩放属性中的值发生变化时,以下示例使用更新闭包来更改球体的大小:
struct SphereView: View {
var scale = false
var body: some View {
RealityView { content in
let model = ModelEntity(
mesh: .generateSphere(radius: 0.1),
materials: [SimpleMaterial(color: .white, isMetallic: true)])
content.add(model)
} update: { content in
if let model = content.entities.first {
model.transform.scale = scale ? [1.2, 1.2, 1.2] : [1.0, 1.0, 1.0]
}
}
}
}
有关如何使用RealityKit创建内容的信息,请参阅RealityKit。
响应与RealityKit内容的交互
要处理与RealityKit场景实体的交互:
•将手势识别器附加到您的RealityView,并将targetedToAnyEntity()修饰符添加到其中。
•将InputTargetComponent附加到实体或其父实体之一。
•向支持交互的RealityKit实体添加碰撞形状。
targetedToAnyEntity()修饰符在手势识别器和您的RealityKit内容之间架起了一座桥梁。例如,要识别某人何时拖动实体,请指定DragGesture并向其添加修饰符。当指定的手势发生在实体上时,SwiftUI执行提供的闭包。
以下示例将点击手势识别器添加到上一个示例的球形视图中。该代码还将InputTargetComponent和CollisionComponent组件添加到形状中,以允许交互发生。如果您省略这些组件,视图将不会检测到与您的实体的交互。
struct SphereView: View {
@State private var scale = false
var body: some View {
RealityView { content in
let model = ModelEntity(
mesh: .generateSphere(radius: 0.1),
materials: [SimpleMaterial(color: .white, isMetallic: true)])
// Enable interactions on the entity.
model.components.set(InputTargetComponent())
model.components.set(CollisionComponent(shapes: [.generateSphere(radius: 0.1)]))
content.add(model)
} update: { content in
if let model = content.entities.first {
model.transform.scale = scale ? [1.2, 1.2, 1.2] : [1.0, 1.0, 1.0]
}
}
.gesture(TapGesture().targetedToAnyEntity().onEnded { _ in
scale.toggle()
})
}
}
在Volume中显示3D内容
Volume是一种以三维方式增长的窗口,以匹配其包含的内容的大小。Windows和Volume都可以容纳2D和3D内容,并且在许多方面是相似的。然而,Windows剪辑3D内容从窗口表面延伸得太远,因此Volume是主要是3D内容的更好选择。
要创建Volume,请将WindowGroup场景添加到您的应用程序中,并将其样式设置为体积。此样式告诉SwiftUI为3D内容创建一个窗口。在Volume中包含您想要的任何2D或3D视图。您还可以添加RealityView来使用RealityKit构建内容。以下示例使用存储在应用程序捆绑包中的一些气球的静态3D模型创建一个Volume:
struct MyApp: App {
var body: some Scene {
WindowGroup {
Model3D("balloons")
}.windowStyle(style: .volumetric)
}
}
Windows和Volume是显示有界2D和3D内容的便捷方式,但您的应用程序不会控制该内容在人周围的位置。系统在显示时设置每个窗口和音量的初始位置。该系统还添加了一个窗口栏,允许某人重新定位窗口或调整其大小。

有关何时使用Volume的更多信息,请参阅人机界面指南>Windows。
在一个人的环境中显示3D内容
当您需要对应用程序内容的位置进行更多控制时,请将该内容添加到ImmersiveSpace中。沉浸式空间为您的内容提供了一个无界区域,您可以控制空间内内容的大小和位置。获得用户许可后,您还可以使用带有沉浸式空间的ARKit将内容集成到周围环境中。例如,您可以使用ARKit场景重建来获取家具和附近对象的网格,并让您的内容与该网格交互。
ImmersiveSpace是您与应用程序的其他场景一起创建的场景类型。以下示例显示了一个包含沉浸式空间和窗口的应用程序:
@main
struct MyImmersiveApp: App {
var body: some Scene {
WindowGroup() {
ContentView()
}
ImmersiveSpace(id: "solarSystem") {
SolarSystemView()
}
}
}
如果您没有在ImmersiveSpace声明中添加样式修饰符,系统将使用mixed样式创建该空间。此样式显示您的内容以及显示该人周围环境的传递内容。其他样式允许您在不同程度上隐藏直通。使用 immersionStyle(selection:in:)修饰符来指定您的空间支持哪些样式。如果您指定了多个样式,您可以使用修饰符的选择参数在样式之间切换。
警告:
注意您在使用混合风格的沉浸式场景中包含多少内容。填充屏幕很大一部分的内容,即使该内容部分是透明的,也可以防止人们看到周围环境的潜在危险。如果您想让人沉浸在您的内容中,请以完整的风格配置您的空间。有关更多信息,请参阅在应用程序中创建完全身临其境的体验。
请记住设置您放置在沉浸式空间中的物品的位置。使用修饰符定位SwiftUI视图,并使用其转换组件定位RealityKit实体。SwiftUI最初将空间的起源放在人的脚下,但可以根据其他事件改变这个起源。例如,系统可能会移动原点,以适应SharePlay活动,该活动以空间角色显示您的内容。如果您需要将SwiftUI视图和RealityKit实体相对定位,请使用RealityView内容参数中的方法执行任何所需的坐标转换。
要显示您的ImmersiveSpace场景,请使用您从SwiftUI环境获得的openImmersiveSpace操作打开它。此操作异步运行,并使用提供的信息来查找和初始化您的场景。以下示例显示了一个用太阳系标识符打开空间的按钮:
Button("Show Solar System") {
Task {
let result = await openImmersiveSpace(id: "solarSystem")
if case .error = result {
print("An error occurred")
}
}
}
当应用程序显示ImmersiveSpace时,系统会隐藏其他应用程序的内容,以防止视觉冲突。当您的空间可见时,其他应用程序保持隐藏状态,但在您关闭它时返回。如果您的应用程序定义了多个空间,您必须在显示其他空间之前关闭当前可见的空间。如果您不关闭可见空间,当您尝试打开另一个空间时,系统会发出运行时警告。
网友评论