[转]基于四叉树(QuadTree)的LOD地形实现
实现基于四叉树的LOD地形时,我遇到的主要问题是如何修补地形裂缝。
本段我将描述使用LOD地形的优势,我实现LOD地形的思路,实现LOD地形核心模块的详细过程,以及修补地形裂缝的思路。
首先,LOD地形与一般地形不同:一般的地形是这样实现的:整个地形是一个三角形网格,一个513*513的地形包括513*513个顶点,512*512*2个三角形;在开始渲染地形之前,写入地形的顶点缓冲(vertexbuffer)和索引缓冲(indices buffer),顶点缓冲和索引缓冲都是数组;顶点缓冲存储的是地形的顶点,每个顶点的属性包括其自身的坐标;索引缓冲存储的是每一帧渲染的顶点的索引,在顶点缓冲中,每个顶点都有自己的索引,索引缓冲的元素便是存储于顶点缓冲中的元素的索引;每一帧渲染(Render或Draw)地形的时候,只根据索引缓冲便可渲染出地形,比如,一个3*3的地形,顶点缓冲中一共有9个元素,即9个顶点,若索引缓冲中存储的元素是{0,1,3},则渲染的是顶点缓冲中第0、1、3个顶点,渲染出的形状是部分地形:一个三角形,类似的,若索引缓冲中存储的元素是{0,1,3,1,3,4},则渲染出的形状是部分地形:由两个三角形拼接而成的正方形,若索引缓冲中存储的元素是{{0,1,3,}{1,3,4,}{1,2,4,}{2,4,5,}{3,4,6,}{4,6,7,}{4,5,7,}{5,7,8}},则渲染出的是完整的地形。LOD地形是这样实现的:整个地形也是一个三角形网格,与一般地形不同的是,LOD地形当中,距离摄像头(摄像头相当于我们的眼睛)较近的地方,地形的三角网格较多,距离摄像头较远的地形,地形的三角网格较少,这样在距离摄像头较近的地方,我们看到的地形就更细致更真实,在距离摄像头较远的地方,渲染出来的地形比较粗糙,但是我们看到的效果和用一般地形渲染远处地形呈现的效果一样,所以,LOD地形每一帧渲染的顶点个数小于一般地形每一帧渲染的顶点个数,其渲染速度比一般地形的渲染速度高。之所以选择LOD地形,是因为用一般地形的渲染方式渲染大型的地形会导致程序的运行效率比较低,而用LOD地形的渲染方式则会在渲染同样大小的地形时提高程序的运行效率。比如,只渲染512*512的一般地形时,程序的帧速率(FPS)是100帧/秒,而只渲染1024*1024的一般地形时,程序的帧速率降到20帧/秒。3D游戏不仅包括地形,而且包括其他场景,其他场景的渲染效率有时候较低,比如粒子系统、多层纹理映射等都会使程序的渲染效率降低。包括地形在内的整个场景的帧速率至少要达到30帧/秒,才能保证游戏的流畅度。所以,如果使用大型的地形,必须保证地形的帧速率达到90帧/秒以上,这样才能提高整个游戏场景的渲染效率。
其次,我在实现LOD地形时,选择的地形数据结构是四叉树(QuadTree),在开始渲染地形之前,首先写入整个地形的顶点缓冲、索引缓冲,在每一帧开始渲染地形之前,根据摄像头当前的坐标更新索引缓冲,然后根据索引缓冲渲染出地形,接下来我将详细介绍如何在每一帧更新索引缓冲。首先介绍四叉树,地形的四叉树结构QuadTreeData的核心属性:int类型的中心顶点的索引m_nCenter,int类型的左上、右上、左下、右下顶点的索引m_nCorner[4],QuadTreeData*类型的左上、右上、左下、右下四个孩子节点m_pChild[4],bool类型的真实叶子变量m_bRealLeaf,bool类型的虚拟叶子变量m_bVirtualLeaf。整个地形是一个四叉树,以下举例说明如何建造地形:一个5*5的地形,头节点的m_nCenter是12,m_nCorner[4]依次是0、4、20、24,m_pChild[0]的m_nCenter是6,m_nCorner[4]依次是0、2、10、12,m_pChild[1]、m_pChild[2]、m_pChild[3]的属性值可以此类推。以下是我定义的四叉树结构体:
typedef struct QuadTreeData float maxHeight;
float minHeight; vector<int> mCrackU;
vector<int> mCrackR;
vector<int> mCrackB;
vector<int> mCrackL; int m_nCenter; /// 四叉数保存的第一个值,某网格中心点的索引
int m_nCorner[]; /// 四叉树保存的第二个值 bool m_bVisible;
bool m_bVirtualLeaf; ///虚拟的叶子
bool m_bRealLeaf; ///真实的叶子,真实的叶子没有中心 int mLevel;
int mSelfCorner;
bool m_bHandled; vector<byte> mCode;
vector<byte> mCodeU;
vector<byte> mCodeB;
vector<byte> mCodeL;
vector<byte> mCodeR; double mGUID; QuadTreeData* m_pChild[];
QuadTreeData* m_pFather;
QuadTreeData* m_pAncester; QuadTreeData;
我们可以设定整个四叉树的最多层级,比如9,头结点的层级是0。若某个四叉树节点的m_nCorner[1]和m_nCorner[0]相差为1,或者该四叉树节点位于整个四叉树的第9层,则该四叉树节点为真实叶子,其m_bRealLeaf值为true,四个孩子节点的值均为空NULL,至此,整个地形的四叉树建造完成。更新索引缓冲时,首先更新虚拟叶子节点:遍历四叉树的每个节点,并评价每个节点:若该节点为真实节点,则该节点不可再分,将virtualLeaf设置为true;若该节点为虚拟节点,若该节点不满足评价公式(不可再细分),则将该节点的virtualLeaf设置为true。否则将virtualLeaf设置为false(评价公式:g=d/e×r×C1×C2 ,当g<1 ,则该节点可再分,virtualLeaf设置为false。其中,d表示节点和摄像机的距离;e表示节点边长;r=e/diff ,其中diff表示该节点四个角最大高度与最小高度的差值;C1 、C2 代表分辨率。);其次修补地形裂缝,大致思路是:四叉树的每个节点都有自己的huffman编码,通过huffman编码可以遍历到自己的位置,如下图所示:

每个节点同等级的上、下、左、右兄弟节点的huffman编码可以根据自己处于父节点的位置(左上、右上、左下、右下)推导出来。在第一步更新了四叉树的虚拟叶子节点之后,遍历所有的虚拟叶子节,通过每个叶子节点的左上、右上、左下、右下兄弟节点的huffman编码找到每个叶子节点的兄弟节点,若兄弟节点的virtualLeaf值为false,则在兄弟节点与该节点共享的边上存在裂缝,进行修补:找出兄弟节点在该边因细分所添加的三角形网的顶点,将这些点的索引依次压入该节点该条边用于修补裂缝的点的链表。至此,修补裂缝结束;最后创建新的索引缓冲:遍历所有虚拟叶子节点,若该节点四个边的用于修补裂缝的点的列表均为空,则将该节点的索引压入索引缓冲,否则,将该节点存在裂缝的边的用于修补裂缝的点的链表作为构建地形的三角形网的顶点,压入该节点的索引。至此,索引缓冲更新完毕。
效果图如下:


原文链接:
Unity教程之-基于四叉树UQuadtree在Unity中实现场景资源的动态管理
最新-基于四叉树的LOD地形设计
[转]基于四叉树(QuadTree)的LOD地形实现的更多相关文章
- 回想四叉树LOD地形(上)
唉.~事实上这是在差点儿相同一年前实现的东西,但当时没作好记录.放了那么久了,假设不做点总结的话,好像有点对不起自己,于是·········还是做点什么吧. 我脑洞比較小, ...
- [译]2D空间中使用四叉树Quadtree进行碰撞检测优化
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Unity2017.2.0f3 原文出处 : Quick Tip: Use Quadtrees to Detect Lik ...
- C++: 基于四叉树数据结构的自适应网格(初探)
C++: 基于四叉树数据结构的自适应网格 二叉树是一种典型的非线性存储数据结构,查找效率可以达到\(O(log_2N)\),同样,这类树状结构存在许多种变体,详细参考邓俊辉老师的<数据结构C++ ...
- Elasticsearch 在地理信息空间索引的探索和演进
vivo 互联网服务器团队- Shuai Guangying 本文梳理了Elasticsearch对于数值索引实现方案的升级和优化思考,从2015年至今数值索引的方案经历了多个版本的迭代,实现思路从最 ...
- Ogre代码学习之1——Ogre中地形lod的基础:deltaHeight的计算
Ogre的地形系统中的重要概念:高度差,英文HeightDeltas,表示某个完整细节中的顶点,在某个它被隐去的lod中被插值之后的高度和原始高度(即高度图中的高度)之差. DeltaHeight = ...
- 转:Ogre TerrainGroup地形赏析
1.1 参考 http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Ogre+Terrain+System http://www.ogre3d.org ...
- WebGL简易教程(九):综合实例:地形的绘制
目录 1. 概述 2. 实例 2.1. TerrainViewer.html 2.2. TerrainViewer.js 3. 结果 4. 参考 1. 概述 在上一篇教程<WebGL简易教程(八 ...
- Ogre 1.8 terrain 和 paging 组件
以下转自:http://hi.baidu.com/xocoder/item/e8d87cf53d87612b753c4cfd OGRE地形生成 OGRE可以通过两个接口来生成地形,分别是void Te ...
- 游戏引擎架构 (Jason Gregory 著)
第一部分 基础 第1章 导论 (已看) 第2章 专业工具 (已看) 第3章 游戏软件工程基础 (已看) 第4章 游戏所需的三维数学 (已看) 第二部分 低阶引擎系统 第5章 游戏支持系统 (已看) 第 ...
随机推荐
- 安卓第六天笔记--ListView
安卓第六天笔记--ListView 1.AdapteView AdapteView 继承ViewGroup它的本质是容器 AdapterView派生了3个子类: AbsListView AbsSpin ...
- 【原】iOSCoreAnimation动画系列教程(一):CABasicAnimation【包会】
本文的最新版本已经发布在简书[编程小翁]上,强烈建议到上查看简书,[点击这里跳转]. 在iOS中,图形可分为以下几个层次: 越上层,封装程度越高,动画实现越简洁越简单,但是自由度越低:反之亦然.本文着 ...
- c语言中的部分字符串和字符函数
// // main.c // homeWork1230 // // #include <stdio.h> #include <string.h> #include <c ...
- spring aop 拦截业务方法,实现权限控制
难点:aop类是普通的java类,session是无法注入的,那么在有状态的系统中如何获取用户相关信息呢,session是必经之路啊,获取session就变的很重要.思索很久没有办法,后来在网上看到了 ...
- Android平台二维码之生成,扫描 & 识别
1.二维码的前世今生 “二维条码/二维码(2-dimensional bar code)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的:在代码编制上巧妙地利 ...
- dig与dns基本理论——解析和缓存
DNS(Domain Name System,域名系统)也许是我们在网络中最常用到的服务,它把容易记住的域名,如 www.google.com 翻译成人类不易记住的IP地址,如 173.194.127 ...
- Linux网络编程&内核学习
c语言: 基础篇 1.<写给大家看的C语言书(第2版)> 原书名: Absolute Beginner's Guide to C (2nd Edition) 原出版社: Sams 作者: ...
- 命令行方式使用abator.jar生成ibatis相关代码和sql语句xml文件
最近接手一个老项目,使用的是数据库是sql server 2008,框架是springmvc + spring + ibatis,老项目是使用abator插件生成的相关代码,现在需要增加新功能,要添加 ...
- ajaxFileUpload文件上传
一.简介 ajaxFileUpload是一种异步的文件上传控件,通过ajax进行文件上传,并获取上传处理结果.在很多时候我们需要使用到文件上传的功能,但是不需要使用那些强大的上传插件.此时就可以使用a ...
- 第一次wubi安装Ubuntu的经历及所走的弯路
#安装目标:利用xp存储剩余空间安装ubuntu, 形成双系统. 整理出待安装的磁盘空间 #需要无损磁盘工具, 用了"傲梅分区助手", 偷懒没有选其他高大上的英文软件. XP下硬盘 ...