上一篇文章簡單介紹了WebGL繪製Line的bug,很多朋友給我發了私信,看來這個問題你們都趕上過哈。今天這篇文章會講述解決這個問題的work around。html
上一篇文章結尾簡單提了下解決的思路,就是經過三角形來模擬線條。編程
以兩個端點組成的線段爲例,繪製line的時候只用指定兩個端點,若是經過三角形來模擬一條線段,則至少須要兩個三角形,以下圖:post
這是兩個三角形模擬的線段。性能
所以要繪製一條線段,則須要六個頂點,兩個三角形;當時從上圖中,能夠看出有些頂點是共享,實際上只須要四個頂點,而後經過索引的方式繪製兩個三角形,相信熟悉WebGL的同窗都理解這種經過索引來繪製的方式,此處不詳細說明。url
若是要繪製兩條相連的線段呢,則須要增長兩個頂點,也就是6個頂點,繪製四個三角形,依次類推,繪製三條相連的線段須要8個頂點,繪製6個三角形;由此能夠得出一個結論,繪製有n個端點的Line,須要:2 n 個頂點, (n-1) 2個三角形。插件
對於一條線段而言,控制的參數實際上只有兩個端點的座標和線的寬度。 htm
從上面的分析,咱們知道了給定一系列點(n個)和線的寬度,繪製一條線段須要的頂點數是n * 2. blog
當時 n個頂點數據應該如何計算獲得呢? 先舉個簡單的2維繪圖的例子,如今假設給定了兩個端點:索引
(-50,0)和(50,0),要繪製一條寬度爲2的線條,那麼總共是四個頂點,第一個頂點是從第一個端點 + 線寬形成的偏移量,線寬爲2,因此偏移量的基數應該是2 / 2 = 1;開發
第二個頂點是從第一個端點 + 線寬形成的偏移量 (-1),一樣線寬爲2,因此偏移量的基數應該是2 /2 (-1) = -1;
依次類推,那麼應該如何偏移呢? 這個與線段的走向有關,示例中 線段的走向能夠用第二個端點 - 第一個端點計算出來:
(50,0) - (-50,0) = (100,0) ,歸一化以後就是(1,0),此爲線段的方向向量,表示的線段的走向的是沿x軸正方向,對於第一頂點,偏移的方向應該是(1,0)逆時針旋轉90度,即和線段走向垂直的方向(與線段垂直的方向有兩個,此處基於右手法則,選擇逆時針旋轉90度的一個),旋轉90度以後,向量編程了(0,-1)
從圖形學裏面的數學知識能夠得知,向量(x,y)逆時針旋轉90度變成(-y,x);
對於第二個頂點,偏移的方向應該是(1,0)順時針旋轉90度,可是前面,咱們已經把偏移的基數變成-1了,因此能夠認爲偏移的方向仍是(1,0)逆時針旋轉90度,如圖:
基於線段方向計算頂點偏移方向
由此,能夠得出第一個頂點的位置是:
(-50,0) - (0,-1)* 1 = (-50,-1),
第二個頂點的位置是:
(-50,0)-(0,-1) * 1 = (-50,1)
對於第三,第四個頂點的計算也是相似的。
上面討論的是隻有兩個端點的狀況,事實上,若是是多個端點,以上討論的狀況只適合多個端點中第一個端點和最後一個端點的狀況,對於中間的端點,偏移的方向要綜合考慮這個端點鏈接的兩條線段的狀況,一樣舉例說明:
假設三個端點的狀況,三個端點 分別是 (-50,0),(0,0),(0,50),如今要計算第二個端點(0,0)對應的兩個頂點(第3、第四個),如圖:
此時要計算中間的端點的兩個頂點位置,則須要考慮改端點鏈接的兩天線段的方向:
計算的大體思路,經過該端點的和前一個端點相減 計算出第一條線段的方向:
(0,0) - (-50,0) = (50,0) = (1,0)(歸一化)
在經過該該端點的下一個端點減去該端點計算出第二條線段的方向:
(0,50) - (0,0) = (0,50) = (0,1)(歸一化)
而後兩個方向向量相加,在旋轉逆時針旋轉90度,能夠獲得偏移的方向:
(1,0) + (0,1) = (1,1) = (0.707,0.707)(歸一化)
旋轉以後,偏移方向編程了(-0.707,0.707),
須要注意的是,此時的的偏移基數其實也是發生了變化的,拐角處的偏移量此時應該變成大了,即有了一個放大因子。 能夠經過 1 / 偏移方向 點乘 第一條線段的方向 來獲取這個放大因子,不過若是兩條線段夾角很小,點乘的值也很小,放大因子很大,爲了拐角處的尖角不顯得是否大,咱們通常限定放大因子不超過2. 所以公式能夠變成:
1 / max(偏移方向 . 第一條線段的方向,0.5)
上面大量篇幅講述瞭如何計算頂點座標,事實上,前面文字所述的一切計算方法都是發生在頂點着色器中的,並且也只能在着色器中計算,由於最終顯示到屏幕上的頂點與鏡頭相關,上文中只是簡單的用了2維的狀況模擬,若是在js端計算,將極大消耗性能。 (那你不是瞎扯嗎,咱們都還沒搞清楚如何計算出要傳遞給頂點着色器的數據呢),其實不是瞎扯,由於只有搞清楚了在着色器中如何計算最終的頂點,才知道如何向頂點着色器中組織數據,
以上文中「多個端點的狀況」的爲例,咱們能夠總結出計算出一個頂點須要哪些數據:
端點座標,偏移量,前一個端點座標,後一個端點座標
所以在着色器中須要定義四個attribute變量 position,offset,positionPrev,positionNext,分別用來接收端點座標,偏移量,前一個端點座標,後一個端點座標。
對於前面兩頂點,其端點沒有前一個端點,此時前一個端點就取端點座標,而後在着色器中判斷 若是前一個端點點座標 == 端點座標,則代表是第一個端點;使用兩個端點的狀況計算。
低於後面兩個頂點,其端點沒有後一個端點,此時後一個端點就取端點座標,而後在着色器中判斷 若是後一個端點點座標 == 端點座標,則代表是最後一個端點;使用兩個端點的狀況計算。
對於中間的頂點,既存在端點座標,也存在前一個端點的座標,和後一個端點的座標,就使用前面多個端點的狀況計算。
仍是以以前三個端點的例子爲例,三個端點的(50,0,0),(0,0,0),(0,50,0),線寬爲2(注意此時已是三維座標了,以前模擬的狀況是用屏幕上的2維座標來模擬頂點在着色器中經過透視變換變成了二維座標的狀況)
那麼第一個頂點的四個變量的數據分別是:
端點座標, 偏移量, 前一個端點座標,後一個端點座標
(50,0,0),2/2, (50,0,0) (0,0,0)
第二個頂點的四個變量的數據分別是:
端點座標, 偏移量, 前一個端點座標,後一個端點座標
(50,0,0),-2/2, (50,0,0) (0,0,0)
第三個頂點的四個變量的數據分別是:
端點座標, 偏移量, 前一個端點座標,後一個端點座標
(0,0,0),2/2, (50,0,0) (0,50,0)
第四個頂點的四個變量的數據分別是:
端點座標, 偏移量, 前一個端點座標,後一個端點座標
(0,0,0),-2/2, (50,0,0) (0,50,0)
第五個頂點的四個變量的數據分別是:
端點座標, 偏移量, 前一個端點座標,後一個端點座標
(0,50,0),2/2, (0,0,0) (0,50,0)
第六個頂點的四個變量的數據分別是:
端點座標, 偏移量, 前一個端點座標,後一個端點座標
(0,50,0),-2/2, (0,0,0) (0,50,0)
到此爲止,咱們知道了如何組織繪製須要的頂點的數據。
下一篇將貼上相關代碼說明。
若是你對WebGL 感興趣,能夠了解下咱們用WebGL開發的3D機房項目: