ROAM实时动态LOD地形渲染(转)

ROAM实时动态LOD地形渲染(转)[@more@]

  1 引言

  

  如果没有接触过涉及到细节等级(LOD)的地形生成法则,恐怕你就不能在地形可视化的世界里任意挥舞你的指挥棒了。细节等级是一种使用了一系列启发式的方法来决定地形的哪一部分需要看起来有更多的细节的技术。在这里,对于地形渲染的许多技术挑战之一是如何存储一个地形的特征。高度图是事实上的标准解决方案,简单的说他们就是保存地形每点高度的二维数组。

  

  2 LOD地形法则概论

  

  一个LOD地形法则的优秀概述可以被三篇论文来描述,作者分别为[1微软的Hoppe][2 Lindstrom][3 Duchaineau]。在第一位作者的论文中描绘了一个基于Progressive Meshes的法则,这是一个与增加三角形到任意网格来达到你需要的细节相关的新的和绝妙的技术。这篇论文是一篇精彩的读物但有点复杂,同时这项技术需要大量的内存。第二篇论文的作者是Lindstrom,他描述了一个叫四叉树(Quad Tree)的结构用于描绘地形碎片(PATCH),一个四叉树递归的把一个地形分割成一个一个小块(tessellates)并建立一个近似的高度图。四叉树非常简单但很有效。第三篇论文的作者是Duchaineau,他描述了一个基于二元三角树结构的法则ROAM(实时优化自适应网格)。这里每一个小片(PATCH)都是一个单独的正二等边三角形,从它的顶点到对面斜边的中点分割三角形为两个新的正等边三角形,分割是递归进行的可以被子三角形重复直到达到希望的细节等级。由于ROAM法则的简单和可扩展性吸引了我的目光。不幸的是这片论文非常短,仅仅只有少量的伪代码。但无论如何,他可以在连续的范围实现从最基本的平面到最高级的优化。而且ROAM分割成小方块非常快速,而且可以动态更新高度图。

  

  3 ROAM执行初步

  

  代码用Visual C++ 6.0来写的,使用OPENGL来渲染。

  

  ROAM资源说明

  

  让我使用一个概述来介绍这个法则,然后讨论单独的小块是如何相互影响的:

  

  1高度图文件被载入内存并和一个Landscape类的实例相联系,多个Landscape物体连接起来产生无限的地形。

  

  2一个新的Landscape物体把载入的高度图的一部分包裹到新的Patch类物体中,这一步的目的是:

  

  (1)使用基于树的结构来控制随着深度而呈指数增长的内存,这样可以保持他们的深度在一个很小的有限的范围。

  

  (2)动态更新高度图需要在变更场景时有一个完整的变更树从算操作。过大的Patch类物体在实时重新计算时非常慢。

  

  3每一个Patch类物体被调用来建立一个MESH的近似值(分割成小块)。Patch类物体使用了一个叫二元三角树的结构来存储即将显示在屏幕上的三角的坐标。这些三角形顶点坐标被非常合理的存储,ROAM使用36字节以上的内存来存储每一个三角形。高效的坐标计算也是渲染的一部分(见下)。

  

  4在分割完高度图后,引擎已经建立了二元三角树。树的叶节点保存了需要进入图形渲染流水线的三角形。

  

  高度图文件格式

  

  高度图使用一个RAW的数据格式来保存,这个格式包含了8位的高度信息。通常高度图必须从头至尾保存在内存中,在高级标题中我将讨论如何扩展法则来呈现大的数据集。

  

  二元三角树Binary Triangle Trees

  

  ROAM使用了二元三角树来保持三角坐标而不是存储一个巨大的三角形坐标数组来描绘地形。这个结构可以看作是一个测量员把地形切断为一个一个小三角块的结果。这些三角块逻辑上看就象一组相连的邻居一样(左右邻居)。同样的当一个三角块把土地当作遗产时,他需要平等的分给两个儿子。

  

  用这样进行扩展,这个三角块就是二元三角树的根节点,其他三角块也是他们各自树的根节点。Landscape类如同一个局域的土地注册表,保存所有三角块的索引,同时也保存他们之间的层次关系。由于大量子三角块的产生,分割土地也成为一个沉重的负担,但是大量的细节可以被需要更好模拟的区域的种群'population'来简单的处理。看图一:

  
  2004.12.28.16.13.58.1.gif

  
图一 二元三角树结构等级0-3

  

  二元三角树被TriTreeNode结构保存,同时他还保存ROAM需要的五个最基本的数据,参考图二。

  

  struct TriTreeNode {

  TriTreeNode *LeftChild;

  // Our Left child

  TriTreeNode *RightChild;

  // Our Right child

  TriTreeNode *BaseNeighbor;

  // Adjacent node, below us

  TriTreeNode *LeftNeighbor;

  // Adjacent node, to our left

  TriTreeNode *RightNeighbor;

  // Adjacent node, to our right

  };

  

  
  2004.12.28.16.14.37.2.gif

  
图二 基本的二元三角树的子和邻节点

  

  当对高度图建立一个网格模拟值时,我们需要向二元三角树中添加子节点直到达到我们需要的细节。这一步完成后重新遍历整个树,此时把子节点中保存的三角形数据渲染到屏幕上。这就是一个最基本的引擎了但需要重新设置每一帧,这种递归的方法最大的优点是我们不需要保存每一个顶点的数据,可以释放大量的内存给其他物体。实际上,TriTreeNode结构需要多次的建立和销毁,但这种方法是非常高效的,同时我们或许需要建立几万个这样的结构,因此我们需要一个指针指向我们需要的内存,TriTreeNode结构是通过一个静态内存池来分配的,而不是动态分配,他也给了我们一个快速的重新设置状态的方法。

  
  2004.12.28.16.14.48.3.gif

  
