曲线的生成算法实现_PCGPlanet1-地形生成算法简介

2a65bb71897d0a6110e36d5e1fc4d3e1.png

比较常用的地形生成算法有三种:

四叉树算法,GeoMipmap算法,移动立方体算法

目前市面游戏采用的方案基本都是以这三种算法为基础实现的,下面依次进行介绍

四叉树算法

很经典的算法,在没有GPU的时代就已经出现了,原始算法是纯cpu的实现,不过在现在已经可以将其实现为GPU-Driven的形式。

这里主要介绍CPU上的实现,GPU实现将在之后进行单独的介绍。

a7006b78f91b6a2b56b1dbb3597d6954.png

四叉树,顾名思义,就是每个根节点最多有四个孩子的树,其结构能够很好的表现平面的分化。

a542b4ba39608e3d2fdf079b17d40a7f.png

算法简介:

初始化时为一个根节点

视点靠近时四分

每个节点对应一个网格

分化公式:

距离/节点边长>CL CL为自己设置的一个值,CL越大,越容易分化

此外,也可以根据屏幕占比进行分化

f45ced0528f8de9187527f1b04d4db81.png

这里也可以进行一个优化,预处理生成一份陡峭度数据去干预分化,越复杂的地形越易分化,如果地形没有任何起伏,那么完全不分化也是没问题的。

下图展示了动态的分化过程

b1fdf0540c9f02c035642852c1342184.gif

0226e4a7b483706a4a725642e14ce66b.gif

到这里,基本的思路就已经讲完了,但还需要解决一个问题,也就是“裂缝”,见下

e157cf84eb7acc15c07bf6242258121b.gif

如上图所示,由于不同分化层级网格毗邻处顶点数不一致,采样精度不同,就会导致漏面的情况

859c471729690f4ae820c3ff81d8c244.png

在经典算法中,是这么解决的:

将网格分为5个部分,其中上下左右四个部分会根据邻居节点的分化程度去控制网格的生成方式,如下所以,如果邻居的分化程度较低,则会去掉一些顶点,使边界顶点正好对齐来保证采样精度一致。

此外,也要保证相邻节点的lod层级最多相差1,在根据公式分化后还要依次检测每个节点的邻居是否存在分化程度比自身高两个层级的节点,是的话要强制分化该节点。

5c1fa854c661141264d6f0c9265ae941.png

8908dd604b3aecdfe6cec580291351a9.png

这个算法其实不是很好,目前也没看到哪个游戏采用这种方式。

解决裂缝的方式还有很多,下面主要介绍三种

1.强制对齐

4f1723ac64d173bb9943ce0cc2f132d1.png

2.向下生成一圈外围网格

68ffd1a018d2e94a26c70864b7c6f8ea.png

3.边界处按最密进行分化

29d5881c94dbcdbca7d7e76295d15c5d.png

最后效果如下

ed5905eec11a54af5990edaa4cb4e276.gif

至此,四叉树算法就介绍完了,之后的实现也是采用的此算法。

此外,unity也是采用的此算法,但老版unity没有采用GPUInstance,导致dc奇多,新版本虽然进行了优化,但由于unity本身不开源,无法进行定制开发,所以还是不推荐。

下面两种算法我没有进行具体的实现,所以只是简介。

GeoMipmap算法

此算法是虚幻4采用的算法

大致思路为:

将地图分为固定数量的mesh,每个mesh根据lod生成不同精度的网格

47c46ad35f4834230c3ef6cd1a4f44b4.png

见下图,lod为0时生成完整网格,lod为1时会把黑色的顶点去掉,用剩余的白色顶点去生成网格,这个过程是完全在GPU进行的。

d0c297049d5880b8677ab5a035b5d3dd.png

移动端的话基本就采用的上面的两种方式。

下面对比一下两种方式:

四叉树算法的网格近多远少,且能通过GpuInstance进行优化,dc大概在10左右,面数在6w左右。当距离较远时,极端情况只有一个mesh。由于地形一般包含多种植被,如沼泽,沙漠,森林,且移动端由于性能限制最多也只能采样3次,所以1个mesh时会不能很好的表现整个地形面貌。但可以通过烘培一个低模,远处用低模,近处用四叉树的方式优化。

Geomipmap网格固定,dc固定,大概在40-60左右,顶点数在2w左右。距离较远时,Mesh数量固定,纹理采样不受影响。但为了减dc,一般也会烘培一个低模。

最后总结一下,unity建议自己写四叉树,虚幻直接用自带的geomipmap

移动立方体算法

