本文在线示例查看。更多精彩内容尽在数字孪生平台,关注公众号:sky的数孪技术,技术交流、源码下载请添加VX:digital_twin123
地形构建
我们目的要搭建一个中间平坦、两侧有凹凸山脉效果并且能够一直绵延不断的地形,接下来我们通过三个问题来进行分析。
采用什么样的几何图形
通常情况下,采用PlaneGeometry
一般是大多数人的选择,但是PlaneGeometry
没有凹凸不平的效果,而且我们还希望在地形道路上沿着三角网绘制霓虹灯线条。但是问题是相邻的三角形面,在对角线上着色会发生变化,如果使用普通的PlaneGeometry
形状会造成中间的道路上的霓虹灯线条显得不对称。
如果我们想避免对角线问题,有如下3种方法:
- 整体旋转
PlaneGeometry
45度; - 自定义一个
BufferGeometry
,并旋转正方形的方位; - 在 y 方向上切变
PlaneGeometry
直到拥有对称三角形的排布。
进行切变,其中 xy 设置为 -0.5")
现在我们对这三种方式进行评估,因为我们需要在地形中铺设一条绵延的长路,所以我们可能需要复制并连接平面以使其绵延不断。
- 对于选项 1,连接多个旋转平面会带来一个明显的问题:它们两侧会有很大的空白空间。将一个指向前方的菱形镶嵌成一条道路将是非常低效的。
- 对于选项 2,自定义几何看起来不错,但开销太高;我们将不得不计算和设置顶点的位置,并且精确地连接平面,这会更加复杂。
- 对于选项 3,我们只需要多写2-3行代码就可以对它进行切变,直到三角形对称为止。开销很小。虽然整个平面是沿对角线拉伸的,但仍然很容易将平面连接起来,如果我们正确设置相机和动画循环,用户也不会注意到切变的影响。
所以很显然,我们选用第三种方式。
如何让地形中间平坦,两边凹凸不平?
我们首先需要的是高度图图像。它是一张灰度图,其中白色表示最高,黑色表示最低。我们可以用 Affinity Designer 绘图软件使用径向渐变和纹理画笔生成一张灰度图。很明显,中间的垂直矩形区域保持黑色,用来将其渲染成平坦道路。
下一个问题是使用来自该高度图的高度数据来渲染我们的平面几何图形。我一开始尝试用TextureLoader
加载高度图图像,然后将纹理分配给MeshStandardMaterial
的displacementMap
(置换贴图)属性。但是这种方法不适用于稍后创建的霓虹灯线,因为displacementMap
属性仅在运行时更新vertexShader
中的顶点位置,我们主js程序中平面几何对象的位置数组不受影响。
因此,我们必须手动从置换贴图图像中提取灰度值,对其进行缩放并将其值直接分配给我们几何对象的每个顶点的z值。
如何为地形制作动画来达到无尽绵延的道路效果?
这个问题其实存在于很多需要某种无尽之路的游戏/动画中,这个问题本身很容易解决。大致就是假设我们有多个平面实例连接在一起形成了道路,我们将它们加速朝向相机,这样看起来我们正在向前移动。一旦道路的头部移动到我们的相机后面,我们就把它的位置放回道路的尾部,这就是让我们的道路看起来无穷无尽的方法。
在我们的例子中,有个额外的问题是我们如何确保平面实例在它们的连接处完美连接而没有间隙。我们可以想象一下,我们采用的heightmap
对所有平面实例使用相同的高度图像素,高度图的顶行像素很可能与底行像素不匹配,这样就会产生这样的间隙: