龙书笔记(13)

2023-11-13

chap 13 地形绘制基础

主要是创建一个 地形类 (Terrain)


1.高度图
其实是一个数组,每个元素都指定了地形方格中某一顶点的高度值,每个元素只分配了1个字节的存储空间,
当加载到程序时,重新分配 浮点型 或 整型 数据来存储这些高度值,高度图的图形表示有很多,

比如:灰度图,地形中某点海拔越高,相应点在灰度图中的亮度越大


(1)创建高度图
用photoshop完成是不错的选择,一旦完成高度图的创建,将其保存为 8位 的RAW文件
RAW文件:仅连续存储图像中以字节为单位的每个像素的灰度值,他的特点是读取方便,可以理解为一个连续的字节存储块

当photoshop提示是否为RAW文件增加一个文件头时,选择"否"


(2)加载RAW文件
	std::vector<int> _heightmap;				//分配整型数据来存储高度值
	bool Terrain::readRawFile(std::string fileName)
	{
		std::vector<BYTE> in(_numVertices);
		std::ifstream inFile(fileName.c_str(), std::ios_base::binary);
		if(inFile == 0)
			return false;
		inFile.read( (char *)&in[0], in.size() );	//把RAW文件中的内容读入到BYTE容器in里面
		inFile.close();
		_heightmap.resize( _numVertices );
		for(int i = 0; i<in.size(); i++)
			_heightmap[i] = in[i];			//再把in的内容赋给int容器_heightmap,这样就得到了每个顶点的整型 高度值
		return true;
	}


(3)访问和修改高度值
	int  Terrain::getHeightmapEntry(int row, int col)
	{
		return _heightmap[row * _numVertsPerRow + col];
	}
	void Terrain::setHeightmapEntry(int row, int col, int value)
	{
		_heightmap[row * _numVertsPerRow + col] = value; 
	}


2.创建地形集合信息
每行顶点数 和 单元数,每列顶点数 和 单元数,高度比例因子,总宽度,总深度,总顶点数,三角元数
地形顶点(TerrainVertex) 是 一个嵌套类,他只在地形类(Terrain)中有用

(1)顶点计算
	bool Terrain::computeVertices()
	{
		HRESULT hr = 0;
		hr = _device->CreateVertexBuffer(
			_numVertices * sizeof(TerrainVertex);
			D3DUSAGE_WRITEONLY,
			TerrainVertex::FVF,
			D3DPOOL_MANAGED,
			&_vb,
			0
		);
		if(FAILED(hr))
			return false;
		int startX = -_width/2;
		int startZ =  _depth/2;
		int endX =  _width/2;
		int endZ = -_depth/2;
		float uCoordIncrementSize = 1.0f / (float)_numCellsPerRow;
		float vCoordIncrementSize = 1.0f / (float)_numCellsPerCol;
				
		TerrainVertex *v = 0;
		_vb->Lock(0,0,(void**)&v,0);
		int i = 0;
		for(int z = startZ; z >= endZ; z -= _cellSpacing)
		{
			int j = 0;
			for(int x = startX; x <= endX; x += cellSpacing)
			{
				int index = i * _numVertsPerRow + j;
				v[index] = Terrain(
					(float)x,
					(float)_heightmap[index],
					(float)z,
					(float)j*uCoordIncrementSize,
					(float)i*vCoordIncrementSize
				);
				j++;
			}
			i++;
		}
		_vb->Unlock();
		return true;
	}


(2)索引计算
	//为什么要用索引,因为创建的顶点是按行创建的,不是按三角元创建的
	bool Terrain::computeIndices()
	{
		HRESULT hr = 0;
		hr = _device->CreateIndexBuffer(
			_numTriangles * 3 * sizeof(WORD),
			D3DUSAGE_WRITEONLT,
			D3DFMT_INDEX16,
			D3DPOOL_MANAGED,
			&_ib,
			0
		);
		if(FAILED(hr))
			return false;
		WORD *indices = 0;
		_ib->Lock(0,0,(void**)&indices,0);
		int baseIndex = 0;
		for(int i=0; i<_numCellsPerCol; i++ )
		{
			for(int j=0; j<_numCellsPerRow; j++)
			{
				indices[baseIndex] 		= i * _numVertsPerRow + j;
				indices[baseIndex + 1] 	= i * _numVertsPerRow + j + 1;
				indices[baseIndex + 2]	= (i+1) * _numVertsPerRow + j;
				indices[baseIndex + 3]	= (i+1) * _numVertsPerRow + j;
				indices[baseIndex + 4]	= i * _numVertsPerRow +j + 1;
				indices[baseIndex + 5]	= (i+1) * _numVertsPerRow + j +1;
				baseIndex += 6;
			}
		}
		_ib->Unlock();
		return true;
	}


3.纹理映射


方案一:
	bool Terrain::LoadTexture(std::string fileName)
	{
		HRESULT hr = 0;
		hr = D3DXCreateTextureFromFile(
			_device,
			fileName.c_str(),
			&_tex
		);
		if(FAILED(hr))
			return false;
		return true;
	}

方案二:
还有另一种纹理映射的方式,他的主要思路是使用一个"空"的纹理,然后基于一些已定义好的参数计算出纹理元的颜色,
例如,可以根据顶点不同的高度给出不同的颜色
(1)D3DXCreateTexture 创建一个空纹理
(2)由于一个纹理对象可有多级渐近纹理,所以要先 锁定 顶层纹理
(3)遍历每个纹理元并对其上色
//第一种方法是 通过文件去创建纹理,可以理解为直接粘贴纹理图
//第二种方法是 创建空纹理,然后再依据某些特定属性去生成的"立即纹理"
			bool Terrain::genTexture(D3DXVECTOR3 * directionToLight)
			{
				HRESULT hr = 0;
				int texWidth  = _numCellsPerRow;
				int texHeight = _numCellsPerCol;
				
				hr = D3DXCreateTexture(
					_device,
					texWidth, texHeight,
					0,			//创建一个完整的多级渐近纹理链
					0,			//Usage
					D3DFMT_X8R8G8B8,
					D3DPOOL_MANAGED,
					&_tex
				);
				if(FAILED(hr))
					return false;
				//确保顶点的格式	
				D3DSURFACE_DESC textureDesc;
				_tex -> GetLevelDesc(0, &textureDesc);
				if(textureDesc.Format != D3DFMT_X8R8G8B8)
					return false;
				
				D3DLOCKED_RECT lockedRect;
				_tex -> LockRect(
					0,
					&lockedRect,
					0,
					0
				);
				DWORD *imageData = (DWORD*)lockedRect.pBits;
				//pitch每行字节数,pBits第一个字节地址
				for(int i = 0; i < texHeight; i++)
				{
					for(int j = 0; j < texWidth; j++)
					{
						D3DXCOLOR c;
						float height = (float)getHeightmapEntry(i,j);
						
						if((height)<42.5f)				c = d3d::BEACH_SAND;
						else if((height)<85.0f)			c = d3d::LIGHT_YELLOW_GREEN;
						else if((height)<127.5f)		c = d3d::PUREGREEN;
						else if((height)<170.0f)		c = d3d::DARK_YELLOW_GREEN;
						else if((height)<212.5f)		c = d3d::DARKBROWN;
						else 							c = d3d::WHITE;
						
						imageData[i * lockedRect.Pitch / 4 + j] = (D3DCOLOR)c;
					}
				}
				_tex->UnlockRect(0);
				if(!lightTerrain(directionToLight))				//照亮地形,主要是明暗因子的计算
				{
					::MessageBox(0,"lightTerrain() - FAILED",0,0);
					return false;
				}
				hr = D3DXFilterTexture(
					_tex,
					0,
					0,
					D3DX_DEFAULT
				);
				if(FAILED(hr))
					return false;
				return true;
			}


