问题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()