Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
要: 在WebGIS的瀏覽器端存在繪圖效率差、不能直接支持矢量繪圖等問(wèn)題。為提高客戶端的交互性和實(shí)時(shí)性,在解決瀏覽器不支持矢量繪圖和渲染速度慢、存儲(chǔ)空間小、傳輸速率慢這些問(wèn)題的基礎(chǔ)上,結(jié)合HTML5中的Canvas、WebSocket、WebStorage技術(shù),構(gòu)建了WebGIS實(shí)時(shí)客戶端,有效地改善了客戶端存在的問(wèn)題,改善用戶的體驗(yàn)。
0 引言
WebGIS是GIS技術(shù)與Internet的結(jié)合體,是對(duì)網(wǎng)絡(luò)GIS的發(fā)展,它將GIS從一種使用計(jì)算機(jī)的處理地理信息的系統(tǒng)工具,變?yōu)橐环N網(wǎng)絡(luò)共享資源,提高了地理信息的使用效率,使地理信息的價(jià)值得以充分體現(xiàn)[1]。WebGIS的實(shí)現(xiàn)手段主要是基于Web技術(shù)的多級(jí)B/S體系結(jié)構(gòu),即瀏覽器、GIS服務(wù)器、數(shù)據(jù)庫(kù)等。B/S模式的構(gòu)架簡(jiǎn)化了客戶端系統(tǒng)的部署,降低了用戶使用難度,同時(shí)也極大提高了系統(tǒng)的可維護(hù)性[2]。但是這種被動(dòng)的工作模式無(wú)法滿足用戶實(shí)時(shí)性的需求。對(duì)于WebGIS的架構(gòu)研究,以前主要是對(duì)服務(wù)器端技術(shù)的改進(jìn),如使用CGI、Server API等服務(wù)端技術(shù),但是這些技術(shù)對(duì)于服務(wù)器及網(wǎng)絡(luò)的要求較高。隨著客戶端技術(shù)的發(fā)展,Java Applet技術(shù)、Plug-in技術(shù)、Ajax技術(shù)的出現(xiàn)擴(kuò)展了客戶端的功能,但是用戶需要預(yù)先安裝這些插件,安裝插件帶來(lái)了一定的安全隱患和不方便性。對(duì)比這兩種形式,使用HTML5的新技術(shù)實(shí)現(xiàn)的功能并不需要插件支持,且其本地存儲(chǔ)功能和高效率的雙向通信功能,還有動(dòng)態(tài)快速繪圖功能的提出,使實(shí)時(shí)客戶端的實(shí)現(xiàn)成為可能。
1 實(shí)時(shí)客戶端的WebGIS系統(tǒng)結(jié)構(gòu)
HTML5是W3C推出的新標(biāo)準(zhǔn),其強(qiáng)大功能已經(jīng)被大部分的瀏覽器支持,同時(shí),相對(duì)于以前的版本,HTML5的改變不僅僅是使用更方便。第一,它新增了更具有語(yǔ)義化的標(biāo)簽和使用更智能化的表單;第二,HTML5還新增了許多JavaScript API,如實(shí)時(shí)繪圖(Canvas和SVG)、離線存儲(chǔ)(WebStorage)、實(shí)時(shí)通信(WebSocket)API等,這些API為實(shí)現(xiàn)實(shí)時(shí)客戶端提供了可能。用HTML5來(lái)實(shí)現(xiàn)WebGIS有地圖無(wú)限縮放而圖不失真,地圖的顯示渲染效果逼真的優(yōu)勢(shì);且支持JavaScript腳本實(shí)現(xiàn)地圖的漫游、縮放、查詢等功能,這些功能都無(wú)需插件支持并可在不同平臺(tái)與設(shè)備上運(yùn)行[3]。根據(jù)這些特性,本文在傳統(tǒng)架構(gòu)的基礎(chǔ)上,構(gòu)建了圖1所示的WebGIS實(shí)時(shí)客戶端。
在客戶端這些模塊中使用HTML5和JavaScript技術(shù),實(shí)現(xiàn)數(shù)據(jù)地圖的繪制、本地存儲(chǔ)、數(shù)據(jù)傳輸?shù)裙δ埽瑢⒉糠趾?jiǎn)單的功能交給客戶端完成,增加了WebGIS客戶端的交互能力,減少了服務(wù)器的傳輸壓力,也增加了數(shù)據(jù)傳輸?shù)男剩瑢?shí)現(xiàn)了客戶端的實(shí)時(shí)性。
2 WebGIS客戶端的具體設(shè)計(jì)
2.1 數(shù)據(jù)實(shí)時(shí)更新與傳輸設(shè)計(jì)
空間數(shù)據(jù)格式有柵格數(shù)據(jù)和矢量數(shù)據(jù)。柵格數(shù)據(jù)交互性能差,可用來(lái)展示空間數(shù)據(jù),矢量數(shù)據(jù)交互性較好,可用來(lái)表示空間對(duì)象,但是客戶端不能直接支持矢量數(shù)據(jù)的二進(jìn)制格式傳輸,所以數(shù)據(jù)在傳輸中就要進(jìn)行格式編碼,目前使用的比較多的數(shù)據(jù)傳輸格式是GeoJSON(基于JSON數(shù)據(jù)格式的地理要素表示格式)。JSON(JavaScript Object Notation)是輕量級(jí)數(shù)據(jù)交換格式,適合于服務(wù)器與瀏覽器(通過(guò)JavaScript)交互[4],在瀏覽器端JSON能夠簡(jiǎn)單快速地解析成可以被客戶端操作的JavaScript地理信息,不需要使用專門的文本解析API進(jìn)行操作。空間數(shù)據(jù)傳輸大多使用Ajax的異步傳輸方式,但Ajax輪詢方式的時(shí)延較長(zhǎng),傳輸?shù)膶?shí)時(shí)性不高,因此將Ajax用于地圖數(shù)據(jù)的推送。實(shí)時(shí)性方面還是需要HTML5的WebSocket API實(shí)現(xiàn)。WebSocket使瀏覽器具有客戶機(jī)/服務(wù)器(C/S)模式下應(yīng)用程序的實(shí)時(shí)通信能力[5]。WebSocket的優(yōu)勢(shì)有:(1)為瀏覽器和服務(wù)器之間建立的更高效的雙向通信提供支持。其連接本質(zhì)為TCP連接,因此瀏覽器通過(guò)JavaScript向服務(wù)器發(fā)出建立WebSocket連接的請(qǐng)求,onopen事件接收消息,連接建立以后,客戶端和服務(wù)器端就可通過(guò)TCP連接直接交換數(shù)據(jù)。(2)WebSocket有更為輕量級(jí)的Header,除了首次建立鏈接時(shí)需要發(fā)送頭部與普通Web鏈接類似的數(shù)據(jù)之外,連接建立后,相互溝通的Header就會(huì)很簡(jiǎn)潔,大大減少了冗余的數(shù)據(jù)傳輸[6];通過(guò)新建WebSocket實(shí)例建立握手并完成與服務(wù)器的連接,建立好連接之后數(shù)據(jù)就可以以全雙工模式在客戶端與服務(wù)器之間進(jìn)行雙向傳輸,并一直保持連接,直到用戶主動(dòng)關(guān)閉[3]。圖2是傳統(tǒng)傳輸方式與WebSocket傳輸方式數(shù)據(jù)量的對(duì)比,從結(jié)果可以看出,當(dāng)傳輸數(shù)據(jù)量增大時(shí),WebSocket的效率更高。
需要在服務(wù)器端安裝開源的WebSocket支持?jǐn)?shù)據(jù)庫(kù),如Node.js、LibWebSockets、PHP WebSocket Server等,以調(diào)用接口使用。具體傳輸過(guò)程是:GIS服務(wù)器從空間數(shù)據(jù)庫(kù)獲取數(shù)據(jù),將空間數(shù)據(jù)解析成JSON的格式,然后發(fā)送到已經(jīng)與WebSocket服務(wù)器連接的客戶端,客戶端WebSocket實(shí)例的onmessage事件接收數(shù)據(jù)并使用JSON.parse函數(shù)將JSON字符串解析成JavaScript對(duì)象,再根據(jù)對(duì)象的內(nèi)容在WebGIS的地圖中解析顯示。WebSocket API一個(gè)顯著特點(diǎn)是,連接建立后,服務(wù)器可主動(dòng)推送消息。支持WebSocket協(xié)議的服務(wù)端接受請(qǐng)求和處理WebSocket任務(wù),在客戶端可用WebStorage存儲(chǔ)模塊緩存?zhèn)鬏斶^(guò)來(lái)的數(shù)據(jù),WebSocket的中間傳輸機(jī)制就實(shí)現(xiàn)了數(shù)據(jù)實(shí)時(shí)更新。
2.2 客戶端空間數(shù)據(jù)緩存設(shè)計(jì)
客戶端緩存功能主要是由WebStorage API來(lái)實(shí)現(xiàn),WebStorage API是以Key-Value形式來(lái)進(jìn)行數(shù)據(jù)的持久性存儲(chǔ)。傳統(tǒng)客戶端一般是使用Cookie存儲(chǔ)數(shù)據(jù),但是它效率低,存儲(chǔ)空間小,不能滿足大量矢量數(shù)據(jù)的存儲(chǔ)。WebStorage提供的兩種存儲(chǔ)方式可以改善這個(gè)狀況,一種是SessionStorage,它是一種會(huì)話級(jí)別的存儲(chǔ)方式,存儲(chǔ)的數(shù)據(jù)只在當(dāng)前頁(yè)面有效,當(dāng)頁(yè)面關(guān)閉時(shí),數(shù)據(jù)也會(huì)隨之刪除,據(jù)此SessionStorage可以用在矢量圖繪制的緩存方面,即讓SessionStorage自動(dòng)緩存解析好的JSON格式的矢量層數(shù)據(jù),當(dāng)需要數(shù)據(jù)時(shí)直接從SessionStorage中提取JSON數(shù)據(jù),這比從空間數(shù)據(jù)庫(kù)中獲取再解析效率明顯更高,數(shù)據(jù)顯示模塊可以直接從中獲取數(shù)據(jù)進(jìn)行繪制。另一種方式是LocalStorage,它是一個(gè)跨多窗口且數(shù)據(jù)永久存儲(chǔ)的方式,只有使用清除函數(shù)clear、removeItem或手動(dòng)刪除數(shù)據(jù)時(shí)數(shù)據(jù)才會(huì)從瀏覽器中清除,同時(shí)它的數(shù)據(jù)可以在同源的窗口或標(biāo)簽共享使用。因此它可以用來(lái)永久存儲(chǔ)空間分析后的數(shù)據(jù)或服務(wù)器發(fā)送的數(shù)據(jù)和用戶數(shù)據(jù),下次用戶打開瀏覽器可直接使用這些數(shù)據(jù)。圖3是具體矢量數(shù)據(jù)本地存儲(chǔ)過(guò)程。將數(shù)據(jù)緩存到本地,不用與服務(wù)器發(fā)生交互,客戶端存儲(chǔ)的數(shù)據(jù)可以由JavaScript訪問(wèn)。
WebStorage存儲(chǔ)技術(shù)和WebSocket技術(shù)可結(jié)合使用并與JavaScript一起實(shí)現(xiàn)數(shù)據(jù)的實(shí)時(shí)更新,減輕服務(wù)器壓力。用戶發(fā)送數(shù)據(jù)請(qǐng)求后,WebSocket建立連接,將得到的數(shù)據(jù)解析后存儲(chǔ)在WebStorage預(yù)先定義好的空間中,等待用戶提取。對(duì)于常須更新地圖數(shù)據(jù)的操作采用這種預(yù)先存儲(chǔ)的方式,可以加快數(shù)據(jù)的渲染效率。為了提高圖3的實(shí)時(shí)更新效果,可以設(shè)定異步存儲(chǔ)機(jī)制,過(guò)程如下:(1)創(chuàng)建并初始化WebStorage對(duì)象,設(shè)置緩存區(qū)大小(緩存區(qū)分段);(2)用戶發(fā)出消息,觸發(fā)onopen事件;(3)為WebSocket對(duì)象的信息添加偵聽器;(4)服務(wù)器調(diào)用received函數(shù)處理事件;(5)客戶端接收服務(wù)器發(fā)送的消息,觸發(fā)緩存判斷函數(shù),判斷緩存大小,如果超出,設(shè)置緩存片段的編號(hào),對(duì)象異步sends數(shù)據(jù)請(qǐng)求服務(wù)器處理;(6)服務(wù)器將片段編號(hào)入隊(duì)(服務(wù)端設(shè)置),直到傳輸完成,清除編號(hào)。這種傳輸方式將進(jìn)一步減少網(wǎng)絡(luò)流量,減少服務(wù)器的負(fù)載,提升傳輸效率。
2.3 數(shù)據(jù)顯示設(shè)計(jì)
HTML5現(xiàn)提供了Canvas API,它可以解決傳統(tǒng)開發(fā)瀏覽器支持度差、跨平臺(tái)性不強(qiáng)和繪制矢量圖形需要插件的問(wèn)題,通過(guò)JavaScript在瀏覽器不依賴任何插件的情況下高效地繪制動(dòng)態(tài)圖形[7],避免了安裝插件帶來(lái)安全風(fēng)險(xiǎn)。
2.3.1 繪制方法
Canvas API使用比較簡(jiǎn)單,像其他HTML標(biāo)簽一樣,只需在HTML5的頁(yè)面中添加一個(gè)<canvas>元素即可。Canvas繪圖首先要獲得上下文(context),因?yàn)镃anvas自己本身并沒有繪圖能力,所以所有的繪圖工作要由JavaScript完成。它的工作過(guò)程為:先定義Canvas元素的id,然后通過(guò)getElementById函數(shù)找到自己前面創(chuàng)建好的Canvas元素,最后用JavaScript調(diào)用繪圖API接口得到上下文繪圖環(huán)境后就可在畫布上繪制任何的圖形了。但Canvas只支持一種基本圖形——矩形,想使用Canvas繪制其他的圖形,就要使用其提供的路徑(Path)繪制函數(shù)[8],使用beginPath開始繪制,使用moveTo、lineTo繪制直線,繪制完畢后調(diào)用fill、stroke進(jìn)行填充或者設(shè)置邊框,最后調(diào)用closePath結(jié)束圖形繪制。Canvas在矢量數(shù)據(jù)方面是像素級(jí)管理,Canvas的路徑操作能充分滿足矢量數(shù)據(jù)中的點(diǎn)要素、線要素、面要素以及符號(hào)的表達(dá)要求。
2.3.2 數(shù)據(jù)顯示過(guò)程
用Canvas與JavaScript技術(shù)實(shí)現(xiàn)地圖實(shí)時(shí)繪制。地理實(shí)體對(duì)象可以根據(jù)OGC的簡(jiǎn)單要素規(guī)范和GIS界的研究將其分為:點(diǎn)狀實(shí)體、線狀實(shí)體、面狀實(shí)體、標(biāo)注實(shí)體和柵格實(shí)體[3]。Canvas可直接使用這些實(shí)體,對(duì)于柵格實(shí)體,可以用JavaScript對(duì)象表示,通過(guò)API drawImage直接在HTML5 Canvas中繪制。矢量實(shí)體的地理要素從GeoJSON文本轉(zhuǎn)化為JavaScript對(duì)象,根據(jù)該對(duì)象的信息,調(diào)用坐標(biāo)轉(zhuǎn)換對(duì)象,將坐標(biāo)轉(zhuǎn)換成Canvas元素里的屏幕坐標(biāo)來(lái)對(duì)應(yīng)顯示要素。實(shí)現(xiàn)實(shí)時(shí)繪圖的流程為:(1)服務(wù)器從數(shù)據(jù)庫(kù)獲取數(shù)據(jù);(2)數(shù)據(jù)進(jìn)行JSON格式解析;(3)瀏覽器加載地圖,調(diào)用Canvas畫布及函數(shù)實(shí)現(xiàn)繪圖和地圖的顯示;(4)地圖操作由自定義腳本實(shí)現(xiàn)地圖渲染。Canvas在客戶端展現(xiàn)地理數(shù)據(jù)的靈活性與互操作性要優(yōu)于傳統(tǒng)的切片技術(shù),并且在地圖加載速度方面有明顯的優(yōu)勢(shì)[8],因此將Canvas和WebStorage結(jié)合起來(lái),可以提高實(shí)時(shí)性能,將要顯示或者要存儲(chǔ)的數(shù)據(jù)先經(jīng)過(guò)緩存,再進(jìn)行顯示或存儲(chǔ),這種機(jī)制效率明顯更高。圖4說(shuō)明了從數(shù)據(jù)推送到顯示的流程。
3 客戶端整體過(guò)程
Canvas實(shí)現(xiàn)實(shí)時(shí)繪圖和快速渲染,WebSocket API在通信方面提供了支持。WebStorage提供了客戶端的本地存儲(chǔ)技術(shù),以地圖放大操作為例,用戶提交請(qǐng)求,數(shù)據(jù)獲取函數(shù)可以從SessionStorage中獲取數(shù)據(jù),然后將緩存的數(shù)據(jù)轉(zhuǎn)換成JavaScript對(duì)象,最后通過(guò)Canvas直接添加在地圖中,同時(shí),緩存中的數(shù)據(jù)不斷更新。WebSocket的雙向通信機(jī)制和WebStorage的異步存儲(chǔ)機(jī)制加速了數(shù)據(jù)交換效率,空間數(shù)據(jù)庫(kù)也通過(guò)WebGIS服務(wù)器,在實(shí)時(shí)通信的基礎(chǔ)上,將數(shù)據(jù)以JSON文本格式傳輸?shù)娇蛻舳耍嫒隨essionStorage中,窗口關(guān)閉后,所有數(shù)據(jù)存入LocalStorage,供用戶下次直接使用。這種方式的效率很明顯會(huì)比從服務(wù)器獲取數(shù)據(jù)的方式高,實(shí)時(shí)性要好,如需要執(zhí)行其他的交互操作,也可以基于這種方式實(shí)現(xiàn)。
4 結(jié)論
隨著Web技術(shù)的發(fā)展,客戶端的交互性和實(shí)時(shí)性要求不斷提升,據(jù)此,本文將HTML5的新特性與JavaScript技術(shù)結(jié)合,在WebSocket雙向通信機(jī)制和WebStorage緩存機(jī)制實(shí)現(xiàn)異步存儲(chǔ)提供的數(shù)據(jù)支撐,Canvas能實(shí)現(xiàn)動(dòng)態(tài)繪圖和快速渲染的基礎(chǔ)上,提出了一種實(shí)時(shí)性更強(qiáng)的WebGIS客戶端,為建立實(shí)時(shí)的WebGIS客戶端提供了一種方案。HTML5中的新技術(shù)雖然強(qiáng)大,還是有需要加強(qiáng)的地方,WebStorage讓數(shù)據(jù)能夠緩存在本地,但是由于是存儲(chǔ)在本地,數(shù)據(jù)容易泄漏,安全性還有欠缺。未來(lái)WebGIS的發(fā)展會(huì)隨著數(shù)據(jù)量的增大實(shí)現(xiàn)云平臺(tái)化,資源更龐大,數(shù)據(jù)更易共享,用戶使用起來(lái)也會(huì)更方便。
參考文獻(xiàn)
[1] 孟令奎,史文中,張鵬林,等.網(wǎng)絡(luò)地理信息系統(tǒng)原理與技術(shù)[M].北京:科學(xué)出版社,2010.
[2] 李博霏,李欣,李艷明.基于瀏覽器的地理信息服務(wù)客戶端技術(shù)研究[J].計(jì)算機(jī)工程與設(shè)計(jì),2011(9):3031-3035.
[3] 龍?jiān)?基于HTML5的WebGIS研究[D].贛州:江西理工大學(xué),2013.
[4] CROCKFORD D. The application/json media type for JavaScript Object Notation(JSON)[EB/OL]. [2006-07]. http://tools.ietf.org/html/rfc4627.
[5] 徐卓揆.基于HTML5、Ajax和Web Service的WebGIS研究[J].測(cè)繪科學(xué),2012,37(1):145-147.
[6] 魏進(jìn)鋒,孫春華.應(yīng)用HTML5的WebSocket實(shí)現(xiàn)BiDirection數(shù)據(jù)交換[EB/OL].[2012-12-28](2015-02-25).http://www.ibm.com/developerworks/cn/web/1112_weijf_websocket/.
[7] 王曉.基于HTML5的矢量地圖發(fā)布關(guān)鍵技術(shù)研究[D].南京:南京師范大學(xué),2011.
[8] 梁春雨,李新通.使用HTML5 Canvas構(gòu)建基于GeoJSON的輕量級(jí)WebGIS[J].計(jì)算機(jī)科學(xué)與應(yīng)用,2012(2):189-196.
數(shù)據(jù)可視化中,使用頻率最高的展現(xiàn)方式肯定是地圖可視化。基本上現(xiàn)有的大屏都是以地圖作為主視圖來(lái)呈現(xiàn)的,沒有一幅地圖放到大屏中央,已經(jīng)不好意思給同行、媒體界通告自己企業(yè)數(shù)據(jù)分析有多牛了。
怎么將地理數(shù)據(jù)處理得更好,怎么把地圖設(shè)計(jì)出更好的視覺效果也一直是我們研究的方向。億信ABI作為億信華辰自主研發(fā)的一款全能型數(shù)據(jù)分析產(chǎn)品,具備強(qiáng)大的數(shù)據(jù)地圖功能,內(nèi)置世界地圖、五大洲地圖、中國(guó)地圖,囊括各省、市區(qū)縣地圖,每個(gè)地圖都有flash、圖片和html5三種格式,還能實(shí)現(xiàn)鉆取、聯(lián)動(dòng)等功能。
下面帶大家一起來(lái)看一下億信ABI中地圖可視化的那些事兒。
渲染地圖適合展示數(shù)據(jù)在地理區(qū)塊空間的分布狀況,用顏色來(lái)區(qū)分?jǐn)?shù)值大小。隨意切換全國(guó)任意省市地圖方便快捷,還可以通過(guò)事件聯(lián)動(dòng)其他組件和下鉆。
標(biāo)點(diǎn)地圖主要用于展示地理區(qū)域內(nèi)的空間分布,非常適合展示一組或多組數(shù)據(jù)在地理空間的分布狀況,數(shù)據(jù)的地理屬性確定點(diǎn)位置,數(shù)據(jù)大小則通過(guò)點(diǎn)的顏色來(lái)體現(xiàn),通常會(huì)配以色帶來(lái)映射顏色的取值范圍和大小關(guān)系。
一般是用于數(shù)據(jù)中具有兩個(gè)維度的地理信息,用于展示數(shù)據(jù)的流入&流出情況。其經(jīng)常使用的場(chǎng)景包括:世界范圍或者全國(guó)范圍內(nèi)的人口遷移,不同地區(qū)飛機(jī)/船舶/高鐵等交通航線的繁忙程度和流向情況,不同地區(qū)包裹的寄出量或收貨量等。
億信ABI中的Flash地圖只需要電腦安裝有Flash插件即可使用,非常方便。通過(guò)簡(jiǎn)單的組件拖拽以及屬性設(shè)置,就可以動(dòng)態(tài)地在地圖上顯示屬性信息,可以自定義Flash地圖的區(qū)塊顏色、注記、鏈接、音效等。不僅如此Flash地圖是基于矢量結(jié)構(gòu)儲(chǔ)存,可以做到無(wú)極縮放、無(wú)縫連接的同時(shí),圖像質(zhì)量并無(wú)損失,展示效果非凡。
億信ABI中內(nèi)置有集成百度地圖、天地圖、arcgis地圖三大主流地圖的應(yīng)用接口,可以一鍵與多種分析手段相結(jié)合,將ABI中強(qiáng)大的報(bào)表分析引擎與GIS應(yīng)用強(qiáng)強(qiáng)聯(lián)合,實(shí)現(xiàn)動(dòng)態(tài)參數(shù)、顏色渲染、地圖標(biāo)點(diǎn)分布、地圖鉆取、預(yù)警分析等會(huì)多重效果。
在需要按照地區(qū)分析數(shù)據(jù)時(shí),更直觀的展示數(shù)據(jù)我們可以使用3D地圖,數(shù)值大小映射到柱形圖的顏色和大小上,能夠一目了然看出各個(gè)地區(qū)數(shù)據(jù)的分布,展示出來(lái)更加直觀,增加地圖的立體感,還可以360度旋轉(zhuǎn)噢~如下圖所示:
有了億信ABI內(nèi)置的地圖組件,你只需要拖拉拽,不需要寫代碼,簡(jiǎn)單、快捷的實(shí)現(xiàn)地圖可視化。
薦:使用NSDT 編輯器快速搭建3D應(yīng)用場(chǎng)景
大多數(shù) 3D 對(duì)象是 使用建模工具創(chuàng)建,這是有充分理由的。創(chuàng)建復(fù)雜對(duì)象 (如飛機(jī)甚至建筑物)很難在代碼中完成。建模工具 幾乎總是有意義的,但也有例外!其中之一可能是案例 就像飛行拱廊島連綿起伏的丘陵一樣。我們最終使用了 我們發(fā)現(xiàn)更簡(jiǎn)單,甚至可能更直觀的技術(shù):一個(gè) 高度圖。
高度圖是一種 使用常規(guī)二維圖像來(lái)描述 像島嶼或其他地形一樣的表面。這是一種非常常見的使用方式 高程數(shù)據(jù),不僅在游戲中,而且在地理信息系統(tǒng)中 制圖師和地質(zhì)學(xué)家使用的 (GIS)。
幫助您獲得想法 有關(guān)其工作原理,請(qǐng)查看此交互式演示中的高度圖。嘗試?yán)L圖 ,然后檢出生成的地形。
高度圖背后的概念 很簡(jiǎn)單。在上圖所示的圖像中,純黑色是 “地板”和純白色是最高峰。介于兩者之間的灰度顏色 表示相應(yīng)的高程。這為我們提供了 256 個(gè)海拔高度,這 是我們游戲的大量細(xì)節(jié)。實(shí)際應(yīng)用程序可能會(huì)使用完整的 色譜可存儲(chǔ)更多層次的細(xì)節(jié)(2564=4,294,967,296 級(jí) 詳細(xì)信息(如果包含 Alpha 通道)。
高度圖有幾個(gè) 與傳統(tǒng)多邊形網(wǎng)格相比的優(yōu)勢(shì):
一、高度圖很多 更緊湊。僅存儲(chǔ)最重要的數(shù)據(jù)(高程)。它 需要以編程方式轉(zhuǎn)換為 3D 對(duì)象,但這是 經(jīng)典交易:您現(xiàn)在節(jié)省空間,稍后通過(guò)計(jì)算付款。通過(guò)存儲(chǔ) 數(shù)據(jù)即圖像,您將獲得另一個(gè)空間優(yōu)勢(shì):您可以利用標(biāo)準(zhǔn) 圖像壓縮技術(shù)并使數(shù)據(jù)變小(相比之下)!
其次,高度圖是一個(gè) 生成、可視化和編輯地形的便捷方式。非常直觀 當(dāng)你看到一個(gè)。感覺有點(diǎn)像看地圖。這被證明是 對(duì)飛行街機(jī)特別有用。我們?cè)O(shè)計(jì)和編輯了我們的島嶼 在 Photoshop 中!這使得根據(jù)需要進(jìn)行小調(diào)整變得非常簡(jiǎn)單。 例如,當(dāng)我們想確保跑道完全平坦時(shí), 我們只是確保以單一顏色在該區(qū)域上繪畫。
您可以看到高度圖 下面的飛行拱廊。看看你是否能發(fā)現(xiàn)我們?yōu)?跑道和村莊。
飛行街機(jī)島的高度圖。它是在Photoshop中創(chuàng)建的,它基于著名的太平洋島鏈中的“大島”。有什么猜測(cè)嗎?
在解碼高度貼圖后映射到生成的 3D 網(wǎng)格上的紋理。更多內(nèi)容見下文。
我們用Babylon.js建造了飛行拱廊,Babylon給了我們一個(gè)漂亮的 從高度圖到 3D 的簡(jiǎn)單路徑。Babylon提供了一個(gè) API 來(lái)生成 來(lái)自高度圖圖像的網(wǎng)格幾何體:
ar ground=BABYLON.Mesh.CreateGroundFromHeightMap(
'your-mesh-name',
'/path/to/heightmap.png',
100, // width of the ground mesh (x axis)
100, // depth of the ground mesh (z axis)
40, // number of subdivisions
0, // min height
50, // max height
scene,
false, // updateable?
null // callback when mesh is ready
);`
細(xì)節(jié)量是 由該細(xì)分的財(cái)產(chǎn)決定。需要注意的是, 參數(shù)是指高度圖兩側(cè)的細(xì)分?jǐn)?shù)量 圖像,而不是單元格總數(shù)。所以稍微增加這個(gè)數(shù)字可以 對(duì)網(wǎng)格中的頂點(diǎn)總數(shù)有很大影響。
在下一節(jié)中,我們將 了解如何為地面設(shè)置紋理,但在嘗試使用高度貼圖時(shí) 創(chuàng)建時(shí),查看線框很有用。這是應(yīng)用簡(jiǎn)單代碼 線框紋理,因此很容易看到高度圖數(shù)據(jù)是如何轉(zhuǎn)換為的 網(wǎng)格的頂點(diǎn):
// simple wireframe material
var material=new BABYLON.StandardMaterial('ground-material', scene);
material.wireframe=true;
ground.material=material;`
一旦我們有一個(gè)模型,映射一個(gè) 質(zhì)地相對(duì)簡(jiǎn)單。對(duì)于飛行街機(jī),我們簡(jiǎn)單地創(chuàng)建了一個(gè) 非常大的圖像,與我們的高度圖中的島嶼相匹配。圖像得到 延伸到地形的輪廓上,所以紋理和高度圖 保持相關(guān)性。這真的很容易想象,再一次,所有 制作工作是在Photoshop中完成的。
原始紋理圖像是 創(chuàng)建于 4096x4096。那可是挺大的!(我們最終將尺寸減小了 為了保持下載合理,級(jí)別到2048x2048,但所有 使用全尺寸圖像進(jìn)行開發(fā)。這是來(lái)自 原始紋理。
原始島嶼紋理的全像素示例。整個(gè)城鎮(zhèn)只有大約300平方像素。
這些矩形表示 島上城鎮(zhèn)的建筑。我們很快注意到 我們可以在地形和 其他 3D 模型。即使使用我們巨大的島嶼紋理,區(qū)別在于 令人分心的明顯!
為了解決這個(gè)問(wèn)題,我們“混合” 以隨機(jī)噪聲的形式進(jìn)入地形紋理的附加細(xì)節(jié)。您可以 請(qǐng)參閱下面的之前和之后。注意額外的噪點(diǎn)如何增強(qiáng)外觀 地形細(xì)節(jié)。
我們創(chuàng)建了一個(gè)自定義著色器 添加噪音。著色器為您提供了對(duì) WebGL 3D 場(chǎng)景的渲染,這是著色器如何 有用。
WebGL著色器由兩個(gè)組成 主要部分:頂點(diǎn)和片段著色器。頂點(diǎn)的主要目標(biāo) 著色器是將頂點(diǎn)映射到渲染幀中的某個(gè)位置。片段(或 像素)著色器控制像素的結(jié)果顏色。
著色器是用 稱為GLSL(圖形庫(kù)著色器語(yǔ)言)的高級(jí)語(yǔ)言,它 類似于C。此代碼在 GPU 上執(zhí)行。深入了解如何 著色器工作,請(qǐng)參閱此處 有關(guān)如何為 Babylon.js 創(chuàng)建自己的自定義著色器的教程,或參閱此圖形著色器編碼初學(xué)者指南。
我們不會(huì)改變我們的 紋理映射到地面網(wǎng)格體,因此我們的頂點(diǎn)著色器非常簡(jiǎn)單。 它只是計(jì)算標(biāo)準(zhǔn)映射并分配目標(biāo)位置。
precision mediump float;
// Attributes
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
// Uniforms
uniform mat4 worldViewProjection;
// Varying
varying vec4 vPosition;
varying vec3 vNormal;
varying vec2 vUV;
void main() {
vec4 p=vec4( position, 1.0 );
vPosition=p;
vNormal=normal;
vUV=uv;
gl_Position=worldViewProjection * p;
}
我們的片段著色器有點(diǎn) 更復(fù)雜。它結(jié)合了兩個(gè)不同的圖像:基礎(chǔ)圖像和混合圖像。 基礎(chǔ)圖像映射到整個(gè)地面網(wǎng)格。在飛行街機(jī)中,這個(gè) 是島嶼的彩色圖像。混合圖像是使用的小噪點(diǎn)圖像 在近距離為地面提供一些紋理和細(xì)節(jié)。著色器 組合每個(gè)圖像中的值以創(chuàng)建跨 島。
飛行的最后一課 街機(jī)發(fā)生在有霧的日子,所以我們的像素著色器的另一個(gè)任務(wù)是 調(diào)整顏色以模擬霧。調(diào)整基于頂點(diǎn)的距離 來(lái)自相機(jī),遠(yuǎn)處像素被“遮擋”得更厲害 在霧中。您將在函數(shù)中看到此距離計(jì)算 在主著色器代碼上方。calcFogFactor
// #ifdef GL_ES
precision highp float;
// #endif
uniform mat4 worldView;
varying vec4 vPosition;
varying vec3 vNormal;
varying vec2 vUV;
// Refs
uniform sampler2D baseSampler;
uniform sampler2D blendSampler;
uniform float blendScaleU;
uniform float blendScaleV;
// #define FOGMODE_NONE 0.
// #define FOGMODE_EXP 1.
// #define FOGMODE_EXP2 2.
// #define FOGMODE_LINEAR 3.
// #define E 2.71828
uniform vec4 vFogInfos;
uniform vec3 vFogColor;
float calcFogFactor() {
// gets distance from camera to vertex
float fogDistance=gl_FragCoord.z / gl_FragCoord.w;
float fogCoeff=1.0;
float fogStart=vFogInfos.y;
float fogEnd=vFogInfos.z;
float fogDensity=vFogInfos.w;
if (FOGMODE_LINEAR==vFogInfos.x) {
fogCoeff=(fogEnd - fogDistance) / (fogEnd - fogStart);
}
else if (FOGMODE_EXP==vFogInfos.x) {
fogCoeff=1.0 / pow(E, fogDistance * fogDensity);
}
else if (FOGMODE_EXP2==vFogInfos.x) {
fogCoeff=1.0 / pow(E, fogDistance * fogDistance * fogDensity * fogDensity);
}
return clamp(fogCoeff, 0.0, 1.0);
}
void main(void) {
vec4 baseColor=texture2D(baseSampler, vUV);
vec2 blendUV=vec2(vUV.x * blendScaleU, vUV.y * blendScaleV);
vec4 blendColor=texture2D(blendSampler, blendUV);
// multiply type blending mode
vec4 color=baseColor * blendColor;
// factor in fog color
float fog=calcFogFactor();
color.rgb=fog * color.rgb + (1.0 - fog) * vFogColor;
gl_FragColor=color;
}
我們定制的最后一件作品 Blend shader 是 Babylon 使用的 JavaScript 代碼。主要目的 此代碼用于準(zhǔn)備傳遞給頂點(diǎn)和像素著色器的參數(shù)。
function BlendMaterial(name, scene, options) {
this.name=name;
this.id=name;
this.options=options;
this.blendScaleU=options.blendScaleU || 1;
this.blendScaleV=options.blendScaleV || 1;
this._scene=scene;
scene.materials.push(this);
var assets=options.assetManager;
var textureTask=assets.addTextureTask('blend-material-base-task', options.baseImage);
textureTask.onSuccess=_.bind(function(task) {
this.baseTexture=task.texture;
this.baseTexture.uScale=1;
this.baseTexture.vScale=1;
if (options.baseHasAlpha) {
this.baseTexture.hasAlpha=true;
}
}, this);
textureTask=assets.addTextureTask('blend-material-blend-task', options.blendImage);
textureTask.onSuccess=_.bind(function(task) {
this.blendTexture=task.texture;
this.blendTexture.wrapU=BABYLON.Texture.MIRROR_ADDRESSMODE;
this.blendTexture.wrapV=BABYLON.Texture.MIRROR_ADDRESSMODE;
}, this);
}
BlendMaterial.prototype=Object.create(BABYLON.Material.prototype);
BlendMaterial.prototype.needAlphaBlending=function () {
return (this.options.baseHasAlpha===true);
};
BlendMaterial.prototype.needAlphaTesting=function () {
return false;
};
BlendMaterial.prototype.isReady=function (mesh) {
var engine=this._scene.getEngine();
// make sure textures are ready
if (!this.baseTexture || !this.blendTexture) {
return false;
}
if (!this._effect) {
this._effect=engine.createEffect(
// shader name
"blend",
// attributes describing topology of vertices
[ "position", "normal", "uv" ],
// uniforms (external variables) defined by the shaders
[ "worldViewProjection", "world", "blendScaleU", "blendScaleV", "vFogInfos", "vFogColor" ],
// samplers (objects used to read textures)
[ "baseSampler", "blendSampler" ],
// optional define string
"");
}
if (!this._effect.isReady()) {
return false;
}
return true;
};
BlendMaterial.prototype.bind=function (world, mesh) {
var scene=this._scene;
this._effect.setFloat4("vFogInfos", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
this._effect.setColor3("vFogColor", scene.fogColor);
this._effect.setMatrix("world", world);
this._effect.setMatrix("worldViewProjection", world.multiply(scene.getTransformMatrix()));
// Textures
this._effect.setTexture("baseSampler", this.baseTexture);
this._effect.setTexture("blendSampler", this.blendTexture);
this._effect.setFloat("blendScaleU", this.blendScaleU);
this._effect.setFloat("blendScaleV", this.blendScaleV);
};
BlendMaterial.prototype.dispose=function () {
if (this.baseTexture) {
this.baseTexture.dispose();
}
if (this.blendTexture) {
this.blendTexture.dispose();
}
this.baseDispose();
};
Babylon.js使它變得容易 創(chuàng)建基于著色器的自定義材質(zhì)。我們的混合材料相對(duì)簡(jiǎn)單, 但它確實(shí)對(duì)島嶼的外觀產(chǎn)生了很大的影響,當(dāng) 飛機(jī)低空飛到地面。著色器將 GPU 的強(qiáng)大功能帶到 瀏覽器,擴(kuò)展可應(yīng)用于 3D 的創(chuàng)意效果類型 場(chǎng)景。在我們的案例中,這是畫龍點(diǎn)名!
原文鏈接:使用 WebGL 為 HTML5 游戲創(chuàng)建逼真的地形
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。