欢迎光临
我们一直在努力

第18章:CesiumJS 从入门到精通 18:建筑师的工具:3D Tiles 变换裁剪与自定义着色器

写在前面

前序章节掌握 3D Tiles 基础加载、Cesium3DTileStyle属性着色,仅能完成基础可视化;工业 BIM、倾斜摄影数字孪生项目常需要剖切查看内部结构、自定义动态光影特效、大场景流畅加载、显存防崩溃管控。 本章讲解五大生产级核心能力:ClippingPlaneCollection模型剖切、CustomShaderGPU 自定义着色器、debug 瓦片调试工具、skipLevelOfDetail跳级加速加载、maximumMemoryUsage内存管控,配套多特性组合综合案例,覆盖建筑剖面、动态热力、大场景性能优化业务需求。

本章学习目标

  • 掌握ClippingPlane单 / 多平面剖切,区分并集 / 交集裁剪模式,实现滑块动态剖切交互
  • 理解CustomShader顶点 / 片元着色器、uniform 传参、GLSL 基础语法,实现高度热力、脉冲发光特效
  • 熟练使用全套debugShow调试工具,快速定位瓦片缺失、层级切换、加载异常问题
  • 掌握跳级加载策略,区分 REPLACE/ADD 瓦片细化规则,适配鸟瞰 / 室内漫游不同场景
  • 配置显存内存上限,监听瓦片全生命周期事件,实现内存监控,解决大模型 OOM 崩溃问题

  • 一、ClippingPlaneCollection 模型剖切平面

    1.1 核心原理

    裁剪平面由法线向量+距离值定义:法线指向保留渲染一侧,平面将三维空间分割两部分,另一侧模型直接剔除不渲染;多平面通过集合统一管理,支持两种裁剪运算模式。

    • ClippingPlane:单剖切刀,法线 + distance 定义切割位置
    • ClippingPlaneCollection:剖切平面组,统一控制切面轮廓、开关、运算逻辑
    • unionClippingRegions:true = 并集(任意平面裁掉即隐藏),false = 交集(多平面重叠区域才隐藏)

    1.2 基础配置参数

    const clipPlanes = new Cesium.ClippingPlaneCollection({
    planes: [
    // 法线向下,高度50米处水平切割
    new Cesium.ClippingPlane(new Cesium.Cartesian3(0,0,-1), 50)
    ],
    unionClippingRegions: true,
    edgeColor: Cesium.Color.CYAN, // 切面描边颜色
    edgeWidth: 2, // 切面线宽
    enabled: true
    });
    tileset.clippingPlanes = clipPlanes;

    1.3 常用实战案例

    案例 1:水平剖切,切除建筑上部露出地基

    const clipPlanes = new Cesium.ClippingPlaneCollection({
    planes: [new Cesium.ClippingPlane(new Cesium.Cartesian3(0,0,-1), 50)],
    edgeColor: Cesium.Color.CYAN,
    edgeWidth:2
    });
    tileset.clippingPlanes = clipPlanes;

    案例 2:双平面对角剖切(交集模式切角落)

    const multiClip = new Cesium.ClippingPlaneCollection({
    planes: [
    new Cesium.ClippingPlane(new Cesium.Cartesian3(1,0,0),0),
    new Cesium.ClippingPlane(new Cesium.Cartesian3(0,1,0),0)
    ],
    unionClippingRegions: false, // 交集模式
    edgeColor: Cesium.Color.YELLOW
    });
    tileset.clippingPlanes = multiClip;

    案例 3:滑块动态调节剖切高度

    <input id="clipSlider" type="range" min="0" max="200" value="100">

    const clipPlanes = new Cesium.ClippingPlaneCollection({
    planes: [new Cesium.ClippingPlane(new Cesium.Cartesian3(0,0,-1), 100)],
    edgeColor: Cesium.Color.RED
    });
    tileset.clippingPlanes = clipPlanes;
    document.getElementById("clipSlider").oninput = e=>{
    clipPlanes.get(0).distance = parseFloat(e.target.value);
    viewer.scene.requestRender();
    }

    1.4 两种裁剪模式对比

    参数unionClippingRegions:true 并集unionClippingRegions:false 交集
    逻辑 任一平面剔除则隐藏 仅多平面重叠区域剔除
    效果 平面越多,剔除范围越大 平面越多,剔除范围越小
    适用 顶部、侧面多面同时剖切 只切除建筑角落一小块

    二、CustomShader 自定义 GPU 着色器

    2.1 适用场景

    基础Cesium3DTileStyle仅支持简单静态着色,无法实现:高度渐变热力、脉冲呼吸发光、实时数据映射、菲涅尔边缘光;CustomShader 直接编写 GLSL 片元 / 顶点着色代码,在 GPU 并行运算,实现高级视觉特效。

    2.2 基础结构说明

  • uniforms:JS 向 GLSL 传递全局变量(颜色、时间、阈值)
  • vertexShaderText:顶点着色,修改模型几何顶点位置
  • fragmentShaderText:片元着色,修改每个像素最终颜色(最常用)
  • mode:MODIFY_MATERIAL(基于原始材质修改,推荐)/REPLACE_MATERIAL(完全覆盖原有纹理)
  • 2.3 内置核心变量

    变量作用
    fsInput.attributes.positionMC 模型局部坐标 Z 值,实现按高度着色
    fsInput.attributes.normalMC 顶点法线,制作边缘高光
    material.diffuse 模型基础漫反射颜色
    material.emissive 自发光,不受太阳光影响

    2.4 实战 1:建筑高度热力渐变着色

    const heatShader = new Cesium.CustomShader({
    uniforms:{
    u_minH:{type:Cesium.UniformType.FLOAT,value:10},
    u_maxH:{type:Cesium.UniformType.FLOAT,value:300}
    },
    fragmentShaderText:`
    void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material){
    float h = fsInput.attributes.positionMC.z;
    float t = clamp((h-u_minH)/(u_maxH-u_minH),0.0,1.0);
    vec3 color = mix(vec3(0,0,1),vec3(1,0,0),t);
    material.diffuse = color;
    material.emissive = color*0.2;
    }
    `
    });
    tileset.customShader = heatShader;

    2.5 实战 2:选中建筑金色脉冲呼吸效果

    const pulseShader = new Cesium.CustomShader({
    uniforms:{
    u_time:{type:Cesium.UniformType.FLOAT,value:0},
    u_selected:{type:Cesium.UniformType.BOOL,value:false}
    },
    fragmentShaderText:`
    void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material){
    if(u_selected){
    float pulse = 0.6 + 0.4*sin(u_time*5.0);
    vec3 gold = vec3(1,0.84,0);
    material.diffuse = mix(material.diffuse,gold,pulse*0.5);
    material.emissive = gold*pulse*0.6;
    }
    }
    `
    });
    tileset.customShader = pulseShader;
    // 每帧更新时间,驱动动画
    viewer.scene.preRender.addEventListener(()=>{
    pulseShader.setUniform("u_time", performance.now()/1000);
    })

    2.6 mode 模式选择建议

    • MODIFY_MATERIAL:保留原始纹理、PBR 光照,仅叠加特效,性能开销低,绝大多数场景首选
    • REPLACE_MATERIAL:完全丢弃原始贴图,自定义纯色 / 线框 / X 光效果,适合分析类场景

    三、debugShow 瓦片调试工具集

    3.1 六大调试开关,快速定位渲染异常

    // 瓦片整体包围盒线框,排查瓦片缺失
    tileset.debugShowBoundingVolume = true;
    // 瓦片内部几何包围盒
    tileset.debugShowContentBoundingVolume = true;
    // 标注瓦片几何误差,判断层级精细度
    tileset.debugShowGeometricError = true;
    // 冻结当前瓦片,停止加载新数据
    tileset.debugFreezeFrame = true;
    // 随机分色区分相邻瓦片,看清瓦片边界
    tileset.debugColorizeTiles = true;

    3.2 问题排查速查表

    现象调试工具判断依据
    部分建筑消失 debugShowBoundingVolume 无包围盒 = 瓦片请求失败;有盒无图形 = 几何损坏
    远处模型模糊粗糙 debugShowGeometricError 几何误差数值过大,调高精细层级
    缩放时画面闪烁 debugColorizeTiles 瓦片层级切换边界突兀
    页面加载卡顿 debugFreezeFrame 冻结后统计当前渲染瓦片数量

    四、skipLevelOfDetail 跳级加载优化

    4.1 常规逐级加载缺陷

    默认瓦片加载严格 0→1→2→3 逐级加载,远距离浏览时长期显示模糊低精度瓦片,缩放拉近时大量请求中间层级瓦片,带宽消耗高、画面刷新慢。 跳级加载:跳过中间层级,直接加载当前视距匹配精度瓦片,大幅减少请求数量。

    4.2 使用前置条件

    仅瓦片细化策略为REPLACE时生效;ADD 叠加细化瓦片不支持跳级加载,检测代码:

    tileset.readyPromise.then(()=>{
    const refine = tileset.root.refine;
    if(refine === Cesium.Cesium3DTileRefine.ADD){
    console.warn("ADD细化,跳级加载无效");
    }
    })

    4.3 完整配置参数

    const tileset = await Cesium.Cesium3DTileset.fromUrl("tileset.json",{
    skipLevelOfDetail:true, // 开启跳级
    skipLevels:1, // 最多跳过1层,保守策略
    immediatelyLoadDesiredLevelOfDetail:false // 子瓦片加载时保留父瓦片,防空白闪烁
    })

    4.4 场景参数配置推荐

    场景skipLevelOfDetailskipLevelsimmediatelyLoadDesiredLevelOfDetail
    城市鸟瞰、大范围飞行 true 2 false
    室内精细漫游、近距离浏览 false
    低带宽移动端 true 3 true

    五、maximumMemoryUsage 显存内存管控与瓦片事件

    5.1 内存溢出问题

    3D Tiles 瓦片几何、纹理存储在 GPU 显存,无上限管控会持续加载,触发浏览器 OOM 崩溃,通过maximumMemoryUsage设置显存硬阈值,超出自动卸载远距离瓦片。

    5.2 设备适配内存配置

    // 移动端低配:128MB
    maximumMemoryUsage:128 * 1024 * 1024
    // 笔记本集成显卡:256MB
    maximumMemoryUsage:256 * 1024 * 1024
    // 台式独立显卡:512~1024MB
    maximumMemoryUsage:1024 * 1024 * 1024

    5.3 瓦片全生命周期监听事件

    // 单瓦片加载完成/失败
    tileset.tileLoad.addEventListener(tile=>{
    if(tile.contentFailed) console.warn("瓦片加载失败",tile._header.uri);
    })
    // 瓦片进入视野可见
    tileset.tileVisible.addEventListener(tile=>{})
    // 当前视野全部瓦片加载完成
    tileset.allTilesLoaded.addEventListener(()=>{})
    // 初始根瓦片加载完毕
    tileset.initialTilesLoaded.addEventListener(()=>{})

    5.4 简易显存监控工具

    setInterval(()=>{
    const memMB = (tileset.totalMemoryUsageInBytes / 1024 / 1024).toFixed(1);
    const limitMB = (tileset.maximumMemoryUsage / 1024 / 1024).toFixed(0);
    console.log(`显存占用:${memMB}MB,上限${limitMB}MB,使用率${(memMB/limitMB*100).toFixed(1)}%`)
    },1000)


    六、综合实战:建筑剖面可视化(剖切 + 着色器 + 跳级)

    整合本章全部能力,实现可动态剖切、高度热力渐变、悬停脉冲发光、大场景流畅加载的建筑剖面 Demo:

    async function createBuildingView(viewer){
    // 1.加载瓦片,开启跳级、内存限制
    const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(96188,{
    skipLevelOfDetail:true,
    skipLevels:1,
    maximumMemoryUsage:512 * 1024 * 1024
    })
    viewer.scene.primitives.add(tileset);
    await tileset.readyPromise;

    // 2.水平剖切平面
    const clipPlanes = new Cesium.ClippingPlaneCollection({
    planes:[new Cesium.ClippingPlane(new Cesium.Cartesian3(0,0,1),-20)],
    edgeColor:Cesium.Color.CYAN,
    edgeWidth:1.5
    })
    tileset.clippingPlanes = clipPlanes;

    // 3.热力+脉冲自定义着色器
    const customShader = new Cesium.CustomShader({
    uniforms:{
    u_time:{type:Cesium.UniformType.FLOAT,value:0},
    u_hoverH:{type:Cesium.UniformType.FLOAT,value:-1},
    u_min:{type:Cesium.UniformType.FLOAT,value:0},
    u_max:{type:Cesium.UniformType.FLOAT,value:20}
    },
    fragmentShaderText:`
    void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material){
    float h = fsInput.attributes.positionMC.z;
    float t = clamp((h-u_min)/(u_max-u_min),0.0,1.0);
    vec3 heat = mix(vec3(0,0.8,1),vec3(1,0,0),t);
    material.diffuse = heat;
    if(abs(h – u_hoverH) < 0.5){
    float pulse = 0.5+0.5*sin(u_time*4);
    vec3 gold = vec3(1,0.85,0.1);
    material.diffuse = mix(heat,gold,pulse*0.7);
    material.emissive = gold*pulse*0.5;
    }
    }
    `
    })
    tileset.customShader = customShader;

    // 驱动动画时间
    viewer.scene.preRender.addEventListener(()=>{
    customShader.setUniform("u_time", performance.now()/1000)
    })

    // 鼠标悬停更新楼层高度
    const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
    handler.setInputAction(move=>{
    const pos = viewer.scene.pickPosition(move.endPosition);
    if(Cesium.defined(pos)){
    const cart = Cesium.Cartographic.fromCartesian(pos);
    customShader.setUniform("u_hoverH", cart.height);
    }else{
    customShader.setUniform("u_hoverH", -1);
    }
    },Cesium.ScreenSpaceEventType.MOUSE_MOVE)

    viewer.camera.flyTo({destination:tileset.boundingSphere.center,orientation:{heading:Cesium.Math.toRadians(45),pitch:Cesium.Math.toRadians(-30),roll:0}})
    return {tileset,clipPlanes,customShader}
    }


    七、性能调优清单

  • 加载优化:大范围场景开启skipLevelOfDetail,室内漫游关闭;合理调高maximumScreenSpaceError减少瓦片加载数量
  • 内存管控:按设备显存设置maximumMemoryUsage,定期监控显存使用率,超过 90% 降低上限
  • 剖切优化:远距离浏览时动态关闭clippingPlanes.enabled,减少 GPU 平面计算
  • 着色器优化:简化 GLSL 分支判断,降低 uniform 每帧更新频率,非动画参数固定值不实时刷新
  • 渲染调试:上线前关闭所有 debug 调试开关,避免额外线框绘制消耗性能

  • 本篇总结

  • ClippingPlaneCollection实现三维模型任意角度剖切,支持单平面水平切楼、多平面组合剖切,滑块交互动态调节切割高度,区分并集 / 交集两种剔除模式,切面可自定义描边。
  • CustomShader自定义 GPU 着色器通过 GLSL 代码实现基础样式无法完成的高级特效,uniform 完成 JS 与着色器数据互通,高度热力、脉冲发光是数字孪生高频业务效果。
  • 全套debugShow调试工具可视化瓦片包围盒、几何误差、瓦片边界,快速定位瓦片缺失、层级切换、加载卡顿等渲染问题。
  • skipLevelOfDetail跳级加载跳过中间瓦片层级,减少网络请求,仅支持 REPLACE 细化瓦片,鸟瞰飞行场景大幅提升加载速度。
  • maximumMemoryUsage限制显存占用,防止大 BIM / 倾斜摄影模型 OOM 崩溃;瓦片生命周期事件实现加载监控、失败捕获、显存统计面板。
  • 多特性可组合叠加:剖切 + 热力着色器 + 跳级加载实现完整建筑剖面分析系统,是智慧城市、园区 BIM 项目标准解决方案。
  • 课后实操练习

  • 剖切实验:分别实现水平切顶部、垂直切侧面、双平面对角剖切,对比 unionClippingRegions 两种模式视觉差异。
  • 着色器开发:编写高度渐变热力着色器,增加时间 uniform 实现颜色缓慢流动呼吸动画。
  • 瓦片调试:依次开启全部 debug 调试开关,缩放观察瓦片层级切换、包围盒分布规律。
  • 内存监控:实现控制台显存监控面板,调低内存上限观察引擎自动卸载远距离瓦片行为。
  • 综合进阶:整合剖切滑块、热力着色、悬停脉冲、跳级加载,完成完整建筑剖面浏览 Demo。
  • 下一篇预告

    CesiumJS 从入门到精通 19:光影魔术师:光照模型与后期处理特效

    讲解全局太阳光、环境光遮蔽 AO、屏幕空间反射 SSR,使用PostProcessStage实现泛光、景深、电影级调色后期特效,打造真实写实三维渲染氛围。

    赞(0)
    未经允许不得转载:171主机测评 » 第18章:CesiumJS 从入门到精通 18:建筑师的工具:3D Tiles 变换裁剪与自定义着色器
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址