如何在webgl中畫一根2px的線-

「可以畫個世界地圖的邊框么」 —— 設計

「可以,沒問題」 —— 開發

「你這邊框能再粗點么,都看不清」 —— 設計

「……」 —— 開發

在傳統的canvas繪圖技術中,畫一條有粗細的線,並非難事,但是對於WebGL來說,這簡直難死寶寶了。

1px的世界地圖邊框

WebGL的繪製支持三種模式,分別是點、線、面。然而,在繪製線條的時候,在某些瀏覽器中(比如chrome)線的寬度只能設置為1,在 alteredqualia.com/tmp/w 這個地址中,可以測試你當前的瀏覽器是否支持線的粗細。

這是chrome一直以來的bug,從2010年被提起,至今,沒!有!被!解!決!在chrome的bug issue中(bugs.chromium.org/p/chr),nicolasc*的一句「別再想粗線了,數學意義上根本沒有這玩意」,終結了所有人的幻想。同時提出應該用Polygon來實現粗線。

既然Chrome自己也不想解決這個問題,我們也說服不了自己的產品和設計,那麼,我們就只能自己想辦法通過用面的方式,來模擬一根線。

那麼如何通過面來模擬一根線條呢?

以一條線段為例,描述一條線段只需要兩2個端點,如果用面來描述,則需要4個點;繪製2條線段,需要6個點,以此類推,每多畫一條線段,就要多2個點。因此,如果想用面去表示一條n個端點的線,就需要2n個端點去描述它。

那麼如何確定面上點的位置呢?

以上圖為例,我們取每個線段端點的法線方向為a1方向,取法線負方向為a2方向,分別乘以寬度的一半,就有了a1和a2的位置,b點同理。

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

圖片來自(http://codeflow.org/entries/2012/aug/05/webgl-rendering-of-solid-trails/)

以下圖為例,用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;

這樣就得到一個可以任意旋轉看,都是有粗度的「麵線」了。

代碼請戳:

codepen.io/mysisi/pen/W

參考:

[1] cnblogs.com/twaver/p/72

[2] blog.mapbox.com/drawing

[3] codeflow.org/entries/20

請大家持續關注我們的公眾號

我們會不斷地分享更多有趣的乾貨~

筆芯~

weixin.qq.com/r/nSqrs1P (二維碼自動識別)


推薦閱讀:

數據可視化的開源方案: Superset vs Redash vs Metabase (二)
為什麼我們要數據可視化
預測:國內可視化數據分析工具2018功能趨勢
利用Python對NBA SportUV數據進行可視化及分析

TAG:數據可視化 | 前端數據可視化 | WebGL |