上面的两种算法都存在一个缺陷,由于是基于二维高度图,所以不能表现洞穴,地洞地形。

而移动立方体算法则解决了这个问题。无人深空中即采用了此算法。

4e4c1d630fe7ce2acae4bffce4d2c902.png

该算法将场景看成由无限多个立方体组成。

当立方体足够小时,可以近似将穿过该立方体的面看做标准曲面

曲面方程表示为:

F(x,y,z)=a0+a1x+a2y+a3Z+a4xy+a5yz+a6xz+a7xyz

立方体存在8个顶点,每个顶点都有一个状态,空气中,土壤中

由0和1表示。8个顶点可以存在一个int中,如:00011001

如果为边界,则表示需要生成网格

3a70144b7b0f872817d69b3035ea817b.png

一共有2的8次方,即256种情况

除去对称的情况,归纳为15种,这里归为15种只是为了好分析,实际编码时仍需256种情况单独考虑。针对每种情况,将网格生成方式存在一个查找表中。

9dc43521ec229220ee332212c3411c16.png

20fabd7956f68af666f104c393562a6a.png

这种算法存在一个二义性问题,如图所示,假设黑点为在土地中,则下面两种生成方式均可满足。

9d12e5c542892475efca22b5f0e45315.png

这里假设某一面所在的平面方程为z=z0,

代入式F(x,y,z)=a0+a1x+a2y+a3Z+a4xy+a5yz+a6xz+a7xyz可以得到:

b0+b1x+b2y+b3xy=C0

两边除xy即可得到一个双曲线方程

897d5d972919e711ff17baf119060e88.png

求出该双曲线两条渐近线的交点,根据正负即可决定最终该如何生成。

02a11717a0755f5fcb7ca01c7a74f9e7.png

看起来很简单,但落实到实现还有巨多坑。

其实现在看来,这个算法生成的地形其实就相当于方块变小无数倍的“我的世界”,生成的方块数是奇多的,在无人深空中,基本常态就是百万量级的顶点,所以在移动端自然就被Pass了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/271000.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库安全:数据库加密技术介绍

数据库加密是计算机系统对信息进行保护的一种最可靠的方法。它利用密码技术对信息进行加密,实现信息屏蔽,从而起到保护信息安全的作用。对数据库中的数据进行加密,可以防止数据在存储和传输过程中失密。常用的数据加密技术按照作用不同分为数…

poj 1201 差分约束

转自:優YoU http://user.qzone.qq.com/289065406/blog/1307063918 大致题意: 给出数轴上的n个区间[ai,bi],每个区间都是连续的int区间。 现在要在数轴上任意取一堆元素,构成一个元素集合V 要求每个区间[ai&#xff0c…

oracle11 删除表空间,oracle11g启动停止服务,修改字符集,导入导出,创建删除表空间,卸载oracle等...

oracle11g启动停止服务,修改字符集,导入导出,创建删除表空间,卸载oracle等1. 【启动停止服务】//启动停止监听 www.2cto.comlsnrctl start;lsnrctl stop;//启动停止服务sqlplus orcl as sysdba; //登录>shutdown immediate;>STARTUP;或者ps -ef|grep ora_dbw0_$O…

Java中包装类型和基本类型的使用场景(阿里开发规范)

基本数据类型和包装数据类型推荐使用场景 所有的 POJO 类属性必须使用包装数据类型RPC 方法的返回值和参数必须使用包装数据类型所有的局部变量推荐使用基本数据类型

数据库:整理四个实用的SQLServer脚本函数

今天给大家分享小编自己日常工作积累的四个SQLServer脚本函数 目录 1、字符串指定字符分割为list 2、数字去掉末尾的0 3、创建表、视图、函数、存储过程判断是否存在 4、金额转换为大写 1、字符串指定字符分割为list 功能:主要适用于数据库字段存储字段用逗号等分隔…

python排名分析_用Python分析了近几年胡润排行榜,我酸了……

10 月 20 日,胡润研究院发布《2020 胡润百富榜》,也就是富富富豪排行榜杭州的马云毫无悬念的再次摘下中国首富桂冠,深圳的马化腾位列第二榜单被我翻烂了,还是没有找到我的名字,难道是被遗漏了吗?&#xff1…

sublime代码片段

创建方法&#xff1a;Tools > New Snippet 这时你会看到如下示例代码&#xff1a; <snippet><content><![CDATA[Hello, ${1:this} is a ${2:snippet}.]]></content><!-- Optional: Set a tabTrigger to define how to trigger the snippet -->…

