如何在webgl中画一根2px的线
Posted 360企业安全可视化实验室
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在webgl中画一根2px的线相关的知识,希望对你有一定的参考价值。
“可以画个世界地图的边框么” —— 设计
“可以,没问题” —— 开发
“你这边框能再粗点么,都看不清” —— 设计
“……” —— 开发
在传统的canvas绘图技术中,画一条有粗细的线,并非难事,但是对于WebGL来说,这简直难死宝宝了。
这是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/
好啦,今天的分享就到这里啦~
也欢迎留言与我们讨论互动喔!
◆ ◆ ◆
我们会不断地分享更多有趣的干货~
笔芯~
以上是关于如何在webgl中画一根2px的线的主要内容,如果未能解决你的问题,请参考以下文章