WebGL绘制有宽度的线

  WebGL中有宽度的线一直都是初学者的一道门槛,因为在windows系统中底层的渲染接口都是D3D提供的,所以无论你的lineWidth设置为多少,最终绘制出来的只有一像素。即使在移动端可以设置有宽度的线,但是在拐弯处原生api没有做任何处理,所以往往达不到项目需求,再者比如对于虚线、导航线的绘制,原生api是无能为力。差不多从事WebGL开发已经一周年,总结一下绘制线的方法和踩过的坑,聊以慰藉后来者。

WebGL绘制有宽度的线

宽度线绘制原理

  宽度线的绘制最核心的思想就是利用三角形来绘制线,将一根有宽度的线,看成是多个三角形的拼接

WebGL绘制有宽度的线

  将线剖分成三角形的过程是一个计算密集型的过程,如果放在主线程中会阻塞渲染造成卡顿,通常来讲都是放到顶点着色器中来处理,利用GPU并行计算来处理。通常来着色中,将顶点沿着法线方向平移lineWidth/2的距离。对于一个顶点只能平移一次,所以在cpu中我们需要把一个顶点复制两份传给gpu同时提前确定好剖分出来的三角形的顶点索引顺序。

WebGL绘制有宽度的线

  对于拐弯处,需要做一系列的计算来确定拐角的距离,比如:

WebGL绘制有宽度的线

  但这幅图过于复杂,我比较喜欢下面这个比较简单的图

WebGL绘制有宽度的线

  假设dir1为向量last->current的单位向量,dir2为向量current->next的单位向量,根据这两个向量求出avg向量,avg向量 = normalize(dir1 + dir2);将avg向量旋转九十度即可求出在拐角处的偏移向量,当然这个向量可向下,也可以向上,所以一般对上文中重复的顶点还有对应的一个side变量,来告诉着色器应该向下还是向上偏移,同样上面图中的last和next也要传入对应上一个和下一个顶点的坐标值。对应的着色器代码:

// ios11下直接使用==判断会有精度问题导致两个数字不相同引出bug ' if( abs(nextP.x - currentP.x)<=0.000001 && abs(nextP.y - currentP.y)<=0.000001) dir = normalize( currentP - prevP );', ' else if( abs(prevP.x - currentP.x)<=0.000001 && abs(prevP.y - currentP.y) <=0.000001) dir = normalize( nextP - currentP );', // ' if( nextP.x == currentP.x && nextP.y == currentP.y) dir = normalize( currentP - prevP );', // ' else if( prevP.x == currentP.x && prevP.y == currentP.y ) dir = normalize( nextP - currentP );', ' else {', ' vec2 dir1 = normalize( currentP - prevP );', ' vec2 dir2 = normalize( nextP - currentP );', ' dir = normalize( dir1 + dir2 );', '', '', ' }', '', ' vec2 normal = vec2( -dir.y, dir.x );',

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpypgs.html