【Cesium】3Dtiles建筑模型分层渲染的思路

欢迎查看

真的很久没有更新过博客了,最近入职了新公司,要做一个新的项目,使用到cesium,翻阅外网和国内各大网站,发现资料真的很少。国内很多资料都是翻译外网的,所以,没去过外网的同学,其实去不去也没必要了。而国内的环境真的是一筹莫展:要么就是有经验的人二次封装了js组件出售给人使用;要么就是有经验的人分享如何使用cesium,进阶的很少;要么就是有经验了,有demo,但是要钱,这个倒还好,钱也不算多,还可以进群和大家一起交流。

进群后,发现一个残酷的现实,大家使用cesium都是拿来做gis的,极少像我一样使用来渲染建筑类型。甚至有的,还要搭配three.js一起使用。想了一下,还是贡献一下这段时间探索的经验吧,给有需要的人参考。

分层渲染思路

我自己摸索的就这2种,其中第一种是我自己正在使用的,第二种是看了其他二次封装的商用JS组件后发现的,还没尝试,不过应该也不难。

1. 在建筑模型数据上就已经切割分好层,前端直接拿到渲染就可以了。

我目前就是这样做的,可以使用PrimitiveCollection 或者 scene.primitives.add循环把模型实例加进去。然后,对应的变量名就存在window下(当然存在别的地方也可以,建议是全局变量的形式),用的时候直接根据逻辑提取出来。

核心代码:

// tilesetUrlArr是模型tileset.json的地址集合
for (let i = 0; i < tilesetUrlArr.length; i++) {
    
    
   window['tileset' + i] = new Cesium.Cesium3DTileset({
    
     url: tilesetUrlArr[i], tilesOption });
   // ...中间这里可以做很多操作,例如对模型的材质颜色进行修改、相机视角调整、模型偏移、楼层楼栋数据拆分等等
   viewer.scene.primitives.add(window['tileset' + i]);
}

这种方式建模师比较耗时间,当然前端也不容易(难点在于全局变量的使用),不过好处就是

每一个楼层都是单独的模型,可以一次性加载,也可以懒加载/按需加载

2. 一整栋模型里面每个构件赋予楼层属性。

然后,建议在渲染的时候就把符合的楼层属性的组件赋予到对应的楼层变量。控制分层渲染的时候,对这些变量进行处理就行(符合当前楼层的,就控制拥有当前楼层属性的构件显示,其余隐藏)。

大概核心代码:

window.allFeature = []; // 所有的构件信息

// 设置瓦片加载完成监听事件,以获取瓦片内的构件信息
tileset.tileLoad.addEventListener(function(tile) {
    
    
    processTileFeatures(tile, (feature) => {
    
      // Tips:这里不采取别的方法绕一圈取得值的话,好像是没办法获得构件属性
        let properties = [];
        const propertyIds = feature.getPropertyIds();    // 点击设备构件后,可以通过GlobalId去设备列表中找到对应的设备
        propertyIds.forEach(item => {
    
    
            properties.push({
    
    
                'key': item, // 属性名
                'value': feature.getProperty(item) // 属性值
            });
        });
        feature.properties = properties;
        allFeature.push(feature); // TODO 数据太大,真不适合存起来,后续可以考虑怎么优化
    });
});

/**
 * 循环获取tile.content里面的Features(构件)
**/
function processContentFeatures(content, callback) {
    
    
    let featuresLength = content.featuresLength;
    for (let i = 0; i < featuresLength; i++) {
    
    
        let feature = content.getFeature(i);
        callback(feature);
    }
}
/**
 * 获取tile里面的content
 * Cesium3DTileset 通过 tileLoad、tileUnload等事件获取 Cesium3DTile(也就是tile),
 * 然后,Cesium3DTile通过content(tile.content)获取 Cesium3DTileContent(Cesium3DTileset 中瓦片的内容,也就是Feature)
**/
function processTileFeatures(tile, callback) {
    
    
    let content = tile.content;
    let innerContents = content.innerContents;
    if (Cesium.defined(innerContents)) {
    
    
        let length = innerContents.length;
        for (let i = 0; i < length; i++) {
    
    
            processContentFeatures(innerContents[i], callback);
        }
    } else {
    
    
        processContentFeatures(content, callback);
    }
}

// ...之后就对allFeature所有构件信息进行匹对,符合楼层属性的就显示。感觉如果构件多的话,会崩溃,慎用

注意的是:

这种方法的话,模型就只能一次性加载出来。且不适合大模型。

效果类似这种:Mars3D-BIM分层展示

猜你喜欢

转载自blog.csdn.net/jiangxinyu50/article/details/129519495