用Ogre实现无缝地图

2023-05-16

Ogre实现无缝地图

         1.7版本之前,如果想用Ogre内建的地形系统实现一个像样的无缝地图,恐怕要闹到抓狂。所幸sinbad1.7Ogre加入了全新的地形组件,它囊括了一个地形系统所需要的基本功能,并且具备扩展出丰富特性的能力,使开发者得以避免重复造轮子的麻烦。

         以《魔兽世界》为标杆,我们尝试使用Ogre的新地形系统,构建一个类似的无缝地图,它理论上支持无限扩展、支持挖洞、支持缤纷易变的地貌、采用分层纹理混合的方式进行渲染。

 

分页

         无缝地图的精髓在于分块,动态地加载视野所及的地形块,动态地卸载不再活跃的地形块,这是实现无限连续地形的基本原理。

         Ogre使用分页模块(OgrePaging)和地形模块(OgreTerrain)配合实现地形的动态加载。

         分页模块的类构架如下:

         PageManager

                  PagedWorld

                            PagedWorldSection

                                     Page        

                                               ContentCollection

                                                        Content

         PageManger管理整个分页系统,这一层保存着下层对象的工厂列表,同时实现了一些

实例化下层对象的方法。

         PagedWorld类用于声明一个分页的世界,扮演的角色相对较弱。

         PagedWorldSection按照字面意思是世界中一块区域,这一层是分页功能主体所在。本层通过当前的分页策略PageStrategy类对象,根据Page和相机的距离,调用loadPage(),驱动Page发送WorkQueueRequest以完成加载,或者调用unloadPage()完成Page卸载,这是分页的关键。

         下来的一层是受PagedWorldSection管理的Page,即分页系统中的基本单元——页,再下来是内容集类ContentCollection及其下的内容类Content,它们代表了一个页中包含的内容。

         配合分页模块,地形模块代码结构如下:

         TerrainPaging

                  PageManager

         TerrainPagedWorldSection

                   TerrainGroup

         可以看到,地形模块的类和分页模块的类结构并非一一对应。

         TerrainPaging类包含了一个PageManager的对象,仅此而已,可以将其视为等同于PageManagerPagedWorld类直接被略过。

         继承自PagedWorldSection TerrainPagedWorldSection类则比较关键,其中包含有一个TerrainGroup对象。在TerrainPagedWorldSection中,地形Terrain被视为和Page处于对等地位的块,这些地形被按照位置映射存储在TerrainGroup里,重载的loadPage()unloadPage()在加载、卸载Page的同时,驱动TerrainGroup加载、卸载对应位置槽里的Terrain实例。

         Ogre一贯秉承“结构重于特性”的理念,所以代码读起来难免有些拗口。总得来说,Ogre借助Paging分页系统,管理一个TerrainGroup下的多个地形,完成了地形的分块加载。

       实际上,如果不需求分页动态加载的话,你还可以选择不使用OgrePaging系统,而使用自己的方法来管理TerrainGroup

 

         地形上的洞要求地形的一部分镂空或不予显示,一般用来制作深入地形的洞穴或地堡。

         Ogre地形挖洞的问题在Ogre社区里有不少讨论,但似乎没有公认的靠谱办法。在开洞处使用透明贴图过于笨拙且浪费资源,而更改地形的顶点索引留出开洞部分也由于略显复杂而少有人问津。

         我们使用隐藏挂接于地形四叉树下的场景节点的方法。Ogre的地形使用四叉树管理LOD,整个地形被细分为一颗四叉树,不同深度的树节点代表LOD系统中不同的地形细节,可以想象根节点代表着LOD最粗糙的一级,往下类推。每个四叉树节点下包含一个场景节点,用于显示该节点对应的顶点列表。这些场景节点被挂接在地形实例所创建的场景根节点上,组成一棵深度为2的场景树。地形四叉树节点和场景节点的关系如下图所示。

