與直接調用官方 API 不同,本例直接使用 Geometry 和 Appearance 類進行構造圖形,靈活度較大。
博客園 @四季留歌
1 目的與結果
有如下一個經緯高數組,表示三角形的三個點,逆時針順序:
const coords_geo = [
[112.470, 25.694, 200000],
[109.961, 19.862, 200000],
[118.122, 21.921, 200000]
]
其在GIS軟件中繪製的形狀如下:
最終在 Cesium 的繪製效果如下:
2 實現原理
使用 Primitive 創建靜態圖形,不依賴官方封裝好的 XXGeometry(最方便的應該是 PolygonGeometry)和 XXAppearance,只用最基礎的 Geometry 類和 Appearance 類。
Primitive API 創建圖形對象的結構如下:
+Primitive
- GeometryInstance | GeometryInstance[]
- Geometry
- GeometryAttributes
- GeometryAttribute
- Appearance
座標系統選擇
如果使用 ENU 座標,則需要計算轉換矩陣,官方已提供了例子。
此處全爲經緯高座標,需要藉助 Cesium 數學API 進行世界座標轉換。
Primitive API 直到傳遞給 WebGL 之前,想要在地球上繪製正確,必須是世界座標。
3 踩坑點
3.1 GeometryAttribute 的構造
3.1.1 position 的構造 - 數值類型
使用 Cesium.ComponentDatatype.DOUBLE
,values 必須傳遞 Float64Array
,否則頂點着色器中匹配不到 attribute vec3 position3DHigh
和 attribute vec3 position3DLow
。
若改爲 Cesium.ComponentDatatype.FLOAT
,values 傳遞 Float32Array
,會導致異常。
暫不清楚傳遞 Float32Array
時,頂點着色器的座標 attribute 應該改成什麼(或許根本不應傳遞 Float32Array)
3.1.2 頂點着色器中 attribute 變量的名稱
參考 GeometryAttributes
的文檔,允許的 attribute 有如下幾個:
- 座標 position,需爲 Float64 的數值,且每個點必須是 xyz 三個維度的
- 紋理座標 st,需爲 Float32 的數值,且必須是 xy 兩個維度的
- 頂點顏色 color,需爲 Uint8 的數值,且必須是 xyzw 四個維度的
- 頂點法線 normal,需爲 Float32 的數值,且必須是 xyz 三個維度的
- (不知道是什麼,應該是切線之類的)bitangent,需爲 Float32 的數值,且必須是 xyz 三個維度的
- 頂點切線向量 tangent,需爲 Float32 的數值,且必須是 xyz 三個維度的
在 Primitive.prototype.update 方法運行時,有一個 if (createSP)
分支會調用 createShaderProgram
函數,其內會調用函數 validateShaderMatching
來檢測着色器與 js 對象中 GeometryAttribute 的匹配情況。
頂點着色器中的 attribute 變量名,理應與 attributes
中的 key 一樣,除了 position 被分解成了 position3DHigh
和 position3DLow
(原因大家應該都知道,就是精度不夠,需要分別編碼)。
3.1.3 頂點着色器必須有 batchId attribute
否則會報錯。
3.2 僅 3D 模式
若 new Viewer 時不指定 scene3DOnly
,Primitive 的着色器要處理二三維的全部情況,這裏只關心三維的情況,故要指定僅使用三維模式。
new Cesium.Viewer('cesiumViewport', {
scene3DOnly: true,
})
若不指定僅三維模式,且不計算範圍球(見3.4),必報錯。
3.3 Appearance 的 renderState
一個對象,這個 renderState 對象的屬性會在渲染時覆蓋默認的 renderState。
- depthMask:是否將深度值寫入緩衝區
- blending:透明度混合
- depthTest:
- enabled 深度檢測
具體更多細節見 Renderer/RenderState.js
這裏必須指明的是,即使什麼 renderState 都不給,也要在 new Appearance 時給 renderState 一個空對象:
new Cesium.Appearance({
renderState: { },
vertexShaderSource: `...`,
fragmentShaderSource: `...`
})
否則會報錯:
3.4 Geometry 的 boundingSphere
若不指定,圖形就不會出現。
Cesium.BoundingSphere.fromVertices(coords_world)
coords_world 是世界座標數組,[x1, y1, z1, x2, y2, z2, ...]
若不計算包圍球且不指定僅三維模式(見3.2),程序將報錯:
3.5 Primitive 的異步計算
new Primitive 時,有一個 asynchronous
選項用於指定異步計算生成圖形,要自己寫 WebWorker
,在這裏因爲沒有寫 WebWorker
,所以將其指定爲 false 進行同步計算。
若不寫 WebWorker 也不指定其爲 false,將報錯:
const primitive = new Cesium.Primitive({
/* 其他屬性 */
asynchronous: false
})