Skip to content

Cesium 引擎

问题来源

场景中存在3dtiles模型,模型由多个构件组成,需要按指定时机控制某些构件的显示与隐藏或是设置样式(比如某些构件透明度为 1.0,其余构件透明度为 0.1,以示区别)。

主要问题

某模型构件数为三万以上,在按条件设置构件的样式时会明显卡顿。

官方做法

js
function fun (e) {
	//要显示的模型构件数组
	const showArr = e;
	const conditions = []
	for (let index = 0; index < showArr.length; index++) {
		const element = showArr[index]
    conditions.push(["regExp('" + element + "').test(${name})", "rgb(255, 255, 255)"])
	}
	conditions.push(["true", "rgba(255, 255, 255, 0.1)"])
	  this.bimModelLayer.style = new Cesium.Cesium3DTileStyle({
	    color: {
	      conditions
			}
		})
},

官方是按每个构件的属性信息去设置构件的样式属性,这样做在遇到大数据量的改变时会有明显卡顿。

验证发现在除了[”true”, “rgba(255, 255, 255, 0.1)”]之外的数据量少时也能有较高的效率,所以认为性能消耗主要来源是两部分:

  1. 读取数组[["regExp('" + element + "').test(${name})", "rgb(255, 255, 255)"],…]后去循环处理数组中存在的每个构件的样式的性能消耗
  2. 单纯进行构件样式设置时的性能消耗(主要卡顿原因)

解决方案

弃用官方做法,改用手动设置每个构件,这种做法在执行构件显隐时很有用,但是控制构件样式(颜色或透明度)时依然会明显卡顿。

js
/** 方法一 */
function fun (data) {
  //要显示的模型构件数组: data
  let ids = {};
  data.forEach((i) => { //构造 键值对 对象
    ids[i] = 1;
  });
  //显示/隐藏场景下所属构件
  const cesium3DTiles = this.bimModelLayer.tileset.root.children;
  //这里能拿到当前3dtiles图层的构件数据
  for (let j = 0; j < cesium3DTiles.length; ++j) {
    let content = cesium3DTiles[j].content;
    let f = [];
    if (content instanceof Cesium.Batched3DModel3DTileContent) {
      f.push(content);
    } else if (content instanceof Cesium.Composite3DTileContent) {
      f.push(...content._contents);
    }
    for (let k = 0; k < f.length; ++k) {
      let featuresLength = f[k].featuresLength;
      for (let i = 0; i < featuresLength; i++) {
        f[k].getFeature(i).show = true;
        if (!ids[f[k].batchTable._properties.name[i]]) {
          f[k].getFeature(i).show = false;
        }
      }
    }
  }
},

/** 方法二 */
//获取3D tiles中所有feature的数据
let tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
	url: '.././data/sz/tileset.json'
}));
viewer.zoomTo(tileset);
//设置瓦片加载完成监听事件
tileset.tileLoad.addEventListener(function(tile) {
	let content = tile.content;
	let featuresLength = content.featuresLength;
	console.log("要素数量为:");
	console.log(featuresLength);
	console.log("第一个要素为:");
	let feature = content.getFeature(0);
	console.log(feature);
})

/** 方法三:原生Cesium3DTileset类可以直接获取到所有子构件 */
tileset.style = new Cesium.Cesium3DTileStyle({
    color : 'color("red")'
});
tileset.tileVisible.addEventListener(function(tile) {
    const content = tile.content;
    const featuresLength = content.featuresLength;
    for (let i = 0; i < featuresLength; i+=2) {
        content.getFeature(i).color = Cesium.Color.fromRandom();
    }
});