OgreTerrain_Tree 

         Ogre中显示或隐藏一个场景节点是很方便的,我们可以找到开洞部分对应的场景节点,将其隐藏,从而达到地形挖洞的效果。

         Ogre地形使用Skirt技术解决LOD带来的T裂缝问题,即每个LOD地形块由四周往外延伸出一格并垂直折下,宛如为自己围上一条裙子,用来遮挡当相邻地形块处于不同LOD层级时可能会出现的裂缝,这样的地形块看起来就像一个没有底面的方形盒子。如果在地形上开洞,留意把SkirtSize设小一点,以免透过洞口看到这些盒子的侧边。

 

LOD结构

         有三个参数对Ogre地形的网格结架比较重要:terrainSizeminBatchmaxBatch

terrainSize决定地形的顶点数目,minBatch决定四叉树非叶节点所包含的顶点数目,maxBatch决定四叉树叶节点所包含的顶点数目。

LOD的数目也并非等同于四叉树的层数,在非叶节点,一层四叉树对应一个LOD,顶点数目为minBatch;但是在叶节点,则包含了从minBatchmaxBatch的一套LOD列表。

         按照理论,Ogre地形LOD层数及四叉树深度计算公式如下:

LODlevels = log2(size - 1) - log2(minBatch - 1) + 1

TreeDepth = log2((size - 1) / (maxBatch - 1)) + 1

值得一提的是,由于OgreTerrain的顶点采用16位索引,所以所能索引到最大顶点数目为TERRAIN_MAX_BATCH_SIZE,这样一来,不仅仅顶点索引会根据四叉树分层,顶点数据本身也会根据四叉树分块,理论上顶点数据被分为terrainSize / TERRAIN_MAX_BATCH_SIZE块,但由于上层LOD不能跨块进行索引,Ogre会再开辟一些新的块,所以总共用到的顶点数据会多于实际数据,另外层与层之间视情况还可能共享顶点,比较复杂。根据官方的解释,这种多建顶点的办法更易实现且数目不大,所以是可接受的;更重要的是在制作超大场景的时候,大量底层顶点缓存可以在低LOD时被释放,这在降低内存占用上很重要。TERRAIN_MAX_BATCH_SIZE这一特殊设定的存在,限定了地形的maxBatch不能大于TERRAIN_MAX_BATCH_SIZE,地形本身的size不能小于TERRAIN_MAX_BATCH_SIZEterrainSize小于TERRAIN_MAX_BATCH_SIZE会导致只有Top节点有顶点数据)。TERRAIN_MAX_BATCH_SIZE = 129,在使用时需要谨记。

 

渲染

         魔兽世界渲染地形时使用最多4层地形贴图和一张混合贴图,地形贴图的Alpha通道用于高光贴图,混合贴图的Alpha通道用于阴影。

         尽管在资源压缩利用上可能没有魔兽这么严格,但这种时下标准的地形渲染方式在Ogre新地形系统中也都得到了较完善的支持。另外Ogre地形还内建有动态阴影、顶点色图、合成图生成、光照图生成等功能,不过如没有特别需求,可以尝试适当关闭其中几个,此举能在保持基本效果的同时,为最终生成的每个地形文件省去非常可观的大小。

 

定制

每个Terrain使用一个材质,为了保证地貌足够丰富,Terrain作为最基本的渲染单元,size不能太大,terrainSize取最小值129worldSize100/3;而在地形分块时,由于TerrainPagingTerrain为单位进行分页,所以只能以Terrain同时作为动态加载单元,这和魔兽不同,魔兽相当于16x16Terrain组成一个MapTile作为动态加载单元。

         地形上每一个洞需要隐藏一个TerrainQuadTreeNode叶节点来实现,minBatch决定了非叶节点的大小,而maxBatch决定了叶节点的大小,所以maxBatch必须不能很大,考虑到wow一个单元可以开4x4个洞,所以maxBatch(terrainSize - 1)/4 + 133minBatch可自行定夺,这里取5,这样得到的LOD层数为6,四叉树深度为3

         这种定制方案看起来更加倚重Ogre地形的分页特性,而淡化了其LOD功能。

