关于腾讯地图:基于UE4Unity绘制地图基础元素线上篇

6次阅读

共计 3657 个字符,预计需要花费 10 分钟才能阅读完成。

前言

这篇文章是应用游戏引擎摸索地图可视化的开篇。传统的地图渲染通常是在 iOS/Android/Web 平台进行的,为了探索更酷炫的地图展现,会记录基于 UE4/Unity 进行地图渲染的摸索过程。

地图根底元素 – 线

线作为地图渲染的根本元素,在地图中能够代表各种模式的路线。路线数据通常以离散点串模式存储,因而如何将点串绘制成有宽度的线是渲染最关注的问题。本文记录了绘制有宽度的线的办法,并对优化线展现成果的各种线帽和拐角进行了论述。

绘制有宽度的线

路线数据通常以离散点串和其对应线宽进行存储,为了在游戏引擎中进行显示,就须要将其扩大为有宽度的线。UE4 和 Unity 都能够应用代码生成 Mesh 进行根本图元的渲染展现(UE4 应用 Procedural Mesh Component,Unity 应用 MeshFilter 和 MeshRenderer),而 Mesh 渲染的根本单位是三角形,因而问题就转化为如何依据点串和线宽,结构出一组三角形使其可能拼合产生具备宽度的线。

对于只有两个点的直线,通过获取与直线垂直的向量,向两个方向各扩大 lineWidth/ 2 长度产生顶点,划分为三角形即可。

而对于多个离散点形成的线,绘制的时候遇到 2 个问题:

  • 仅应用相邻点计算垂直向量,导致裁减出的线拐角处会有断裂,如下图所示。能够看到,仅仅每个相邻线段进行裁减是不够的,还须要思考如何解决线的拐角。

  • 思考解决线的拐角,但获取顶点裁减向量的方向和大小不对,导致绘制的线不等宽。下图依据相隔顶点连线的垂线确定裁减向量,但因向量随顶点地位变动而变动,因而不能作为生成等宽线的根据。

有了下面的思考,工作就变成了裁减出等宽且有拐角的线:相隔点的顶点地位会变动,但由其确定的向量方向是不变的,因而依附顶点两侧线段的单位向量,就能确定出惟一的裁减向量。确定裁减方向后,还须要确定裁减向量的大小使得最终的线等宽。

伪代码如下,裁减方向可由线段单位向量组合确定,须要留神裁减长度并不是 lineWidth/2,而是须要依据线段夹角进行计算调整。裁减向量计算好之后,即可依据离散点串生裁减顶点,依据顶点坐标剖分为三角形,构建 Mesh 进行渲染。

// 计算裁减方向
Vec2f a = (P1 - P0) * normalized()
Vec2f b = (P2 - P1) * normalized()
Vec2f avg = a + b
Vec2f direction =  Vec2f(-avg.y, avg.x).normalized() // 裁减方向为 avg 的垂直方向

// 计算裁减长度
float t =  Abs(Asin(a × b)) / 2  // 单位向量叉乘取得夹角正弦
float length = lineWidth / 2 / Cos(t)  // 依据角度调整裁减长度

绘制线帽 LineCap

依据上一节操作曾经能够绘制出有宽度的线,但也可能看出线在结尾和结尾处都是矩形,不够优雅好看。因而本节次要会解决绘制线帽的问题。

较为罕用的 LineCap 次要有以下三种:

  • Butt 无线帽模式,上一节绘制的线默认即为 Butt
  • Round 在线的两端增加额定的半圆,其半径为 lineWidth/2
  • Square 在线两端增加额定的矩形,其高度为 lineWidth/2

Square 模式的线帽绘制较为简单,只须要在结尾和结尾局部依据延长方向额定增加矩形即可,两个矩形能够很简略的划分为四个三角形,增加在画线 mesh 中一起渲染。而 Round 模式的半圆线帽在绘制上就麻烦了许多,在实际过程中次要摸索了以下三个计划:

1、应用三角形近似绘制半圆

最直观的形式就是间接绘制半圆线帽,然而渲染的最小单元是三角形,因而只能通过增加多个三角形近似示意半圆。这种形式须要依据增加三角形的个数,进行几何运算确定各个顶点坐标,通过三角形组合成半圆,尽管办法直观可行,但为了使线帽圆滑,额定增加的较多顶点和进行的大量数学运算都会对性能带来影响,存在性能和成果的取舍。

2、应用图片近似绘制半圆

第二种计划借助图片能够省去增加额定顶点和进行数学计算的步骤,近似失去半圆线帽。

图片工具大小为 16×16 像素,左右两局部别离绘制半圆和矩形。对于半圆局部,外部点透明度设置为 1,圆弧上笼罩的像素点,通过调低透明度值弱化锯齿感,圆弧之外局部则将透明度设置为 0,整体应用透明度构建出近似的半圆。矩形局部则作为工具,用于填充非线帽局部。

