立體地圖的圖形細分
來自專欄 360企業安全可視化實驗室
今天,我來講地球的故事,先從為什麼要細分圖形開始。
我們希望實現這樣的效果:
我們希望做一種可交互的地球,當滑鼠懸浮到國家時,展示當前國家的信息。這樣比貼圖更有立體感、也能方便地獲取當前國家的屬性做些交互。
實現過程簡單地描述一下:我們把geojson勾邊描成平面形狀,將形狀拉抻為下圖中所示平面地圖幾何體,將幾何體轉為地球的坐標即可。
當我們完成平面轉立體的坐標後,發現俄羅斯和南極洲有些地方發生了塌陷(圖一中 俄羅斯白色的區域)
什麼原因呢?當我們用GeoJson勾出的幾何圖形時,實際上圖形由很多的三角形組成。圖二中看到三角形的描線的中間空出的白色,是由於邊長較大三角形蓋在地球表面,但圖形在地球上經度跨度很大,導致三角形的厚度沒能蓋住地球表面弧度產生的,如圖三。
解決的辦法,就是讓這些形狀細分成更多的三角形,將圖形細分,就不會出現這個問題了。如下圖:
調研兩種細分圖形方法
一、Subdivision
在線例子 代碼地址
它的細分採用「使用循環細分」的原理,傳入循環的次數(subdivisions)進行循環。但不擅長處理銳利的邊緣(sharp edges)
庫的使用方法:
var tess = new THREE.SubdivisionModifier(1);tess.modify(geometry);var mesh = new THREE.Mesh(geometry, material);
耗時實驗:
在本文的時間實驗中,我們使用同一組圖形數據進行實驗。
運行如上代碼進行一次細分,時間為 26.787109375ms ,把循環次數增加一次,則時間會加倍,57.43603515625ms。速度有點慢,但是這個庫得到的細分效果如下圖,能滿足我們需求。
使用後對比:
二、TessellateModifier
代碼地址
這種細分採用 「把長度超過「限定邊長值」(maxEdgeLength)的邊進行細分」的方法,處理後,會細分為很多的小三角形
庫的使用方法:
所以使用時,需要一個maxEdgeLength,在調用modify方法:
var tessellateModifier = new THREE.TessellateModifier( 8 );for ( var i = 0; i < 6; i ++ ) { tessellateModifier.modify( geometry );}
時間實驗:
在數據相同的情況下,用如上函數調用一次TessellateModifier方法,用時為 2.52294921875ms,如果將 for循環的次數增加 2次 , 則 2.96484375ms ,時間增長幅度很小,但是得到的圖形填充色後有縫隙,有一些不足。
使用前後對比:
看,地圖裡麵線條(三角形)分得很細
三、兩種庫的對比
從上面的實驗我們得到了兩組庫的對比結果:
TessellateModifier 比 Subdivision 速度更快,如果側重速度,選擇TessellateModifier。
但是TessellateModifier實現的效果中填充後有縫隙,效果不如Subdivision。
本例中我們選擇Subdivision庫,本例在線地址
推薦閱讀: