获取南京地形高度图数据
上节我们自己生成另一个平面地形,这节我们生成一个带有真实地形高度的【南京玄武区】的地形图。
如果大家玩过《城市天际线》的画,都知道游戏里面可以导入现实世界真实的地图的。其官网提供了一个工具:
http://terrain.party/

这是一个使用openlayers地图库制作的一个在线生成真实世界地形高度图的工具,我们在上面找到想要生成高度图的区域,就可以使用右侧的工具栏下载按钮进行下载。
下载下来一个压缩包:

里面有文件的说明信息,请自行查看。这里我们使用融合过的高度图【nanjing Height Map (Merged).png】
接着,将之前生成平面网格时赋予每个顶点高度为0的代码,改成从高度图中读取高度数据。

因为高度图是一个灰度图,里面的像素值的范围是(0,255)。这里需要根据自己的需求来使用这个高度值。比如:有的区域比较平坦,一张高度图中的像素值可能都集中在125左右,那么你绘制出来地形的高度起伏并不是很明显,特别是地形图很大的时候(也就是上节说的生成地形时SIZE设置很大时)。如果有的区域,地形的起伏刚好较为均匀,地形图的像素值在(0,255)分布较为均匀,直接使用像素值作为OpenGL中顶点的y值,那么效果可能也会不错。
总之,数据是死的, 人是活的。怎么使用数据,取决于你最终想要的效果。
"计算机图形学中,只要你看起来是对的,那就是对的。" --忘了哪本书上讲的。
处理高度数据
首先,我们先直接使用像素值来作为要绘制的高度来看看效果怎么样。

我们这里使用的是PNG图片,有RGBA四个通道组成。
因为是灰度图,所以 R=G=B (常识),这里我们没有使用到透明度通道,因为这里没有物体的混合嘛。
我们随便取R通道作为来代表该点实际的高度值。
Java中使用 BufferedImage.getRGB() 返回一个int
Java中int占4个字节,刚好每个字节(占8bit)存储一个像素值,看下图:

那么如果要获取R的像素值,就需要对返回的int进行右移16位,再使用0xFF(1个字节=8bit)进行与运算,这样就能得到R的像素值。 这个不难理解吧。
A通道、G通道和B通道的值获取以此类推,只不过这里没用到。
那么我们直接将R的值返回,看看绘制的地形图是什么样的。


好像还不错, 我们使用归一化的方法来看看效果。

BufferedImage.getRGB()返回的int的范围是[-256*256*256,+256*256*256]
,也就是我们这里定义的 MAX_PIXCEL_COLOR

因为int我们只用到了后面3个字节(RGB),第一个字节(表达A通道),这里我们没用到。后3个字节全为1时(也就是 MAX_PIXCEL_COLOR )该int绝对值值最大。

那么任取 h 属于 [-MAX_PIXCEL_COLOR,MAX_PIXCEL_COLOR]
h += MAX_PIXCEL_COLOR
h的范围变成 [ 0, 2 * MAX_PIXCEL_COLOR]
然后, h /= 2 * MAX_PIXCEL_COLOR
那么,h的范围编程 [ 0, 1],这样h就归一化为 [0,1]范围内了。
最后,乘以 我们定义的地形的最大高度 MAX_HEIGHT 来进行绘制。

好像也差不多,大家可以根据实际情况,不一定要将高度值归一化到[0,1]之间,归一化到 [1/4, 3/4]范围内也是可以的嘛。
OK,本节结束。
欢迎大家关注我的公众号【OpenGL编程】。
每天进步一点点,探索3D编程背后的技术细节,不再做只会“调包”的傻小白。以幽默风趣的行文风格,近乎白话文的专业知识讲解,分享3D编程的心得、教程、算法,带你走进3D编程的世界。