2025Cesium进阶教程(3) 发光流动线实例讲解,实现自定义 MaterialProperty(上)

在 Cesium 开发中,实体(Entity)的材质系统是实现个性化可视化效果的核心。Cesium 内置了丰富的材质类型,但面对复杂的业务需求(如动态流动的发光线、渐变纹理等),自定义 MaterialProperty 成为必然选择。

图片

若要实现自定义材质属性(MaterialProperty),核心是继承并实现 Cesium 提供的抽象基类。

本文将基于 “发光流动线” 需求,完整拆解自定义 MaterialProperty 的实现逻辑。

一、核心前提:自定义 MaterialProperty 的底层要求

Cesium 的 MaterialProperty 是抽象类,需强制实现 2 个只读属性 和 3 个核心方法,同时要遵循其响应式机制(属性变更触发视图更新)和材质缓存注册规则。

图片

我们参考cesium源码中的colorMaterialProperty,可以看到他有两个只读的属性和 三个方法:

分析这段代码并结合相关文档以及cesium运行机制我们发现定义一个实体材质需要注意以下方面

1、私有变量规范:在构造函数中,我们发现有带_的变量,这种变量属于材质属性中的私有变量,外部不要去直接访问与修改,而是通过不带下划线的变量,比如color,再去修改属性

2、响应式实现:Object.defineProperties(ColorMaterialProperty.prototype,...}中的内容,就是使用createPropertyDescriptor去对_变量做更新,更新之后的事件触发等。

3、必填属性约束

  • 定义isConstant属性:这个属性用来控制这个材质属性是否随clock的变化而变化
  • 定义definitionChanged属性,这个属性是一个event,用来监听变化核心方法约束:需实现三个核心方法:

4、必填属性约束

  • getType:返回材质唯一标识,用于匹配缓存中的材质;
  • getValue:获取当前时间对应的材质属性值(传给着色器的 uniform 变量);
  • equals:判断两个材质属性是否等价,用于 Cesium 识别材质是否变化;

5、材质注册:最终需将自定义材质注册到 Cesium 材质缓存,确保渲染时能被正确加载;在这个阶段,可以自定义着色器

图片

二、搭建 PolylineFlowMaterialProperty 基础框架

第一步:搭建类的基础框架

先定义 PolylineFlowMaterialProperty 类,明确静态属性、构造函数、必填属性和方法的机构:

class PolylineFlowMaterialProperty {
  // 静态材质类型名,用于材质缓存注册(全局唯一)
  static materialType = "PolylineFlow";

  constructor(options) {}

  // 只读属性:是否为常量(不随时间变化)
  get isConstant() {}

  // 只读属性:属性变化事件
  get definitionChanged() {}

  // 获取材质类型名
  getType(time) {}

  // 获取指定时间的材质参数
  getValue(time, result) {}

  // 判断两个材质属性是否等价
  equals(other) {}
}
三、准备流动线核心着色器(Shader)

着色器是材质渲染效果的核心,以下 shader 已实现 “发光流动 + 拖尾” 效果,需外部传入 3 个关键参数(后续会通过属性定义关联):

  • color:流动线基础颜色;
  • glowPower:发光强度;
  • taperPower:颜色 / 亮度递减强度;
czm_material czm_getMaterial(czm_materialInput materialInput)
{
    vec2 st = materialInput.st;
    czm_material material = czm_getDefaultMaterial(materialInput);
    // 动态时间参数,用于流动效果
    float iTime = fract(czm_frameNumber / 60.0);
    iTime = clamp(iTime, 0.0, 1.0);
    // 颜色基础设置(需要外部传入 color)
    vec3 baseColor = color.rgb;
    // 拖尾参数设置(st.s方向)可以通过外界传入
    float headLength = 0.05;
    float tailLength = 0.1;
    // 横向宽度控制(st.t方向),中心在0.5处
    float verticalWidth = 0.5;
    float glowFalloff = 1.0 - smoothstep(0.0, verticalWidth, abs(st.t - 0.5));
    // 拖尾遮罩计算(平滑拖尾)
    float headMask = smoothstep(iTime, iTime + headLength, st.s);
    float tailMask = 1.0 - smoothstep(0.0, tailLength, iTime - st.s);
    float flowMask = clamp(tailMask * (1.0 - headMask), 0.0, 1.0);
    // 应用遮罩增强发光
    vec3 diffuseColor = baseColor;
    vec3 emissionColor = baseColor * (glowFalloff * flowMask * 6.0);
    float alpha = glowFalloff * flowMask * color.a * 0.6;
    // 最终输出
    material.diffuse = diffuseColor;
    material.emission = emissionColor * 0.4;
    material.alpha = alpha;
    return material;
}
四、定义响应式属性(关联 Shader 参数)

为了让 colorglowPowertaperPower 三个参数支持 “修改后自动更新视图”,必须使用 Object.defineProperties 定义属性描述符 ——Cesium.createPropertyDescriptor 会自动绑定私有变量和 definitionChanged 事件,这是 Cesium 响应式机制的核心(ES6 类字段无法替代,因其不能定义属性描述符):

Object.defineProperties(PolylineFlowMaterialProperty.prototype, {
  color: Cesium.createPropertyDescriptor("color"),
  glowPower: Cesium.createPropertyDescriptor("glowPower"),
  taperPower: Cesium.createPropertyDescriptor("taperPower"),
});

至此,自定义流动线材质的 “基础骨架” 已搭建完成,包括类结构、着色器核心、响应式属性定义。下一篇将聚焦构造函数、只读属性、核心方法的具体实现,以及最终的材质注册流程。

看不明白没关系,点这里可以查看视频解析👇

3.cesium进阶教程:封装自定义materialProperty_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1yrs1zEE79?spm_id_from=333.788.videopod.episodes&vd_source=8c32bbccf29164719fe4e4c40c768444&p=3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值