Unity大面积草地渲染——4、对大面积草地进行区域剔除和显示等级设置

本文主要是介绍Unity大面积草地渲染——4、对大面积草地进行区域剔除和显示等级设置,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录
1、Shader控制一棵草的渲染
2、草地的动态交互
3、使用GPUInstancing渲染大面积的草
4、对大面积草地进行区域剔除和显示等级设置

Unity使用GPU Instancing制作大面积草地效果

大家好,我是阿赵。
这里开始讲大面积草地渲染的第四个部分,对大面积草地进行区域剔除和显示等级设置。
在上一篇文章里面,我使用了GPU Instancing来渲染草,渲染的合并是比较的成功,但如果草地的面积太大,会导致同屏渲染100多万的面。这个数量级比较高,对显卡有一定的要求。所以这一篇文章来想办法解决这个问题。

一、一个区域内的草的多种等级渲染

我这里在一个5X5的范围内,分别生成了不同数量的草:
等级1,总共有1000棵草
在这里插入图片描述

等级2,总共有500棵草
在这里插入图片描述

等级3,有100棵草
在这里插入图片描述

这三个等级,有点类似于LOD的概念,我打算在不同的距离观察这个5X5区域时,会显示不同等级的草。当然,如果有需要,继续增加等级,比如等级4 、5之类。

二、九宫等级显示

刚才我们已经有了三个等级的草,我现在先忽略了地形的区别,假设有一片无限大的草地,都是平的。然后我从顶视图把这个草地划分为每5X5为一格。然后不同深度的格子,是不同显示等级的草。纯绿色的是1级,然后颜色渐渐变浅等级就越低。
假设中间红色的小球是一个人,他走到了这个格子的时候,如果按照标准的九宫格来显示草的疏密等级,就有以下这个图:
在这里插入图片描述
直观的显示成刚才的3种等级的草,会是这样的:
在这里插入图片描述

但这个九宫的设计会有一个问题,当角色走到格子边缘的时候,会看到明显的接缝,然后跨越格子的时候,会明显的看到草地的疏密变化,效果不是很好:
在这里插入图片描述

于是,我在这个基础上,把最里面的等级1,增加多一圈,变成了下图这样:
在这里插入图片描述

这个情况下,当人走到一个格子的边缘时,人周围一圈的格子草地都保证不会发生疏密变化,只有在更远一圈的地方才会发生变化。
在这里插入图片描述

从顶视图看的效果是这样的:

开放世界大地图草地算法

三、草地LOD信息的存储

由于我们的草是用同一个网格模型渲染出来的,所以原则上我们只需要记录同一个区域内,每一颗草的位置就行了。位置有xyz三个信息,我这里是使用了图片的格式加一个配置文件来存储。比如下面这个区域的草地信息,我保存如下:
在这里插入图片描述
在这里插入图片描述

从配置文件看,这是一个5X5区域的草地,总共有250棵草,所有草的坐标的最小XYZ值,还有从最小值到最大值的偏移值,都记录下来了。
然后每棵草的坐标,其实就是图片里面的rgb颜色。
这里有250棵草,一张16X16的贴图,就有256个像素,就已经够存储了。
具体的算法是,每个坐标减去最小值再除以偏移值,就是它的颜色值。还原的时候同样的算法。

接下来思考几个扩展问题:
1、加入一个山坡有不同的高度变化,不再是一片平底,该怎样处理呢?这里有3个做法可以作为参考:

1.每一片5X5的区域生成一个贴图和配置信息,配置信息里面加上这块5X5区域的中心点坐标
2.还是用同一片5X5区域信息,在首次生成某个5X5区域的草地时,使用碰撞的方式获取一下当前草地的高度,并存起来,作为生成单棵草时的高度。
3.还是用同一片5X5区域信息,给山坡的大区域生成一个高度图,然后当需要生成某个坐标的草时,通过高度图来获取草的实际高度。 反正做法有很多。

2、假如我希望显示的草的旋转和缩放有不一样,该怎么办呢?

