[Ogre][地形]OgreTerrain的实现原理分析
转自:http://www.xuebuyuan.com/1482609.html
一.世界地图
将整个世界切分成多个Tile,每个Tile大小相同,用二维坐标形式索引起来,如图:
中心点(0,0)位置的Tile为世界地图的中心点,例如坐标可以定位为(0,0,0),由于Tile大小相等,世界坐标与Tile就可以进行转换,可以根据玩家所在的坐标快速的定位Tile。例如,当tile长度为12000时,玩家坐标为(13000,13000) 那么可以知道玩家在索引为(1,1)的Tile上。
二.Tile实现
从顶点组织和材质两个主要方面做说明
顶点组织
Tile可以设置用多少个顶点来表达真实世界的多大单位,如用513*513个顶点来渲染出游戏世界的12000*12000面积的地表。
由于要支持LOD,既根据相机到地表的距离,提交渲染的三角形要相应的减少。我们采用顶点数目不变,通过提交不同的索引来达到减少三角形的目的。
现在的问题是,如果规划这些索引来满足这个需求。用四叉树进行分割是比较好的方式。
由于是基于Ogre实现,就可以把顶点交由Rendable对象管理,这样材质的处理和到相机的距离判断都很方便。四叉树从根节点开始每一个节点都是一个Readable对象。树的根结点用最粗糙的索引,越向下越精细。这样当玩家站在这个大Tile上时,通过相机去查看有哪些节点可以被玩家看到,然后再根据距离和节点的高度(delta值)计算lod来决定是当前节点被渲染还是它的子节点应该被渲染。被渲染的节点被加入到渲染队列,渲染时回调Rendable对象的getRenderOption函数来要求提供顶点和索引,这时节点可以在这里提供自己的索引和顶点。
注意顶点的组织有一些特殊。以下以2049*2049个顶点来表示一块Tile为例做说明
LOD 0: 2049 vertices, 32 x 65 vertex tiles (tree depth 5)vdata 0-15 [129x16]
LOD 1: 1025 vertices, 32 x 33 vertex tiles (tree depth 5)vdata 0-15 [129x16]
LOD 2: 513 vertices, 16 x 33 vertex tiles (tree depth 4)vdata 0-15 [129x16]
LOD 3: 257 vertices, 8 x 33 vertex tiles (tree depth 3)vdata 16-17 [129x2]
LOD 4: 129 vertices, 4 x 33 vertex tiles (tree depth 2)vdata 16-17 [129x2]
LOD 5: 65 vertices, 2 x 33 vertex tiles (tree depth 1)vdata 16-17 [129x2]
LOD 6: 33 vertices, 1 x 33 vertex tiles (tree depth 0) vdata 18 [33]
LOD 0 为最清晰的级别定点数最多,根结点(tree depth 0)为做粗糙的级别,顶点数最少
树的级别还有LOD的计算公式见Terrain::determineLodLevels()函数。
LOD0 行的信息表明这个LOD级别有2049*2049个顶点,节点数有32*32个,每个节点有65*65个顶点。
LOD1行的信息表明这个LOD级别是与LOD0位于同一个树深度上,只不过是以不同的索引来确定顶点数
LOD2行的信息表明这个LOD级别位于深度为4的树节点上,节点数为16*16,每个节点的顶点数为33*33
以上3个LOD级别可以共用一套顶点,位于深度为4的树节点上,每个节点上顶点数为129*129
LOD3行的信息表明这个LOD级别位于深度为3的树节点上,节点数为8*8,每个节点上的顶点数为33*33
LOD4行的信息表明这个LOD级别位于深度为2的树节点上,节点数为4*4,每个节点上的顶点数为33*33
LOD5行的信息表明这个LOD级别位于深度为1的树节点上,节点数为2*2,每个节点上的顶点数为33*33
以上三个LOD级别共用一套顶点,挂在树的深度为1的节点上
LOD6行的信息表明这个LOD级别位于树的根结点上,节点数为1,节点上顶点数为33*33
解读一下以上绿色部分让人疑惑的内容
l 为什么出现的各种数据都是2N+1?
很简单,因为整个地表都是根据四叉树分割的规则的格子,例如5*5个顶点才可以表示4*4个格子
l 为什么实际节点块的大小是129?
因为索引数据是用的16位整数,最大寻址能到129*129,下一个257*257超出了范围
l 为什么叶子节点有2个LOD级别?
计算公式(Math::Log2(mMaxBatchSize- 1.0f) -Math::Log2(mMinBatchSize
- 1.0f) + 1.0f); 上例中的最大批次为65,最小批次为33。所以计算出叶子节点上的lod级别为2,最大级别65是最精细的lod,33是次级,这样做是为了配合地表高度(delta)和相机距离来计算出更多样的lod层级。
l 怎么知道哪些LOD层级/树深度可以共用一套顶点?
顶点块都是129*129的,如上例所示16*16那一深度的129*129个顶点可够它自己和下一个深度的32*32的节点使用。2*2那一个树深度的129*129个顶点可供4*4和8*8的节点使用。具体的计算公式见Terrain::distributeVertexData()
l 为什么总的顶点数要多于2049*2049?
2049^2 = 4198401 vertices
最后使用的顶点数:(16 * 129)^2 + (2 * 129)^2 + 33^2 = 4327749 vertices
因为不是简单的平面切分顶点,而是用四叉树做分割,根据总的顶点数和最大批次最小批次等参数来决定数的深度以及顶点如何共用,所以要有2049只是作为一个基数来参考,最后用的129*129的块数才决定最终的顶点数。
具体的计算方法见Terrain::distributeVertexData()
http://blog.csdn.net/xuantao/article/details/7304073
http://blog.csdn.net/pizi0475/article/details/6321094
http://blog.csdn.net/swq0553/article/details/5888954
[Ogre][地形]OgreTerrain的实现原理分析的更多相关文章
- [Ogre][地形]OgreTerrain分析以及使用
Ogre 1.7.2中的地形教程 ○读者可以对照着Ogre1.7.2中的terrain.h源码进行阅读加深理解,蓝色部分均为源码 ○去除了一些具体场景比如添加mesh,设置setAmbientLigh ...
- Handler系列之原理分析
上一节我们讲解了Handler的基本使用方法,也是平时大家用到的最多的使用方式.那么本节让我们来学习一下Handler的工作原理吧!!! 我们知道Android中我们只能在ui线程(主线程)更新ui信 ...
- Java NIO使用及原理分析(1-4)(转)
转载的原文章也找不到!从以下博客中找到http://blog.csdn.net/wuxianglong/article/details/6604817 转载自:李会军•宁静致远 最近由于工作关系要做一 ...
- 原子类java.util.concurrent.atomic.*原理分析
原子类java.util.concurrent.atomic.*原理分析 在并发编程下,原子操作类的应用可以说是无处不在的.为解决线程安全的读写提供了很大的便利. 原子类保证原子的两个关键的点就是:可 ...
- Android中Input型输入设备驱动原理分析(一)
转自:http://blog.csdn.net/eilianlau/article/details/6969361 话说Android中Event输入设备驱动原理分析还不如说Linux输入子系统呢,反 ...
- 转载:AbstractQueuedSynchronizer的介绍和原理分析
简介 提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架.该同步器(以下简称同步器)利用了一个int来表示状态,期望它能够成为实现大部分同步需求的基础.使用的方法是继承,子类通过 ...
- Camel运行原理分析
Camel运行原理分析 以一个简单的例子说明一下camel的运行原理,例子本身很简单,目的就是将一个目录下的文件搬运到另一个文件夹,处理器只是将文件(限于文本文件)的内容打印到控制台,首先代码如下: ...
- NOR Flash擦写和原理分析
NOR Flash擦写和原理分析 1. NOR FLASH 的简单介绍 NOR FLASH 是很常见的一种存储芯片,数据掉电不会丢失.NOR FLASH支持Execute On Chip,即程序可以直 ...
- 使用AsyncTask异步更新UI界面及原理分析
概述: AsyncTask是在Android SDK 1.5之后推出的一个方便编写后台线程与UI线程交互的辅助类.AsyncTask的内部实现是一个线程池,所有提交的异步任务都会在这个线程池中的工作线 ...
随机推荐
- sh.status()
mongos> sh.status({"verbose":1})sh.status({"verbose":1}) --- Sharding Status ...
- 在Entity Framework 4.0中使用 Repository 和 Unit of Work 模式
[原文地址]Using Repository and Unit of Work patterns with Entity Framework 4.0 [原文发表日期] 16 June 09 04:08 ...
- EF Code First DataAnnotations
Key EF框架要求每个实体必须有主键字段,他需要根据这个主键字段跟踪实体.CodeFirst方法在创建实体时,也必须指定主键字段,默认情况下属性被命名为ID.id或者[ClassName]Id,将映 ...
- ADO.net 实体类 、数据访问类
程序分三层:界面层.业务逻辑层.数据访问层 比较规范的写程序方法,要把业务逻辑层和数据访问层分开,此时需要创建实体类和数据访问类 实体类: 例 using System; using System.C ...
- 位置式PID与增量式PID算法
位置式PID与增量式PID算法 PID控制是一个二阶线性控制器 定义:通过调整比例.积分和微分三项参数,使得大多数的工业控制系统获得良好的闭环控制性能. 优点 ...
- 如何写一个c++插件化系统
1.为什么需要插件化系统 “编程就是构建一个一个自己的小积木, 然后用自己的小积木搭建大系统”. 但是程序还是会比积木要复杂, 我们的系统必须要保证小积木能搭建出大的系统(必须能被组合),有必须能使各 ...
- [Ubuntu] Ubuntu13.04, the desktop freezed after login
My os version is Ubuntu13.04, today, after started and logined, my desktop freezed. But i can still ...
- 【crunch bang】论坛tint2配置讨论贴
地址: http://crunchbang.org/forums/viewtopic.php?id=3232
- 【crunch bang】 增加“菜单项”
[右键菜单]->[Settings]->[Openbox]->[GUI Menu Editor] 挑选合适的位置,增加[菜单项],编辑内容.
- 《C语言入门1.2.3—一个老鸟的C语言学习心得》—清华大学出版社炮制的又一本劣书及伪书
<C语言入门1.2.3—一个老鸟的C语言学习心得>—清华大学出版社炮制的又一本劣书及伪书 [薛非评] 区区15页,有80多个错误. 最严重的有: 通篇完全是C++代码,根本不是C语言代码. ...