【Unity】移动端草海解决方案

2024-08-25 01:12

本文主要是介绍【Unity】移动端草海解决方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

      草海是开放大世界渲染的必不可少的因素,Unity 原生的 Terrain 草海效率较低,而且无法与 RVT 结合起来,无法在移动端上实现。因此我们自己搓出来一套草海系统,使用 C# 多线程辅助运算,并能支持割草、烧草等进阶玩法。草的位置、密度、类型还需要根据美术和地形的信息进行自适应。

        最终效果可以看这个演示视频(虽然这个视频美术表现力不行,但是已经可以看到 GpuTerrain基础下的实时运算的草海效果了。对于游戏开发者而言,显然能明白这个演示已经实现了既定目标)

GpuTerrain+草海_哔哩哔哩_bilibili地形用GpuTerrain渲染;草海是自定义实时生成运算+Gpu渲染。, 视频播放量 103、弹幕量 0、点赞数 0、投硬币枚数 0、收藏人数 0、转发人数 0, 视频作者 魔术师dix, 作者简介 我们这么努力,不是为了改变世界,而是为了不让世界改变我们。,相关视频:Island_G效果演示(8月版本),原型工程1.0演示视频,玲珑岛12贴图版本_1.0,Unity3D 战斗系统核心技术: 高度可扩展的技能与多Buff系统(收藏级),【中配】A*寻路算法:算法解释 - Sebastian Lague,很多3a游戏的马还不如塞尔达的真实生动,新动作又被虐了,Skyrim Special Edition-定海神针-金箍棒,【Unity3D/资产发布】拟真向URP海面渲染系统——HigWaterSystem,游戏,还是现实?icon-default.png?t=N7T8https://www.bilibili.com/video/BV1nj411D7tm

方案设计

        这里我按照 1*1 的范围将地图进行分块,每一块视为一整片草,进行整体剔除和计算。

        如上图的示例,将草分块之后,进行AOI剔除,最后得到所有可能在视野中的草(注意:这里没有进行视锥体剔除),之后再使用生成式算法得到最终的草数据(精确到每一株草的实体)。然后再直接将数据打包传入 GPU,使用之前提到过的 GPU 驱动的渲染上屏,完成草海渲染。

        这里就涉及到之前的一些实现过的架构了:

  • 需要得到地面的高度和法线,与 开放大世界的 GpuTerrain + RVT-CSDN博客 共用一张高度法线图。
  • 上屏方案 : GPU驱动的大规模静态物件渲染-CSDN博客

        除此之外,草海还需要一张密度图(表示每个格子的草的密度和类型),和 GpuTerrain 的高度法线图每个像素一一对应。

        有了上述数据之后,草海就能正常运转了。在项目前期,我们是将草海的生成式算法放到C#多线程中的,目的是为了方便调试和交互。后续功能稳定了,可以将这个算法移动到 ComputeShader 中,效率可以更高(这也是最终成型方案)。

框架与数据管理

        制作地图时,生成棋盘格,每个格子 1*1 米,每512 *512 个棋盘生成视为一个地块。统一棋盘格的尺寸,对应高度图、植被密度图的数据。

        一般来讲,对于视野远端的地块,不需要生成格子,也不需要计算。对于近处的地块,才需要生成草海,当然距离越近性能越好。按照一些文章的说法,80米的视野范围就能满足需求,如果加上视锥体剔除,视角设置为60度,那么算下来大概需要 3696 个格子参与生成计算(后面按照4000个格子计算)。

        4000 个格子,每个格子生成 64 棵草(密度最大),每颗草的数据(Transfrom数据)大约为 30 byte,算下来总共占用约 7.5 MB 内存,即便是移动端也可以接受。(为了减少对GPU的数据传输,我们其实使用了4个80*80的区域,内存占用更多,原因下文有解释)

草海系统的生命周期管理

        对于 Patch 而言,最高运算的部分在生成(以及根据玩法对数据的修改部分),因此在运行时并没有复杂逻辑,就只是在原地不动。生成之后最大的性能瓶颈就是在玩法(例如割草)上对实体的遍历。但因为能实现限制 Patch 进行刷新,所以遍历的量并不会很大。

草海编辑工具

        因为草海已经脱离了 Unity 的Terrain,所以需要一编辑工具。

  • 根据 GpuTerrain + RVT 数据直接还原地形的工具,方便美术开发。
  • 类似于 Terrain 的刷子工具,可以绘制草海密度图。
  • 草海类型配置:配置不同类型的草,以及其出现频率,可以实时预览。
  • 运行时调试工具,方便运行时查找问题。
草海密度图示例

        

其他细节问题        

        这里记录一些细节问题,可以帮助大家实现时做参考。

