threejs創建地球


上個月底,在朋友圈看到一個號稱“這可能是地球上最美的h5”的分享,點進入后發現這個h5還很別致,思考了一會,決定要不高仿一個?

到今天為止,高仿基本完成,

除了手機端的media控制沒有去兼容,其他的基本都給仿了。 那為了讓你覺得是高仿,最好使用chrome的手機調試模式進行訪問。微信打開將聽不見聲音看不到視頻... (后面再有時間看是不是仿的再進一步)

之所以要仿它,因為覺得這個h5還挺酷,想看看自己需要花多長時間找到並實現它的技術路徑。

需求分析

這個h5的主要玩法很簡單:地球自轉的時候會播放背景音樂(比如海浪聲),為了找到這個聲音是從哪個地球上哪個地方傳來的,需要長按下方的按鈕,這時地球會自動轉動到目標地點,然后鏡頭拉近,穿過雲層,最后你會看到和這段聲音相關的視頻內容;松開手之后,上面的過程會倒退回去,地球又開始自轉,播放着下段神秘的背景音樂。

個人覺得這個設計還是很新穎的,不是說用了3D的效果,而是將一個看起來很復雜的動畫(從宇宙拉近到地表的過程),使用最基礎的3D效果和其他一些常規的動畫手法去實現,並且能流暢的運行在手機瀏覽器上。另外還有聲音和視頻的完美搭配,用戶體驗不錯。

反復觀察,理清頁面功能:

  1. 加載:加載進度百分比,饒橢圓軌道運行的小行星作為loading動畫(這個動畫我沒有做)

  2. 地球:3D球體,旋轉入場動畫,自轉,漂移的雲層,城市的坐標點,鏡頭的旋轉與拉近,穿越雲層動畫

  3. 星空背景:靜態星空背景圖,動態(閃爍的)星星,划過的流星

  4. 隱藏的音頻和視頻:按內容(地理位置)划分的音頻和視頻內容

  5. 其他:操作指引示意動畫,地球上方會顯示當前城市的經緯度,“了解更多”的結語頁面等

尋找技術路徑

打開chrome inspect一下。

首先是這個地球,得看看它是真3D還是假3D(因為很多3D效果是拿雪碧圖做的,比如這里的旋轉的3D飛機),結果找到了:

<div class="ns-webgl-page">
    <canvas width="750" height="1200" style="width: 375px; height: 600px;"></canvas>
</div>

並且在網站source文件中搜到了THREE,那就是threejs沒跑了。

然后是那個穿越雲層的效果,猜測可能是GIF,可能是SpriteSheet Animation,也有可能是一段視頻。但是考慮到這個穿越的動畫可以正反雙方播放,那么就很可能是是SpriteSheet Animation了,否則GIF或者視頻文件需要兩個動畫方向各准備一份。這個從chrome debug工具的network下找到了證據—— 頁面下載了一系列名為kf_cloud_0000X.jpg的圖片文件。順手就把它們down下來,備用。

再就是背景音樂和隱藏視頻的問題,同樣在network下,找到了兩個文件,一個mp3一個mp4,每個文件都包含了所有片段,就像是media的雪碧圖,只在需要的時候控制播放對應片段而已。

其他的內容都沒什么問題,CSS動畫或者CANVAS都好做。那么到此,技術路徑都清楚了,准備開始寫代碼。

難點突破

對於我而言,用threejs繪制地球可能會是難點,threejs沒有用過,而且印象中對3D的東西,一直比較敬畏。如果3D的地球弄不出來,這個項目其他的都做完了,在浩瀚的宇宙中是怎么也找不到“聲音來自何方”了。

OK,來看threejs怎么能弄出個地球來。(這個階段並沒有開始項目代碼,而是盡量的在一個臨時文件中進行塗鴉,快速隨意的達到繪制出地球的目的就行了)

官網

對於新的技術,首先得看官網。這里並不是來全面學習threejs的,而是抱着很強的目的性去實現特定功能,因此直接去示例中找,是否有類似實現可以借鑒。在官網首頁中,通過縮略圖,找到了下面三個關於地球的例子。

