zoukankan      html  css  js  c++  java
  • UE4/Unity绘制地图基础元素-面和体

    前言

    基于UE4/Unity绘制地图基础元素-线(上篇)

    基于UE4/Unity绘制地图基础元素-线(下篇)

    搞定地图画线之后,接下来就是绘制面和体了:

    面作为地图渲染的基本元素之一,在地图中可以代表各种形式的区域,例如海面、绿地等。面数据通常以离散点串形式存储,因此渲染时最关注的是如何将其展现为闭合的图形。

    体可以理解为带有高度的面,在地图中代表各种建筑,通常是由其顶部面数据和高度数据处理得到。

    本文记录了绘制面和体的流程以及解决闪烁问题的方案。

    绘制多边形区域面

    面数据通常以离散点串形式存储,面的绘制与线的绘制原理类似。渲染的基本单位是三角形,线是通过扩展线宽构造三角形后渲染,而面是通过将多边形拆分为多个三角形后渲染。

    拆分为三角形的过程被称为三角剖分,常用的三角剖分算法是耳切法(Ear Clipping),比较成熟的方案是Mapbox的earcut,对于有 [公式] 个顶点的多边形,其时间复杂度为 [公式] ,值得注意的是,三角剖分的解可能是不唯一的,任何一种剖分方式都能够渲染得到面,但细小的三角形更容易使面中的同一像素绘制多次,造成过度绘制(Overdraw),因此根据多边形特征做一些剖分次序的调整可以作为一个优化点。

    剖分完成的多边形区域,在指定了每一个顶点的颜色之后,就能绘制得到纯色的面。和道路线的Z-fighting问题类似,区域面也需要处理同一高度叠加显示的问题。同时,二维的道路线和区域面整体也处于同一个高度上,因此也需要统一考虑层级关系,将所有的道路线置于区域面之上。统一处理完成就可以得到二维的地图底板了。

    绘制多边形建筑体

    二维地图底板完成后,就轮到地图上的楼块建筑了。为了减少数据量,通常的存储方式是顶面点串和其对应的拔起高度,在渲染时增加顶点构成闭合体。

    顶面渲染流程和闭合区域面一致,侧面则是根据楼高进行绘制,在每两个相邻顶点间渲染一个矩形从而构成闭合体的侧面,为了减少绘制次数通常只绘制朝向外侧的侧面,底面在正常视角下看不到,也可以酌情选择是否绘制。

    建筑体的渲染只比区域面多了拔高产生的侧面,逻辑比较简单,处理得到所有三角形数据后,配置好顶点颜色即可完成渲染。

    奇怪的建筑体Z-fighting问题

    理论上来说,建筑体数据的顶面通常不会重合,因此在拔起渲染后不会出现Z-Fighting问题,但奇怪的是,渲染后仍然发现一些体存在侧面闪烁问题。通过全链路的排查,才查出是多边形数据的问题。

    三角剖分在使用时有一个前置条件:使用对象必须为简单多边形,即多边形中的任何两条边仅可以在顶点处相交。下图(a)多边形为满足定义的简单多边形,图(b)多边形边01和23在非顶点处相交,因此是非简单多边形。

    对于非简单多边形,使用三角剖分只能得出较为满意的结果,但不能保证其正确性。从下图四个顶点构成的非简单多边形的三角剖分结果可以看到,多边形渲染时会丢失顶点并且产生错误的三角形,无法还原数据真实情况。

    按照这种想法对现有数据进行了边的相交检测,确实存在一小部分的多边形不是简单多边形。而体元素的立面拔起是按照原始数据在每一组相邻顶点间绘制矩形,因此会产生问题。以上述的非简单多边形(b)为例,边12拔起生成矩形1245,边23拔起生成矩形2364,两个侧面矩形在面1245上完全重合,当外立面贴上不同的纹理后就会产生Z-Fighting现象。同时,因为外立面仅仅绘制朝向外侧一面,面1245在对侧查看时会消失,产生非常诡异的效果。

    针对这个问题,比较容易想到的解决方法主要是以下三个:

    1、直接过滤,简单粗暴。

    2、根据多边形计算外接矩形,减少细节

    3、根据三角剖分结果剔除多余顶点,重新生成简单多边形

    以上三个方案对于多边形的细节保留由少到多,但并不是完全还原真实数据。尤其对于一些复杂建筑,某一个面的错误会导致最终拼装得到的渲染结果错误。因此比较理想的方式是修复非简单多边形,将其分解为多个简单多边形,分别渲染还原细节。

    简单多边形的判定与修复

    根据简单多边形的定义,很容易想到采用暴力解法进行判定:一个 边形有 条边,每条边只需要和其他的 条不相邻边判断是否相交即可达到目的,其时间复杂度为 ,对于仅需要进行一遍数据清洗的静态数据来说已经足够。但对于需要实时处理的动态数据来说,其需要遍历所有组合,尤其对于可能仅存在少量相交点的情况,冗余计算太多,因此可以引入时间复杂度更低的相交判定算法进行处理。

    对于一个非简单多边形,在分解为多个简单多边形后,绘制所有面积不为0的图形就可以了。这种方案可以最大限度还原原始数据,并且规避闪烁问题。

    小结

    解决了数据造成的闪烁问题后,就可以在建筑的侧面和顶面使用纯色或者纹理贴图进行装饰,搭配天空盒和一些纯色元素去装饰,已经可以简略模仿出城市的效果。但在当前的建筑拔起渲染方式下,只能通过贴图的形式去表达建筑细节,如果需要更精细的表达效果,例如玻璃窗体结构、楼顶设施等,需要增加额外的三角形去进行呈现。

    作者:程序员阿Tu

    链接:https://zhuanlan.zhihu.com/p/266870185

    来源:知乎

    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    react路由组件&&非路由组件
    react函数式组件(非路由组件)实现路由跳转
    react使用antd组件递归实现左侧菜单导航树
    【LeetCode】65. Valid Number
    【LeetCode】66. Plus One (2 solutions)
    【LeetCode】68. Text Justification
    【LeetCode】69. Sqrt(x) (2 solutions)
    【LeetCode】72. Edit Distance
    【LeetCode】73. Set Matrix Zeroes (2 solutions)
    【LeetCode】76. Minimum Window Substring
  • 原文地址:https://www.cnblogs.com/Yi-Xiu/p/14377199.html
Copyright © 2011-2022 走看看