探索用于通过 compositor services 打造沉浸式 app 的 metal 渲染的最新改进。了解如何通过添加悬停效果来突出展示 app 的交互式元素,以及如何通过动态渲染质量实现更高保真度的渲染。了解新的 progressive 沉浸样式。探索如何通过将 mac 中的 metal 内容直接渲染至 vision pro,来为 macos app 提供沉浸式体验。

要充分利用好本次讲座,请先观看 wwdc23 讲座“探索 metal 技术打造沉浸式 app”。

视频封面
视频地址

此文章由AI生成,可能存在错误,如有问题,请联系djs66256@163.com

用于打造沉浸式 App 的 Metal 渲染新功能

苹果在 WWDC 上展示了通过 Compositor Services 打造沉浸式应用的 Metal 渲染最新改进。这些新功能包括悬停效果、动态渲染质量和渐进式沉浸风格,为开发者提供了更丰富的工具来提升应用交互性和视觉效果。

新渲染循环 API

Metal 沉浸式应用的渲染流程始于新的渲染循环 API。开发者需要创建包含合成器层的沉浸空间,该层提供用于渲染循环的层渲染器对象。今年的 Compositor Services 新增了返回数组的 queryDrawables 函数,根据系统上下文,该数组将包含 1 或 2 个 drawables。

// 场景渲染循环
extension Renderer {
    func renderFrame(with scene: MyScene) {
        guard let frame = layerRenderer.queryNextFrame() else { return }
        
        frame.startUpdate()
        scene.performFrameIndependentUpdates()
        frame.endUpdate()
        
        let drawables = frame.queryDrawables()
        guard !drawables.isEmpty else { return }
        
        guard let timing = frame.predictTiming() else { return }
        LayerRenderer.Clock().wait(until: timing.optimalInputTime)
        frame.startSubmission()
        scene.render(to: drawable)
        frame.endSubmission()
    }
}

悬停效果

新的悬停效果功能让用户能直观看到哪些对象可交互。系统会动态高亮用户注视对象,为应用和游戏添加更丰富的交互细节。

开发者需要在层配置中设置追踪区域格式:

// 层配置
struct MyConfiguration: CompositorLayerConfiguration {
    func makeConfiguration(capabilities: LayerRenderer.Capabilities,
                           configuration: inout LayerRenderer.Configuration) {
        let trackingAreasFormat: MTLPixelFormat = .r8Uint
        if capabilities.supportedTrackingAreasFormats.contains(trackingAreasFormat) {
            configuration.trackingAreasFormat = trackingAreasFormat
        }
    }
}

对象渲染时需要处理悬停效果:

// 对象渲染函数
extension MyObject {
    func render(drawable: Drawable, renderEncoder: MTLRenderCommandEncoder) {
        var renderValue: LayerRenderer.Drawable.TrackingArea.RenderValue? = nil
        if self.isInteractive {
            let trackingArea = drawable.addTrackingArea(identifier: self.identifier)
            if self.usesHoverEffect {
                trackingArea.addHoverEffect(.automatic)
            }
            renderValue = trackingArea.renderValue
        }
        self.draw(with: commandEncoder, trackingAreaRenderValue: renderValue)
    }
}

Metal 片段着色器需要同时输出颜色和追踪区域值:

// Metal 片段着色器
struct FragmentOut
{
    float4 color [[color(0)]];
    uint16_t trackingAreaRenderValue [[color(1)]];
};

fragment FragmentOut fragmentShader( /* ... */ )
{
    return FragmentOut {
        float4(outColor, 1.0),
        uniforms.trackingAreaRenderValue
    };
}

动态渲染质量

动态渲染质量功能允许应用根据场景复杂度调整内容分辨率。开发者可以指定适合应用的最大渲染质量,并根据显示内容类型在运行时调整质量。

// 质量常量
extension MyScene {
    struct Constants {
        static let menuRenderQuality: LayerRenderer.RenderQuality = .init(0.8)
        static let worldRenderQuality: LayerRenderer.RenderQuality = .init(0.6)
        static var maxRenderQuality: LayerRenderer.RenderQuality { menuRenderQuality }
    }
}

层配置中需要设置最大渲染质量:

// 层配置
struct MyConfiguration: CompositorLayerConfiguration {
    func makeConfiguration(capabilities: LayerRenderer.Capabilities,
                           configuration: inout LayerRenderer.Configuration) {
       if configuration.isFoveationEnabled {
           configuration.maxRenderQuality = MyScene.Constants.maxRenderQuality
       }
    }
}

运行时可以根据场景类型调整渲染质量:

// 设置运行时渲染质量
extension MyScene {
    var renderQuality: LayerRenderer.RenderQuality {
        switch type {
        case .world: Constants.worldRenderQuality
        case .menu: Constants.menuRenderQuality
        }
    }
}

extension Renderer {
    func adjustRenderQuality(for scene: MyScene) {
        guard layerRenderer.configuration.isFoveationEnabled else { return }
        layerRenderer.renderQuality = scene.renderQuality
    }
}

渐进式沉浸

渐进式沉浸风格允许用户通过旋转 Digital Crown 控制沉浸程度。系统仅渲染当前沉浸级别内的内容,通过门户模板屏蔽外部内容,节省计算资源。

相关资源

开发者可以通过以下资源深入了解这些新功能:

相关视频:

文档: