大多数浏览器和
Developer App 均支持流媒体播放。
-
利用 RealityKit 音频让空间计算 App 更加引人入胜
利用 RealityKit 音频提升空间计算体验。探索如何利用空间音频打造身临其境般的沉浸式 3D 体验。从环境音频和混响,到能够让 3D 内容更显个性的程序化实时音频,了解 RealityKit 音频 API 如何帮助你打造更引人入胜的 App。
章节
- 0:00 - Introduction
- 2:01 - Spatial audio
- 11:43 - Collisions
- 16:57 - Reverb presets
- 18:24 - Immersive music
- 20:41 - Mix groups
资源
相关视频
WWDC24
-
下载
大家好 我叫 James 就职于 RealityKit 音频团队 今天 我们将聊聊 RealityKit 中的部分全新音频 API 它们将使你的 空间计算体验 更具互动性和沉浸感 我的同事 Yidi 一直在开发一款游戏 在这款游戏中 你可在真实环境下 乘坐虚拟太空飞船 除了真实的环境 你甚至还可在自定虚拟环境中 或是通过一扇通往外太空的传送门 来实现这一体验 这款 App 采用全新的 SpatialTrackingService API 来流畅地追踪 用于操纵太空飞船的手势
它利用全新的物理特效 比如力效应 来打造一个 日益变化莫测的小行星带
并利用物理关节来连接一个 运载贵重货物的拖车 当你飞得过快时 这个拖车就会来回摆动 此外 它还利用全新的 传送门穿越组件 这样你就能驾驶太空飞船 穿越一个传送门进出外太空
其中每个新功能 都能激发 虚拟与现实之间的动态互动
请观看讲座“探索适用于 iOS、macOS 和 visionOS 的 RealityKit API” 进一步了解 这款游戏的构建过程 在本讲座中 我将借助 RealityKit 音频的强大功能来 大幅提升这款游戏的沉浸感和互动性 现在 我们就来探索一下具体方法
本讲座下方列出了示例项目的链接 你可以把它下载下来跟着一起操作 首先 我会使用音频文件播放功能 以及实时生成的音频 将空间音频添加到太空飞船 接下来 我会为虚拟物体之间的碰撞 以及虚拟对象与真实对象之间的碰撞 添加空间音频 然后 我会在沉浸式环境中 加入混响 以便随太空飞船 前往一片新的太空 我会使用环境音频来播放音乐 以营造氛围 最后 我会让观众 使用音频混音组 根据自己的喜好来调整音效 首先 我们来处理一下 太空飞船自身的音频 为与自身的视觉效果相呼应 太空飞船采用了多层次的声音设计
太空飞船共有两个引擎 每个引擎都有一条水汽尾迹、 一个排气管和一台涡轮机 在视觉领域 水汽尾迹是一种粒子效果 无论油门有多大它都会喷射 而排气尾迹则会 随着太空飞船的油门变大而变长 对于涡轮机 则没有具体的视觉表现 因为它包裹在太空飞船的船体内 但我们可通过声音设计 来呈现那些看不见的物体 对于水汽尾迹 我会播放一段较柔和的噪音 而无论油门有多大 这个噪音的响度始终保持不变 对于排气管 我会播放一段 更粗犷有力的噪音 这个噪音会随油门变大而提高音量 对于涡轮机 我会动态生成一段声音 声音的参数 取决于油门 现在 我们来快速听一听
首先 我们会听到 水汽尾迹音频 当尾迹转动并远离我们时 这个声音就会变得略轻和低沉 然后 我会打开排气管 并操纵油门 现在 大家可以听到 随着油门变大 声音会变大
我们看看如何在代码中实现这个效果
我将通过 App 套装来加载 水汽尾迹音频文件 然后 我会立即使用 Entity.playAudio 通过引擎实体来播放这个音频
RealityKit 中的音频播放 默认采用空间音效 只需几行代码 我们的音频便可 以六个自由度进行渲染 于是 当你或音频源发生移动或旋转时 音频的音量或音调便会更新 由于它们会根据 物理距离发生衰减 因此当音频源 远离你时 音量便会自然而然地减弱
最后 空间音频源 还对音频应用了混响效果 这个效果是通过实时模拟 真实环境生成的
需要注意的一点是 以空间音效播放 的音频在进行空间化处理之前 会缩混为 一个单声道 因此 建议编写单声道文件 以确保不会在空间渲染期间 添加多余的缩混项目
我们的水汽尾迹音频文件较短 并且被设计为无缝循环播放 不含任何爆音和杂音 你可设置 AudioFileResource.Configuration 的 shouldLoop 属性 以便在播放这个短文件时 能产生连续噪声的效果
我要通过两个引擎来播放 同一个较短的循环文件 通过设置 shouldRandomizeStartTime 属性 当两个引擎都发出声音时 它们将从这个文件 的不同位置开始播放 通过将循环播放与开始播放时间 随机化功能结合使用 我们可在高效利用资源的同时 提供丰富的音频体验 由于水汽尾迹杂音音频文件 被设计为无缝循环播放 因此它会突然之间就开始播放 通过对音频进行淡入处理 我们可以优化音频体验 首先 我们需保留 Entity.playAudio 方法 返回的 AudioPlaybackController
AudioPlaybackController 就像一个遥控器 用于控制通过某一实体 播放的 AudioResource 的 特定声音事件实例 每次调用 Entity.playAudio 或 Entity.prepareAudio 时 都会返回一个AudioPlaybackController 你可以选择保留这个对象 以便进行配置 或是进行传输控制 比如在运行时播放、暂停和停止 接着 我会将 gain 设为 -.infinity AudioPlaybackController 的 gain 属性以相对分贝为单位 其中 -.infinity 表示静音 而 zero 则表示名义上音量较高 所有声音的 上限均为零分贝
然后 我会调用 AudioPlayback Controller.fade(to:duration:) 方法 这样声音就能在一秒内 淡入为零分贝
虽然我们会播放水汽尾迹音频 但在驾驶太空飞船时 我们希望这个音频听起来自然又灵动 例如 当太空飞船的引擎 正对我们时 我们需要听到引擎声的 各种细节 但是 当飞船引擎 背对我们时 引擎声应变得更小声、更低沉 接着 我将通过 SpatialAudioComponent 和 directivity 来配置引擎的空间渲染效果
首先 我会添加一个新的 Entity() 它仅代表 audioSource 接下来 我会将它 添加为引擎的子项 接着 我会通过 audioSource 而不是引擎来播放音频
我将为 audioSource 实体 设置一个 SpatialAudioComponent 然后 我会将 SpatialAudioComponent的 directivity 设为焦距为 0.25 的波束模式
指向性定义了音频从空间音频源 进行传播的方式 波束指向性模式的作用范围 从 0 到 1 其中 0 表示全向 也就是所有声音均以 相同的音调向各个方向传播 1 则表示窄波束模式 此时声音在后方会比在前方 更为小声和低沉
最后 我会旋转 audioSource 以便声音 能从排气管所在的 引擎排气孔发出 现在 随着飞船的旋转 我们会听到音量和音调的变化
通过 SpatialAudioComponent 可以设置空间音频源的 方向特性 此外 你还可通过它为从一个实体 发出的所有声音事件设置响度 由于 SpatialAudioComponent 遵从 Component 协议 因此它在自定系统环境下 有助于动态控制 某一音频源的响度 例如 单个油门值可驱动 太空飞船的物理特效、图形和音频 当油门值为 0 时 引擎的排气声会静音 当油门值为 1 时 则会达到最高响度 油门值还会在 这两个极值之间进行插值 我有一个自定音频系统 每次更新时它都会读取油门值 将线性油门值中的值 映射为对数分贝数 然后用这个分贝值 更新 SpatialAudioComponent 的 gain 属性 这样一来 太空飞船音频的实现 就会变得更加动态化 当太空飞船飞来飞去时 我们就能随指向性模式的变化 而听到响度和音调的变化 在加减油门时 排气声也相应变强或减弱 在蓝色光晕和噪音的背后 有一对涡轮机 加减油门时 虽然我们 看不到它们 但却能听到 它们在加速或减速
在 Hangar 视图中 我们会加速太空飞船的涡轮机 来听听它们会发出怎样的声音 请注意这个声音的频率 会如何随着油门的变化而变化
现在 我们来看看如何通过代码 完成这个音效
首先 我会使用一个方法 来接收代表某一引擎的 Entity 然后 我会调用 Entity.playAudio 方法的变体 我不会播放这个 Entity 中的 音频资源 而是提供一个回调 通过这个回调 我可将样本直接写入 音频系统所渲染的缓冲区中 这个 Entity.playAudio 变体 会返回 AudioGeneratorController App 必须保留这个返回的对象 才能继续播放这个音频
对于使用 AudioGeneratorController 写入的音频缓冲区 它们的作用就像是 在实体上播放的音频资源 默认情况下 播放会采用空间音效 但你可配置这些实体的 空间、环境与通道音频组件 来控制缓冲区的渲染 就像处理 音频文件播放一样
我们的 App 中有一个名为 AudioUnitTurbine 的自定 audioUnit 这个 audioUnit 有一个 Objective-C 接口 它的渲染块中附带了 实时安全代码 AudioUnitTurbine 有一个 介于 0 到 1 之间的油门值 audioUnit 实现会使用这个值 来驱动多个振动器 首先 我会对这个音频单元 使用 instantiate() 接下来 我会准备 AudioGeneratorController 的配置 然后 我会创建 audioUnit 输出的格式 并在 audioUnit.outputBusses 上 进行设置 随后 我会分配这个音频单元的渲染资源 然后捕获 audioUnit.internalRenderBlock 接下来 我会 通过音频生成器配置 来配置 AudioGeneratorController
最后 我会对 音频生成器回调中 提供的音频数据调用 audioUnit.internalRenderBlock
借助附带 AudioGeneratorController 的实时音频 你可通过 Apple 提供的音频单元、 自定音频单元 00:09:55.914 --> 00:10:00.177 或是你自己的音频引擎输出 来传输音频
这个音频将由 RealityKit 和 visionOS 提供的 光线追踪空间音频进行渲染 无论你如何生成声音 它们都具有共享空间中的声学效果 以及与其他系统声音 相一致的混合沉浸式空间、 渐进沉浸式空间和全沉浸式空间音效
RealityKit 中的音频播放 默认采用空间音效 而且我们已 竭尽全力让默认音效 达到尽可能自然的效果 当然 由于我们的太空飞船 会在现实与虚拟之间遨游 因此我们可以为它搭配一些物理特效 例如 当太空飞船飞近我们时 我们可以透过它的窗户听到 从驾驶舱传出的微弱音乐声 我们来听听看
如果我们要用默认空间音频组件参数 来播放这个音轨 则总是会听到 立体声播放 通过自定空间音频组件的距离衰减值 我们就能实现 所需的效果
通过自定距离衰减值 你可让某些声音只有在离声源 很近时才能听到 此外 你还可通过自定 让声音在离你很远时 00:11:07.800 --> 00:11:09.553 也能被听到
滚降系数 1 是 空间音频源的自然默认值 将滚降系数设为 2 会使声音 以自然衰减速度的两倍进行衰减 而将滚降系数设为 0.5 则会让声音 以自然衰减速度的 0.5 倍衰减 现在 我们来为音频 配置距离衰减值
在这里 我会将 distanceAttenuation 的 滚降系数设为 4 这样 当太空飞船离我们非常近时 我们只能听到某些声音 接着 我会调低 这个空间音频源的增益 这样 只有当太空飞船离我们很近时 才能听到它传出的音乐声 接下来 我们看看 当内容中的实体相互碰撞时 它们会如何发出声音 首先 我们来听一听 注意听一听当太空飞船 撞击到混凝土地面、 木箱、金属横梁或玻璃时 会发出怎样的声音
太空飞船可能会撞击到 小行星等移动的虚拟物体 以及静态虚拟物体 例如工作室环境中的 水泥地面、木质方块和金属横梁 在混合沉浸感体验中 太空飞船可能会与 通过你周围的真实物体 所重建的网格环境发生碰撞 通过在我们的 App 中整合 由物理材料产生的音频 我可让这些碰撞 更具震撼效果
首先 我需要 响应 CollisionEvents 为此 我会编写一个用于处理 .Began 碰撞事件的方法 这个事件会提供 有关两个实体之间碰撞的信息 我会检索已经加载的 AudioFileResource 然后 在发生碰撞的 第一个实体上播放这个对象
这是一个不错的开端 但它也意味着 每当任意两种物体发生碰撞时 都会以同一响度来播放同一声音 而不论这两种物体的 碰撞程度有多严重 通过使用 AudioFileGroupResource 我可以优化我们的实现 AudioFileGroupResource 由 一组音频文件资源构成 每次通过 AudioFileGroupResource 调用 Entity.playAudio 时 都会播放随机选取的 音频文件资源 对于碰撞音频 我可以加载一组声音 这些声音都是 同一声音事件的细微变体
这样 每当两个物体碰撞时 发出的声音也会自然地发生变化
太空飞船和小行星 都是极其多变的 它们的移动速度可快可慢 因此当它们发生碰撞时 碰撞声的响度 应能真实反映撞击的强度
就像我们在处理 水汽尾迹音频的淡入效果时那样 我会通过调用 Entity.playAudio 来检索音频播放控制器 然后 我会将 AudioPlaybackController 的增益 设为根据这两个实体的速度 计算得出的增益水平
这样可确保当这两个物体 发生高速正面碰撞时 碰撞声能足够震撼人心
而如果它们以低速碰撞 则碰撞声会 适当衰减
在当前实现中 我将同一组声音用于 发生碰撞的任意两个物体 当太空飞船与小行星、 电脑屏幕或植物发生碰撞时 我可以发出专为这个碰撞所涉及的 两种材料而定制的声音
首先 我会定义一组声音 以便在我们的 App 中 与它们进行交互 例如 我们的太空飞船 由塑料制成 而小行星由岩石构成 工作室环境中的各种表面 均标记了所用的材料 比如混凝土、木头、金属和玻璃
在 App 中 我会定义一个 AudioMaterial 枚举和一个自定 AudioMaterialComponent 其中储存了某一实体的 AudioMaterial 接着 设置我们希望 从中发出碰撞声的 所有虚拟物体的 AudioMaterialComponent 例如 我会设置 小行星的岩石音频素材 以及太空飞船的 塑料音频素材
当两个虚拟物体发生碰撞时 我会先尝试读取对这些物体 设置的 audioMaterials 然后 我会从一组已通过 audioMaterials 配对 来加载并创建索引的 AudioFile GroupResources 中进行选取 因此 太空飞船与小行星 的碰撞声 可由塑料和岩石 共同产生 而太空飞船与 这张桌子之间的碰撞声 可由塑料和木头来产生
现在 我们的实现支持 当虚拟物体 相互碰撞时发出音频 由于虚拟工作室环境中的表面 均标记有材料 因此当太空飞船与 这些表面或物体 发生碰撞时 我们便可提供自定的碰撞声 但是 我们并不一定 要将自己局限于虚拟空间 我们还可将同一行为 添加到现实空间 中的表面和物体 我们可使用源自现实环境的 ARKit 场景重建网格 其中提供了网格分类类型 可用于识别室内的 不同表面和物体 然后关联到太空飞船与 它们相撞时所播放的某种声音 现在 我们来看看 如何实现这一行为
首先 我需要确定 动态物体将与 网格的哪个表面碰撞 接下来 我需读取 这个特定表面的网格分类 然后 我会将这个网格分类 映射到自定音频素材枚举 现在 我可为虚拟物体与真实物体的 两种材料 播放正确的声音 我们来听听这些动态物体 与我们身边的现实世界 发生碰撞时会发出哪些声音 请注意 当太空飞船与 不同类型的物体碰撞时 会发出不同的碰撞声 例如 当太空飞船与桌子、 iMac 或椅子相撞时 听听分别会发出什么声音
太棒了! 不得不说 在这个 沉浸式的工作室环境中 在现实世界中驾驶太空飞船 的体验与在 飞来飞去的小行星之间 进行穿梭一样有趣
进入这个虚拟空间时 我们发现虚拟物体 会通过基于图像的自定灯光 以不同的方式点亮 对于音频 我们也应实现这样的效果 这样虚拟音频源 听起来就像是 投射到 这个虚拟环境中 而不是我现在所处的室内 我们可使用新的 ReverbComponent 和混响预设 来营造一个全新的声学世界 为此 只需将 ReverbComponent 置于 实体层次结构中的某个位置 一次只有一个混响处于活动状态 根据你的工作流程 你可将这个内容制作到 Reality Composer Pro 中的个人场景内 或是使用 RealityKit API 就像这里显示的一样 在 visionOS 1 中 RealityKit 中的 所有空间音频均会进行混响处理 而这依据的是 现实世界的实时模拟声学效果 这个特性适用于 混合式沉浸用例 在这些用例中 用户可通过 视觉透视功能看到真实的周边环境 混合式沉浸用例中的音频 应做到听感与观感协调一致: 仿佛它们就位于用户的空间内
借助 visionOS 2 中的 这些全新混响预设 你可通过渐进沉浸式空间和 全沉浸式空间 将用户带入 一个世外桃源 在渐进沉浸式环境中 根据实际的沉浸程度 用户的真实声学效果 会与混响预设有效融合 而在完全沉浸式环境中 空间音频源只能通过 ReverbComponent 的预设集 进行混响处理 请观看今年 WWDC 由 Jonathan 主讲的讲座 “在自定环境中 提升媒体观赏体验的沉浸度” 了解我们如何 将混响融入到 Destination Video 示例中的 Reality Composer Pro 软件包内 现在 我们来看看如何 通过环境音乐播放来设置氛围
当我们进入 App 的某些阶段时 会播放契合特定心情 的不同音乐
例如 在 Joy Ride 阶段 我们会听到好似漂浮在半空中的 轻快、空灵的音乐 但进入 Work 阶段时 音乐在播放时会加入动感
太空飞船有一个重要特性 那就是它可以绕着你飞行 而不仅仅是在你面前飞行 新的行星可能会在你身后形成 因此你需要环顾四周 我们希望无论太空飞船驶向何处 音乐总能相伴左右 此外 我们希望音乐 没有明显的前进方向感 因为这可能会 削弱 App 的空间感 同时我们还希望 这个音频文件的声道 来自世界锁定的方向 这样我们就不会觉得 它是我们头脑幻想出来的
我们制作了一首 包含四个声道的音轨 并采用了名为 “四声道”的声道布局 四声道布局 可在你的四周 均匀分布四个声道 因此不会产生明显的前进方向感 这个问题常出现在 专为影院级演示而设计的 其他多声道布局中 我们在创作音乐时 会确保在各个声道之间 均匀分配音频信号 这样无论你看向哪里 都能产生均衡的混音效果 此外 我们还确保各种音轨 比如引擎的 水汽尾迹声和排气声 都能无缝循环播放 而不出现任何爆音和杂音 现在 我们来看看如何 通过 RealityKit 将这个音轨 整合到我们的 App 中
对于已加载到 RealityKit 中的 多声道音频文件 必须将它们的 声道布局写入这个文件 否则 RealityKit 就无法 从正确的角度 渲染这个音频文件的各个声道 此外 我将 loadingStrategy 设为 .stream 而不是 默认的 preload stream 加载策略将对磁盘中的 音频数据进行流式传输 从而实时解码 而 preload 加载策略则会 加载音频数据并对这些数据进行解码 以作为加载流程的一部分 stream 加载策略可减少内存使用量 但可能会产生额外延迟 我们的环境音乐 并不像碰撞声那样 具有严格的延迟要求 但由于环境文件很大 因此 stream 加载策略 最适合这个用例 然后 我会设置音乐播放实体的 AmbientAudioComponent() 环境音频源经渲染后 会有三个自由度 源与头部旋转可观察到 但平移则不然 我们的 App 已有 好几种音频类别 根据当下的心情 有时我想同时听到 太空飞船发出的动态音频、 碰撞声和音乐 但有时我却只想听到音乐 App 中的混音器 可用于分别控制 每个音频类别的音量 这样 当我沉浸于飞翔的快感时 就能营造出完美的氛围 我们来看看具体的做法
首先 我会调低音乐音量
接下来 我会调低行星声调
最后 我会调低 太空飞船发出的声音
现在 恢复行星声调
然后在混音中加入音乐
现在 我们看看 如何在代码中实现这个效果 首先 加载 音乐音频资源 在 AudioFileResource 配置中 将 mixGroupName 属性 设为“Music” 它将作为我们在混音器中 调整的混音组的名称 混音组会控制 App 中 所有音乐资源的音量 接下来 创建一个 Entity 用于存储 AudioMixGroupsComponent 为混音组更新音量时 我会创建 AudioMixGroup 并设置它的增益 最后 我会构建 AudioMixGroupsComponent 并对 audioMixerEntity 设置这个对象 你可使用 UI 更新 来更新 AudioMixGroupsComponent 就像我之前的操作一样 由于 AudioMixGroupsComponent 遵从组件协议 它也适合在自定 RealityKit 系统的环境中 进行更新
太棒了 有了音频混音组 我们现在就能控制 App 中的不同声音 从而根据我们的心情来定制体验
我们将空间音频源 与实时生成的音频搭配使用 以便营造栩栩如生的太空飞船 同时我们还制作了 虚拟界面与现实界面之间 激动人心的碰撞声 然后 我们将 这些空间音效 添加到附带混响预设的 沉浸式环境中 最后 我们还在 App 中 使用音频混音组 来实现音乐与声音的完美混音 我希望你们能用一用这个 App 同时我也等不及想看你们用 RealityKit 音频实现了哪些震撼效果
-
-
3:11 - Play vapor trail audio
// Vapor trail audio import RealityKit func playVaporTrailAudio(from engine: Entity) async throws { let resource = try await AudioFileResource(named: "VaporTrail") engine.playAudio(resource) }
-
4:02 - Make vapor trail audio playback more dynamic
// Vapor trail audio import RealityKit func playVaporTrailAudio(from engine: Entity) async throws { let resource = try await AudioFileResource( named: "VaporTrail", configuration: AudioFileResource.Configuration( shouldLoop: true, shouldRandomizeStartTime: true ) ) let controller: AudioPlaybackController = engine.playAudio(resource) controller.gain = -.infinity controller.fade(to: .zero, duration: 1) let audioSource = Entity() audioSource.orientation = .init(angle: .pi, axis: [0, 1, 0]) audioSource.components.set( SpatialAudioComponent(directivity: .beam(focus: 0.25)) ) engine.addChild(audioSource) let controller = audioSource.playAudio(resource) }
-
7:10 - Exhaust audio
// Exhaust audio import RealityKit func updateAudio(for exhaust: Entity, throttle: Float) { let gain = decibels(amplitude: throttle) exhaust.components[SpatialAudioComponent.self]?.gain = Audio.Decibel(gain) } func decibels(amplitude: Float) -> Float { 20 * log10(amplitude) }
-
8:17 - Turbine audio
// Turbine audio import RealityKit var turbineController: AudioGeneratorController? func playTurbineAudio(from engine: Entity) { let audioUnit = try await AudioUnitTurbine.instantiate() let configuration = AudioGeneratorConfiguration(layoutTag: kAudioChannelLayoutTag_Mono) let format = AVAudioFormat( standardFormatWithSampleRate: Double(AudioGeneratorConfiguration.sampleRate), channelLayout: .init(layoutTag: configuration.layoutTag)! ) try audioUnit.outputBusses[0].setFormat(format) try audioUnit.allocateRenderResources() let renderBlock = audioUnit.internalRenderBlock turbineController = try engine.playAudio(configuration: configuration) { isSilence, timestamp, frameCount, outputData in var renderFlags = AudioUnitRenderActionFlags() return renderBlock(&renderFlags, timestamp, frameCount, 0, outputData, nil, nil) } }
-
11:28 - Setting distance attenuation and gain
import RealityKit func configureDistanceAttenuation(for spaceshipHifi: Entity) { spaceshipHifi.components.set( SpatialAudioComponent( gain: -18, distanceAttenuation: .rolloff(factor: 4) ) ) }
-
12:36 - Loudness variation
// Loudness variation import RealityKit func handleCollisionBegan(_ collision: CollisionEvents.Began) { let resource: AudioFileGroupResource // … let controller = collision.entityA.playAudio(resource) controller.gain = relativeLoudness(for: collision) }
-
14:44 - Defining audio materials
// Audio materials import RealityKit enum AudioMaterial { case none case plastic case rock case metal case drywall case wood case glass case concrete case fabric } struct AudioMaterialComponent: Component { var material: AudioMaterial }
-
14:53 - Setting audio materials
// Setting Audio Materials asteroid.components.set( AudioMaterialComponent(material: .rock) ) spaceship.components.set( AudioMaterialComponent(material: .plastic) )
-
15:04 - Handling collision audio
// Audio materials import RealityKit func handleCollisionBegan(_ collision: CollisionEvents.Began) { guard let audioMaterials = audioMaterials(for: collision), let resource: AudioFileGroupResource = collisionAudio[audioMaterials] else { return } let controller = collision.entityA.playAudio(resource) controller.gain = relativeLoudness(for: collision) }
-
17:18 - Reverb presets
// Reverb presets import Studio func prepareStudioEnvironment() async throws { let studio = try await Entity(named: "Studio", in: studioBundle) studio.components.set( ReverbComponent(reverb: .preset(.veryLargeRoom)) ) rootEntity.addChild(studio) }
-
20:05 - Immersive music
// Immersive music import RealityKit func playJoyRideMusic(from entity: Entity) async throws { let resource = try await AudioFileResource( named: “JoyRideMusic”, configuration: .init( loadingStrategy: .stream, shouldLoop: true ) ) entity.components.set(AmbientAudioComponent()) entity.playAudio(resource) }
-
21:57 - Using AudioMixGroup with a RealityKit entity
// Audio mix groups import RealityKit let resource = try await AudioFileResource( named: “JoyRideMusic”, configuration: .init( loadingStrategy: .stream, shouldLoop: true, mixGroupName: “Music” ) ) var audioMixerEntity = Entity() func updateMixGroup(named mixGroupName: String, to level: Audio.Decibel) { var mixGroup = AudioMixGroup(name: mixGroupName) mixGroup.gain = level let component = AudioMixGroupsComponent(mixGroups: [mixGroup]) audioMixerEntity.components.set(component) }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。