地形——高度图

地形——高度图在游戏中,我们将采用高度图来模拟现实生活中的丘陵和山谷。高度图其实就是一个数组,而该数组的每个元素都指定了地形方格中某一个顶点的高度值。线框模式普通地形模式在高度图中,通常为其每一个元素只分配一个字节的存储空间,以至于高度能在区间[0,255]内取值。但在实际应用中,为了匹配3D世界的尺度,可能要对高度值进行比例变换,就很可能超出上述区间范围。因此,可以分配一个整型或浮点型数组来存储这些高…

大家好,又见面了,我是你们的朋友全栈君。

在游戏中,我们将采用高度图来模拟现实生活中的丘陵和山谷。高度图其实就是一个数组,而该数组的每个元素都指定了地形方格中某一个顶点的高度值。
线框模式线框模式

普通地形模式
普通地形模式
在高度图中,通常为其每一个元素只分配一个字节的存储空间,以至于高度能在区间[0,255]内取值。但在实际应用中,为了匹配3D世界的尺度,可能要对高度值进行比例变换,就很可能超出上述区间范围。因此,可以分配一个整型或浮点型数组来存储这些高度值,从而可以很好地匹配任何尺度。
高度图中有很多种表现形式,其中一种最常见的就是灰度图,在该图中,地形中的某点海拔越高,相应的该点在图中的亮度就越大,反之,海拔越低,则亮度就越暗。

灰度图表示的高度图
灰度图表示的亮度图
制作高度图,可以通过纯代码编程来实现,不过对代码的要求能力有点高,不容易实现;其次可以采用PhotoShop等绘图软件来制作高度图,由于这类软件提供了一种可视化的交互环境,所以只要会美工,那么难度就会降低很多。
当制作完成之后,只需将文件保存为8位的RAW文件即可。(RAW文件存储了图像中以字节为单位的每个像素的灰度值)。
(1)加载RAW文件
由于RAW文件本质上是一个连续的字节存储块。

std::vector<unsigned char> in(m * n);
	std::ifstream inFile;
	inFile.open(filename.c_str(), ios_base::binary);
	if (!inFile) HR(E_FAIL);
	inFile.read((char*)&in[0], (streamsize)in.size());
	inFile.close();
	mHeightMap.resize(m, n, 0);
	for (int i = 0; i < m; ++i)
	{
		for (int j = 0; j < n; ++j)
		{
			int k = i * n + j;
			mHeightMap(i, j) = (float)in[k] * heightScale + heightOffset;
		}
	}
filter3x3();

将RAW文件中的值复制到一个浮点型向量中,然后再对该浮点型向量中的值进行过滤,目的是对高度值进行比例变换从而突破0~255的限制。

地形平面图
地形平面图
一张地形的平面图,其中竖轴为Z轴,横轴为X轴,而对于Y轴,只要查询所加载的高度图数据结构中的对应项,便可获取到。创建地形几何信息,可通过指定每行和每列的顶点数以及单元间距来定义地形的尺寸。
(2)顶点计算
只需从顶点start开始,逐行生成每个顶点,保持相邻顶点的行列间距均为单元间隔,直至到底顶点end为止。

地形与纹理顶点对应关系
地形与纹理顶点对应关系
图中的X轴对应于纹理图中的U轴,而Y轴对应于纹理图中的V轴。
设:
Ucoord=1/横坐标间距;
Vcoord=1/纵坐标间距;
那么地形中位于(i,j)顶点相对应的纹理坐标(u,v)则可得
u=jUcoord;
v=i
Vcoord;
(3)索引的计算
方格的顶点
方格的顶点
计算各个顶点的索引,从左上角(0,0)起到右下角,依次遍历每个方格,并计算构成每个方格的三角面片的顶点索引。
从图中可以得出,对于处在(i,j)位置的方格,有:
△G1WP1={ivertsPerRow+jivertsPerRow+j+vertsPerRow+j}
△WV1P1={(i+2)vertsPerRow+ji
vertsPerRow+j+vertsPerRow+j+2}
其中vertsPerRow为行间距。
(4)纹理映射
将纹理图片映射到地形网格上,使其生动形象具体。