面片草还是网格草?

  • 面片草顶点数少,但是依赖 AlphaTest,这一步在很多移动设备上非常昂贵。
  • 网格草顶点数高,但因为是 实体渲染,性能表现远远优于 AlphaTest。

        此外,对于某些表现效果(例如高光、碰撞弯曲)上,面片制作起来困难;在视角上,面片草存在穿帮死角,大致上只适合固定视角。所以还是建议使用网格草。

草海密度图存的什么数据?

        草海密度图我这里将每个像素的 rgba 各设置为一种类型的草的密度,每一个草的密度取值从 0~256表示其密度。在生成草海数据时,查询到某个位置有颜色,则根据通道(例如 R通道 表示杂草,G表示花、B表示地衣、小石头)密度算出需要生成特定类型、特定数量的实体。生成完成之后,将数据收集起来统一传给 GPU。

        实际上,每一个通道的256的值对于密度还是太多了,本来一个地块最多64个实体,精度肯定超标了。后续如果要优化,完全可以将密度的精度降低到8,再将其他位记录其他地图数据。

生成式算法

        成式算法其实是根据项目相关,所以不必去网上特意查找。一般来讲,只需要设置一个随机方式(噪声图、或者固定随机种子),根据算法进行随机。只要满足一个要求就行:每一次生成的位置、旋转、缩放都是相同的结果。

        同时,在生成时可能需要根据地形信息有所变化,这点也需要考虑到。

草海实时重建的频率

        在计算哪些草块(Pitch)需要计算时,为了减少对 GPU 交互的频率,改为周围 80m 的棋盘格都计算了一起扔给 GPU。因此这样占用的内存大了4倍,但数据交互频率显著降低,就不用每帧都生成一次数据了。否则,一旦加上视锥体剔除,那么一旦相机旋转了,每帧都要实时计算一次、传值,数据大了还是很不划算的(实际上,视锥体剔除我们也试过,数据量少了很多,但传输数据的频率就大幅提升了)。

        当然这是妥协,如果在 GPU 里计算草海就没这个问题了。所以,最终的完整版本还是要在 ComputeShader 里生成草海。

图片数据读取

        GPU端直接通过 Texture.GetPixel 也太蠢了,效率还低。这里我们的做法是将图片转换成 NativeArray 然后再在多线程读取。这里需要注意的时,如果是多线程读取 NativeArray ,需要一点点操作:

NativeArray<Color32> HeightMap = texture.GetPixelData<Color32>(0);//获取图片的原始数据//根据已有的数据生成不安全的只读 NativeArray,否则多线程无法使用。
NativeArray<Color32> ConvertedHeightMap= NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<Color32>(HeightMap.GetUnsafeReadOnlyPtr(), HeightMap.Length, Allocator.Invalid);#if ENABLE_UNITY_COLLECTIONS_CHECKS 
//只有编辑器下才存在 SetAtomicSafetyHandle 
NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref ConvertedHeightMap, AtomicSafetyHandle.Create());
#endif

        按照上图示例,就可以在多线程中使用 Unity 的 NativeArray 了。要注意的是,SetAtomicSafetyHandle 只在编辑器下使用,在真机上是会报错的。参考:NativeArrayUnsafeUtility seems to not work in builds - Unity Engine - Unity Discussions

割草烧草如何实现

        类似于塞尔达的割草、烧草效果,如果是在 CPU 端是比较好弄的。直接可以将技能(或者玩家交互)的计算结果记录下来,然后调用一次草海刷新,然后就能根据新的数据计算出结果,再传给 GPU 即可。

        如果是在 GPU 端实现,有一个简单的方案:从头顶照一个相机下来使其能覆盖所有的草。然后所有的技能一般都会有一些特效显示,这个相机就专门照这个特效。然后 GPU 直接就能读取到这个相机生成的图片,就可以直接拿来计算了,根本不用写 CPU 和 GPU 的交互,非常地方便。

模型上种草如何实现

        目前只实现了地形上种草,而模型上种草没有实现。

        模型上种草其实也有过设计,需要提前将模型进行烘培,且需要让美术指定模型的哪些地方是可以种草的(类似于刷 UV 图)。然后在渲染模型时,根据模型的草皮图、法线等直接生成草海,后续的步骤和地皮生成草海类似了。

参考文章

移动端草海的渲染方案(一)_terrain detail 交互-CSDN博客

移动端草海的渲染方案(二)_nature renderer-CSDN博客

移动端草海的渲染方案(三)-CSDN博客

移动端草海的渲染方案(四)_恶毒的狗 草海-CSDN博客

移动端草海的渲染方案(五)-CSDN博客