4.光照


方案一:

自己设置灯


方案二:
关键:计算地形三角元的明暗因子,他是一个0到1之间的浮点数

使用指定 到达光源的方向 来描述平行光 的光向量(L) 是为了更适合 漫射光光照的 计算
每个方格的面法向量设为N
注意:光的方向向量应为单位向量,这是为了求后面的cosine值,因为面的法向量也将被单位化,在对LN进行 点乘 的时候,直接得到明暗因子

LN夹角越大,此方格接受到的光照就越少,当这个角度超过了90度,很明显,光就照不到方格了
		//计算每个面的明暗因子
		float Terrain::ComputeShade(int cellRow, int cellCol, D3DXVECTOR3 *directionToLight)
		{
			float heightA = getHeightEntry(cellRow, cellCol);
			float heightB = getHeightEntry(cellRow, cellCol + 1);
			float heightC = getHeightEntry(cellRow + 1, cellRow);
			
			D3DXVECTOR3 u(_cellSpacing, heightB - heightA, 0.0f);
			D3DXVECTOR3 v(0.0f, heightC - heightA, -_cellSpacing);
			
			D3DXVECTOR3 n;
			D3DXVec3Cross(&n, &u, &v);
			D3DXVec3Normalize(&n, &n);
			
			float cosine = D3DXVec3Dot(&n, directionToLight);		//计算出法向量和光照方向的cos值,这是一个0~1之间的数
			
			if(cosine<0.0f)
				cosine = 0.0f;
			return cosine;
		}
		//对地形进行着色,也称 明暗处理
		DWORD *imageData = (DWORD*)lockedRect.pBits;
		for(int i = 0; i<textureDesc.Height; i++)
		{
			for(int j = 0; j<textureDesc.Width; j++)
			{
				int index = i * lockedRect.Pitch / 4 + j;
				D3DXCOLOR c(imageData[index]);
				
				c *= ComputeShade(i, j, directionToLight );
				iamgeData[index] = (D3DCOLOR)c;
			}
		}


5.在地形中“行走”


关键点:得到对应x,z坐标的高度值
		float Terrain::getHeight(float x, float z)
		{
			x = ((float)_width / 2.0f) + x;					
			z = ((float)_depth / 2.0f) - z;
			x /= (float)_cellSpacing;
			z /= (float)_cellSpacing;
			float col = ::floorf(x);
			float row = ::floorf(z);						//以上可以求出坐标所在的方格
			float A = getHeightmapEntry(row,   col);
			float B = getHeightmapEntry(row,   col+1);
			float C = getHeightmapEntry(row+1, col);
			float D = getHeightmapEntry(row+1, col+1);		//得此方格的4个顶点
			float dx = x - col;								//把此方格移到起始点
			float dz = z - row;
			float height = 0.0f;
			if(dz < 1.0f - dx) 								//判断此点是位于方格的上三角面还是下三角面
			{
				float uy = B - A;
				float vy = C - A;
				height = A + d3d::Lerp(0.0f, uy, dx) + d3d::Lerp(0.0f, vy, dz);
			}
			else 
			{
				float uy = C - D; 
				float vy = B - D; 
				height = D + d3d::Lerp(0.0f, uy, 1.0f - dx) + d3d::Lerp(0.0f, vy, 1.0f - dz);
			}
			return height;									//求得坐标所在点的高度值
		}		


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

龙书笔记(13) 的相关文章

  • Android Studio安装配置、环境搭建详细步骤及基本使用

    前言 Android Studio的安装配置及使用篇终于来啦 废话不多说 以下针对JDK正确安装 及其环境变量配置完毕 即Java开发环境下 Android Studio的安装 配置 以及创建工程 主题字体更换 窗口工具 布局 快捷方式等的
  • oracle账号共享

    各位小伙伴 在oracle官网下载JDK需要oracle账号 本人提供账号共享 方便大家下载 希望大家不要改密码 方便更多的人 账号 908344069 qq com 密码 Java2019 jdk 8u271 linux x64 tar
  • Element ui 格式化后端时间、el-date-picker日期格式化

    目录 1 el组件格式化后端时间 1 el组件格式化前端时间 1 el组件格式化后端时间 1 引入moment js 先安装 npm install moment save 导入 import moment from moment 使用
  • EDG王者归来

    11月7日凌晨1点 刚刚落幕的英雄联盟S11全球总决赛 中国战队EDG以3 2击败韩国战队DK 一举夺得S11总冠军 随着BO5最后一场 EDG破三路 摧毁敌方水晶 6年的努力 6年的汗水与泪水 都在这一刻得到了见证 断剑重铸之日 骑士归来
  • torch.autograd.set_detect_anomaly在mmdetection中的用法

    这里写自定义目录标题 作用 添加位置 作用 添加位置
  • 关于数据库的备份个人见解

    一 关于数据备份和还原 1 在工作中 经常碰到生产环境上面数据库数据需要进行一些变更或者改动 这个时候呢 很多人的第一反应就是先备份整张表为一张临时表 然后就开始对表数据进行操作 如果出现数据异常 需要回退的时候 就直接删除现在表 然后把备
  • 50个知名的开源网站

    1 http snippets dzone com tag c 数以千计的有用的C语言源代码片段 2 http www hotscripts com category c cpp scripts programs Hotscripts 提供
  • Python 文件的读写操作

    文章目录 1 文件对象 1 1 文件打开方式 1 1 1 打开文件 1 1 2 关闭文件 1 1 3 访问模式 1 2文件读取 1 2 1 read 1 2 2 readline 1 2 3 readlines 1 3 文件迭代 1 4 文
  • 最短路径:迪杰斯特拉算法

    算法步骤 1 初始化 1 将源点v0加到S中 即S v0 true 2 将v0到各个终点的最短路径长度初始化为权值 即D i G arcs v0 vi vi属于V S 3 如果v0和顶点vi之间有弧 则将vi的前驱置为v0 即Path i
  • 硬件系统工程师宝典(28)-----关于LDO,应该知道的事

    各位同学大家好 欢迎继续做客电子工程学习圈 今天我们继续来讲这本书 硬件系统工程师宝典 上篇我们说到BJT配合MOSFET控制电源开关的四种电路以及MOSFET的均流电路 今天我们来讲讲LDO的应用分析 LDO的结构 LDO Low Dro
  • XML格式数据集转TXT(YOLO)

    我从网上下载了一个数据集 underwater 它们提供了xml格式的数据 但是我想用yolov5进行训练 所以需要将xml格式转化为txt格式 正常的xml格式的数据集可以参考 目标检测中将已有的 xml数据集转换成 txt数据集 附代码
  • 深入浅出VA函数的使用技巧

    深入浅出VA函数的使用技巧 作者 钟小兵 发文时间 2005 04 11 本文主要介绍可变参数的函数使用 然后分析它的原理 程序员自己如何对它们实现和封装 最后是可能会出现的问题和避免措施 VA函数 variable argument fu
  • MySQL——模糊查询(LIKE关键字与通配符:百分号%和下划线_的使用和理解)——(运用场景+通俗易懂)

    使用mysql模糊查询主要点 LIKE关键字和这两个通配符配合使用 任意一个字符 任意0或多个字符 那么我们立即上手吧 一 使用LIKE和通配符 场景1 我要搜索一个名字 可我都忘记叫什么了 只知道是3个字符的 那怎么搜索呢 三个下划线 代
  • elasticsearch7.9 修改指定JDK

    错误 future versions of Elasticsearch will require Java 11 your Java version from usr local nlp java jdk1 8 0 162 jre does
  • 大致解决 Ubuntu 18.04 系统启动极慢的问题

    早在一两个月之前就想升级到 18 04 或是 18 10 了 然而那会儿用 LiveCD 测试得速度实在是慢 启动要很久 干脆没过多纠缠 旧暂时不管了 现因实际需要 不得不升级系统 以便获取到更新的软件包 从 17 10 向上升级很方便 直
  • hdoj 题目分类

    1001 整数求和 水题 1002 C语言实验题 两个数比较 水题 1003 1 2 3 4 5 简单题 1004 渊子赛马 排序 贪心的方法归并 1005 Hero In Maze 广度搜索 1006 Redraiment猜想 数论 容斥
  • 论文笔记——CVPR 2017 Annotating Object Instances with a Polygon-RNN

    文章主页 http www cs toronto edu polyrnn 1 简介 文章作者基于深度学习提出一种半自动目标事例标注 semi automatic annotation of object instances 的算法 大多数前
  • @property基本概念

    1 什么是 property property是编译器的指令 什么是编译器的指令 编译器指令就是用来告诉编译器要做什么 property会让编译器做什么呢 property 用在声明文件中告诉编译器声明成员变量的的访问器 getter se
  • maven自定义archetype

    在开发过程中我们经常会创建一系列结构类似的新项目 这些项目结构和基础配置基本或完全一致 maven就提供了archetype类型来规定新建项目的结构及基础配置 利用archetype就可以快速简单的搭建新项目 一 创建Maven项目的一般步
  • 网络安全笔记7——防火墙技术

    网络安全笔记7 防火墙技术 参考课程 中国大学MOOC 网络安全 北京航空航天大学 文章目录 网络安全笔记7 防火墙技术 防火墙概述 防火墙的类型及结构 防火墙的发展史 防火墙的分类 OSI模型与防火墙的关系 静态包过滤防火墙 操作 工作原

