VisionPro开发 - 轻松实现天空盒并添加光照


VisionPro开发系列首页:漫游Apple Vision Pro

系列项目全部代码:github.com/xuchi16/vis...


大家好,我是 xChester。

当我们希望给用户提供沉浸式体验时,常需要利用环境贴图构造天空盒。而 visionOS 本身不提供天空盒的功能,本文将实现一个简单的天空盒效果。

本文主要包含以下内容:

  • 简单的天空盒效果(Skybox),提供沉浸的体验

  • 为其中的物体添加基于图形的光照(Image Based Lighting,IBL),提供反射效果。

最终效果如下,可以看到沉浸式的天空和,同时其中的物体有相应的反射效果。

基本概念

HDRI(High Dynamic Range Imaging,高动态范围成像)环境贴图是一种提供详细光照信息的全景图像技术,用于在 3D 渲染和视觉效果中创建更加真实的光照和反射效果。

简单来说,当我们使用一张普通的全景图片作为环境贴图时,由于其中仅包含了拍摄时的曝光信息,当后续 3D 场景中渲染光照发生变化时图片中无论亮部还是暗部都会统一变化,如当光照变暗时,普通的图片会显得更"灰"。而相比于普通的全景图像,HDRI 图像在拍摄时就会对环境进行多次曝光,生成一系列曝光度不同的照片,并将它们合并成一个动态范围更广的图像。其中包含了更丰富的光照信息,包括色彩、亮度和反射细节等,在 3D 场景和模型的构建中能够营造更为真实的效果。

左。 HDR / 右。 JPG

IBL(Image Based Lighting)是一种在三维图形和视觉效果中使用的照明技术,通过使用 HDRI 图片来模拟光照,从而创造出更加真实和动态的视觉效果。RealityKit 就使用了 IBL 技术来模拟真实的反射效果。

主要步骤

  1. 获取 HDRI 资源并创建材质

  2. 创建模拟天空盒的球体并将 HDRI 贴图材质应用到天空盒上

  3. 加载 HDRI 资源并创建环境资源

  4. 创建环境中的物体并使用 IBL 光照

基本实现

获取 HDRI 资源并创建材质

PolyHeaven中找到想要的 HDRI 图片并下载,我们这里使用了一张上海外滩的夜景图。下载该图并导入 Xcode 项目中。利用如下代码

  1. 创建TextureResource
  2. 创建UnlitMaterial并使用上述贴图

UnlitMaterial是一种简单的材料,不会对环境中的其他光源做出响应。

swift 复制代码
guard let resource = try? await TextureResource(named: "shanghai_bund_4k") else {
    fatalError("Unable to load texture.")
}
var material = UnlitMaterial()
material.color = .init(texture: .init(resource))

创建天空盒球体

创建一个半径为 1000 的巨大球体,并将上述贴图应用到该球体上。另外,需要指定其 scale 的 x 方向为负,这样可以将贴图材质应用到球体的内表面。此时运行程序,我们仿佛已经置身上海外滩。

swift 复制代码
skybox.components.set(ModelComponent(
    mesh: .generateSphere(radius: 1000),
    materials: [material]
))

// Reverse x to let the picture applied to the inner side of skybox
skybox.scale = .init(x: -1 * abs(skybox.scale.x), y: skybox.scale.y, z: skybox.scale.z)

加载 HDRI 资源并创建环境资源

但如果此时在场景中添加物体,会发现物体并没有反射天空盒中的景色,呈现出黑色的无光照效果。

为了给物体添加 IBL 光照,仍需要使用刚刚的 HDRI 环境贴图。在 RealityKit 中,想要将该图用作 IBL 资源,需要

  1. 创建一个文件夹,并将其后缀改为.skybox

  2. 将 HDRI 文件放入上述文件夹中

  3. 将该文件夹拖到 Xcode 项目中,并选择"Create folder reference",将其添加到项目中

这样 Xcode 就能够将这张图片编译为环境资源,可以在代码中获取到该资源。

swift 复制代码
guard let environment = try? await EnvironmentResource(named: "shanghai_bund_4k") else {
    return
}

创建环境中的物体并使用 IBL 光照

创建一个球体,并将球体颜色设置为白色,isMetallic设置为ture,模仿光滑的金属表面,从而获得更好的反射效果。

swift 复制代码
let sphere = ModelEntity(
    mesh: .generateSphere(radius: 0.25),
    materials: [SimpleMaterial(color: .white, isMetallic: true)]
)

然后,创建一个ImageBasedLightComponent,通过该组件引用上述环境资源。再创建一个ImageBasedLightReceiverComponent作为关键光照的接收组件。将上述两组件应用到球体上,即可获得逼真的光照反射效果。

swift 复制代码
sphere.components.set(ImageBasedLightComponent(source: .single(environment)))
sphere.components.set(ImageBasedLightReceiverComponent(imageBasedLight: sphere))

最终效果

关注我

欢迎在掘金上关注我和我的专栏VisionOS Workshop,以及各种收藏/围观/评论/反馈/批评/Star/点歌

相关推荐
晓得迷路了15 分钟前
栗子前端技术周刊第 97 期 - Viteland:8 月回顾、Redux Toolkit 2.9、Nuxt 4.1...
前端·javascript·nuxt.js
前端双越老师18 分钟前
前端开发 AI Agent 智能体,需要掌握哪些知识?
前端·node.js·agent
EndingCoder20 分钟前
Electron 安全性最佳实践:防范常见漏洞
前端·javascript·electron·前端框架·node.js·桌面端
学前端搞口饭吃27 分钟前
React props的使用
前端·javascript·react.js
灵感__idea1 小时前
JavaScript高级程序设计(第5版):前端的能力边界
前端·javascript·程序员
华洛1 小时前
SEO还没死,GEO之战已经开始
前端·javascript·产品
IT_陈寒1 小时前
Python性能优化:5个被低估的魔法方法让你的代码提速50%
前端·人工智能·后端
As33100101 小时前
Chrome 插件开发入门指南:从基础到实践
前端·chrome
不想上班只想要钱1 小时前
vue3 ts:声明的一个数组不能将类型“boolean”分配给类型“never”。
前端·vue.js
OEC小胖胖1 小时前
Next.js 介绍:为什么选择它来构建你的下一个 Web 应用?
开发语言·前端·web·next.js