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

相关文章

Java实现为PDF设置背景色和背景图片

《Java实现为PDF设置背景色和背景图片》在日常的文档处理中,PDF格式因其稳定性和跨平台兼容性而广受欢迎,本文将深入探讨如何利用Spire.PDFforJava库,以简洁高效的方式为你的PDF文档... 目录库介绍与安装步骤Java 给 PDF 设置背景颜色Java 给 PDF 设置背景图片总结在日常的

C#中通过Response.Headers设置自定义参数的代码示例

《C#中通过Response.Headers设置自定义参数的代码示例》:本文主要介绍C#中通过Response.Headers设置自定义响应头的方法,涵盖基础添加、安全校验、生产实践及调试技巧,强... 目录一、基础设置方法1. 直接添加自定义头2. 批量设置模式二、高级配置技巧1. 安全校验机制2. 类型

C#实现SHP文件读取与地图显示的完整教程

《C#实现SHP文件读取与地图显示的完整教程》在地理信息系统(GIS)开发中,SHP文件是一种常见的矢量数据格式,本文将详细介绍如何使用C#读取SHP文件并实现地图显示功能,包括坐标转换、图形渲染、平... 目录概述功能特点核心代码解析1. 文件读取与初始化2. 坐标转换3. 图形绘制4. 地图交互功能缩放

Python进行word模板内容替换的实现示例

《Python进行word模板内容替换的实现示例》本文介绍了使用Python自动化处理Word模板文档的常用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友... 目录技术背景与需求场景核心工具库介绍1.获取你的word模板内容2.正常文本内容的替换3.表格内容的

python库pydantic数据验证和设置管理库的用途

《python库pydantic数据验证和设置管理库的用途》pydantic是一个用于数据验证和设置管理的Python库,它主要利用Python类型注解来定义数据模型的结构和验证规则,本文给大家介绍p... 目录主要特点和用途:Field数值验证参数总结pydantic 是一个让你能够 confidentl

Git进行版本控制的实战指南

《Git进行版本控制的实战指南》Git是一种分布式版本控制系统,广泛应用于软件开发中,它可以记录和管理项目的历史修改,并支持多人协作开发,通过Git,开发者可以轻松地跟踪代码变更、合并分支、回退版本等... 目录一、Git核心概念解析二、环境搭建与配置1. 安装Git(Windows示例)2. 基础配置(必

Java利用Spire.XLS for Java设置Excel表格边框

《Java利用Spire.XLSforJava设置Excel表格边框》在日常的业务报表和数据处理中,Excel表格的美观性和可读性至关重要,本文将深入探讨如何利用Spire.XLSforJava库... 目录Spire.XLS for Java 简介与安装Maven 依赖配置手动安装 JAR 包核心API介

Nginx中配置使用非默认80端口进行服务的完整指南

《Nginx中配置使用非默认80端口进行服务的完整指南》在实际生产环境中,我们经常需要将Nginx配置在其他端口上运行,本文将详细介绍如何在Nginx中配置使用非默认端口进行服务,希望对大家有所帮助... 目录一、为什么需要使用非默认端口二、配置Nginx使用非默认端口的基本方法2.1 修改listen指令

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

MySQL按时间维度对亿级数据表进行平滑分表

《MySQL按时间维度对亿级数据表进行平滑分表》本文将以一个真实的4亿数据表分表案例为基础,详细介绍如何在不影响线上业务的情况下,完成按时间维度分表的完整过程,感兴趣的小伙伴可以了解一下... 目录引言一、为什么我们需要分表1.1 单表数据量过大的问题1.2 分表方案选型二、分表前的准备工作2.1 数据评估