随机推荐

  • es的配置文件(elasticsearch.yml)

    config目录下有2个配置文件 es的配置文件 elasticsearch yml 和日志配置文件 logging yml cluster name elasticsearch 配置es的集群名称 默认是elasticsearch es会
  • arduino IDE搭建ESP8266开发环境和简单使用

    arduino IDE搭建ESP8266开发环境和简单使用 文章目录 arduino IDE搭建ESP8266开发环境和简单使用 安装 下载IDE 在Arduino IDE上安装esp8266库 下载安装esp8266库 使用 选择开发板
  • Java进阶3 - 易错知识点整理(待更新)

    Java进阶3 易错知识点整理 待更新 该章节是Java进阶2 易错知识点整理的续篇 在前一章节中介绍了 ORM框架 中间件相关的面试题 而在该章节中主要记录关于项目部署中间件 监控与性能优化等常见面试题 文章目录 Java进阶3 易错知识
  • 使用mybatis-plus的insert方法遇到的坑(添加时id值不存在异常)

    在使用mybatis plus的insert方法的时候 报错 java sql SQLException Field id doesn t have a default value 后来了解到使用mybatis plus的insert方法
  • 05-2_Qt 5.9 C++开发指南_Model/View结构实例(QFileSystemModel、QStringListModel、QStandardItemModel;编程实例)

    接上篇 本篇主要介绍Model View框架下的模型类 QFileSystemModel QStringListModel QStandardItemModel的使用方法和编程实例 文章目录 1 QFileSystemModel 1 1 Q
  • 「拓数派(OpenPie)2022 发布会实录 」PieCloudDB Database 优化器

    10 月 24 日程序员节 拓数派 Openpie 发布了云原生数据库 PieCloudDB PieCloudDB 以云计算架构为设计基础 实现云上存算分离 打造了 元数据 计算 存储 分离三层架构 在计算层 PieCloudDB 设计了高
  • Microsoft Store 微软商店无法加载在页面解决

    导致此原因主要是因为你的电脑开启过vpn 开启了系统代理 导致微软商店无法加载 解决方法 1 第一步 开始 设置 2 第二步 网络和internet 3 第三步 点击代理 关闭手动代理服务器这一项 然后再打开微软商店 就可以了
  • Dvwa页面标红问题的逐步攻破(二)

    提示 第二个问题花了很长时间 试了很多种办法 都没成功 但是经过后续的操作我发现第二个问题并没有太大的影响 那就说一下在此过程中遇到的问题及解决吧 解决PHP module gd MIssing Only an issue if you w
  • HTML超链接标签

    一 超链接标签 a 的语法 a href 链接路径 target self 链接文本或图像 a 1 a 标签中href属性值是链接的路径 当href 时表示一个空连接 2 a 标签中target属性值表示的是链接在哪个窗口打开 它的常用值是
  • rlwrap

    rlwrap for Command Line History and Editing in SQL Plus and RMAN on Linux linux下安装后 用着确实方便 AIX下能用吗 more http www oracle
  • 【语义分割】13、SegNeXt

    文章目录 一 背景 二 方法 2 1 Convolutional Encoder 2 2 Decoder 三 效果 论文 SegNeXt Rethinking Convolutional Attention Design for Seman
  • 详解多线程中的互斥量;mutex头文件,lock与unlock ,lock_guard,unique_lock

    互斥量 假如你有一张水卡 要放在卡槽才能出水 现在你和小明都要热水 于是你接一下热水 用自己的水卡 他又接一下热水 巧了 两人都接到泡面的热水 互斥量是在Mutex的头文件中 并发的优点 可以极的减少时间 并且能够多个进程的运行东西 并发的
  • pca处理后建模 sklearn_汽油辛烷值建模

    题目来源 2020年研究生数学建模竞赛B题 小编第一次做研究生的竞赛题目 我的整体感受 首当其冲的是 关于题的描述很多 每一个题的页数都有好几页 说下关于B题 汽油辛烷值建模 的思考 就B题的难易程度来说 这个题太容易了 不论从数据量 还是
  • 26.kotlin的get和set方法

    1 kotlin类中的get和set方法 fun main args Array
  • 数据结构--二叉树进阶

    因为我们之前在学习数据结构的时候使用的是C语言 但是并不是所有的数据结构都适合使用C语言学习 如今我们了解了C 的基础语法 具备了学习这些稍微难一点的数据结构的前提 所以我们再次回顾数据结构 使用C 这一更加先进的武器 来解决更加复杂的问题
  • 线程池的几种常见的创建的方式

    每次启动一个线程都要创建一个新的浪费资源的 还有时候线程过多的时候回造成服务器崩溃 所以有了线程池的诞生 线程池是用来管理线程的 下面是常用的几种创建线程的方式 一 创建大小不固定的线程池 这是一个线程类 public class Thre
  • 2020-11-26【路灯】动态规划

    2020 11 26 路灯 动态规划 题目描述 一条长l的笔直的街道上有n个路灯 若这条街的起点为0 终点为l 第i个路灯坐标为ai 每盏灯可以覆盖到的最远距离为d 为了照明需求 所有灯的灯光必须覆盖整条街 但是为了省电 要使这个d最小 请
  • SpringCloud Ribbon客服端负载均衡

    Ribbon与Nginx区别 服务器端负载均衡Nginx nginx是客户端所有请求统一交给nginx 由nginx进行实现负载均衡请求转发 属于服务器端负载均衡 既请求有nginx服务器端进行转发 客户端负载均衡Ribbon Ribbon
  • 文件的读写基本操作

    一 文件是计算机中数据持久化存储的表现形式 读写文件标准操作格式1 1 打开文件 file1 open 文件名 读写模式 2 操作文件 3 关闭文件 file1 close 文件操作完毕后必须关闭 否则长期保持对文件的连接状态 造成内存溢出
  • 龙书笔记(13)

    chap 13 地形绘制基础 主要是创建一个 地形类 Terrain 1 高度图 其实是一个数组 每个元素都指定了地形方格中某一顶点的高度值 每个元素只分配了1个字节的存储空间 当加载到程序时 重新分配 浮点型 或 整型 数据来存储这些高度