如何在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://weixin.qq.com/r/nSqrs1PEDg5xrRfQ93_P (二維碼自動識別)
推薦閱讀:
※數據可視化的開源方案: Superset vs Redash vs Metabase (二)
※為什麼我們要數據可視化
※預測:國內可視化數據分析工具2018功能趨勢
※利用Python對NBA SportUV數據進行可視化及分析