Cesium Primitive API 實踐:繪製一個三角形

與直接調用官方 API 不同,本例直接使用 Geometry 和 Appearance 類進行構造圖形,靈活度較大。
博客園 @四季留歌

1 目的與結果

有如下一個經緯高數組,表示三角形的三個點,逆時針順序:

const coords_geo = [
  [112.470, 25.694, 200000],
  [109.961, 19.862, 200000],
  [118.122, 21.921, 200000]
]

其在GIS軟件中繪製的形狀如下:

image

最終在 Cesium 的繪製效果如下:

image

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 position3DHighattribute 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 被分解成了 position3DHighposition3DLow(原因大家應該都知道,就是精度不夠,需要分別編碼)。

3.1.3 頂點着色器必須有 batchId attribute

否則會報錯。

image

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: `...`
})

否則會報錯:

image

3.4 Geometry 的 boundingSphere

若不指定,圖形就不會出現。

Cesium.BoundingSphere.fromVertices(coords_world)

coords_world 是世界座標數組,[x1, y1, z1, x2, y2, z2, ...]

若不計算包圍球且不指定僅三維模式(見3.2),程序將報錯:

image

3.5 Primitive 的異步計算

new Primitive 時,有一個 asynchronous 選項用於指定異步計算生成圖形,要自己寫 WebWorker,在這裏因爲沒有寫 WebWorker,所以將其指定爲 false 進行同步計算。

若不寫 WebWorker 也不指定其爲 false,將報錯:

image

const primitive = new Cesium.Primitive({
  /* 其他屬性 */
  asynchronous: false
})
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章