细节上,设置地形层混合图大小为64x64

         mTerrainGlobals->setLayerBlendMapSize(64);

         每层贴图worldSize8为佳;

         defaultimp.layerList[0].worldSize = 8;

         不在每层使用法线和高度贴图,所以省掉这张图,同时调用:

         matProfile->setLayerNormalMappingEnabled(false);

         matProfile->setLayerParallaxMappingEnabled(false);

         同时我们关闭了动态阴影、顶点色图、合成图、光照图:

         matProfile->setReceiveDynamicShadowsEnabled(false);

         matProfile->setGlobalColourMapEnabled(false);

         matProfile->setCompositeMapEnabled(false);

         matProfile->setLightmapEnabled(false);

         如果你使用LightMap,可能会发现得到了不跨越地形的光照图,即影子会在地形边界被截断,而不是延伸到相邻地形块。这一般是由于地形块计算光照图时没有考虑进相邻节点导致的,此时相继调用Terraindirty()update()函数,手动让地形块重新计算一遍,即可解决问题。实际情况中,光照图需要扩展,烘焙的时候需要加入地面静态物体的影子计算。

 

Demo

工程源码及资源可以移步此处下载,开发环境为Ogre1.7.3+VS2008,部分资源取自《魔兽世界》。

         源码中默认注释掉了PAGING宏定义,此时地形不使用分页系统,即不会动态异步加载,所以程序启动时会创建所有地形,稍等片刻,这可能会多花一点时间。

         待地形加载、构建完毕,通过H键可以显示或隐藏地形上的洞。

OgreTerrain_ScrnShot_0 

按下Ctrl+S,地形会在Media目录下保存为一个个形如Terrain_00000000.dat之类的文件,动态加载时使用的地形文件正是这些东西。

         接下来打开PAGING宏定义,重新编译,此时地形会在分页系统的管理下被动态加载,漫游场景时你会发现新入视野中的地形被动态加载,淡出视野的块则被动态删除,场景中添加了天空盒和雾,后者能较好地缓和远处地形的突兀变化。

OgreTerrain_ScrnShot_1 

在分页模式下地形挖洞的效果没有实现,这是因为设置挖洞需要等到地形四叉树及场景树构建完毕之后,如果不改写Ogre的源码,很难在异步加载的情况下定位到这些时间点,Demo仅仅演示了一种思路,而实现这样的功能无疑需要在Ogre源码上进行更多更系统性的扩展。

         其实对Ogre稍微熟悉就不难发现,源码和Ogre本身提供的地形例子基本上没有二致,所以Demo更像是对Ogre地形的定制,唯一称得上扩展的部分是setHoleVisible()函数,它用于实现在地形上挖洞。

源码对Ogre有些许修改,增加了几个用于访问地形相关类成员的函数,对照着加上即可。

         最后,记得在编译时开启Ogre多线程

 

 

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

用Ogre实现无缝地图 的相关文章

  • nvidia jetson TX2 踩坑解决记录

    最近拿着一张多年前实验室买的Jetson想刷个软路由玩 xff0c 奈何折腾了一周才把clash meta内核装好 xff0c 记录一下自己踩的坑 xff0c 整理一下以免其他玩jetson TX2的兄弟掉大坑 已经过去一周了很多都记不太清
  • 接收灵敏度

    接收灵敏度是检验基站接收机接收微弱信号的能力 xff0c 它是制约基站上行作用距离的决定性技术指标 xff0c 也是RCR STD 28协议中 xff0c 空中接口标准要求测试的技术指标之一 合理地确定接收灵敏度直接地决定了大基站射频收发信
  • 16行,使用Python制作简易版QQ自动回复机器人(windows版)

    目录 1 安装go cqhttp 2 使用go cqhttp 2 1 发送信息 2 1 1发送 你好 2 1 2 在群里 64 人 2 2获取群成员列表 2 3 实现QQ机器人 1 安装go cqhttp 点此安装go cqhttp xff
  • FPGA在线升级实战应用篇

    FPGA在线升级实战应用篇 1 摘要 项目在运营过程中可能需要根据应用需求更改固件 xff0c 或者对现有产品进行升级及在产品使用过程出现的故障进行分析 xff0c 故需要对产品进行升级维护 以往的产品出现的故障或BUG问题只能通过产品寄回
  • (xTaskNotify)- assert failed! 错误的修复

    今日在测试ESP32代码的时候 xff0c 使用xTaskNotify发生错误 xff0c 提示如下 xff1a xTaskNotify assert failed xff0c 然后系统重启 找了一下原因 xff0c 在xTaskNotif
  • kubernetes dashboard用户界面安装使用

    原文 xff1a https www toocruel net kubernetes dashboardyong hu jie mian an zhuang shi yong 1 下载kubernetes dashboard yaml文件
  • 网络通信编程学习笔记(四):在Ubuntu下创建新用户、用puTTY/VNCViewer远程登录、用ftp上传和下载、用Xming远程连接

    前言 真的用不惯VNCViewer xff0c 树莓派还是外接显示屏来的舒服 xff0c 分辨率也是1080p xff0c 只有全高清壁纸才可以慰籍学习之痛 xff01 Xming也是不如按开机键来的方便 笑哭 目录 一 用puTTY VN
  • node.js和npm离线安装

    离线安装node js和npm 1 下载官方安装包并拷贝到离线机器上 官方下载地址 xff1a https nodejs org en download 2 解压文件 xff1a tar xJf node v8 9 4 linux x64
  • Github 创建新分支

    一 clone Repository clone Github 上的Repository xff0c 如下 xff1a git clone git 64 github span class hljs preprocessor com spa
  • ARM平台基于嵌入式Linux部署ROS

    By Toradex 秦海 随着ARM平台处理能力的日益强大 xff0c 越来越多的工业智能 机器人应用在ARM平台上面实现 xff0c 在这个过程中不可避免的就涉及到将机器人应用开发框架移植到ARM平台来运行 xff0c 因此本文就着重示
  • 如何设计一款低成本的计算机载板- 第一部分

    By Toradex Peter Lischer 1 简介 在以前的博客文章中 xff0c 我们已经在一个硬件项目中使用计算机模块提出了许多讨论 xff0c 因此 xff0c 这里我们假设你已经在项目中决定采用计算机模块SoM xff0c
  • git rebase后commit id的变化

    经测试发现 xff0c 在执行完 git rebase 之后 xff0c 1 xff09 会生成的新的 commit id 2 xff09 新 commit 与旧 commit 的父节点不相同 3 xff09 旧 commit 的父节点保持
  • 嵌入式Linux下串口调试

    By Toradex秦海 1 简介 UART串口是嵌入式设备最为常用的调试和通讯接口之一 xff0c 无论是RS232还是RS422 485都有着非常广泛的应用 xff0c 因此本文就基于嵌入式Linux演示在User Space进行串口调
  • [LeetCode刷题笔记] 关于LeetCode的前言

    原创文章 转载请注册来源http blog csdn net tostq 又到了一年毕业就业季了 xff0c 三年前的校招季我逃避了 xff0c 可这一次终于还是要轮到我了 61 61 作为要准备踏入码农行业的人来说 xff0c 要准备校招
  • 关于机器视觉标定的pnp问题

    https blog csdn net cocoaqin article details 77485436 https blog csdn net cocoaqin article details 77848588利用二维码求解相机世界坐标
  • kvaser在linux中的应用

    本文主要讲解 xff0c kvaser如何使用简单socketcan 1 硬件 kvaser USBcan Pro 2xHS v2 2 准备系统 ubuntu 16 04 由于项目需要在程序中使用socketcan xff0c 所以需要将k
  • 编译错误-build stopped: subcommand failed. 解决方法

    make 1 Leaving directory 96 home sunhz sl8541e out target product sp8541e srvm obj u boot15 39 make Leaving directory 96
  • 如何备份jetson nano 的u盘系统?

    使用工具 xff1a Win32DiskImager 备份步骤 xff1a 1 在本地盘 xff08 C盘或D盘都行 xff0c 盘符剩余内存大于u盘系统内存就行 xff09 新建文本文档 xff0c 连后缀名字一起改成backup img
  • Security Onboard Communication-SecOC

    一 通讯加密的必要性 随着汽车电子的发展及整车功能复杂性的提高 xff0c 车载控制器数量从之前的寥寥几个增加至规模复杂的上百个 基于功能的需求 xff0c 各个控制器每时每刻需要进行大量数据的交互 xff0c 数据交互的方式也多种多样 x
  • 解决VNC远程连接树莓派,窗口显示不全的问题,亲测可行!!

    哇 xff0c 就在刚刚才百度到解决VNC远程连接树莓派 xff0c 窗口显示不全的问题 xff0c 昨晚上查了一晚上都没搞定 xff0c xff0c xff0c 首先说下问题吧 xff0c 就是用VNC远程连接树莓派后 xff0c 会出现

随机推荐

  • Avoid mutating a prop directly since the value will be overwritten whenever

    在vue中 父组件向子组件传值 并在子组件改变了父组件的值 就会发出警告 所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定 xff1a 父级 prop 的更新会向下流动到子组件中 xff0c 但是反过来则不行 这样会防止
  • 【Linux】异步网络库dyad代码阅读

    简介 dyad是一个基于C编写的异步网络库 xff0c 非常精简 xff0c 单C文件 xff0c 仅实现TCP xff0c 很适合用来学习Linux网络编程和异步非阻塞处理 链接 Github链接 基于Dyad的echo server实现
  • 明文签署文件不可用,结果为‘NOSPLIT’

    快速记录一下在 debian上使用 apt update时遇到的一个小问题 明文签署文件不可用 xff0c 结果为 NOSPLIT xff08 您的网络需要认证吗 xff1f xff09 报错现场如下所示 xff1a span class
  • Ubuntu 16.04 安装 Gazebo

    Gazebo 是一款 3D 动态模拟器 xff0c 能够准确有效地模拟复杂室内和室外环境中的机器人群体 虽然类似于游戏引擎 xff0c Gazebo 提供了更高保真度的物理模拟 一套传感器以及用户和程序接口 Gazebo 的典型用途包括 x
  • 设计一款STM32的BootLoader

    参考文章 xff1a https blog csdn net qingtian506 article details 9128899 之前很想做一个属于STM32的BootLoader xff0c 但是想想没什么实际用处就没有下手 xff0
  • vscode之C/C++代码自动补全

    目录 准备 xff1a 步骤 xff1a 安装插件重启加载更改配置选项找到 设置 打开json配置添加配置json保存并重新打开vscode即可自动补全 准备 xff1a IDE xff1a vscode 安装就不展开啦 步骤 xff1a
  • Velodyne 16线三维激光雷达

    Velodyne 16线三维激光雷达VLP 16介绍 16线激光雷达VLP 16是Velodyne公司出品的小型的3维激光雷达 xff0c 保留了电机转速可调节的功能 实时上传周围距离和反射率的测量值 16线激光雷达VLP 16具有100米
  • [gazebo仿真]添加RealSense双目相机传感器

    下载双目相机模型和插件 xff0c 其中包含了T265 R200 D435模型 git clone https span class token operator span span class token operator span sp
  • actionlib的应用:STDR仿真器定点巡航

    关于STDR仿真器的定点巡航 xff0c ROS小课堂提供了非常详细的教程http www corvin cn 892 html xff0c 作者是用python写的巡航脚本 xff0c 下面提供一下C 43 43 版本的巡航代码 若有错误
  • ROS动态调节参数

    参考 xff1a ROS学习之路07 xff1a 编写动态重配置 dynamic reconfigure 参数的节点 https blog csdn net l1216766050 article details 79575423 ROS使
  • Linux C小项目 —— 实现文件传输

    编译运行 xff1a 文档说明 xff1a 1 整体程序设计 服务器程序是一个死循环 xff0c 处理一次连接之后不退出 xff0c 而客户端程序只处理一个连接就可以了 2 客户端程序设计 客户端程序的主要任务 xff1a a 分析用户输入
  • Linux C小项目 —— 聊天室

    多线程的聊天室 服务器端 xff1a 实现多用户群体聊天功能 xff08 人数上限可设置 xff09 xff1b 每个用户所发送的消息 xff0c 其他已连接服务器的用户均可以收到 xff1b 用户输入 bye 退出 xff0c 服务器输入
  • 3.2多纹理效果的像素着色器

    3 2 多纹理效果的像素着色器 下面是像素着色器的代码 xff0c 该代码存储于 ps txt 中 xff0c 该像素着色器根据输入的两套纹理坐标对对应的纹理贴图进行采样 xff0c 根据一定比例 Scalar 混合后输出像素颜色 全局变量
  • 【Git】国内代码托管中心码云(Gitee)

    9 国内代码托管中心码云 Gitee 9 1 简介 众所周知 xff0c GitHub 服务器在国外 xff0c 使用 GitHub 作为项目托管网站 xff0c 如果网速不好的话 xff0c 严重影响使用体验 xff0c 甚至会出现登录不
  • 3.3应用程序

    3 3 应用程序 程序中我们首先创建一个四边形 xff0c 然后使用像素着色器进行纹理混合后对其进行渲染 下面是应用程序代码 xff1a 顶点格式定义 struct CUSTOMVERTEX 定点位置坐标 float x y z 两套纹理坐
  • 4.HLSL Effect(效果框架)

    4 HLSL Effect xff08 效果框架 xff09 进行到这里 xff0c 读者可能会觉得使用着色器多少有些繁琐 xff0c Effect xff08 效果框架 xff09 被提出以解决这些问题 作为一种方法 xff0c Effe
  • 4.2用Effect实现多纹理化效果

    4 2 用 Effect 实现多纹理化效果 前面我们介绍了一个使用像素着色器实现的多纹理化 xff0c 这里用 Effect 框架重新给于实现 xff0c 读者可以比较两者之间的异同 xff0c 体会 Effect 框架给我们带来了哪些方面
  • HLSL初级教程-结语,参考资料

    结语 至此 xff0c HLSL 初级内容介绍完毕 xff0c 相信读者已经对 HLSL 着色器 Effect 等概念有了比较深入的理解 xff0c 并且掌握了 HLSL 编程的基本方法 xff0c 文章中裁去了对 HLSL 语法等细节的讨
  • Unity 3D网页游戏 Demo 展示

    2011 年 xff0c 网页 3D 这一网游开发新趋势逐渐浮出水面 xff0c Unity 作为浏览器及移动设备 3D 引擎领域的佼佼者 xff0c 在国内开始崭露头角 我们团队也完成了首款 Unity Demo 的第一个版本 Demo
  • 用Ogre实现无缝地图

    用 Ogre 实现无缝地图 1 7 版本之前 xff0c 如果想用 Ogre 内建的地形系统实现一个像样的无缝地图 xff0c 恐怕要闹到抓狂 所幸 sinbad 在 1 7 为 Ogre 加入了全新的地形组件 xff0c 它囊括了一个地形