Cesium 可變高度+動態紋理水體

Cesium 可變高度+動態紋理水體

由於任務中的需求,要求使用primitive實體配合動態紋理並且可以進行高度變化,實現一種動態水體的效果。

刪除原實體重新添加新實體的方法會影響系統觀感。

動態紋理

參照文章:cesium動態水面(cesium動態水面_A873054267的博客-CSDN博客_cesium動態水面)

高度變化

參照文章:cesium-動態編輯primitive探索(cesium-動態編輯primitive探索 ( 四) 動態圓柱體_A873054267的博客-CSDN博客_cesium 繪制圓柱體)

結合

當同時使用這兩種方法時,紋理會變成靜態顯示,通過閱讀代碼發現是由於該高度變化方法實際是多次重新渲染該實體,會使得紋理一直顯示初始加載狀態,就像是靜態紋理。

一下為結合網絡文章閱讀cesium源碼後實現改進方法。

參考文章:cesium繪制primitive流程(cesium繪制primitive流程(一)數據準備 – 簡書 (jianshu.com))

實現效果

關鍵代碼(參照cesium-動態編輯primitive探索一文中的代碼進行改進)

primitive自身

/*在getGeometry方法中使用多邊形圖形*/new Cesium.PolygonGeometry({polygonHierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(this._positions)), // 多邊形坐標height: this._height, // 底部高度extrudedHeight: this._extrudedHeight, // 水面高度vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT})

在原基礎上添加init函數

該函數的作用是隻在初次渲染時創建primitive實體,在後面隻調用其update方法對其進行更新。

WaterPrimitive.prototype.init = function () {let geometry = this.getGeometry();if (!geometry) return;this._primitive = new Cesium.Primitive({releaseGeometryInstances: false,geometryInstances: new Cesium.GeometryInstance({geometry}),asynchronous: false,appearance: ... // 參照動態紋理一文});};

updata方法

簡化瞭原來的update方法,不再需要每次重新生成一個primitive,在屬性發生變化時通過修改primitive內部屬性(看WaterPrimitive類構造方法中),對原對象重新執行update函數。

WaterPrimitive.prototype.update = function (frameState) {if (this._primitive) {// console.log(this._primitive);let primitive = this._primitive;primitive.update(frameState);}};

WaterPrimitive類構造方法

在此方法中,主要任務為綁定屬性監聽以及調用init方法。

function WaterPrimitive(options) {/*  此處為屬性賦值代碼*/Object.defineProperty(this, "extrudedHeight", {get() {return this._extrudedHeight;},set(newVal) {if (Object.prototype.toString.call(newVal) !== "[object Number]") return;if (this._primitive) {this._primitive._state = 3; // 關鍵this._primitive._appearance = undefined; // 關鍵this._primitive.geometryInstances.geometry = this.getGeometry();this._extrudedHeight = newVal;}}});this.init(); // 調用init函數}
  • 在創建實例時,使用defineProperty對高度屬性進行數據劫持,監聽其高度屬性的變化。
  • 在高度屬性發生變化後需要重置內部primitive對象的state屬性以及appearance屬性

由於primitive的渲染是狀態驅動,因此在我們想要讓其重新渲染時需要講狀態碼從5(已渲染完成)重置為3(合並中),從而重新執行cesium源碼中primitive對象的update函數。

重置appearance屬性使其重新執行rsFunc(創建渲染狀態)、spFunc(創建著色器程序)、commandFunc(執行渲染命令)三個函數

源碼

/*cesium源碼中部分update函數*/var appearance = this.appearance;var material = appearance.material;var createRS = false;var createSP = false;if (this._appearance !== appearance) {this._appearance = appearance;this._material = material;createRS = true;createSP = true;} else if (this._material !== material) {this._material = material;createSP = true;}var depthFailAppearance = this.depthFailAppearance;var depthFailMaterial = defined(depthFailAppearance) " >.material : undefined;if (this._depthFailAppearance !== depthFailAppearance) {this._depthFailAppearance = depthFailAppearance;this._depthFailMaterial = depthFailMaterial;createRS = true;createSP = true;} else if (this._depthFailMaterial !== depthFailMaterial) {this._depthFailMaterial = depthFailMaterial;createSP = true;}var translucent = this._appearance.isTranslucent();if (this._translucent !== translucent) {this._translucent = translucent;createRS = true;}if (defined(this._material)) {console.log("material update");this._material.update(context);}var twoPasses = appearance.closed && translucent;if (createRS) {var rsFunc = defaultValue(this._createRenderStatesFunction, createRenderStates);rsFunc(this, context, appearance, twoPasses);}if (createSP) {var spFunc = defaultValue(this._createShaderProgramFunction, createShaderProgram);spFunc(this, frameState, appearance);}if (createRS || createSP) {var commandFunc = defaultValue(this._createCommandsFunction, createCommands);commandFunc(this, appearance, material, translucent, twoPasses, this._colorCommands, this._pickCommands, frameState);}var updateAndQueueCommandsFunc = defaultValue(this._updateAndQueueCommandsFunction, updateAndQueueCommands);updateAndQueueCommandsFunc(this, frameState, this._colorCommands, this._pickCommands, this.modelMatrix, this.cull, this.debugShowBoundingVolume, twoPasses););updateAndQueueCommandsFunc(this, frameState, this._colorCommands, this._pickCommands, this.modelMatrix, this.cull, this.debugShowBoundingVolume, twoPasses);

動畫

entity可以利用callbackProperty綁定動態屬性,但隻適用與entity實體,對於primiitve實體,可以利用Cesium.questAnimationFrame()進行回調實現動畫,在函數中對extrudedHeight進行更改。

function waterGrow() {if(waterPrimitive.extrudedHeight < maxHeight) {waterPrimitive.extrudedHeight += growSpeed;Cesium.requestAnimationFrame(waterGrow);}}
本文來自網絡,不代表程式碼花園立場,如有侵權,請聯系管理員。https://www.codegarden.cn/article/31352/
返回顶部