在Cesium里面,我们可以用Entity
加载实体的方式,来通过CallbackProperty
来更新实体的位置,但是如果涉及到大量实体(比如线)位置更新的话,用Entity
会造成一定的性能问题。
我们可以用Primitive
来绘制大量实体,但是Primitive
中没有位置更新的回调方法,只能先移除再重新创建。创建primitive时,我们可以指定异步方式,当我们设置asynchronous: false
时,是同步创建,可以在创建时移除,缺点是大量渲染会造成阻塞。但是如果指定异步方式,就会出现渲染闪烁的问题,因为无法确定primitive在哪一帧才能创建完成。
对于这个问题,我们可以利用primitive.ready
属性来判断primitive何时创建完成,但是需要通过setInterval
等轮询方式来进行更新。这里我们以绘制polyline为例,写一个管理器来对polyline数据进行位置更新,以下是示例代码:
var viewer = new Cesium.Viewer('cesiumContainer', {
});
var scene = viewer.scene;
scene.debugShowFramesPerSecond = true;
viewer.scene.globe.depthTestAgainstTerrain = true;
const currentPosition = {
long: -105, lat: 19 };
const MOVEMENT = 0.08;
const UPDATE_INTERVAL = 500;
const MAX_POLYLINE_SEGMENTS = 2;
const MAX_POLYLINES = 50;
class PolylineManager {
constructor(currentPosition) {
this.primitive = null;
this.posModification = 0;
this.initialPositions = [];
this.colors = [];
for (let i = 0; i <= MAX_POLYLINES; i++) {
const color = `rgb(${
Math.random() * 100 + 100}, ${
Math.random() * 200}, ${
Math.random() * 50})`;
this.colors.push(
Cesium.Color.fromCssColorString(color).withAlpha(0.5)
);
this.initialPositions.push({
...currentPosition,
long: currentPosition.long + i * 0.2
});
}
this.nextPrimitive = this.getNextLineSegmentPrimitive();
viewer.scene.groundPrimitives.add(this.nextPrimitive);
}
getNextLineSegmentPrimitive() {
const geometryInstances = [];
for (let i = 0; i < MAX_POLYLINES; i++) {
const currentPosition = this.initialPositions[i];
const color = this.colors[i];
const positionDegrees = [];
for (let i = 0; i < MAX_POLYLINE_SEGMENTS; i++) {
positionDegrees.push(currentPosition.long, currentPosition.lat + MOVEMENT * this.posModification + i + 1);
positionDegrees.push(currentPosition.long, currentPosition.lat + MOVEMENT * this.posModification + i);
}
const geometryInstance = new Cesium.GeometryInstance({
geometry: new Cesium.GroundPolylineGeometry({
positions: Cesium.Cartesian3.fromDegreesArray(positionDegrees),
width : 2.0,
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(color),
}
});
geometryInstances.push(geometryInstance);
}
this.posModification++;
return new Cesium.GroundPolylinePrimitive({
geometryInstances,
show: false,
appearance : new Cesium.PolylineColorAppearance(),
asynchronous: true,
releaseGeometryInstances: true
});
}
update() {
if (this.nextPrimitive.ready) {
viewer.scene.groundPrimitives.remove(this.primitive);
this.nextPrimitive.show = true;
this.primitive = this.nextPrimitive;
this.nextPrimitive = this.getNextLineSegmentPrimitive();
viewer.scene.groundPrimitives.add(this.nextPrimitive);
}
}
}
function run() {
var initialPosition = Cesium.Cartesian3.fromDegrees(currentPosition.long, currentPosition.lat, 15000.0);
var initialOrientation = new Cesium.HeadingPitchRoll.fromDegrees(45, -20.0, 0.0);
viewer.scene.camera.setView({
destination: initialPosition,
orientation: initialOrientation,
endTransform: Cesium.Matrix4.IDENTITY
});
const manager = new PolylineManager(currentPosition);
manager.update();
setInterval(() => {
manager.update();
}, UPDATE_INTERVAL);
}
run();