TA实践分享:材质与渲染——植物与风(Unity+UE)

【C#】并行编程实战:序章_并行编程实战基于c#8-CSDN博客

这篇关于【Unity】移动端草海解决方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

我在移动打工的日志

客户:给我搞一下录音 我:不会。不在服务范围。 客户:是不想吧 我:笑嘻嘻(气笑) 客户:小姑娘明明会,却欺负老人 我:笑嘻嘻 客户:那我交话费 我:手机号 客户:给我搞录音 我:不会。不懂。没搞过。 客户:那我交话费 我:手机号。这是电信的啊!!我这是中国移动!! 客户:我不管,我要充话费,充话费是你们的 我:可是这是移动!!中国移动!! 客户:我这是手机号 我:那又如何,这是移动!你是电信!!

用Unity2D制作一个人物,实现移动、跳起、人物静止和动起来时的动画:中(人物移动、跳起、静止动作)

上回我们学到创建一个地形和一个人物,今天我们实现一下人物实现移动和跳起,依次点击,我们准备创建一个C#文件 创建好我们点击进去,就会跳转到我们的Vision Studio,然后输入这些代码 using UnityEngine;public class Move : MonoBehaviour // 定义一个名为Move的类,继承自MonoBehaviour{private Rigidbo

js异步提交form表单的解决方案

1.定义异步提交表单的方法 (通用方法) /*** 异步提交form表单* @param options {form:form表单元素,success:执行成功后处理函数}* <span style="color:#ff0000;"><strong>@注意 后台接收参数要解码否则中文会导致乱码 如:URLDecoder.decode(param,"UTF-8")</strong></span>

简单的角色响应鼠标而移动

actor类 //处理移动距离,核心是找到角色坐标在世界坐标的向量的投影(x,y,z),然后在世界坐标中合成,此CC是在地面行走,所以Y轴投影始终置为0; using UnityEngine; using System.Collections; public class actor : MonoBehaviour { public float speed=0.1f; CharacterCo

明明的随机数处理问题分析与解决方案

明明的随机数处理问题分析与解决方案 引言问题描述解决方案数据结构设计具体步骤伪代码C语言实现详细解释读取输入去重操作排序操作输出结果复杂度分析 引言 明明生成了N个1到500之间的随机整数,我们需要对这些整数进行处理,删去重复的数字,然后进行排序并输出结果。本文将详细讲解如何通过算法、数据结构以及C语言来解决这个问题。我们将会使用数组和哈希表来实现去重操作,再利用排序算法对结果

UE5 半透明阴影 快速解决方案

Step 1: 打开该选项 Step 2: 将半透明材质给到模型后,设置光照的Shadow Resolution Scale,越大,阴影的效果越好

MySQL主从同步延迟原理及解决方案

概述 MySQL的主从同步是一个很成熟的架构,优点为: ①在从服务器可以执行查询工作(即我们常说的读功能),降低主服务器压力; ②在从主服务器进行备份,避免备份期间影响主服务器服务; ③当主服务器出现问题时,可以切换到从服务器。 相信大家对于这些好处已经非常了解了,在项目的部署中也采用这种方案。但是MySQL的主从同步一直有从库延迟的问题,那么为什么会有这种问题。这种问题如何解决呢? MyS

安装SQL2005后SQL Server Management Studio 没有出来的解决方案

一种情况,在安装 sqlServer2005 时 居然出现两个警告: 1 Com+ 目录要求 2 Edition change check 郁闷!网上说出现两个警告,是肯定装不成功的!我抱着侥幸的态度试了下,成功了。 安装成功后,正准备 “ 仅工具、联机丛书和示例(T)” 但是安装不了,他提示我“工作站组件”安装过了对现有组件无法更新或升级。 解决办法: 1 打开“控

物联网之流水LED灯、正常流水灯、反复流水灯、移动流水灯

MENU 硬件电路设计软件程序设计正常流水LED灯反复流水LED灯移动流水LED灯 硬件电路设计 材料名称数量直插式LED1kΩ电阻杜邦线(跳线)若干面包板1 每一个LED的正极与开发板一个GPIO引脚相连,并串联一个电阻,负极接GND。 当然也可以选择只使用一个电阻。 软件程序设计 正常流水LED灯 因为要用到多个GPIO引脚,所以最好把所有的GPI

12C 新特性,MOVE DATAFILE 在线移动 包括system, 附带改名 NID ,cdb_data_files视图坏了

ALTER DATABASE MOVE DATAFILE  可以改名 可以move file,全部一个命令。 resue 可以重用,keep好像不生效!!! system照移动不误-------- SQL> select file_name, status, online_status from dba_data_files where tablespace_name='SYSTEM'