图三 典型的地形PATCH,从左至右依次是网格模式,光照模式,纹理模式

  

  4 Landscape类的详解

  

  Landscape类对地形的细节渲染进行了高级的封装,通过一些简单的函数调用我们可以在屏幕缓冲中进行从简单的点的显示到复杂的地形渲染工作。这里是Landscape类的定义。

  

  class Landscape {

  public:

  void Init(unsigned char *hMap);

  // Initialize the whole process

  void Reset();

  // Reset for a new frame

  void Tessellate();

  // Create mesh approximation

  void Render();

  // Render current mesh static

  TriTreeNode *AllocateTri();

  // Allocate a new node for the mesh

  protected:

  static int m_NextTriNode;

  // Index to the next free TriTreeNode

  static TriTreeNode m_TriPool[];

  // Pool of nodes for tessellation

  Patch m_aPatches[][];

  // Array of patches to be rendered

  unsigned char *m_HeightMap;

  // Pointer to Height Field data

  };

  

  Landscape类管理了一个大的正三角块,同时可以和其他Landscape物体一起工作。在初始化过程中,高度图被分割成大量的可管理的小块,同时把他和一个新的Patch物体联系起来。Patch类及其它的方法我们将在下面花费更多的时间讲解。注意这些函数的简单性,Landscape物体本身是设计用于一个简单的渲染流水线的,尤其是在可以免费使用Z缓冲的今天。

  

  5 Patch类详解

  

  Patch类是这个引擎的灵魂,他可以分为两部分,一半是递归部分,另一半是基本函数部分,下面就是这个类的数据成员和基本函数描述:

  

  class Patch {

  public:

  void Init( int heightX, int heightY, int worldX, int worldY, unsigned char *hMap);

  // Initialize the patch

  void Reset();

  // Reset for next frame

  void Tessellate();

  // Create mesh

  void Render();

  // Render mesh void

  ComputeVariance();

  // Update for Height Map changes

  ...

  

  

  protected:

  unsigned char *m_HeightMap;

  // Adjusted pointer into Height Field

  int m_WorldX, m_WorldY;

  // World coordinate offset for patch

  

  unsigned char m_VarianceLeft[];

  // Left variance tree

  unsigned char m_VarianceRight[];

  // Right variance tree

  

  unsigned char *m_CurrentVariance;

  // Pointer to current tree in use

  unsigned char m_VarianceDirty;

  // Does variance tree need updating?

  

  TriTreeNode m_BaseLeft;

  // Root node for left triangle tree

  TriTreeNode m_BaseRight;

  // Root node for right triangle tree

  ...

  

  在上面的代码中,下面要解释的基本函数被每一个PATCH物体所调用,PATCH类的方法名类似于调用他们的Landscape类的方法,这些方法或许太单纯化这里需要详细的解释一下:

  

  Init()函数需要高度图和世界坐标的偏移值,他们用来对地形进行缩放,指向高度图的指针已经经过调整,指向了这个PATCH物体所需要数据的第一个字节。

  

  Reset()函数释放所有无用的TriTreeNodes结构,接着重新连接两个二元三角树成为一个PATCH,现在这些还没有被提及,但是每一个PATCH物体都有两个单独的二元三角树构成一个正方形(ROAM论文中称为'Diamond')。如果不明白的话再看一下图二,详细的内容下一节再讨论。

  

  Tessellate()函数简单的传递适当的高级三角形参数(每一个PATCH物体的两个根节点)给一个递归版本的函数,函数Render()和ComputeVariance()也是这样。

  

  6 ROAM精华

  

  讲了这么多我们只是

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/8225414/viewspace-952138/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/8225414/viewspace-952138/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ECharts(Enterprise Charts)是百度开源的一个数据可视化库,它支持多种图表类型,包括地形图(Geo)。地形图是一种可以展示地理信息的图表类型,可以用来显示地理区域的分布情况、热力图等。 在ECharts中,使用地形图需要引入Geo组件,并设置相应的地理坐标数据。你可以通过提供的地理数据,如经纬度、名称等信息,来构建地形图。 以下是一个使用ECharts绘制地形图的简单示例代码: ```javascript // 引入ECharts库 import echarts from 'echarts'; // 创建地形图实例 const chart = echarts.init(document.getElementById('chart-container')); // 地理坐标数据 const geoData = [ { name: '北京', value: [116.407394, 39.904211] }, { name: '上海', value: [121.473662, 31.230372] }, // 其他地理坐标数据... ]; // 设置地形图配置项 const option = { title: { text: '地形图示例', subtext: '数据仅供参考', left: 'center' }, tooltip: { trigger: 'item' }, geo: { map: 'china', roam: true, label: { emphasis: { show: false } }, itemStyle: { normal: { areaColor: '#dddddd', borderColor: '#666666' }, emphasis: { areaColor: '#cccccc' } } }, series: [ { name: '地形图', type: 'effectScatter', coordinateSystem: 'geo', data: geoData, symbolSize: 10, showEffectOn: 'render', rippleEffect: { brushType: 'stroke' }, hoverAnimation: true, label: { formatter: '{b}', position: 'right', show: true }, itemStyle: { color: '#336699' } } ] }; // 渲染地形图 chart.setOption(option); ``` 以上示例使用ECharts的effectScatter系列来展示地理坐标点,可以根据自己的需求进行配置和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值