整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          基于HTML5的WebGIS實時客戶端設(shè)計

          基于HTML5的WebGIS實時客戶端設(shè)計

          : 在WebGIS的瀏覽器端存在繪圖效率差、不能直接支持矢量繪圖等問題。為提高客戶端的交互性和實時性,在解決瀏覽器不支持矢量繪圖和渲染速度慢、存儲空間小、傳輸速率慢這些問題的基礎(chǔ)上,結(jié)合HTML5中的Canvas、WebSocket、WebStorage技術(shù),構(gòu)建了WebGIS實時客戶端,有效地改善了客戶端存在的問題,改善用戶的體驗。

          0 引言

          WebGIS是GIS技術(shù)與Internet的結(jié)合體,是對網(wǎng)絡(luò)GIS的發(fā)展,它將GIS從一種使用計算機的處理地理信息的系統(tǒng)工具,變?yōu)橐环N網(wǎng)絡(luò)共享資源,提高了地理信息的使用效率,使地理信息的價值得以充分體現(xiàn)[1]。WebGIS的實現(xiàn)手段主要是基于Web技術(shù)的多級B/S體系結(jié)構(gòu),即瀏覽器、GIS服務(wù)器、數(shù)據(jù)庫等。B/S模式的構(gòu)架簡化了客戶端系統(tǒng)的部署,降低了用戶使用難度,同時也極大提高了系統(tǒng)的可維護性[2]。但是這種被動的工作模式無法滿足用戶實時性的需求。對于WebGIS的架構(gòu)研究,以前主要是對服務(wù)器端技術(shù)的改進(jìn),如使用CGI、Server API等服務(wù)端技術(shù),但是這些技術(shù)對于服務(wù)器及網(wǎng)絡(luò)的要求較高。隨著客戶端技術(shù)的發(fā)展,Java Applet技術(shù)、Plug-in技術(shù)、Ajax技術(shù)的出現(xiàn)擴展了客戶端的功能,但是用戶需要預(yù)先安裝這些插件,安裝插件帶來了一定的安全隱患和不方便性。對比這兩種形式,使用HTML5的新技術(shù)實現(xiàn)的功能并不需要插件支持,且其本地存儲功能和高效率的雙向通信功能,還有動態(tài)快速繪圖功能的提出,使實時客戶端的實現(xiàn)成為可能。

          1 實時客戶端的WebGIS系統(tǒng)結(jié)構(gòu)

          HTML5是W3C推出的新標(biāo)準(zhǔn),其強大功能已經(jīng)被大部分的瀏覽器支持,同時,相對于以前的版本,HTML5的改變不僅僅是使用更方便。第一,它新增了更具有語義化的標(biāo)簽和使用更智能化的表單;第二,HTML5還新增了許多JavaScript API,如實時繪圖(Canvas和SVG)、離線存儲(WebStorage)、實時通信(WebSocket)API等,這些API為實現(xiàn)實時客戶端提供了可能。用HTML5來實現(xiàn)WebGIS有地圖無限縮放而圖不失真,地圖的顯示渲染效果逼真的優(yōu)勢;且支持JavaScript腳本實現(xiàn)地圖的漫游、縮放、查詢等功能,這些功能都無需插件支持并可在不同平臺與設(shè)備上運行[3]。根據(jù)這些特性,本文在傳統(tǒng)架構(gòu)的基礎(chǔ)上,構(gòu)建了圖1所示的WebGIS實時客戶端。

          在客戶端這些模塊中使用HTML5和JavaScript技術(shù),實現(xiàn)數(shù)據(jù)地圖的繪制、本地存儲、數(shù)據(jù)傳輸?shù)裙δ埽瑢⒉糠趾唵蔚墓δ芙唤o客戶端完成,增加了WebGIS客戶端的交互能力,減少了服務(wù)器的傳輸壓力,也增加了數(shù)據(jù)傳輸?shù)男剩瑢崿F(xiàn)了客戶端的實時性。

          2 WebGIS客戶端的具體設(shè)計

          2.1 數(shù)據(jù)實時更新與傳輸設(shè)計

          空間數(shù)據(jù)格式有柵格數(shù)據(jù)和矢量數(shù)據(jù)。柵格數(shù)據(jù)交互性能差,可用來展示空間數(shù)據(jù),矢量數(shù)據(jù)交互性較好,可用來表示空間對象,但是客戶端不能直接支持矢量數(shù)據(jù)的二進(jìn)制格式傳輸,所以數(shù)據(jù)在傳輸中就要進(jìn)行格式編碼,目前使用的比較多的數(shù)據(jù)傳輸格式是GeoJSON(基于JSON數(shù)據(jù)格式的地理要素表示格式)。JSON(JavaScript Object Notation)是輕量級數(shù)據(jù)交換格式,適合于服務(wù)器與瀏覽器(通過JavaScript)交互[4],在瀏覽器端JSON能夠簡單快速地解析成可以被客戶端操作的JavaScript地理信息,不需要使用專門的文本解析API進(jìn)行操作。空間數(shù)據(jù)傳輸大多使用Ajax的異步傳輸方式,但Ajax輪詢方式的時延較長,傳輸?shù)膶崟r性不高,因此將Ajax用于地圖數(shù)據(jù)的推送。實時性方面還是需要HTML5的WebSocket API實現(xiàn)。WebSocket使瀏覽器具有客戶機/服務(wù)器(C/S)模式下應(yīng)用程序的實時通信能力[5]。WebSocket的優(yōu)勢有:(1)為瀏覽器和服務(wù)器之間建立的更高效的雙向通信提供支持。其連接本質(zhì)為TCP連接,因此瀏覽器通過JavaScript向服務(wù)器發(fā)出建立WebSocket連接的請求,onopen事件接收消息,連接建立以后,客戶端和服務(wù)器端就可通過TCP連接直接交換數(shù)據(jù)。(2)WebSocket有更為輕量級的Header,除了首次建立鏈接時需要發(fā)送頭部與普通Web鏈接類似的數(shù)據(jù)之外,連接建立后,相互溝通的Header就會很簡潔,大大減少了冗余的數(shù)據(jù)傳輸[6];通過新建WebSocket實例建立握手并完成與服務(wù)器的連接,建立好連接之后數(shù)據(jù)就可以以全雙工模式在客戶端與服務(wù)器之間進(jìn)行雙向傳輸,并一直保持連接,直到用戶主動關(guān)閉[3]。圖2是傳統(tǒng)傳輸方式與WebSocket傳輸方式數(shù)據(jù)量的對比,從結(jié)果可以看出,當(dāng)傳輸數(shù)據(jù)量增大時,WebSocket的效率更高。

          需要在服務(wù)器端安裝開源的WebSocket支持?jǐn)?shù)據(jù)庫,如Node.js、LibWebSockets、PHP WebSocket Server等,以調(diào)用接口使用。具體傳輸過程是:GIS服務(wù)器從空間數(shù)據(jù)庫獲取數(shù)據(jù),將空間數(shù)據(jù)解析成JSON的格式,然后發(fā)送到已經(jīng)與WebSocket服務(wù)器連接的客戶端,客戶端WebSocket實例的onmessage事件接收數(shù)據(jù)并使用JSON.parse函數(shù)將JSON字符串解析成JavaScript對象,再根據(jù)對象的內(nèi)容在WebGIS的地圖中解析顯示。WebSocket API一個顯著特點是,連接建立后,服務(wù)器可主動推送消息。支持WebSocket協(xié)議的服務(wù)端接受請求和處理WebSocket任務(wù),在客戶端可用WebStorage存儲模塊緩存?zhèn)鬏斶^來的數(shù)據(jù),WebSocket的中間傳輸機制就實現(xiàn)了數(shù)據(jù)實時更新。

          2.2 客戶端空間數(shù)據(jù)緩存設(shè)計

          客戶端緩存功能主要是由WebStorage API來實現(xiàn),WebStorage API是以Key-Value形式來進(jìn)行數(shù)據(jù)的持久性存儲。傳統(tǒng)客戶端一般是使用Cookie存儲數(shù)據(jù),但是它效率低,存儲空間小,不能滿足大量矢量數(shù)據(jù)的存儲。WebStorage提供的兩種存儲方式可以改善這個狀況,一種是SessionStorage,它是一種會話級別的存儲方式,存儲的數(shù)據(jù)只在當(dāng)前頁面有效,當(dāng)頁面關(guān)閉時,數(shù)據(jù)也會隨之刪除,據(jù)此SessionStorage可以用在矢量圖繪制的緩存方面,即讓SessionStorage自動緩存解析好的JSON格式的矢量層數(shù)據(jù),當(dāng)需要數(shù)據(jù)時直接從SessionStorage中提取JSON數(shù)據(jù),這比從空間數(shù)據(jù)庫中獲取再解析效率明顯更高,數(shù)據(jù)顯示模塊可以直接從中獲取數(shù)據(jù)進(jìn)行繪制。另一種方式是LocalStorage,它是一個跨多窗口且數(shù)據(jù)永久存儲的方式,只有使用清除函數(shù)clear、removeItem或手動刪除數(shù)據(jù)時數(shù)據(jù)才會從瀏覽器中清除,同時它的數(shù)據(jù)可以在同源的窗口或標(biāo)簽共享使用。因此它可以用來永久存儲空間分析后的數(shù)據(jù)或服務(wù)器發(fā)送的數(shù)據(jù)和用戶數(shù)據(jù),下次用戶打開瀏覽器可直接使用這些數(shù)據(jù)。圖3是具體矢量數(shù)據(jù)本地存儲過程。將數(shù)據(jù)緩存到本地,不用與服務(wù)器發(fā)生交互,客戶端存儲的數(shù)據(jù)可以由JavaScript訪問。

          WebStorage存儲技術(shù)和WebSocket技術(shù)可結(jié)合使用并與JavaScript一起實現(xiàn)數(shù)據(jù)的實時更新,減輕服務(wù)器壓力。用戶發(fā)送數(shù)據(jù)請求后,WebSocket建立連接,將得到的數(shù)據(jù)解析后存儲在WebStorage預(yù)先定義好的空間中,等待用戶提取。對于常須更新地圖數(shù)據(jù)的操作采用這種預(yù)先存儲的方式,可以加快數(shù)據(jù)的渲染效率。為了提高圖3的實時更新效果,可以設(shè)定異步存儲機制,過程如下:(1)創(chuàng)建并初始化WebStorage對象,設(shè)置緩存區(qū)大小(緩存區(qū)分段);(2)用戶發(fā)出消息,觸發(fā)onopen事件;(3)為WebSocket對象的信息添加偵聽器;(4)服務(wù)器調(diào)用received函數(shù)處理事件;(5)客戶端接收服務(wù)器發(fā)送的消息,觸發(fā)緩存判斷函數(shù),判斷緩存大小,如果超出,設(shè)置緩存片段的編號,對象異步sends數(shù)據(jù)請求服務(wù)器處理;(6)服務(wù)器將片段編號入隊(服務(wù)端設(shè)置),直到傳輸完成,清除編號。這種傳輸方式將進(jìn)一步減少網(wǎng)絡(luò)流量,減少服務(wù)器的負(fù)載,提升傳輸效率。

          2.3 數(shù)據(jù)顯示設(shè)計

          HTML5現(xiàn)提供了Canvas API,它可以解決傳統(tǒng)開發(fā)瀏覽器支持度差、跨平臺性不強和繪制矢量圖形需要插件的問題,通過JavaScript在瀏覽器不依賴任何插件的情況下高效地繪制動態(tài)圖形[7],避免了安裝插件帶來安全風(fēng)險。

          2.3.1 繪制方法

          Canvas API使用比較簡單,像其他HTML標(biāo)簽一樣,只需在HTML5的頁面中添加一個<canvas>元素即可。Canvas繪圖首先要獲得上下文(context),因為Canvas自己本身并沒有繪圖能力,所以所有的繪圖工作要由JavaScript完成。它的工作過程為:先定義Canvas元素的id,然后通過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ù)方面是像素級管理,Canvas的路徑操作能充分滿足矢量數(shù)據(jù)中的點要素、線要素、面要素以及符號的表達(dá)要求。

          2.3.2 數(shù)據(jù)顯示過程

          用Canvas與JavaScript技術(shù)實現(xiàn)地圖實時繪制。地理實體對象可以根據(jù)OGC的簡單要素規(guī)范和GIS界的研究將其分為:點狀實體、線狀實體、面狀實體、標(biāo)注實體和柵格實體[3]。Canvas可直接使用這些實體,對于柵格實體,可以用JavaScript對象表示,通過API drawImage直接在HTML5 Canvas中繪制。矢量實體的地理要素從GeoJSON文本轉(zhuǎn)化為JavaScript對象,根據(jù)該對象的信息,調(diào)用坐標(biāo)轉(zhuǎn)換對象,將坐標(biāo)轉(zhuǎn)換成Canvas元素里的屏幕坐標(biāo)來對應(yīng)顯示要素。實現(xiàn)實時繪圖的流程為:(1)服務(wù)器從數(shù)據(jù)庫獲取數(shù)據(jù);(2)數(shù)據(jù)進(jìn)行JSON格式解析;(3)瀏覽器加載地圖,調(diào)用Canvas畫布及函數(shù)實現(xiàn)繪圖和地圖的顯示;(4)地圖操作由自定義腳本實現(xiàn)地圖渲染。Canvas在客戶端展現(xiàn)地理數(shù)據(jù)的靈活性與互操作性要優(yōu)于傳統(tǒng)的切片技術(shù),并且在地圖加載速度方面有明顯的優(yōu)勢[8],因此將Canvas和WebStorage結(jié)合起來,可以提高實時性能,將要顯示或者要存儲的數(shù)據(jù)先經(jīng)過緩存,再進(jìn)行顯示或存儲,這種機制效率明顯更高。圖4說明了從數(shù)據(jù)推送到顯示的流程。

          3 客戶端整體過程

          Canvas實現(xiàn)實時繪圖和快速渲染,WebSocket API在通信方面提供了支持。WebStorage提供了客戶端的本地存儲技術(shù),以地圖放大操作為例,用戶提交請求,數(shù)據(jù)獲取函數(shù)可以從SessionStorage中獲取數(shù)據(jù),然后將緩存的數(shù)據(jù)轉(zhuǎn)換成JavaScript對象,最后通過Canvas直接添加在地圖中,同時,緩存中的數(shù)據(jù)不斷更新。WebSocket的雙向通信機制和WebStorage的異步存儲機制加速了數(shù)據(jù)交換效率,空間數(shù)據(jù)庫也通過WebGIS服務(wù)器,在實時通信的基礎(chǔ)上,將數(shù)據(jù)以JSON文本格式傳輸?shù)娇蛻舳耍嫒隨essionStorage中,窗口關(guān)閉后,所有數(shù)據(jù)存入LocalStorage,供用戶下次直接使用。這種方式的效率很明顯會比從服務(wù)器獲取數(shù)據(jù)的方式高,實時性要好,如需要執(zhí)行其他的交互操作,也可以基于這種方式實現(xiàn)。

          4 結(jié)論

          隨著Web技術(shù)的發(fā)展,客戶端的交互性和實時性要求不斷提升,據(jù)此,本文將HTML5的新特性與JavaScript技術(shù)結(jié)合,在WebSocket雙向通信機制和WebStorage緩存機制實現(xiàn)異步存儲提供的數(shù)據(jù)支撐,Canvas能實現(xiàn)動態(tài)繪圖和快速渲染的基礎(chǔ)上,提出了一種實時性更強的WebGIS客戶端,為建立實時的WebGIS客戶端提供了一種方案。HTML5中的新技術(shù)雖然強大,還是有需要加強的地方,WebStorage讓數(shù)據(jù)能夠緩存在本地,但是由于是存儲在本地,數(shù)據(jù)容易泄漏,安全性還有欠缺。未來WebGIS的發(fā)展會隨著數(shù)據(jù)量的增大實現(xiàn)云平臺化,資源更龐大,數(shù)據(jù)更易共享,用戶使用起來也會更方便。

          參考文獻(xiàn)

          [1] 孟令奎,史文中,張鵬林,等.網(wǎng)絡(luò)地理信息系統(tǒng)原理與技術(shù)[M].北京:科學(xué)出版社,2010.

          [2] 李博霏,李欣,李艷明.基于瀏覽器的地理信息服務(wù)客戶端技術(shù)研究[J].計算機工程與設(shè)計,2011(9):3031-3035.

          [3] 龍云.基于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].測繪科學(xué),2012,37(1):145-147.

          [6] 魏進(jìn)鋒,孫春華.應(yīng)用HTML5的WebSocket實現(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的輕量級WebGIS[J].計算機科學(xué)與應(yīng)用,2012(2):189-196.

          數(shù)據(jù)可視化中,使用頻率最高的展現(xiàn)方式肯定是地圖可視化。基本上現(xiàn)有的大屏都是以地圖作為主視圖來呈現(xiàn)的,沒有一幅地圖放到大屏中央,已經(jīng)不好意思給同行、媒體界通告自己企業(yè)數(shù)據(jù)分析有多牛了。


          怎么將地理數(shù)據(jù)處理得更好,怎么把地圖設(shè)計出更好的視覺效果也一直是我們研究的方向。億信ABI作為億信華辰自主研發(fā)的一款全能型數(shù)據(jù)分析產(chǎn)品,具備強大的數(shù)據(jù)地圖功能,內(nèi)置世界地圖、五大洲地圖、中國地圖,囊括各省、市區(qū)縣地圖,每個地圖都有flash、圖片和html5三種格式,還能實現(xiàn)鉆取、聯(lián)動等功能。

          下面帶大家一起來看一下億信ABI中地圖可視化的那些事兒。

          渲染地圖

          渲染地圖適合展示數(shù)據(jù)在地理區(qū)塊空間的分布狀況,用顏色來區(qū)分?jǐn)?shù)值大小。隨意切換全國任意省市地圖方便快捷,還可以通過事件聯(lián)動其他組件和下鉆。


          標(biāo)點地圖

          標(biāo)點地圖主要用于展示地理區(qū)域內(nèi)的空間分布,非常適合展示一組或多組數(shù)據(jù)在地理空間的分布狀況,數(shù)據(jù)的地理屬性確定點位置,數(shù)據(jù)大小則通過點的顏色來體現(xiàn),通常會配以色帶來映射顏色的取值范圍和大小關(guān)系。


          流向地圖

          一般是用于數(shù)據(jù)中具有兩個維度的地理信息,用于展示數(shù)據(jù)的流入&流出情況。其經(jīng)常使用的場景包括:世界范圍或者全國范圍內(nèi)的人口遷移,不同地區(qū)飛機/船舶/高鐵等交通航線的繁忙程度和流向情況,不同地區(qū)包裹的寄出量或收貨量等。


          Flash地圖

          億信ABI中的Flash地圖只需要電腦安裝有Flash插件即可使用,非常方便。通過簡單的組件拖拽以及屬性設(shè)置,就可以動態(tài)地在地圖上顯示屬性信息,可以自定義Flash地圖的區(qū)塊顏色、注記、鏈接、音效等。不僅如此Flash地圖是基于矢量結(jié)構(gòu)儲存,可以做到無極縮放、無縫連接的同時,圖像質(zhì)量并無損失,展示效果非凡。


          GIS地圖

          億信ABI中內(nèi)置有集成百度地圖、天地圖、arcgis地圖三大主流地圖的應(yīng)用接口,可以一鍵與多種分析手段相結(jié)合,將ABI中強大的報表分析引擎與GIS應(yīng)用強強聯(lián)合,實現(xiàn)動態(tài)參數(shù)、顏色渲染、地圖標(biāo)點分布、地圖鉆取、預(yù)警分析等會多重效果。


          3D地圖

          在需要按照地區(qū)分析數(shù)據(jù)時,更直觀的展示數(shù)據(jù)我們可以使用3D地圖,數(shù)值大小映射到柱形圖的顏色和大小上,能夠一目了然看出各個地區(qū)數(shù)據(jù)的分布,展示出來更加直觀,增加地圖的立體感,還可以360度旋轉(zhuǎn)噢~如下圖所示:


          有了億信ABI內(nèi)置的地圖組件,你只需要拖拉拽,不需要寫代碼,簡單、快捷的實現(xiàn)地圖可視化。

          薦:使用NSDT 編輯器快速搭建3D應(yīng)用場景


          建 模 和 3D 地形

          大多數(shù) 3D 對象是 使用建模工具創(chuàng)建,這是有充分理由的。創(chuàng)建復(fù)雜對象 (如飛機甚至建筑物)很難在代碼中完成。建模工具 幾乎總是有意義的,但也有例外!其中之一可能是案例 就像飛行拱廊島連綿起伏的丘陵一樣。我們最終使用了 我們發(fā)現(xiàn)更簡單,甚至可能更直觀的技術(shù):一個 高度圖。

          高度圖是一種 使用常規(guī)二維圖像來描述 像島嶼或其他地形一樣的表面。這是一種非常常見的使用方式 高程數(shù)據(jù),不僅在游戲中,而且在地理信息系統(tǒng)中 制圖師和地質(zhì)學(xué)家使用的 (GIS)。

          幫助您獲得想法 有關(guān)其工作原理,請查看此交互式演示中的高度圖。嘗試?yán)L圖 ,然后檢出生成的地形。

          高度圖背后的概念 很簡單。在上圖所示的圖像中,純黑色是 “地板”和純白色是最高峰。介于兩者之間的灰度顏色 表示相應(yīng)的高程。這為我們提供了 256 個海拔高度,這 是我們游戲的大量細(xì)節(jié)。實際應(yīng)用程序可能會使用完整的 色譜可存儲更多層次的細(xì)節(jié)(2564=4,294,967,296 級 詳細(xì)信息(如果包含 Alpha 通道)。

          高度圖有幾個 與傳統(tǒng)多邊形網(wǎng)格相比的優(yōu)勢:

          一、高度圖很多 更緊湊。僅存儲最重要的數(shù)據(jù)(高程)。它 需要以編程方式轉(zhuǎn)換為 3D 對象,但這是 經(jīng)典交易:您現(xiàn)在節(jié)省空間,稍后通過計算付款。通過存儲 數(shù)據(jù)即圖像,您將獲得另一個空間優(yōu)勢:您可以利用標(biāo)準(zhǔn) 圖像壓縮技術(shù)并使數(shù)據(jù)變小(相比之下)!

          其次,高度圖是一個 生成、可視化和編輯地形的便捷方式。非常直觀 當(dāng)你看到一個。感覺有點像看地圖。這被證明是 對飛行街機特別有用。我們設(shè)計和編輯了我們的島嶼 在 Photoshop 中!這使得根據(jù)需要進(jìn)行小調(diào)整變得非常簡單。 例如,當(dāng)我們想確保跑道完全平坦時, 我們只是確保以單一顏色在該區(qū)域上繪畫。

          您可以看到高度圖 下面的飛行拱廊。看看你是否能發(fā)現(xiàn)我們?yōu)?跑道和村莊。

          飛行街機島的高度圖。它是在Photoshop中創(chuàng)建的,它基于著名的太平洋島鏈中的“大島”。有什么猜測嗎?

          在解碼高度貼圖后映射到生成的 3D 網(wǎng)格上的紋理。更多內(nèi)容見下文。

          解碼高度圖

          我們用Babylon.js建造了飛行拱廊,Babylon給了我們一個漂亮的 從高度圖到 3D 的簡單路徑。Babylon提供了一個 API 來生成 來自高度圖圖像的網(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ì)分的財產(chǎn)決定。需要注意的是, 參數(shù)是指高度圖兩側(cè)的細(xì)分?jǐn)?shù)量 圖像,而不是單元格總數(shù)。所以稍微增加這個數(shù)字可以 對網(wǎng)格中的頂點總數(shù)有很大影響。

          • 20 個細(xì)分=400 細(xì)胞
          • 50 個細(xì)分=2,500 細(xì)胞
          • 100 個細(xì)分=10,000 細(xì)胞
          • 500 個細(xì)分=250,000 細(xì)胞
          • 1,000 個細(xì)分=1,000,000 細(xì)胞

          在下一節(jié)中,我們將 了解如何為地面設(shè)置紋理,但在嘗試使用高度貼圖時 創(chuàng)建時,查看線框很有用。這是應(yīng)用簡單代碼 線框紋理,因此很容易看到高度圖數(shù)據(jù)是如何轉(zhuǎn)換為的 網(wǎng)格的頂點:

          // simple wireframe material

          var material=new BABYLON.StandardMaterial('ground-material', scene);

          material.wireframe=true;

          ground.material=material;`

          創(chuàng)建紋理細(xì)節(jié)

          一旦我們有一個模型,映射一個 質(zhì)地相對簡單。對于飛行街機,我們簡單地創(chuàng)建了一個 非常大的圖像,與我們的高度圖中的島嶼相匹配。圖像得到 延伸到地形的輪廓上,所以紋理和高度圖 保持相關(guān)性。這真的很容易想象,再一次,所有 制作工作是在Photoshop中完成的。

          原始紋理圖像是 創(chuàng)建于 4096x4096。那可是挺大的!(我們最終將尺寸減小了 為了保持下載合理,級別到2048x2048,但所有 使用全尺寸圖像進(jìn)行開發(fā)。這是來自 原始紋理。

          原始島嶼紋理的全像素示例。整個城鎮(zhèn)只有大約300平方像素。

          這些矩形表示 島上城鎮(zhèn)的建筑。我們很快注意到 我們可以在地形和 其他 3D 模型。即使使用我們巨大的島嶼紋理,區(qū)別在于 令人分心的明顯!

          為了解決這個問題,我們“混合” 以隨機噪聲的形式進(jìn)入地形紋理的附加細(xì)節(jié)。您可以 請參閱下面的之前和之后。注意額外的噪點如何增強外觀 地形細(xì)節(jié)。

          我們創(chuàng)建了一個自定義著色器 添加噪音。著色器為您提供了對 WebGL 3D 場景的渲染,這是著色器如何 有用。

          WebGL著色器由兩個組成 主要部分:頂點和片段著色器。頂點的主要目標(biāo) 著色器是將頂點映射到渲染幀中的某個位置。片段(或 像素)著色器控制像素的結(jié)果顏色。

          著色器是用 稱為GLSL(圖形庫著色器語言)的高級語言,它 類似于C。此代碼在 GPU 上執(zhí)行。深入了解如何 著色器工作,請參閱此處 有關(guān)如何為 Babylon.js 創(chuàng)建自己的自定義著色器的教程,或參閱此圖形著色器編碼初學(xué)者指南。

          頂點著色器

          我們不會改變我們的 紋理映射到地面網(wǎng)格體,因此我們的頂點著色器非常簡單。 它只是計算標(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;
          }

          碎片著色器

          我們的片段著色器有點 更復(fù)雜。它結(jié)合了兩個不同的圖像:基礎(chǔ)圖像和混合圖像。 基礎(chǔ)圖像映射到整個地面網(wǎng)格。在飛行街機中,這個 是島嶼的彩色圖像。混合圖像是使用的小噪點圖像 在近距離為地面提供一些紋理和細(xì)節(jié)。著色器 組合每個圖像中的值以創(chuàng)建跨 島。

          飛行的最后一課 街機發(fā)生在有霧的日子,所以我們的像素著色器的另一個任務(wù)是 調(diào)整顏色以模擬霧。調(diào)整基于頂點的距離 來自相機,遠(yuǎn)處像素被“遮擋”得更厲害 在霧中。您將在函數(shù)中看到此距離計算 在主著色器代碼上方。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)備傳遞給頂點和像素著色器的參數(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ì)。我們的混合材料相對簡單, 但它確實對島嶼的外觀產(chǎn)生了很大的影響,當(dāng) 飛機低空飛到地面。著色器將 GPU 的強大功能帶到 瀏覽器,擴展可應(yīng)用于 3D 的創(chuàng)意效果類型 場景。在我們的案例中,這是畫龍點名!

          原文鏈接:使用 WebGL 為 HTML5 游戲創(chuàng)建逼真的地形


          主站蜘蛛池模板: 无码人妻一区二区三区在线视频 | 日韩一区二区三区无码影院| 国产福利电影一区二区三区久久老子无码午夜伦不 | 亚洲性色精品一区二区在线| 一区二区亚洲精品精华液| 欧洲精品一区二区三区在线观看| 免费av一区二区三区| 亚洲AV一区二区三区四区 | 国产成人无码精品一区不卡| 国产无套精品一区二区 | 精品久久综合一区二区| 久久久久久免费一区二区三区 | 好湿好大硬得深一点动态图91精品福利一区二区 | 精品无码综合一区| 国产精品一区二区久久精品无码 | 国产精品久久一区二区三区| 中文字幕一区二区三区免费视频| 波多野结衣av高清一区二区三区| 亚洲AV无码一区二区三区性色| 久久se精品一区二区国产| 红桃AV一区二区三区在线无码AV| 国产观看精品一区二区三区| 又紧又大又爽精品一区二区| 精品国产一区二区三区| av一区二区三区人妻少妇| 国产一区二区三区影院| 国产成人一区二区精品非洲| 午夜视频一区二区| 中文字幕国产一区| 久久久久一区二区三区| 国产高清在线精品一区| 风间由美在线亚洲一区| 精品成人av一区二区三区| 精品亚洲一区二区| 在线视频一区二区三区四区| 精品中文字幕一区二区三区四区 | 韩国精品一区视频在线播放| 波多野结衣一区在线观看| 一区二区三区人妻无码| 国产伦精品一区二区三区无广告 | 国产精品视频免费一区二区|