如何在webgl中画一根2px的线

“可以画个世界地图的边框么”——设计

“可以,没问题”——开发

“你这边框能再粗点么,都看不清”——设计

“……”——开发

在传统的canvas绘图技术中,画一条有粗细的线,并非难事,但是对于WebGL来说,这简直难死宝宝了。

WebGL的绘制支持三种模式,分别是点、线、面。然而,在绘制线条的时候,在某些浏览器中(比如chrome)线的宽度只能设置为1,在http://alteredqualia.com/tmp/webgl-linewidth-test/这个地址中,可以测试你当前的浏览器是否支持线的粗细。

这是chrome一直以来的bug,从2010年被提起,至今,没!有!被!解!决!在chrome的bug issue中(https://bugs.chromium.org/p/chromium/issues/detail?id=60124),nicolasc*的一句“别再想粗线了,数学意义上根本没有这玩意”,终结了所有人的幻想。同时提出应该用Polygon来实现粗线。

既然Chrome自己也不想解决这个问题,我们也说服不了自己的产品和设计,那么,我们就只能自己想办法通过用面的方式,来模拟一根线。

那么如何通过面来模拟一根线条呢?

以一条线段为例,描述一条线段只需要两2个端点,如果用面来描述,则需要4个点;绘制2条线段,需要6个点,以此类推,每多画一条线段,就要多2个点。因此,如果想用面去表示一条n个端点的线,就需要2n个端点去描述它。

那么如何确定面上点的位置呢?

以上图为例,我们取每个线段端点的法线方向为a1方向,取法线负方向为a2方向,分别乘以宽度的一半,就有了a1和a2的位置,b点同理。

如何得到a和b的法线方向呢?

以下图为例,用last、current、next三点,算出current点的切线方向,切线方向乘以复数i,逆时针旋转90就为法线方向,乘以复数-i,顺时针旋转90度为负法线方向,则有了Normal和-Normal。

vec2 dir2=normalize(currentV2-prevV2);

vec2 dir=normalize(dir1+dir2);

vec2 normal=vec2(-dir.y,dir.x);

现在有了面线,但这只是一个二维方法,但是转个角度看,就又变成了一根线。

我们想要的是无论相机怎么看,线都是一样粗的,就好像面是一个三维的面一样,那怎么办呢?我们将这一步计算留在着色器里,对乘完投影矩阵后的二维坐标进行线的“拉宽”计算。

mat4 pvm=projectionMatrix*modelViewMatrix;

vec4 currentV4=pvm*vec4(position,1.0);

vec4 prevV4=pvm*vec4(prevPositions,1.0);

vec4 nextV4=pvm*vec4(nextPositions,1.0);

vec2 currentV2=currentV4.xy/currentV4.w;

currentV2.x*=aspect;

vec2 prevV2=prevV4.xy/prevV4.w;

prevV2.x*=aspect;

vec2 nextV2=nextV4.xy/nextV4.w;

nextV2.x*=aspect;

这样就得到一个可以任意旋转看,都是有粗度的“面线”了。

https://codepen.io/mysisi/pen/WJerrB?editors=1010

就这样解决了问题。。。

参考:

[1] https://www.cnblogs.com/twaver/p/7228687.html

[2] https://blog.mapbox.com/drawing-antialiased-lines-with-opengl-8766f34192dc

[3] http://codeflow.org/entries/2012/aug/05/webgl-rendering-of-solid-trails/

好啦,今天的分享就到这里啦~

也欢迎留言与我们讨论互动喔!

◆◆◆

请大家持续关注我们的公众号

我们会不断地分享更多有趣的干货~

笔芯~

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20180423G0GMJW00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券