其实非常简单,还是用rgb把它们存储起来就行了,根据需要,同一个等级的图片增加一张单独旋转的和一张缩放的就行。

3、假如我希望显示的草不止一种,而是有很多种,该怎么办?

注意我们刚才使用了图片的rgb而已,还有alpha没有用。所以如果我们用上的话,0-255的alpha值保存在图片的每个像素上,我们最多可以支持256种草,按道理怎么都够用了吧?

刚才的例子,我生成了4个级别的LOD草信息,总共是这么多文件,容量加起来只有5k,就能渲染无限大面积的草地了:
在这里插入图片描述

值得注意的是,读取这个图片,我们有可能会发现读取出来的颜色值和实际保存的值不一样。
如果是直接放在Unity内部的图片,要记得取消所有压缩设置
在这里插入图片描述

四、使用API渲染策略

上面我们已经有了数据了,那么我们怎样才能实现LOD渲染呢?是不是应该把草都摆在场景里面,然后使用Unity的LOD Group呢?
这里我的做法是这样的:
1、先获取角色当前的坐标,如果我们是以5X5做为一格,那么算出当前角色所在的5X5区域的横竖Index
2、通过区域的坐标,算出当前5X5区域的中心点,根据实际需要显示的圈数,通过遍历,找到相邻多圈的其他5X5区域
3、计算每个区域应该显示的LOD等级,然后获取每个区域的坐标矩阵
4、如果想中间的区域显示多少圈等级1的草,可以再加多一个参数控制
5、得到所有需要显示的区域的坐标矩阵之后,按照列表长度不超过1023,重新把它们存放到一个或者多个矩阵数组里面。
6、通过API渲染:Graphics.DrawMeshInstanced(mesh, 0, mat, matrixs, matrixs.Length);
从上面的算法看,好像有很复杂的计算,其实并没有。因为当第1步计算当前角色所在的区域Index时,可以和上一次计算的值做对比,如果没有发生变化,证明角色并没有跨区域,所以2-5步都可以省略掉,直接执行第6步就可以了。

然后我看了一些网上介绍大面积草地做法的文章,他们比我做得更精细,还通过各种算法,去剔除摄像机背面的草,剔除被物体挡住的草,等等。我并没有这么做。因为我觉得,现在这一套策略,在GPU不是太差的情况下,真正的瓶颈是在CPU的计算上,而那些剔除算法,基本上都是需要额外增加CPU的计算的,而且还是每一帧都需要计算。我现在的CPU压力只会在角色跨过一个5X5区域时,稍微有一次计算,对比起来,其实是省了很多计算的。
如果真的担心GPU承受不了,我们可以通过游戏内提供显示质量等级让玩家来选择。

五、不同质量等级的显示控制

留意看刚才的渲染策略,可以发现,我留了2个参数控制草地显示的范围:
1.实际显示的圈数
2.中间显示多少圈等级1
我再加多一个参数,
3.最高等级显示到多少级
通过这三个参数的组合,我们可以组合出很多种显示质量等级了,比如我这个例子里面设置了高中低三个等级:
在这里插入图片描述

最高等级,有300多万面需要渲染,不过效果很好,一望无际,移动的过程中也完全看不出草地的接缝变化。
在这里插入图片描述

中等等级,有一百多万面需要显示,稍微可以看出远处有草的疏密变化
在这里插入图片描述

低等级,有30万面,草看起来比较稀疏,在移动过程中疏密变化比较明显。

这个demo我发到手机和模拟器上面跑过,就算调到最高显示质量,实际上都是60帧满帧的,所以看着好像很可怕的几百万面,在使用了GPU Instancing合并渲染之后,其实效率还是比较高的。如果实在是害怕有手机跑不动,其实还可以进一步的调整草的模型面数,我现在这一束草的面数有一百多面,其实也偏高了一些。

这篇关于Unity大面积草地渲染——4、对大面积草地进行区域剔除和显示等级设置的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/155882

相关文章

Ubuntu中Nginx虚拟主机设置的项目实践

《Ubuntu中Nginx虚拟主机设置的项目实践》通过配置虚拟主机,可以在同一台服务器上运行多个独立的网站,本文主要介绍了Ubuntu中Nginx虚拟主机设置的项目实践,具有一定的参考价值,感兴趣的可... 目录简介安装 Nginx创建虚拟主机1. 创建网站目录2. 创建默认索引文件3. 配置 Nginx4

Nginx如何进行流量按比例转发

《Nginx如何进行流量按比例转发》Nginx可以借助split_clients指令或通过weight参数以及Lua脚本实现流量按比例转发,下面小编就为大家介绍一下两种方式具体的操作步骤吧... 目录方式一:借助split_clients指令1. 配置split_clients2. 配置后端服务器组3. 配

Linux虚拟机不显示IP地址的解决方法(亲测有效)

《Linux虚拟机不显示IP地址的解决方法(亲测有效)》本文主要介绍了通过VMware新装的Linux系统没有IP地址的解决方法,主要步骤包括:关闭虚拟机、打开VM虚拟网络编辑器、还原VMnet8或修... 目录前言步骤0.问题情况1.关闭虚拟机2.China编程打开VM虚拟网络编辑器3.1 方法一:点击还原VM

Python使用DeepSeek进行联网搜索功能详解

《Python使用DeepSeek进行联网搜索功能详解》Python作为一种非常流行的编程语言,结合DeepSeek这一高性能的深度学习工具包,可以方便地处理各种深度学习任务,本文将介绍一下如何使用P... 目录一、环境准备与依赖安装二、DeepSeek简介三、联网搜索与数据集准备四、实践示例:图像分类1.

如何关闭 Mac 触发角功能或设置修饰键? mac电脑防止误触设置技巧

《如何关闭Mac触发角功能或设置修饰键?mac电脑防止误触设置技巧》从Windows换到iOS大半年来,触发角是我觉得值得吹爆的MacBook效率神器,成为一大说服理由,下面我们就来看看mac电... MAC 的「触发角」功能虽然提高了效率,但过于灵敏也让不少用户感到头疼。特别是在关键时刻,一不小心就可能触

CSS模拟 html 的 title 属性(鼠标悬浮显示提示文字效果)

《CSS模拟html的title属性(鼠标悬浮显示提示文字效果)》:本文主要介绍了如何使用CSS模拟HTML的title属性,通过鼠标悬浮显示提示文字效果,通过设置`.tipBox`和`.tipBox.tipContent`的样式,实现了提示内容的隐藏和显示,详细内容请阅读本文,希望能对你有所帮助... 效

Nginx配置系统服务&设置环境变量方式

《Nginx配置系统服务&设置环境变量方式》本文介绍了如何将Nginx配置为系统服务并设置环境变量,以便更方便地对Nginx进行操作,通过配置系统服务,可以使用系统命令来启动、停止或重新加载Nginx... 目录1.Nginx操作问题2.配置系统服android务3.设置环境变量总结1.Nginx操作问题

Go使用pprof进行CPU,内存和阻塞情况分析

《Go使用pprof进行CPU,内存和阻塞情况分析》Go语言提供了强大的pprof工具,用于分析CPU、内存、Goroutine阻塞等性能问题,帮助开发者优化程序,提高运行效率,下面我们就来深入了解下... 目录1. pprof 介绍2. 快速上手:启用 pprof3. CPU Profiling:分析 C

grom设置全局日志实现执行并打印sql语句

《grom设置全局日志实现执行并打印sql语句》本文主要介绍了grom设置全局日志实现执行并打印sql语句,包括设置日志级别、实现自定义Logger接口以及如何使用GORM的默认logger,通过这些... 目录gorm中的自定义日志gorm中日志的其他操作日志级别Debug自定义 Loggergorm中的

Java中有什么工具可以进行代码反编译详解

《Java中有什么工具可以进行代码反编译详解》:本文主要介绍Java中有什么工具可以进行代码反编译的相关资,料,包括JD-GUI、CFR、Procyon、Fernflower、Javap、Byte... 目录1.JD-GUI2.CFR3.Procyon Decompiler4.Fernflower5.Jav