『轉載』在Cesium中繪製動態線段
轉載自 https://blog.csdn.net/yue1241630499/article/details/118344231 請支援原創!
在Cesium中繪製動態線段
以下實現方法均屬野路子。
理想中,可以擴充套件
polylinegeometry
增加一個customdata
屬性用於提交除位置外的其他頂點資料,類似於下文使用的color
計劃實現類似於螞蟻線的效果,在Cesium中翻看各種材質,沒法發現滿足條件的material或Appearance。那麼只能自己手工實現了。
基本思路
- 傳遞頂點時,附加每個頂點距線段起點的距離,用此距離來實現線段分段
- shader中對傳入的距離取模,即可實現分段繪製不通的顏色
使用fabric
查看了fabric的相關資料後,發現fabric只能自定義uniform
變數,沒有提供介面可以傳遞額外的頂點資料。Fabric
僅是材質,想來不可能通過材質提交新的頂點資料。此路不通,但是可以使用uniform
型別的變數。
如何提交除頂點外的其他頂點資料?
看到PolylineGeometry
可以額外提供頂點顏色,此時考慮可以將頂點距離通過每個頂點的color傳入到shader中。
傳入的color
為歸一化後的資料,因此計算距離時,需要將距離歸一化到0~1
之間。
最終解決方案
PolylineColorAppearance + Fabric
在PolylineColorAppearance
fragmentShaderSource
,此處需要注意,同Material
不同,Material
中需要重寫獲取材質方法,但是Appearance中需要完全替換main方法。
建立Appearance後,將appearance的材質替換為fabric,此時可以通過color獲取每個頂點對應的距離。
此時已經可以分段繪製線段了。
分段的線要動起來,可以傳入Cesium繪製的時間,通過preRender
事件可以獲取繪製的起始事件,當前時間減起始時間即為已經開始繪製的時間。
uniform變數如何傳遞??
都知道fabric
中可以指定uniforms
屬性來傳遞額外的變數,而且uniforms
fabric:{
uniforms:{
//glsl中對應的變數名
u_itime:10.0, //u_itime_0
u_trailpercent:0.3, //u_trailpercent_1
u_trailmovespeed:5.0/50.0, //u_trailmovespeed_2
}
}
到這裡就沒有問題了。。。。。
shader裡實現分段,使用mod
即可,拖尾效果使用smoothstep
實現,shader程式碼如下:
precision highp float;
varying vec4 v_color;
void main(){
float r=v_color.r-u_itime_0*u_trailmovespeed_2;
float dist=smoothstep(0.0,u_trailpercent_1,mod(r,u_trailpercent_1));
//紅白混合
gl_FragColor=mix(vec4(1.0,0.0,0.0,1.0),vec4(1.0),dist);
}
完整程式碼,可在sandcastle中執行
var viewer = new Cesium.Viewer("cesiumContainer");
var scene = viewer.scene;
var material=new Cesium.Material({
fabric:{
uniforms:{
u_itime:10.0,
u_trailpercent:0.3,
u_trailmovespeed:5.0/50.0,
}
}
});
var primitive = new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.PolylineGeometry({
positions: Cesium.Cartesian3.fromDegreesArray([
0.0,
6.0,
5.0,
6.0,
7.0,
8.0,
]),
width: 50.0,
vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT,
colorsPerVertex: true,
colors: [
new Cesium.Color(0.1,0.0,0.0,1.0),
new Cesium.Color(0.7,0.0,0.0,1.0),
new Cesium.Color(1.0,0.0,0.0,1.0)
],
}),
}),
appearance: new Cesium.PolylineColorAppearance({
translucent: false,
fragmentShaderSource: `precision highp float;
varying vec4 v_color;
void main(){
float r=v_color.r-u_itime_0*u_trailmovespeed_2;
float dist=smoothstep(0.0,u_trailpercent_1,mod(r,u_trailpercent_1));
gl_FragColor=mix(vec4(1.0,0.0,0.0,1.0),vec4(1.0),dist);
}
`,
}),
});
primitive.appearance.material=material;
scene.primitives.add(primitive);
scene.preRender.addEventListener(function(s,t){
let elaspTime=Cesium.JulianDate.now().secondsOfDay-t.secondsOfDay;
primitive.appearance.material.uniforms.u_itime=elaspTime;
});
現有問題
拐角處,被彎折
圖中,中間的白色色帶明顯未沿線方向,而是有一處彎折,這是由於,cesium將線擴充為面時,是沿頂點法線方向向兩側擴充,但是擴充後的兩個點對應的線的距離是一樣的,但是實際長度不同明顯下方拐角處的點要比上放的點的距離要長才符合實際情況,導致顏色變化時不一致。
如果純用fragmentshader來寫是可以避免彎折的情況的,但是目前還不知道如何將完整的canvas繪製到cesium上。對用shahder繪製線感興趣的,可以參考這篇文章,採用距離場方式繪製線段。
後續有時間通過理想方式實現一遍。