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

相关文章

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

业务中14个需要进行A/B测试的时刻[信息图]

在本指南中,我们将全面了解有关 A/B测试 的所有内容。 我们将介绍不同类型的A/B测试,如何有效地规划和启动测试,如何评估测试是否成功,您应该关注哪些指标,多年来我们发现的常见错误等等。 什么是A/B测试? A/B测试(有时称为“分割测试”)是一种实验类型,其中您创建两种或多种内容变体——如登录页面、电子邮件或广告——并将它们显示给不同的受众群体,以查看哪一种效果最好。 本质上,A/B测

遮罩,在指定元素上进行遮罩

废话不多说,直接上代码: ps:依赖 jquer.js 1.首先,定义一个 Overlay.js  代码如下: /*遮罩 Overlay js 对象*/function Overlay(options){//{targetId:'',viewHtml:'',viewWidth:'',viewHeight:''}try{this.state=false;//遮罩状态 true 激活,f

利用matlab bar函数绘制较为复杂的柱状图,并在图中进行适当标注

示例代码和结果如下:小疑问:如何自动选择合适的坐标位置对柱状图的数值大小进行标注?😂 clear; close all;x = 1:3;aa=[28.6321521955954 26.2453660695847 21.69102348512086.93747104431360 6.25442246899816 3.342835958564245.51365061796319 4.87

uniapp设置微信小程序的交互反馈

链接:uni.showToast(OBJECT) | uni-app官网 (dcloud.net.cn) 设置操作成功的弹窗: title是我们弹窗提示的文字 showToast是我们在加载的时候进入就会弹出的提示。 2.设置失败的提示窗口和标签 icon:'error'是设置我们失败的logo 设置的文字上限是7个文字,如果需要设置的提示文字过长就需要设置icon并给

lvgl8.3.6 控件垂直布局 label控件在image控件的下方显示

在使用 LVGL 8.3.6 创建一个垂直布局,其中 label 控件位于 image 控件下方,你可以使用 lv_obj_set_flex_flow 来设置布局为垂直,并确保 label 控件在 image 控件后添加。这里是如何步骤性地实现它的一个基本示例: 创建父容器:首先创建一个容器对象,该对象将作为布局的基础。设置容器为垂直布局:使用 lv_obj_set_flex_flow 设置容器