同樣在這篇文章開始前重申一下,山海鯨並沒有使用ThreeJS引擎。但由於ThreeJS引擎使用廣泛,下文中直接用ThreeJS同CesiumJS的整合方案代替山海鯨中3D引擎和CesiumJS整合。
系列傳送門:
山海鯨視覺化:GIS融合之路(一)技術選型CesiumJS/loaders.gl/iTowns?
山海鯨視覺化:GIS融合之路(二)CesiumJS和ThreeJS深度緩衝區整合
按照慣例,文章開始前先自誇,大家可以參考一下山海鯨中相機整合的效果。
詳細的內容可以前往這篇視訊教學:
感興趣朋友也歡迎下載軟體試一試:山海鯨視覺化-一站式數位孿生開發平臺-海量資料視覺化大屏模板
相機的整合分為三個部分,分別是:1.同步相機fov 2.同步相機位置 3.同步相機方向
一、同步相機fov
我們先來處理最簡單的相機fov,我們先看下相機的fov是什麼:
可以看出,相機的fov就是相機的視角寬度和高度,我們日常所說的廣角相機,魚眼相機就是fov很大的相機,而相機主要有兩個fov引數,一個是橫向的vfov,一個是縱向的hfov,因此我們只需要把兩個相機自己的fov對應設定上即可,我們先看一下兩邊的檔案中分別怎麼描述自己的fov的:
此處一定要敲黑板,fov本身是一個很簡單的概念,理論上直接同步兩邊相機的fov就可以完成。但這裡面起碼有兩個坑,一個是Cesium用的是radians,而threejs用的是degrees,需要做一次轉換。另外 CesiumJS有兩個fov,和threejs對應的是fovy。這兩個問題處理好了就簡單了,程式碼也很簡單。
THREE.camera.fov = Cesium.Math.toDegrees(CESIUM.viewer.camera.frustum.fovy)
當然山海鯨採用的是雙向同步,反過來的話只需要根據檔案內容將山海鯨引擎的fov賦值給CESIUM即可。
二、同步相機位置
搞定了相機fov,下一步就是同步相機的位置,同步相機位置就得先了解一下Cesium的座標系,我們主要要用到Cesium的兩套座標系,一個是地心座標,一個是經緯度座標系。這兩個座標系間Cesium提供了標準的轉換方法。
而Cesium同Threejs的座標轉換時,Threejs使用的座標系對應在Cesium中實際上是東北上座標系,這兩個座標系的關係如圖所示:
Cesium也提供的標準的函數來獲得東北上座標系和地心座標系的轉換矩陣,因此我們可以通過如下程式碼將Threejs中的座標轉換為Cesium中的地心座標系,同理也可以反過來將Cesium中的地心座標系轉換為東北天座標系,也就是threejs中的座標系,實現座標系的雙向轉換。
let origin = Cesium.Cartographic.toCartesian(originCartographic)
let transform = Cesium.Transforms.eastNorthUpToFixedFrame(origin);
let result1 = Cesium.Matrix4.multiplyByPoint(transform, cameraPosition);
山海鯨中需要提供了兩種控制方式,一種是控制Threejs相機同步到Cesium相機中,一種是控制Cesium相機同步到Threejs中。所以最後值得注意的就是在第一種方式中需要將Cesium相機自己的控制個關閉掉,這個也很簡單,只需要呼叫以下程式碼即可:
scene.screenSpaceCameraController.enableInputs = false;
最後,值得注意的是Cesium除了提供3d球面繪製模式( Cesium.SceneMode.SCENE3D)以外,還提供了2.5d的繪製模式(Cesium.SceneMode.COLUMBUS_VIEW),在COLUMBUS_VIEW的模式下,則需要做一步web墨卡託座標的投影才能夠完成座標轉換。
至此,我們終於實現了雙向的相機同步。完成了這些,GIS系統算是正式可以在山海鯨中使用了。而且後面的章節我們會提到,山海鯨開放了整合CesiumJS的介面,因此只需要開啟反向相機同步,即可無縫的將之前的CesiumJS程式碼遷移過來了。雖然整合成功了,但是CesiumJS依然是CesiumJS的樣子,並沒有任何變化,如果是這樣,為什麼不直接用CesiumJS,幹嘛還有整合呢?
我們當然不能就此止步,作為一個對客戶負責的技術負責人,客戶不僅要求山海鯨可以載入所有的GIS資料,還拿效果和UE對比,覺得Cesium For Unreal的視覺效果更好看。要求我們把Unreal的效果搬到Web上來,什麼,你說不可能?沒有條件,創造條件也要上。只能再苦一苦開發團隊了。