與直接調用官方 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
})
