矢量在全球规则格网地形上的叠加绘制方法

为了精确、高效地将传统的且对地形有约束作用的二维矢量数据叠加绘制到多分辨率全球地形上,提出了一种基于矢量高程纹理矢量叠加绘制方法。首先将矢量高程渲染到矢量高程纹理金字塔中,然后在GPU中采用膨胀方法对高程纹理进行处理,在绘制地形网格时根据从矢量高程纹理中的采样值调整顶点高度,最后叠加绘制矢量网格。实验表明,该方法可与Clipmap等主流多分辨率规则格网地形模型结合,在地形上精确绘制矢量,并有效解决由于地形网格精度导致的矢量边缘被地形遮挡问题。
    一个三维场景通常由地形和地形表面上的矢量共同构成。由此产生一个问题,如何在三维地形上叠加绘制矢量。特别是当前多数三维场景均采用了多分辨率地形模型,使得地形几何表面随视点变化[1],这增加了问题的难度。已有的研究集中于如何将矢量数据紧贴着地形绘制到场景中[2-4],这种绘制方法对于抽象化的矢量符号是足够的,但在具有真实感的场景中,矢量数据的存在往往会对地形产生约束作用5,对于这种情况下矢量在地形上的叠加绘制研究较少。文献[5]提出采用足迹纹理和高程纹理合成绘制矢量地形的方法,但其论述是基于平面场景的,而对于如何将足迹纹理应用到规则球面地形网格及如何解决地形网格精度不够时的矢量压盖等关键问题并未深入探讨。
    受文献[5]启发,本文以面状矢量要素为例,提出了GPU友好的在规则球面地形网格上叠加绘制矢量数据的方法,并对其中出现的矢量边缘被地形压盖的问题进行了分析和改进。本文采用的矢量绘制方法主要分为4个步骤:1)将要绘制的矢量数据预先正射的绘制到一张32位浮点型矢量高程纹理上,这张纹理称为矢量高程纹理;2)对矢量高程纹理进行膨胀修正,以避免矢量边缘被地形压盖的问题;3)在绘制地形网格的顶点着色器中,从矢量高程纹理中采样出高程值,据此修改顶点高程;4)将要绘制的矢量构建成三角网,然后进行绘制。

  • 1地形数据的组织
        为平衡全球海量地形的渲染质量和速度,一般采用面向全球的多分辨率金字塔模型组织地形[6]。这种技术把全球地形按经纬度分成不同的层和块,所有地形块的地形网格连在一起,构成全球地形网格。当视点移动时,需将已不在视锥体内的地形块从内存中卸载,并用新的地形块替换。当视点向地球靠近时,使用精细的地形块替换粗糙的地形块。相反,当视点离开地球时,使用粗糙的地形块替换精细的地形块。参考文献[1]中的方法组织并绘制地形,建立一个以视点为中心的L层,每一层由M*M个四边形组成地形网格金字塔,每一层网格的边长是相邻粗糙层的1/2。不同地形层间的关系和每个地形块内的网格结构如图1所示。
  • 2矢量高程纹理的绘制
      2.1矢量高程纹理的组织
      通过把同一层地形块范围内的矢量数据正射的绘制到与地形范围重合的浮点纹理上来获得矢量高程纹理,其与传统基于纹理的矢量绘制方法不同的是,写入纹理的数据是矢量高程。
      为了减少纹理分辨率引起的变形,并控制纹理开销,本文采用实时纹理金字塔技术[3]管理矢量高程纹理,将矢量高程动态绘制到数量和范围与地形层次相同的L张纹理上。由于精细层范围是粗糙层范围的1/4,但用的纹理分辨率相同,这就保证了越靠近视点使用的高程纹理越精细。
      2.2纹理坐标和纹理矩阵的计算
      为把球面上地形网格的顶点映射到矢量高程纹理上,采用切圆柱墨卡托投影将球面投影到平面矩形上,并以矩形的左上角点为原点,纬线方向为u轴,经线方向为v轴,建立图2所示纹理坐标系。
      
      采用下式计算每个地形顶点的纹理坐标(u,v):
      
      式中:x为顶点经度,西经为负,东经为正;y为顶点纬度,北纬为正,南纬为负。计算出的坐标称为全局纹理坐标,为将其映射为每个矢量纹理的坐标,需对其进行矩阵变换:
      
      其中:ω、φ分别为矢量纹理左、右上角经度,width为矢量高程纹理u方向跨过的经度,height为v方向跨过的纬度。因为GPU所能接受的纹理坐标精度为32位浮点型,为了减小舍入误差,提高纹理坐标精度,为每个顶点纹理坐标扩大了2L倍,L为顶点所在层号,所以实际采用的纹理矩阵是:
      
      通过把每一层纹理的全局纹理坐标范围传给GPU,可以在绘制地形的顶点着色器中计算出当前顶点所位于的最精细层是哪一层,然后把其全局纹理坐标乘以相应层的纹理矩阵,从而获得用来在矢量高程纹理中采样的纹理坐标。
      2.3动态生成矢量高程纹理
      文献[2]为了解决矢量覆盖区地形和周边地形间的平滑过渡问题,引入了Z曲线,但采用此方法需要把矢量在构建三角网时划分为边界和内部两部分,使得问题复杂化。本文只考虑强制地形位于矢量下方的情况,因此只需把矢量的高程保存到矢量三角剖分后的顶点属性中,就可以在片元着色器中将矢量高程写入纹理中。
      根据当前绘制的最粗糙层的范围,从矢量图层中查询出范围内的矢量纹理,将矢量三角剖分为三角链后,采用正射投影的方式绘制矢量。以32位浮点纹理作为矢量纹理,将纹理默认值设置为一个极大值作为非法值,将矢量高程写入纹理中,这一过程在片元着色器中完成。
  • 3.矢量高程纹理的膨胀修正及对地形高程的修改
      3.1矢量边缘压盖问题
      在使用矢量高程纹理修改地形的过程中,由于矢量覆盖区域与高程纹理栅格并不重合,会引起矢量边缘的精度损失。如图3所示,虚线网格为矢量高程纹理的栅格结构,实线区域为原始的矢量范围,黑色区域为写入矢量高程纹理的矢量范围,灰色区域为矢量边缘精度损失部分。这会导致当矢量叠加绘制到地形后,其边缘被地形压盖、闪烁等现象(图4)。
      
      
      可以通过提高矢量高程纹理分辨率和地形网格密度来减少边缘精度损失。对于平面场景,可通过将一小块规则网格不断地平移和缩放联结成整个场景的地形,因此对这一小块地形提高精度对其渲染性能影响不大。但是对于球面场景,由于不同纬度的四边形网格形状不同,需要把整套网格顶点放在顶点缓冲区并进行渲染,所以提高地形格网密度对性能影响很大。
      3.2膨胀修正方法
      对矢量纹理进行“膨胀”操作,使得到的矢量高程纹理比原来大一圈,以保证修改后的矢量在高程纹理上的对应像素区域能够完全包含矢量本身的范围。需要确定这个膨胀范围多大合适,膨胀范围应该恰好能够比膨胀前多压盖一个地形网格。由于每一层地形都对应一张矢量纹理,纹理的大小pp和每层的地形网格数n都是固定的,所以每个地形网格的一条边占用了纹理上的p/n个像素。所以为了使得在纹理上膨胀的部分能够压盖一个完整网格,需要膨胀√2p/n个像素。
      图像膨胀操作的基本原理是:用一个(2k+1)
    (2k+1)大小的结构元素扫描原图像的每个元素,用结构元素与其覆盖的二值图像做“与”操作,如果都为0,则结果图像的该元素为0,否则为1,其结果图像将比原图像扩大k个像素大小的一圈。根据上述计算结果,结构元素k=√2p/n。
      为了提高膨胀操作的速度,把它放在GPU中处理。方法是绘制一个大小与矢量纹理相同的与屏幕对齐的矩形到一个32位浮点纹理中,在片元着色器中以原始图像作为纹理输入,进行膨胀操作。其glsl语言的片元着色器代码如下:
    const int KernelSize=170;
    uniform sample2D baseImage
    uniform vec2 offset[KernelSize];
    uniform float MAXVALUE;
    void main(){
      float heightValue=0.0;
      float resultHeightValue=0.0;
      resultHeightValue=texture2D(baseImage,gl_TexCoord[0].st);
      for(int i=0;i<kernelsize;i++){
      heightValue=texture2D(baseImage,gl_TexCoord[0].st+offset[i]);
      if(heightValue!=MAXVALUE){
       resultHeightValue=heightValue;
       break;
      }

      gl_FragColor=vec4(resultHeightValue);

      其中:KernelSize为(2k+1)
    (2k+1),baseImage为原始的矢量纹理,offset数组保存的是结构元素矩阵中每个元素相对于矩阵中心的偏移量。MAX-VALUE是矢量纹理中没有被矢量覆盖区域存储的标识值。
      3.3使用矢量高程纹理修改地形高程
      绘制地形时,在顶点着色器中根据顶点纹理坐标分别从矢量纹理和高程纹理中采样出纹理值,以矢量纹理中的非极大值的采样值修改地形顶点高度。在以球心为原点的世界坐标系中,球面网格顶点可由下式计算:

     在地形顶点着色器中,可按下式调整顶点位置:
     
     pos.xyz=pos.xyz*(Radius+h)/Radius
      其中:Radius为地球半径,latitude和longitude为顶点经纬度,h为从矢量高程纹理中获得的采样值。
  • 4.矢量的叠加绘制
      采用墨卡托切圆柱投影将面状矢量的顶点投影到一个横轴为经度、纵轴为纬度的矩形平面上,在此平面坐标系下进行三角剖分,将面状矢量转化为一个相互连接的三角网结构,由式(1)得到矢量顶点在三维空间中的位置。这样一个二维面状矢量就转化为了三维空间中一个随地球弯曲的三角形构成的折面,将此折面叠加绘制到修改过高程的地形上即可。
      当面状矢量范围很大,此时矢量折面与球面地形贴合不好,可用模板阴影体法代替上述方法。
  • 5.实验结果
      在Win32平台下,基于C++和OGRE渲染引擎构建了一个验证系统。动态绘制6层地形网格,每一层包含6464个四边形地形网格,每一个网格剖分为2个三角片。默认视场角为90°,屏幕分辨率为1440900,由此计算出最精细层地形三角面占大约30.625个像素。使用6张1024*1024分辨率的纹理作为矢量高程纹理,此时纹理资源大小为24M。纹理覆盖范围与地形网格相应层对应。
      实验中采用上文提出的方法以解决在地形上叠加绘制水体的问题,通过“展平”水体矢量所覆盖地形,使得水体不被地形所遮挡。实验地形数据采用京津地区分辨率为30m的地形数据,矢量数据采用京津地区湖泊数据。图5a为没有采用本文方法时水体矢量被地形遮挡的情况,图5b为采用本文方法后矢量与地形的叠合情况,图6a为使用矢量高程纹理修改地形前后的地形网格情况。可见通过矢量高程修改纹理,可以有效解决矢量数据被地形遮挡的问题。
      
      
      
      
  • 6结语
      本文提出了基于矢量高程纹理在球面规则地形网格上叠加绘制矢量的方法。理论和实验证明,通过把矢量动态绘制到6张矢量高程纹理上,再在GPU顶点着色器中动态修改地形高程,可以有效地解决由于地形数据和矢量数据精度不同导致的地形遮挡矢量问题。通过对矢量高程纹理进行膨胀操作,使矢量的边界部分不会被地形网格遮挡。

矢量在全球规则格网地形上的叠加绘制方法相关推荐

  1. arcgis中dem坐标定义_GIS基础-DEM Grid规则格网结构

    Grid规则格网定义 将区域空间切分为规则的格网单元,每个格网单元对应一个数值.数学上可表示为矩阵,计算机实现中则是二维数组,每个格网单元的一个元素对应一个高程值.每一个网格(cell)具有唯一的行( ...

  2. 构建规则格网进行体积计算

    构建规则格网进行体积计算 1.构建规则格网 1.1生成所有格网点 2.计算体积 2.1计算凸包所包含的所有格网点 2.2插值计算凸包内格网点的高程 2.3计算体积 总体步骤: 生成凸包多边形 构建规则 ...

  3. 一种基于格网的快速等值线充填算法

    摘 要:本文提出一种基于格网的等值线跟踪,适用于任意边界分割的快速充填算法,实现充填的矢量化效果.根据边界线与非封闭等值线间的关系,建立等值线间的拓扑关系,并以树结构方式存储,以准确快速地实现边界线. ...

  4. TIN与DEM的知识介绍及格网DEM生成不规则三角网TIN方法

    1.DEM    数字高程模型(Digital Elevation Model, DEM)作为地理信息系统数据库中最为重要的空间信息资料和赖以进行地形分析的核心数据系统,国家测绘部门将其作为国家空间数 ...

  5. (JAVA)全球格网图幅编号计算基于图幅进行GIS数据切瓦片的思路

    本篇就是随便写的,想到哪写到哪,不谈什么算法和源码,就是看效果,先看张图: 上面的格网(矢量图层)是采用1:25W的比例尺计算而来的 标准的比例尺总过有8种,如下: 首先我们要想要对江浙沪皖(江苏,浙 ...

  6. c++多边形扫描线填充算法_基于3DGIS技术的梯形格网构建及其简化算法设计

    传统矢量地图LOD绘制流程包含简化.剖分与渲染三个步骤.由上述分析可知,传统矢量地图LOD绘制流程中简化与剖分是两个独立的过程,重复的剖分计算导致其渲染效率相对低下.梯形格网方法解决了传统方法中重复剖 ...

  7. ArcGIS基础:获取栅格数据边界的线要素和独立格网面

    本操作是为了提取栅格DEM数据的边界数据: 看一下原始数据:是一个非常普通的DEM栅格数据. [方法:1]:使用[栅格范围]工具,通过搜索工具进行查找,如下所示: 该工具可以直接提取栅格外边界数据,得 ...

  8. ArcGIS基础实验操作100例--实验24提取栅格独立格网面

    本实验专栏参考自汤国安教授<地理信息系统基础实验操作100例>一书 实验平台:ArcGIS 10.6 实验数据:请访问实验1(传送门) 基础编辑篇--实验24 提取栅格独立格网面 目录 一 ...

  9. c++实现快速气象格网数据成图: 风力图, 卫星云图,雷达反射图, 雨量图,温度图

    输入数据格式说明: 以上DISK和REG开头都为气象云图为红外数据 PRCP为降雨量图 TMP为温度图 U和V开头的为水平和垂直风力分量数据 Z_OTH为雷达反射图 先放成图效果,后方成图算法,效果图 ...

最新文章

  1. 解决robotframework安装时提示wxPython not found问题
  2. (chap8 确认访问用户身份的认证) DIGES认证(摘要认证)
  3. vs五子棋c语言代码,五子棋代码C语言版.doc
  4. 关于SQLContext过期,SparkSession登场
  5. 亚马逊 OpenJDK 发行版 Corretto GA
  6. linux coreutils升级,Coreutils
  7. IOS scrollView 知识点
  8. linux定时任务不能执行.sh脚本,求助sh脚本手动可以执行crontab不能执行的问题
  9. java int和String类型之间的相互转换
  10. 杀不死的人狼——我读《人月神话》(四)
  11. 单点登录(SSO)解决方案之 CAS服务端数据源设置及页面改造
  12. pandas将某列复制到另一个表_使用pandas将列从一个数据帧复制到另一个数据帧的最快方法?...
  13. Character的static方法
  14. 通过 微软 pai-fs 上传数据到HDFS (Microsoft OpenPAI)
  15. IDEA快速生成测试用例类和完成单元测试
  16. Java中的类加载器详解
  17. 方程从pdf转word_在Word中创建化学方程式和图表
  18. 日本IT公司工作体验
  19. kernel logo的制作
  20. 微信点餐html5模板,【瑞蚁原创分享】12:springboot微信点餐之微信模板

热门文章

  1. VB与VB.NET的区别
  2. 数据结构课程主页-2016级
  3. 层次分析法------小学生都会的算法~~~
  4. MySQL用户管理-密码修改-用户授权
  5. 导航栏不变 页面切换 最简单的方法
  6. stm32外设-RCC
  7. 杨辉三角中第 n 行第 m 个数字
  8. 有趣的转义字符,常见转义字符大全,转义字符速查手册 Escape character
  9. lenovo服务器换系统重装系统_thinkserver服务器怎么重装系统?
  10. android 存储盘 dcim,DCIM是什么?教你轻松理清照片存放路径