VisionOS文档翻译与实践3-向你的应用添加3D内容

深化并拓展你的visionOS应用,并探索如何将你的应用内容整合到用户的环境中。

概述

配备立体显示的设备让人们以更真实的方式体验3D内容。内容呈现出真实的深度,人们可以从不同的角度观看,使其看起来就像在他们面前一样。

当为visionOS构建应用时,思考你可能会如何增加应用界面的深度。系统提供了多种显示3D内容的方式,包括在你现有的窗口中、在体积中和在沉浸式空间中。选择最适合你的应用和你提供的内容的选项。

窗口

空间容器元素(volume)

沉浸式空间(immersive space)

在传统的2D窗口中添加深度

窗口是应用界面的重要部分。对于visionOS,应用自动获得具有visionOS外观和感觉的材质,完全可调整大小的窗口,以及用于你的自定义控制的高亮度调整。

视频

在需要的时候,将深度效果整合到你的自定义视图中,并使用3D布局选项来在你的窗口中排列视图。

  • 应用shadow(color:radius:x:y:)或visualEffect(_:)修改器到视图上。
  • 当有人看向视图时,使用hoverEffect(_:isEnabled:)修改器来提升或突出视图。
  • 使用ZStack来布局视图。
  • 使用transform3DEffect(_:)来动画化与视图相关的改变。
  • 使用rotation3DEffect(_:axis:anchor:anchorZ:perspective:)修改器来旋转视图。

除了给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时,它只执行一次你的代码以创建实体和其他内容。因为创建实体相对昂贵,所以视图只运行一次你的创建代码。当你想要更新你的实体的状态时,改变你的视图的状态,并使用一个更新闭包来将这些改变应用到你的内容中。下面的示例使用一个更新闭包来改变球体的大小,当scale属性的值改变时:

struct SphereView: View {




    @State 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。

然后将onChanged(_:)onEnded(_:) 修改器附加到手势以响应交互。下面的示例为RealityView添加一个拖动手势,它改变了offset状态的值:

struct DraggableView: View {
    @GestureState var offset: SIMD3<Float> = [0, 0, 0]


    var body: some View {
        RealityView { content in
                     let model = ModelEntity(
                mesh: .generateSphere(radius: 0.1),
                materials: [SimpleMaterial(color: .white, isMetallic: true)])
                     model.components[InputTargetComponent.self] = InputTargetComponent()
                     content.add(model)
                    } update: { content in
                   if let model = content.entities.first {
                model.transform.translation += offset
            }
                  }
        .gesture(
            DragGesture()
            .updating($offset, body: { (value, state, _) in
                                          state = [Float(value.translation.width), -Float(value.translation.height), 0]
                                         })
            .onEnded({ _ in
                          self.offset = [0, 0, 0]
                         })
        )
    }
}

在这个例子中,DragGestureupdating(_:, body:) 修改器在拖动手势改变时更新offset状态。当拖动手势结束时,onEnded(_:) 修改器重置offset状态为原始值。

为支持交互的RealityKit实体添加碰撞形状。碰撞形状定义了实体的物理形状,并允许RealityKit正确地处理与实体的交互。在创建你的实体时,使用generateCollisionShapes(recursive:) 函数来自动为你的实体和其所有子实体生成碰撞形状。

请注意,你可以使用SwiftUI的 @GestureState属性来跟踪手势的状态,然后在你的update闭包中使用这个状态来更新你的RealityKit实体。

为了更深入地了解如何在你的应用中使用RealityKit,可以参阅RealityKit文档

在空间容器元素中显示3D内容

空间容器元素是一种窗口类型,其在三个维度上增长以匹配其所包含的内容大小。窗口和空间容器元素都可以容纳2D和3D内容,并且在很多方面都相似。然而,窗口会裁剪超出窗口表面的3D内容,所以对于主要是3D的内容,空间容器元素是更好的选择。

创建空间容器元素,需要在你的应用中添加一个WindowGroup场景,并将其样式设置为空间容器元素样式。这种样式告诉SwiftUI创建一个用于3D内容的窗口。在你的空间容器元素中包含任何你想要的2D或3D视图。你也可以添加一个RealityView来使用RealityKit构建你的内容。下面的示例创建了一个空间容器元素,其中包含存储在应用程序包中的一些气球的静态3D模型:

struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            Model3D("balloons")
        }.windowStyle(style: .volumetric)
    }
}

窗口和空间容器元素是显示有界2D和3D内容的便捷方式,但是你的应用并不能控制那些内容在人的环境中的位置。系统在显示时间设置每个窗口和体积的初始位置。系统还添加了一个窗口条,以便人们重新定位窗口或调整其大小。

对于何时使用体积的更多信息,请参见人机接口指南 > 窗口

在人的环境中显示3D内容

当你需要对你的应用内容的位置有更多的控制时,将那些内容添加到一个沉浸式空间。沉浸式空间提供了一个无边界的区域用于你的内容,并且你可以控制空间内内容的大小和位置。在得到用户的许可后,你还可以使用ARKit与沉浸式空间一起,将内容融入他们的环境。例如,你可以使用ARKit场景重建获取家具和附近物体的网格,并让你的内容与该网格进行交互。

沉浸式空间是你创建的与应用的其他场景相同的场景类型。以下示例显示了一个应用,该应用包含一个沉浸式空间和一个窗口:

@main
struct MyImmersiveApp: App {
    var body: some Scene {
        WindowGroup() {
            ContentView()
        }


        ImmersiveSpace(id: "solarSystem") {
            SolarSystemView()
        }
    }
}

如果你不在你的ImmersiveSpace声明中添加一个样式修饰符,系统会使用混合样式创建该空间。这种样式将你的内容与显示人的环境的透视内容一起显示。其他样式让你可以在不同程度上隐藏透视内容。使用immersionStyle(selection:in:) 修饰符来指定你的空间支持的样式。如果你指定了多种样式,可以使用修饰符的选择参数在样式之间切换。

警告:

请注意你在使用混合样式的沉浸式场景中包含的内容有多少。即使那些内容部分透明,也能填满屏幕的一大部分,这可能会阻止人看到他们环境中的潜在危险。如果你想让人沉浸在你的内容中,使用完全样式配置你的空间。更多信息,请参见,创建应用中的全沉浸式体验

记得设置你在ImmersiveSpace中放置的项目的位置。使用修饰符设置SwiftUI视图的位置,并使用其变换组件设置RealityKit实体的位置。SwiftUI最初在人的脚下设置空间的原点,但可以响应其他事件更改此原点。例如,系统可能会移动原点以适应使用空间化角色显示你的内容的SharePlay活动。如果你需要将SwiftUI视图和RealityKit实体相对于彼此定位,使用RealityView内容参数中的方法进行所需的坐标转换。

要显示你的ImmersiveSpace场景,使用从SwiftUI环境获取的openImmersiveSpace动作来打开它。此动作异步运行,并使用提供的信息查找并初始化你的场景。以下示例显示了一个打开带有solarSystem标识符的空间的按钮:

Button("Show Solar System") {
    Task {
        let result = await openImmersiveSpace(id: "solarSystem")
        if case .error = result {
            print("An error occurred")
        }

    }
}

当应用展示ImmersiveSpace时,系统会隐藏其他应用的内容以防止视觉冲突。当你的空间可见时,其他应用保持隐藏,但当你关闭它时,它们会返回。如果你的应用定义了多个空间,你必须先关闭当前可见的空间,然后才能显示不同的空间。如果你没有关闭可见的空间,当你试图打开其他空间时,系统会发出运行时警告。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYxQKO2b' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片