有机猴灬残暴SamaLife · Code · Explore
返回文章
ARTICLE

Cesium 新版本中创建自定义 Material

以流动线和水波纹为例,整理 MaterialProperty、uniforms 与 GLSL source 之间的对应关系。

开发说明

Cesium 自定义材质最难理解的并不是模板,而是 Property、uniforms 和 GLSL source 三者如何传值。把这个关系理顺以后,流动线、水波纹以及扫描圆的结构几乎一致。

MaterialProperty 的职责

类中保存可响应变化的参数,getType 返回材质名,getValue 在每次渲染时把最新值交给 uniforms。definitionChanged 则让 Cesium 知道参数发生了变化。

CODE
export class FlowLineMaterialProperty {
  _definitionChanged = new Event()
  constructor(options = {}) {
    this.color = options.color ?? Color.WHITE
    this.speed = options.speed ?? 1
    this.repeat = options.repeat ?? new Cartesian2(1, 1)
  }
  getType() { return "FlowLine" }
  getValue(time, result = {}) {
    result.color = Property.getValueOrClonedDefault(this._color, time, Color.WHITE)
    result.speed = Property.getValueOrDefault(this._speed, time, 1)
    result.repeat = Property.getValueOrDefault(this._repeat, time, new Cartesian2(1, 1))
    return result
  }
}

注册材质

uniforms 的名字必须与 getValue 返回值以及 source 内使用的变量一致。真正决定视觉效果的是 source,其余代码主要负责把参数安全地送进去。

CODE
Material._materialCache.addMaterial("FlowLine", {
  fabric: {
    type: "FlowLine",
    uniforms: { color: Color.WHITE, speed: 1, repeat: new Cartesian2(1, 1) },
    source: "czm_material czm_getMaterial(czm_materialInput input) { /* GLSL */ }",
  },
  translucent: true,
})

容易踩坑的地方

材质名重复会覆盖缓存;uniform 名称拼错不会给出友好错误;高频创建 Property 会制造额外垃圾回收。推荐在模块初始化时只注册一次材质,业务侧只创建 Property 实例。