当前位置: 首页 > 工具软件 > deck.gl > 使用案例 >

Deck.gl 中着色器属性(attribute)更新原理

史烈
2023-12-01

问题1:Deck.gl中vertex-shader中的attribute数据是如何通过layer.props更新的?

问题2: layer的props中函数型accessor是如何传入到vertex-shader中的?

 

首先,这两个问题并不太容易理解。第一个问题的背景如下:

Deck.lg很多图层(Layer)绘制是通过将几何对象的坐标通过attribute传入到vertex-shader中,比如ArcLayer的shader片段如下:

export default `\

#define SHADER_NAME arc-layer-vertex-shader

attribute vec3 positions;

attribute vec4 instanceSourceColors;

attribute vec4 instanceTargetColors;

attribute vec3 instanceSourcePositions;

// ...

void main(void) {

  geometry.worldPosition = instanceSourcePositions;

  geometry.worldPositionAlt = instanceTargetPositions;

  vec3 source = project_position(instanceSourcePositions, instanceSourcePositions64Low);

  vec3 target = project_position(instanceTargetPositions, instanceTargetPositions64Low);

 

而图层的props定义如下

 const layer = new ArcLayer({
    id: 'arc-layer',
    data,
    pickable: true,
    getWidth: 12,
    getSourcePosition: d => d.from.coordinates,
    getTargetPosition: d => d.to.coordinates,
    getSourceColor: d => [Math.sqrt(d.inbound), 140, 0],
    getTargetColor: d => [Math.sqrt(d.outbound), 140, 0],
  });

那么ArcLayer构造时data,SourcePositions是如何传到shader中的呢?

而d=>d.from.coordinates又是如何对应从data对应的json或binaryBuffer中正确地取到数据的呢?

a) Layer会通过AttributeManager在图层管理着色器的Attributes

AttributeManager会帮助Layer自动生成管理attribute。可以通过数组生成迭代器,并更新为定点着色器的一组attribute,在必要时基于data array更新着色器attribute。要达到以上效果,在构建Layer时,需要进行如下操作:
    1)调用AttributeManager.add()注册动态定点属性(dynamic vertex attributes)
    2)当相关数据填充到图层中或发生变化时,Layer会调用AttributeManager.invalidate()进行定点着色器属性更新
    3)在图层绘制(redners)之前,Layer会调用 AttributeManager.update()确保着色器所需的attributes被构建出来

 

b)AttributeManager.upate在注册attributes,找props中名称相同的prop:

 for (const attributeName in this.attributes) {

      const attribute = this.attributes[attributeName];

 if (attribute.setExternalBuffer(buffers[attributeName])) {

        // Step 1: try update attribute directly from external buffers

      } else if (attribute.setBinaryValue(buffers[accessorName], data.startIndices)) {

        // Step 2: try set packed value from external typed array

      } else if (!buffers[accessorName] && attribute.setConstantValue(props[accessorName])) {

 

c)Attribute最终都会通过setData(opts)进行着色器属性更新

 

d)Attribute通过_autoUpdater对props中函数类Accessor进行迭代器构建

关键是在Attribute的构造函数中下面这段代码:

    Object.assign(this.settings, {

      transition,

      noAlloc,

      update: update || (accessor && this._autoUpdater),

如果accessor不为空,怎update函数就采用_autoUpdater函数

e)在_autoUpdater函数中会判断accessor的类型,如果是函数则会创建数据访问迭代器

    const {accessor, transform} = settings;

    const accessorFunc =

      state.binaryAccessor || (typeof accessor === 'function' ? accessor : props[accessor]);

  // ...

 const {iterable, objectInfo} = createIterable(data, startRow, endRow);

下面就可以通过构造出来的数据迭代器逐个取出数据放入缓存中

for (const object of iterable) {

      objectInfo.index++;

      let objectValue = accessorFunc(object, objectInfo);

  // ...

attribute._normalizeValue(objectValue, value, i);

e)调用attributeTransitionManager.update进行着色器attribute数据传送

 

  // Called by layer manager

  // if this layer is new (not matched with an existing layer) oldProps will be empty object

f)Layer._update()->Layer._updateState()->Layer.updateAttributes()->_setModelAttributes()->model.setAttributes()

 

 类似资料: