重新创建真实世界的地形,反应,三个.js和webgl着色器

2021-02-24 21:44:35

您可能会了解关于Microsoft'去年8月的航班模拟器发布,如我,如果您'对飞行模拟器感兴趣或对现实生活的照片娱乐场所感兴趣,您可能已经花了很多时间盯着敬畏令人惊叹的细节填充到该系列的最新迭代中。

飞行模拟器使用卫星扫描和地形数据从Bing Maps实时生成地形。我赢得了详细信息,但你可以获得一个想法的想法,但是可以安全地说结果是现实生活中最准确的地方的一些娱乐活动如果他们飞向他们的城镇,他们甚至可以发现他们的房子。

本文将帮助您重新创建类似的东西,尽管更低的细节,并且在大多数更小的范围内。但是,我认为你' ll找到它'仍然令人兴奋。

自WebGL以来将OpenGL的巨大能力带到了Web,它使3D环境具有复杂的纹理和光线,通过Web更可访问,可以说是最可访问的平台。它给开发人员提供了一种方法来展示他们在网浏览器和支持WebGL的任何平台上的工作。今天,支持WebGL的平台列表非常大,涵盖了大量用户群。

Three.js通过允许它们在JavaScript中写入代码并与DOM,Audio API和WebSockets与浏览器API交互来说,更轻松地使开发人员更容易成为开发人员。 Three.js仍然可以通过直接调用其API来删除进入WebGL层。

最近,通过向与协调转符提供反应开发人员来说,一个名为React-Three-Fible的库进一步逐步逐步允许它们毫不费力地使用JSX声明地毫不费力地编写三个.js代码。

我们将尝试在Three.js中尝试和重新创建一块地形,并尽可能地尝试作为光电态度。

但首先,让' s得到一个最低工作的应用程序设置,以便我们有形。

3D空间中的一个平面平面,最终会变成一块地形。

有关该代码如何工作的更多指南,您应该在我们的旧博客上查看Vikrant'旧博客解释反应三纤维的基础知识。

"地形"现在只是一个绿色广场。因此,我们的下一步将涉及获取我们需要使它看起来更近地的数据。

对于这篇文章,我会使用现实生活的位置。 Uluru(也称为Ayers Rock)是澳大利亚中部的天然岩层和联合国教科文组织世界遗产。它由砂岩制成,具有独特的红棕色,并被Uluōu-kataTjuğa国家公园的干旱景观所包围。一个完美的测试地点。

美丽,isn' t呢?几乎就像火星的表面。我选择了这个地方,因为地形具有一些突出的特征,这将是有趣的,并且地形高度的变化是截然不同的。

首先,我们' ll修改了我们之前德鲁的平面,以便它具有地形的形状。

对于两个步骤,我们' ll需要不同种类的数据,所以我们' ll在每一步之前得到那些。

在许多情况下,描述某事的最简单方法是用图片。在计算机图形学的情况下,图像可以是最有效的编码数据之一,具有允许人类容易地认为数据的额外优势。

我们需要的第一个数据是地形上每个点的高度或高度映射。这样做的一种方法是将地球' s表面上的点映射到图像中的像素,每个像素表示关于表面上的点或区域的一些数据。

最自然的映射可以想到是:像素较轻,越高的点在地球上。

幸运的是我们,有几个可以给我们的工具。一个漂亮的流行例子是地形。帕蒂,这是城市使用的:地平线社区在游戏中产生地形。

我们需要澳大利亚的特定部分。所以,我做了放大乌鲁鲁坐标的工作:

白色部分是uluru,uluru在距离岩层周围的周围环境较高时。

七巧板努力确保最低的水位(海拔约500m)是黑色的(#000),而乌鲁鲁的山峰(海拔约800m)是白色的(#fff),其余部分呈线性映射在两者之间。

将适当范围的地形导出为PNG后,我缩放并使用GIMP将其裁剪为1024x1024格式。稍后高度和宽度必须为2的幂,这一点很重要。

现在,我们需要将其添加到Three.js场景中,以便我们的飞机开始采用最终地形的形式。

着色器是一种功能,可根据多个参数来确定像素的外观。在WebGL中,有两种类型的着色器:

让我们在3D对象的上下文中讨论这些问题。任何3D对象的表面都可以表示为一堆多边形。通常,我们使用三角形,因为它们既简单又平坦。

在简化意义上,顶点着色器确定这些多边形的顶点在3D空间中的渲染位置,而片段着色器确定这些顶点之间的空间是什么样。

因此,顶点着色器将帮助我们使用高度图来塑造地形,而片段着色器在需要应用纹理时将非常有用。

为此,我们将需要修改之前的代码,因为我们将无法使用与第一个带有绿色正方形的沙箱中使用的材料(MeshBasicMaterial)相同的材料。相反,我们将需要一种称为ShaderMaterial的特殊材料,该材料将使我们能够通过手工制作的着色器。

WebGL着色器使用称为GLSL的语言编写,该语言在某些方面类似于C ++,但经过编译后可以直接在GPU上运行。每个着色器可以具有一个主要功能。此主要功能中的代码适用于GPU上帧缓冲区中的每个像素。

在Three.js中,这些着色器可以作为字符串传递到ShaderMaterial中。只要该字符串是有效的GLSL程序,一切都将起作用。

我们将制作一个顶点着色器,该着色器采用高度图的每个像素的红色分量(RGBA中的R),并将其与比例因子结合起来,以确定XZ平面(我们的地形所在的平面)上方每个点的高度在)。

我们也可以使用蓝色和绿色分量,但是由于所有内容均为灰度,因此这些值将与高度图中的红色分量相同。

我们还将创建一个基本的片段着色器,该片段着色器仅使更高的点位于较浅的绿色阴影上,以便我们可以很容易地看到结果。

//统一是在着色器之间共享的数据//包含在整个帧中统一的数据。 //在这方面,每个点的高度图和缩放常数都是统一的。 //包含高度图的制服imageuniform sampler2D bumpTexture; //包含缩放常数的制服。 //变量是变量,其值是在vertext着色器中确定的//但是,然后在片段着色器中需要它们的值//一个用于存储点变量float vAmount的高度的变量; //顶点变化vec2 vUV的UV映射坐标; void(){//坐标"在UV映射表示中vUV = uv; //在这些坐标处的高度图数据vec4 bumpData = texture2D(bumpTexture,uv); //高度图是灰度的,因此使用r,g或b都没有关系。 vAmount = bumpData.r; //沿普通vec3位置移动newPosition =位置+普通* umpScale * vAmount; //使用标准公式gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition,1.0);}计算顶点的位置

所以我们使用高度图映射到我们的Shadmarial的地形高度,并仔细使用顶点着色器。但它没有看起来像地形。

如果我们需要我们的地形,我们需要真实的纹理看起来像真实的东西。

获得光电型纹理的最简单方法之一是掌握卫星图像。

我采取了简单的方法,使用Mapbox获得乌鲁鲁周围地区的一堆屏幕截图,并使用gimp将它们合并到单个图像中。

这实际上非常耗时,因为我需要注意图像处于正确的缩放级别,并且一切都将与高度图排行。

由于高度图和纹理来自不同的来源,因此我需要调整纹理的大小以匹配高度图' s缩放级别。为了帮助定位,我还需要使用诀窍,如将阈值平衡添加到高度图,以便该功能在高度图中脱颖而出,并帮助我定位。

所以,我们使用高度图和仔细使用顶点着色器,将地形高度映射到我们的Shadmarial。

我们也有一个纹理映射的持有,它是完全相同的大小和缩放级别,以及与高度图相同的位置。

现在我们需要创建一个可以将地形纹理映射到我们的Shadermaterial上的片段着色器。

在我们的情况下,这令人惊讶地简单。我们只需要读取纹理地图图像并使用片段着色器设置相应像素的颜色。

//一个统一的地形纹理Imageuniform Sampler2d Trintainture; //从顶点Shaderving Vec2 Vuv获取变化; // vamount isn' t真正使用过,但可以是必要的浮动vamount; void(){//从uv映射gl_fragcolor = texture2d(terraintexture,Vuv)中的坐标上获取片段的颜色。

在本文中,我们设法设置了一个基本场景,了解了两种类型的材料(MeshbasicMaterial和Sharematerial),着色器,如何使用着色器定制着色剂,并使用三个,使用三个现实世界地形使用三个。反应。

结果非常好。我们可以做的更多事情,但我' ll离开它们了另一个时间。