可惜,貌似這里的例子都是一些產品應用,代碼都是壓縮過的。於是開始去尋找官方示例,最后在examples里找到了canvas_geometry_earth,最棒的是在github上有源碼

示例代碼

clone下threejs的項目代碼,找到上面的示例文件。示例代碼不到200行,閱讀之后發現其實threejs和之前接觸過的一些2D的游戲引擎(createjs,pixijs)等比較類似,都需要有場景(scene),要有渲染循環(render loop),在scene上添加對象(Mesh)或者是group;而Mesh由形狀(Geometry)和材質(Material)組成,Material則又是由圖片創建的紋理(Texture)而來。不同的是,這里有相機(Camera),有光線(Light),還有一些一直都不明白的距離單位問題。

稍微改動一下示例代碼,就能創建出來了earth。但是從使用的資源來看,只有一個地表紋理貼圖(earth4.jpg),而xplan中還有3個關於earth的圖片文件:

不確定bump和spec是什么,我的思路是先在官方文檔中找這些關鍵詞,如果找不到,就加上threejs一起去做google。官網上找到了bump相關的東西,但幫助最大的是google出來的一篇詳細的如何使用threejs創建earth的教程。(如果這個教程早點冒出來,也省了前面改示例代碼的時間了。主要也源於對threejs不熟悉,沒有想到哪些示例可能已經有很多教程了)

換上了earth4.jpg貼圖之后:

earth_bump

了解到bumpmap:

Bump mapping is a technique to simulate bumps and wrinkles on the surface of an object. The result is an apparently bumpy surface rather than a smooth surface although the surface of the underlying object is not actually changed. I'm sorry, you can't tilt the camera to see 3D mountains with this technique. You can adjust the bump effect (how much the map affects lighting) with the bumpScaleparameter

threejs中bumpmap是調節對光線的感知,來使人能明顯感覺到不光滑的表面,而並沒有在mesh中添加起伏,即沒有真的改變形狀。

官方bumpmap示例效果圖如下:

其實這里的earth_bump.jpg就是一個DEM,在threejs中稱作bumpmap,在其他一些地方也有被叫做heightmap。即用灰度圖表達高程,越黑表示高程越低,越亮表示高程越高。GIS專業中常用,unity3D中創建地形也會用到這個。

添加了earth_bump之后:

earth_spec

了解到了earth_spec.jpg是specular map,用來調節鏡面反射的,這里主要是調節海洋對光線的反射,增加真實性。

添加了earth_spec之后:

漂移的雲層

雲層的添加, 前面的教程里已經很詳細了,其實就是一個同心,半徑大一點的球體而已。

添加了雲層之后:

浮動的標簽

xplan中地球表面有城市標簽,會隨着地球的自轉而移動,同時又保持了水平的方向。google關鍵詞:threejs floating label。於是找到:

 

 找到方向就好辦,稍微參考一下官方API文檔和找到的示例代碼,能夠很容易的在earth上添加上浮動標簽。

小結

到這里,3D地球的繪制基本差不多了。雖然threejs是新東西,但是絕大部分功能都容易找到方向,並且改動一下示例代碼都夠快速的實現我們想要的效果,所這個過程並不難。重點是如何在一個未知的領域內找到想要的東西,並且快速的為自己所用。

但過程中我碰到一個性能問題,耽誤了很久。xplan的頁面在chrome的PC和手機模式都有近60的FPS,但是我創建的earth在PC有60,但是在手機模式卻不到30!最后逐一調試代碼,修改參數,花了好久才找到原因:

renderer.setPixelRatio(window.devicePixelRatio)

threejs的示例代碼中都有這么一行,就是這一行導致了我的代碼比xplan的代碼在手機上繪制的像素點翻倍,從而導致了性能成倍的下降。

另外,前面也提到,我對於3D框架中的距離單位和坐標問題,很模糊。於是這里,關於earth的大小,camera朝向,每個城市標簽的三維坐標和其他關與三維坐標的問題,我都硬抄了xplan的參數(幸好他們的代碼沒有壓縮...)。還有一個要承認的,就是地球后面的淡藍色光暈效果,貌似用了一些高級的渲染技術,我也就硬搬了xplan這部分代碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM