在本文中,我们将看看如何使用 Three.js 创建一个充满后期效果和微交互的迷你城市。
推荐:将 NSDT场景编辑器 加入你的3D开发工具链。
1、背景介绍
我是一个游戏爱好者。 我一直梦想创建一个交互式迷你城市,使用饱和的颜色,类似于 SimCity 等。 挑战在于我既没有足够的 3D 知识也没有开发库。
2021年底,我终于决定完成一个旧愿,我选修了Bruno Simon的课程——Three.js Journey。 我是一个喜欢编程的设计师。 由于这门课程,我最终发现自己是一名创意开发人员,在那里我能够使用我对已故 Macromedia Flash 的 ActionScript 2.0 的部分沉睡的知识。
整个项目是在大约 2 周内创建的,这是我在 Neotix 工作的轮班之间。 这感觉太棒了,我喜欢这样做,所以我决定分享一些关于它的有趣信息,这样我就可以以某种方式帮助那些刚开始这段旅程的人。
2、创意挑战
在不影响性能的情况下,使用游戏中存在的各种后处理效果来为这座城市提供体面的真实感至关重要。 我选择遵循的艺术道路是混合使用逼真的灯光和低多边形模型。
3、性能表现
我希望这个项目的部分目的是应用在不同设备(尤其是移动设备)上表现良好的技术。 它需要以可接受的帧速率(至少 30 fps)在尽可能多的设备上运行。 我还希望体验能够尽快加载,文件小于 2MB。
为了实现这一点,我不得不使用我将在下面描述的一系列技术。
4、在 Blender 中创建 3D 模型
我使用 Blender 制作城市模型。
我从互联网上的免费模板中导入了部分建筑物。 我修改了其中的一些以更好地匹配设置。 为了制作地形,我使用了 Blender 的雕刻模式,创建了在光影下看起来很漂亮的山谷和山峰。
每个模型都在导出时考虑了三角形的数量进行了优化。 我选择使用 GLB 格式是因为 Draco 的压缩效果令人难以置信——文件大小有时会小 7 倍。 此外,所有项目资源也在运行时在服务器上使用 gzip 进行压缩,以减少传输。
5、创建自然光
游戏中的光照非常迷人——阴影与地形相互作用的方式,目的是创造一个既赏心悦目又不被现实阻碍的场景。 我使用了 Blender 的全局照明系统,带有一个“world”节点,使用“Nishita”环境照明。 这允许非常自然的照明,环境设置可以快速产生令人愉悦的结果。
6、在 Blender 中使用几何节点分布树
树木起着重要的作用,因为它们有助于创建投射阴影,使地形具有真实感。 我使用 Blender 的 GeometryNodes 来分布模型中的树木并创建大小、形状和旋转的变化。 我还使用了材质选择器,选择树木较多或较少的区域,使用材质选择绘制密度。
7、烘焙照明以供导出
为了让体验在 Three.js 中发挥作用和表现良好,场景加载烘焙到纹理中的光照非常重要。 我为 2048×2048 的地板创建了一个纹理,包含所有阴影。 可以在互联网上的几个教程中找到如何进行阴影烘焙的过程。 最终结果令人印象深刻,并且对性能没有影响。
8、导出到 Three.js
完成烘焙并将纹理连接到地面网格中的颜色节点后,我将所有网格导出为 GLTF 格式。 使用 DRACO COMPRESSION 的整个模型为 1.2MB。 然而,我们的树有一个问题:它们不能一次全部导出,因为 GPU 完成这个过程需要很长时间。
我使用 Three.js 的 MESH SURFACE SAMPLER 创建了树,它正是用于此目的。 您可以使用模型并将其分布在表面上,创建同一模型的变体,但对每个模型进行修改。 因此,性能是令人难以置信的,即使有非常多的变化。
你可以在 Three.js 官方文档中看到这样的例子。
9、在 Three.js 中加载所有内容
使用我为简化事情而创建的样板文件(在文章末尾查看更多相关信息),我加载了导出的模型。 之后,我花了很多时间来调整灯光的颜色、强度和其他让一切变得不同的小细节。 对于使用默认参数的 Three.js 体验而言,3D 渲染的结果并不总是很好。
必须使用 DAT.GUI 才能直观地调整参数。 不可能通过猜测数字来获得正确的颜色和强度。
10、使用 VertexShader 制作树木的动画
给场景带来真实感的一件事是树木的流畅动画。 通过直接从 Blender 导出动画可以做到这一点,但性能会受到很大影响——尤其是考虑到大量树木。
在这些情况下,最好的方法是使用 VertexShader 制作动画,使用 GPU 处理直接处理 3D 世界中的顶点定位。 这样,性能非常好,动画也很漂亮。
11、鸟类动画和体验的其他元素
体验中的其他动画元素,如直升机、汽车和风力涡轮机,是通过直接在渲染循环中改变模型部件的旋转来制作动画的。 这是一种非常简单的动画制作方式。
鸟类的动画效果不同。 我希望他们有翅膀运动和分组感。 因此,我在 blender 中对整个组进行了动画处理,并将动画与 GLFT 文件一起导出。 我使用动画混合器在改变组位置的同时为翅膀设置动画。 结果非常有说服力,而且非常轻巧(只有 200kb)。
12、灯光、阴影和夜间模式
由于阴影是在导入的 GLB 文件中烘焙的,因此我能够通过不必在 Three.js 中使用动态生成的阴影贴图来获得一些性能。
我尝试了灯光效果,创造了夜间模式和世界末日模式。 无需修改模板即可拥有这种创作自由,这很有趣。 可能性是无止境。
世界末日模式是一个彩蛋,任何知道如何激活它的人都可以访问:)。
13、使用 Effect Composer 进行后期处理
我一直很喜欢游戏中的景深效果,但我认为在 Three.js 体验中使用类似的东西会非常困难。 由于库的最近更新,它变得更加容易。
使用 EffectComposer,我能够在白天模式下使用 BokehPass 效果,它会根据与相机的距离生成动态景深效果。 对于夜间模式,我使用 UnrealBlooomPass,它使灯光超级暴露,非常适合此类情况。
出于性能原因,我在夜间和白天模式之间更改效果——使用 insertPass() 和 removePass() 方法。
14、单击并选择建筑物
很多人问我如何制作可点击的建筑 UI 项目。 这是使用 Three.js 的 RayCaster 完成的,它检测相机发射的不可见光线与鼠标之间的交点。 有了这个,我可以检测到何时选择了建筑物,并根据其名称触发事件。
单击建筑物时发生的动画是使用 TWEEN.JS 完成的,方法是将初始相机位置动画化为单击建筑物的位置。 这样,我可以放置多个建筑物并自动生成动画。
15、响应式调整:也适用于移动设备
部分工作还涉及调整体验参数以在移动设备上正常运行。 不仅仅是对 HTML 和 CSS 的响应式调整,还有对相机参数、动画持续时间和其他一些细节的调整。
16、根据用户设备的能力动态调整性能
尽管进行了所有优化,但某些设备仍然无法运行所有效果,尤其是后处理效果。 所以我创建了一个脚本来测量实验开始时的 FPS(在加载过程中)。 这样,当实验开始时,Three.js 知道是否激活某些效果以节省处理并确保性能在该设备可能的范围内。
17、研究智能手表
作为概念证明,我想证明在 Three.js 中完成的实验即使在智能手表上处理和运行也不繁重。 在此过程中,我发现模型中的顶点数量对这些设备的性能影响最大。 因此,我创建了一个模型的“超低多边形”模式,以便在移动设备上使用。 准备好! 代码中的其他任何内容都不需要更改。
原文链接:Three开发沉浸式体验 — BimAnt