场景——地址中“行走”
当地形创建好之后,还想移动摄像机模拟我们在现实生活中行走的过程,如在山脚下行走与在山坡上行走不一样,以人的感觉来说,有一种颠簸银河倾斜感。
为模拟这种现象,就需要不断的调整摄像机的高度,即Y坐标。

平移前
在这里插入图片描述

平移后
在这里插入图片描述
进行平移变换,将顶点start平移至坐标原点,然后通过缩放因子为单元间隔的负倒数的比例变换将坐标方格的单元间隔归一化。
float col=floorf(x);
float row=floorf(z);
列索引等于x坐标的整数部分,行索引等于z坐标的整数部分。
其中,floorf(t)函数表示的是求取不小于t的最大整数。
由此便可求方格中4个顶点的高度。
现在需要求摄像机位于任意位置(x,z)时,坐标方格单元的高度。

对应的y坐标
在这里插入图片描述
由于方格单元中可能沿着多个方向发生倾斜,为了取该高度,先需要判断摄像机当前处于哪个坐标方格内。
设col和row描述当前坐标方格的左上角顶点的位置,那么平移
float dx=x-col;
float dy=z-row;
如果dz<1.0-dx,那么当前就处于上三角形△v4v1v2中,否则就是下三角形△v4v2v3。
然后再通过前面的方法获取该点的高度即可完成。
也可采用线性插值进行计算,对于上图中v1v2看作为u轴,v1v4看作为v轴,对着u轴取微分dx,进行线性插值,同理,对着v轴取微分dy,进行线性插值。
那么指定点的高度便可以得出:
y=A+dxuy+dzvy
其中uy表示u轴方向上,y轴的分量;vy表示v轴方向上,y轴的分量。

源代码详情 github
CSDN内下载

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/141092.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(1)


相关推荐

  • socket默认端口号(socket和端口的关系)

    from:http://www.iana.org/assignments/port-numbers
     
    ////////////////////////////////////////////////////////////////////////////////
     PORTNUMBERS(lastupdated2010-09-24)Theportnumbersaredividedintothreeranges:theWel

  • 差分数组技巧

    差分数组技巧一、差分数组适用题型,和技巧前缀和数组:适用于原始数组不会被修改的情况下,频繁查询某个区间的累加和差分数组:主要适⽤场景是频繁对原始数组的某个区间的元素进⾏增减(比如:给你和数组arr,然后再下标0-4之间各元素加一,2-5之间各个元素减2,求最终的原数组)差分数组技巧1.构建差分数组(diff),diff[0]=nums[0],之后diff[i]=nums[i]-nums[i-1]int[]diff=newint[nums.length];//构造差分数组diff[0]=n

  • 配置JDK环境变量详细步骤「建议收藏」

    配置JDK环境变量详细步骤「建议收藏」jdk安装详解,教你一步步配置环境变量。

  • Python3 发票导出XML转Excel[通俗易懂]

    Python3 发票导出XML转Excel[通俗易懂]发票导出xml后转为Excel

  • anaconda+pycharm安装教程_如何在pycharm中配置anaconda

    anaconda+pycharm安装教程_如何在pycharm中配置anaconda本篇文章主要介绍windows系统下Anaconda和PyCharm的安装和使用。Anaconda是将Python和许多常用的package打包直接来使用的Python发行版本,而PyCharm是python开发较为好用的IDE,望大家参考。

  • matlab中示波器的用法_示波器单次触发设置

    matlab中示波器的用法_示波器单次触发设置在做Simulink仿真时,使用的Scope波形显示模块实际上也是一种Figure窗口,不过Matlab把Scope的菜单栏隐藏起来,只提供了几个有限的参数设置。如果需要对Scope中的图加上坐标、更改界面背景色等,没有菜单栏就基本上无从下手了。可以在打开你的mdl文件之后,在Matlab的命令行输入以下指令来恢复显示Scope的Figure菜单栏:>>set(0,’ShowHidd…

    2022年10月12日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号