定义DO/DTO/VO等POJO类时,不要设定任何属性默认值

定义DO/DTO/VO等POJO类时&#xff0c;不要设定任何属性默认值

php事务 面向对象,关于PHP面向对象的事务脚本模式

下面为大家带来一篇PHP面向对象之事务脚本模式(详解)。内容挺不错的&#xff0c;现在就分享给大家&#xff0c;也给大家做个参考。如下所示&#xff1a;/*事务脚本模式: 类似于thinkphp中的model层&#xff0c;或者说就是操作数据库的类。个人觉得实践中使用起来还是挺简单方便…

分布式数据库相关概念介绍

1、分布式数据库的概念分布式数据库系统&#xff08;Distributed Database System&#xff0c;DDBS&#xff09;是针对面向地理上分散&#xff0c;而管理上有需要不同程度集中管理的需求而提出的一种数据库管理信息系统。2、分布式数据库系统组成LDBMS(Local DBMS)&#xff1a;…

社会管理网格化 源码_为什么说网格化管理是基层社会治理的有效武器

在社会治安综合治理中网格化管理是当前各地加强基层社会治理的一种有效“武器”。为什么要说网格化管理是基层社会治理的有效“武器”&#xff1f;这就要为大家讲讲以下几点了&#xff0c;好让大家清楚的明白为什么。网格化管理适应当代社会的基本特性。网格化服务管理是当前城…

【Time系列一】datetime的妙用

今天在弄个自动关机小脚本的时候&#xff0c;遇到了时间转换的问题&#xff0c;也难怪&#xff0c;以前没学过&#xff0c; 不能怪我不会哦! 首先&#xff0c;先学会打印出当前时间的几种方式 参考开源社区: http://my.oschina.net/u/1032854/blog/198179#OSC_h1_3 菜鸟编程:…

循环体内,字符串的连接方式,使用StringBuilder的append方法进行扩展

循环体内&#xff0c;字符串的连接方式&#xff0c;使用StringBuilder的append方法进行扩展

JS树结构操作:查找、遍历、筛选、树结构和列表结构相互转换

经常有同学问树结构的相关操作&#xff0c;也写了很多次&#xff0c;在这里总结一下 JS 树形结构一些操作的实现思路&#xff0c;并给出了简洁易懂的代码实现。本文内容结构大概如下&#xff1a;JS树结构相关操作1遍历树结构1. 树结构介绍JS中树结构一般是类似于这样的结构&…

python框架django的使用_Django框架的基本使用,若依框架

Django框架的基本使用&#xff0c;若依框架Django框架的基本使用Django是一个功能强大的web框架框架模式1、MVC和MTV框架MVC&#xff1a;Web服务器开发领域里著名的MVC模式&#xff0c;所谓MVC就是把Web应用分为模型(M)&#xff0c;控制器(C)和视图(V)三层&#xff0c;结构说明…

初学js

今天开始接触js&#xff0c;知道了js的功能以及学习的意义&#xff0c; 今天从命名的规范和数值的规则就能看出js是1门非常严谨的课程&#xff0c;只有做好细节才能体现出js的强大之处&#xff0c; var是定义一个名字 var name1&#xff1b; 定义了还能赋值&#xff0c;可以是数…

数据库:SQLServer中GUID用法介绍

今天给大家分享一下SQLServer中生成GUID的用法。一、NEWID用法NEWID()作用是生成无顺序的GUID字符串。用法如下&#xff1a;SELECT NEWID() --生成36位的GUIDSELECT REPLACE(newid(), -, ) -- 生成32 位的GUID二、NEWSEQUENTIALID用法1、NEWSEQUENTIALID是什么&#xff1f;在指…

oracle po:默认申请分组,PR自动创建PO采购订单:强制按照PR行进行分组

有时候&#xff0c;需要实现强制按照PR行来自动创建PO。举个例子&#xff1a;假设2张PR&#xff0c;同一个物料&#xff0c;同一个需求日期等等的&#xff0c;在合并采购订单的时候&#xff0c;希望是2个PO行。按照标准功能的处理逻辑&#xff0c;如果是同一个物料需求日期(配置…

cserialport 循环发送信号_C++信号处理

免费C语言教程&#xff1a;阿里云大学——开发者课堂(点击文章最下方“了解更多”)信号是由操作系统传给进程的中断&#xff0c;会提早终止一个程序。在 UNIX、LINUX、Mac OS X 或 Windows 系统上&#xff0c;可以通过按 CtrlC 产生中断。有些信号不能被程序捕获&#xff0c;但…