这种计划在构建线 Mesh 时,与 Square 线帽计划统一,但须要将纹理 uv 值也与顶点进行绑定。Square 线帽额定增加的矩形绑定图片左侧半圆的 uv,而原有线局部绑定右侧矩形 uv 即可。渲染时,能够在片元着色器中逐像素提取到映射的图片色彩值,输入色彩应用顶点原色,但透明度值采纳图片的透明度值,从而将圆弧外侧像素剔除。应用该计划须要开启透明度混合,从而不显示圆弧外侧像素。

这种计划也是半圆的近似示意,在间隔较近察看时会呈现圆弧线帽发虚,起因是受限于图片大小,如果减少图片大小能够缓解问题,但也会减少开销,也须要做性能和成果的取舍均衡。

3、逐像素绘制半圆

第三种计划由计划二演进而来,不是应用图片剔除像素,而是借助于半圆的个性,在片元着色器中剔除所有不满足条件的像素,做到绘制像素级的半圆线帽。其次要原理是在增加 Square 线帽后,判断渲染时像素间隔线起始顶点间隔,若超过 lineWidth/2(即红色局部)则剔除像素,从而逐像素绘制出半圆线帽。

像素剔除会在片元着色器中并行进行,效率高但无奈存储上下文信息,而剔除逻辑须要获取圆心信息,同时片元着色器的坐标曾经转化为裁剪空间的齐次坐标,无奈进行几何运算,因而须要将一些辅助信息传递到片元着色器中进行操作。

辅助信息定义为二维向量 geometryInfo,其含意为顶点在线中的绝对地位,点串的终点作为 (0,0),起点作为(1,0),两头的点依据间隔转化为[0,1] 间的数值。依据裁减向量失去的顶点,则依据裁减方向,向量 y 值赋值为 1 或 -1。因为曾经人为定义了线宽为 2 的绝对坐标系,因而线帽上顶点的辅助信息 x 值能够转化为 - 1 和 2,这样任何小于 0 和大于 1 的 x 值都能够示意该点是线帽局部,而且能够很不便的和 (0,0)、(1,0) 做间隔计算,并与半圆半径 1 进行比拟。

geometryInfo 绑定在每个顶点传入 shader 后,会在片元着色器中按像素进行线性插值,因而每一个像素都会取得一个能够标识本人部分地位的辅助信息,借助于该信息进行间隔判断就能够进行像素剔除,这里展现的是 Unity Shader 代码,UE4 能够在 Material 中还原逻辑。

fixed4 frag (v2f i) : SV_Target
{if(i.geometryInfo.x < 0)  // 终点侧线帽
    {if(dot(float2(i.geometryInfo.x, i.geometryInfo.y), float2(i.geometryInfo.x, i.geometryInfo.y)) > 1)
        {discard; // 间隔圆心间隔大于 1 则剔除}
    } 
    else if(i.geometryInfo.x > 1) // 起点侧线帽
    {if(dot(float2(i.geometryInfo.x - 1, i.geometryInfo.y), float2(i.geometryInfo.x - 1, i.geometryInfo.y)) > 1)
        {discard;}
    }

    return i.color;
 }

应用该计划生成的圆角,在近距离观看时因为线帽的渲染像素增多,因而也不会产生虚化或者锯齿感,可能失去圆滑的成果。

绘制线拐角 LineJoin

线帽曾经圆润优雅之后,同时也发现绘制的线在一些极其状况下拐角会存在 bad case。例如下图所示,对于夹角较小的线会产生十分大的尖角;而对于线段呈直角状况显示的也同样是直角拐角,不够圆润好看。本节次要会解决绘制线拐角的问题。

较为罕用的 LineJoin 次要有以下三种:

  • Miter 尖角款式,上一节绘制的线即属于 Miter
  • Bevel 切角款式,以横切面代替尖角
  • Round 圆角款式,以圆弧代替尖角

有了裁减线和线帽的绘制教训,从上图能够看出 Bevel 和 Round 款式不须要依据线段夹角计算裁减向量。绘制时依照矩形扩大后,Bevel 款式只须要依据裁减顶点补齐一个三角形形成切面。而对于 Round 款式,除了起起点外,每一个顶点裁减处依据矩形方向绘制两个半圆,叠加就能达到圆拐角成果。

半圆局部的绘制原理和绘制半圆线帽一样,增加矩形再剔除多余像素,因而须要将 geometryInfo 裁减为四维向量,后两位示意顶点在以后段的绝对地位,同样在片元着色器中进行像素剔除。这里片元着色器的代码逻辑与圆角线帽相似,不再赘述。最终的拐角成果如下图。

整体的绘制流程能够简略总结为下图,等宽线作为线渲染的主体,线帽 / 拐角作为线渲染的成果优化项。在具体实际中,能够通过设置配置项的形式不便的更改线帽 / 拐角的款式。

作者:程序员阿 Tu

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

起源:知乎

著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。

正文完
 0