案例研究。Windland - 一个身临其境的Three.js体验

1,245 阅读10分钟

在这篇文章中,我们将看看如何使用Three.js创建一个充满后期效果和微互动的迷你城市。

访问Windland

看看你如何使用这个免费的模板创建你自己的

指南

我是一个无条件的游戏爱好者。我一直梦想着创建一个互动的迷你城市,使用饱和的颜色,类似于模拟城市和类似的东西。挑战在于,我既没有足够的3D知识,也没有一个图书馆。

在2021年年底,我终于决定实现一个古老的愿望,我参加了布鲁诺-西蒙的课程--Three.js之旅。我是一个喜欢编程的设计师。因为这门课程,我最终发现自己是一个有创造力的开发者,在这里我能够使用我沉睡的ActionScript 2.0的部分知识,来自已故的Macromedia Flash。

整个项目是在我在Neotix工作的间隙,在大约2周内完成的。这感觉很奇妙,我很喜欢做这件事,所以我决定分享一些关于它的有趣信息,这样我就可以在某种程度上帮助那些处于这个旅程开始阶段的人。

创意挑战

使用游戏中存在的各种后期处理效果,在不影响性能的情况下给这个城市一个体面的现实水平,这是至关重要的。我选择的艺术道路是使用现实的灯光和低聚物模型的混合。

image3.png

图片显示了城市的3D模型和旁边的Three.js体验。

性能

我对这个项目的部分要求是应用能在不同设备上表现良好的技术,特别是移动设备。它需要在尽可能多的设备上运行,并有一个可接受的帧率(至少30帧)。我还希望这个体验能够尽可能快地加载,文件大小小于2MB。

为了达到这个目的,我不得不使用一系列的技术,我将在下面介绍。

图片显示了Blender内模型上的线框,这一切都从这里开始。

在Blender中创建3D模型

我使用Blender制作城市模型。我从互联网上的免费模板中导入了部分建筑。我对其中一些进行了修改,以更好地匹配环境。为了制作地形,我使用了Blender的雕刻模式,创建了山谷和山峰,在光和影的作用下看起来非常漂亮。

图片显示Blender中线框模式下的3D模型。

在导出时,考虑到三角形的数量,每个模型都进行了优化。我选择使用GLB格式,因为用Draco的压缩功能做了令人难以置信的压缩--有时会缩小7倍,在文件大小上。此外,所有的项目资源在运行时也被压缩,在服务器上用gzip压缩,以减少传输。

创造自然光

游戏中的光照是很迷人的--影子与地形的互动方式,以创造出一个既能让人赏心悦目,又不会被现实牵制的场景。我使用Blender的全局照明系统,有一个 "世界 "节点,使用 "Nishita "环境照明。这可以实现非常自然的照明,环境设置可以迅速得到令人愉悦的结果。

图片显示太阳在不同位置的照明,并叠加在blender的nishita太阳参数上。

在Blender中用几何节点分布树木

树木起着重要的作用,因为它们有助于创造一个投射阴影,使地形有一丝真实感。我使用Blender的几何节点来分布模型中的树木,并创造出大小、形状和旋转的变化。我还使用了材质选择器,来选择有更多或更少树木的区域,用材质选择来绘制密度。

图片显示了blender的界面,以及为在场景中分布树木而创建的几何节点。

烘烤照明以便输出

为了让体验在Three.js中运行并表现良好,重要的是场景要加载烘烤到贴图中的照明。我为地板创建了一个2048×2048的单一纹理,包含所有的阴影。如何进行阴影烘烤的过程可以在互联网上的一些教程中找到。最终的结果是令人印象深刻的,而且对性能没有影响。

图片显示了blender中的3D模型和烘烤过的照明纹理。

导出到Three.js和树的性能问题

在完成烘烤并将纹理连接到地面网格的颜色节点后,我将所有的网格导出为GLTF格式。整个模型,使用DRACO COMPRESSION,是1.2MB。然而,我们在树上遇到了一个问题:它们不能一次性导出,因为GPU需要太长的时间来完成这个过程。

我使用Three.js中的MESH SURFACE SAMPLER创建了这些树,它正是为了这个目的。你可以使用一个模型,并将其分布在一个表面上,创建同一模型的变体,但对每个模型进行修改。因此,即使有非常多的变化,其性能也是惊人的。

你可以在Three.js的官方文档中看到这样的一个例子

图片显示了VSCODE中的MeshSurfaceSampler代码和Three.js场景图片中的投影树。

在Three.js中加载一切

使用我的模板(见文章末尾的更多内容),这是我为了简化事情而创建的,我加载了导出的模型。之后,我花了很多时间来调整光线的颜色、强度和其他小细节,这些都会产生很大的不同。在Three.js中使用默认参数,3D渲染的结果并不总是伟大的体验。

图片显示了Three.js中模型的演变以及作为前后对比的颜色变化。

使用DAT.GUI来直观地调整参数是非常必要的。通过猜测数字不可能得到正确的颜色和强度。

显示Three.js DAT.GUI的图片。

使用VertexShader来制作树木的动画

给场景带来真实感的一件事是树木的平滑动画。通过直接从Blender导出动画,可以做到这一点,但性能会受到很大影响--特别是考虑到树的数量很多。

在这种情况下,最好的方法是使用VertexShader制作动画,直接使用GPU处理三维世界中的顶点定位。有了这个方法,性能非常好,而且动画效果也很好。

VSCODE的截图显示了负责为树木制作动画的顶点着色器的一部分,以及Three.js中的动画树木的图片。

为鸟类和其他体验元素制作动画

体验中的其他动画元素,如直升机、汽车和风力涡轮机,是通过在渲染循环中直接改变模型片的旋转来实现的。这是一种非常简单的动画制作方法。

鸟类的动画制作方式不同。我想让它们有翅膀的运动和群体的感觉。因此,我在blender中为整个小组制作了动画,并将动画和GLFT文件一起导出。我使用动画混合器为翅膀制作动画,同时改变群体的位置。结果是相当有说服力的,而且非常轻巧(只有200kb)。

图片显示了小鸟和它们在blender中的动画时间线,以及在Three.js中的相同小鸟。

灯光、阴影和夜景模式+世界末日

由于阴影是在导入的GLB文件中烤出来的,我能够通过在Three.js中不使用动态生成的阴影贴图来获得一些性能。

我玩了一下照明效果,创建了一个夜间模式和一个世界末日模式。在不修改模板的情况下拥有这样的创作自由是非常有趣的。可能性是无穷的。

世界末日模式是一个复活节彩蛋,任何知道如何激活它的人都可以使用:)。

图片显示夜间模式和世界末日模式。

用Effect Composer进行后期处理

我一直很喜欢游戏中的景深效果,但我认为在Three.js的体验中使用这样的东西会非常困难。多亏了库的最新更新,这就容易多了。

使用EffectComposer,我能够在白天模式下使用BokehPass效果,它可以根据与摄像机的距离,生成动态的景深效果。对于夜间模式,我使用UnrealBlooomPass,它使灯光超级曝光,非常适合这种类型的情况。

由于性能的原因,我在夜间和白天模式之间改变了效果--使用insertPass()和removePass()方法。

点击并选择建筑物

很多人问我如何使建筑物成为可点击的UI项目。这是用Three.js的RayCaster完成的,它可以检测由相机发射的不可见光线与鼠标之间的交点。有了它,我就可以检测到一个建筑物被选中,并根据它的名字来触发一个事件。

图片显示了VSCODE中负责制作物体选择射线器和摄像机动画的源代码。

点击建筑物时发生的动画是用TWEEN.JS完成的,通过将初始摄像机位置动画化为被点击建筑物的位置。这样,我就可以放置多个建筑物,并自动生成一个动画。

响应性的调整。也在移动端工作

部分工作还涉及到调整体验参数,使其在移动设备上运行良好。不仅仅是对HTML和CSS的响应式调整,还包括相机参数、动画持续时间和其他一些细节。

image16.jpg

图片显示Windland在移动模式下运行的响应性。

动态质量。根据用户设备的功率动态调整性能

尽管进行了所有的优化,一些设备仍然无法运行所有的效果,特别是后期处理的效果。所以我创建了一个脚本,在实验开始时(加载过程中)测量FPS。这样,当实验开始时,Three.js知道是否激活某些效果以节省处理,并确保性能在该设备可能的范围内。

image9.png

显示VSCODE中负责检测FPS的代码的图片。

同时在智能手表上工作

作为一个概念证明,我想证明在Three.js中做的实验即使在智能手表上处理和运行也不重。在这个过程中,我发现模型中顶点的数量是对这些设备的性能影响最大的。因此,我创建了一个 "超低聚 "模式的模型,以便在移动设备上使用。准备好了!代码中没有其他需要修改的地方。

image8.png

图片显示Windland在智能手表上运行

Three.js模板。创建您自己的Windland

为了使在Three.js中创建项目变得更容易,我创建了一个易于使用、文档齐全且免费的启动项目。因此,使用这个模板,你只需几行就能在Three.js中创建一个场景并导入一个模型。该模板还说明了如何导出模型和其他一些信息,可以帮助你创建城市。

在GitHub上找到该软件库:https://github.com/ektogamat/threejs-andy-bolierplate

观看关于如何使用它的视频:https://www.youtube.com/watch?v=qM6Ih_cC6Gc

image17.png

有趣的事实

有些人问:使用Three.js制作项目,而不是仅仅使用网站的渲染图像,有什么好处?好吧,这个场景的渲染图片在1920×1080的情况下,在合理压缩的情况下,大小约为2.8mb。在Three.js中的整个场景,包括所有的互动性、动画、界面和你在动画中看到的一切,只有1.8mb。

Windland在2022年3月31日的Awwwards上获得了荣誉奖。它将自己从一个测试项目转变为Three.js的使用案例,变成了模仿游戏外观和感觉的复杂场景。

Three.js越来越成为我最喜欢的库。你可以在我的YouTube频道或我的官方Twitter上找到更多视频。

谢谢你的时间🙂

The postCase Study:Windland - 一个身临其境的Three.js体验》首次出现在Codrops上。