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

本文详细探讨了Deck.gl中如何通过layer.props更新vertex-shader中的attribute数据,以及layer中函数型accessor如何传入到vertex-shader。主要涉及AttributeManager的角色,包括添加动态属性、数据更新、属性设置等步骤。通过分析Attribute的构造过程和_autoUpdater函数,揭示了数据迭代器的创建和数据传递到着色器attribute的过程。

问题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;

<template> <BaseMap @map-loaded="mapLoaded" :class="`${prefixCls}`"> <PlanningLegend legend-type="Stops" :class="`${prefixCls}__legend`" :legend-Data="legendData" /> </BaseMap> </template> <script setup lang="ts"> defineOptions({ name: 'StopsEvaluateMap' }) import * as turf from '@turf/turf' import { createDataTypeStopsLayer } from '@/components/PlanningComps/map' import { initializeMapLayers } from '@/components/PlanningComps/map.ts' import { getPlanLine } from '@/api/planning/line/index' import type { StationPathDtoItem } from '@/api/planning/stop/type' import mapboxgl, { Map as MapboxMap } from 'mapbox-gl' import BaseMap from '@/components/BaseMap/index.vue' import 'mapbox-gl/dist/mapbox-gl.css' import { useRoute, useRouter } from 'vue-router' const { t } = useI18n() const route = useRoute() const router = useRouter() const { getPrefixCls } = useDesign() const prefixCls = getPrefixCls('stop-evaluate-map') const props = defineProps<{ stationPathDto: StationPathDtoItem[] }>() const baseMap = shallowRef<MapboxMap>() const deckMap = shallowRef<DeckGLMap>() // 使用RBush空间索引优化 const legendData = [ { name: 2643, color: '#ff0000' }, { name: 1762, color: '#ffc402' }, { name: 881, color: '#4e79e9' } ] // od两点直线转为有弧度和高度的曲线 const createSmoothCurvedLine = ( start: [number, number], end: [number, number], options = { arcHeight: 0.3, // 弧高系数,推荐范围0.3~1.2 segments: 120 // 曲线平滑度 // 80~200 } ): turf.Feature<turf.LineString> => { // 计算中间控制点(形成弧形) const midPoint = turf.midpoint(turf.point(start), turf.point(end)).geometry.coordinates // 计算垂直偏移点(创建弧高) const bearing = turf.bearing(turf.point(start), turf.point(end)) const offsetPoint = turf.destination( turf.point(midPoint), turf.distance(turf.point(start), turf.point(end)) * options.arcHeight, bearing + 90 ).geometry.coordinates // 生成三次贝塞尔曲线点 const curvePoints: [number, number, number][] = [] for (let i = 0; i <= options.segments; i++) { const t = i / options.segments // 三次贝塞尔曲线方程: $$ B(t) = (1-t)^3P_0 + 3(1-t)^2tP_1 + 3(1-t)t^2P_2 + t^3P_3 $$ const x = Math.pow(1 - t, 3) * start[0] + 3 * Math.pow(1 - t, 2) * t * offsetPoint[0] + 3 * (1 - t) * Math.pow(t, 2) * offsetPoint[0] + Math.pow(t, 3) * end[0] const y = Math.pow(1 - t, 3) * start[1] + 3 * Math.pow(1 - t, 2) * t * offsetPoint[1] + 3 * (1 - t) * Math.pow(t, 2) * offsetPoint[1] + Math.pow(t, 3) * end[1] // 添加抛物线高度 const z = 4 * options.arcHeight * t * (1 - t) // 抛物线方程: $z = 4h t(1-t)$ curvePoints.push([x, y, z]) } return turf.lineString(curvePoints) } // 创建站点od飞线 const createStopOdLine = (map: MapboxMap, stopItem: StationPathDtoItem, stopIndex) => { try { // const flyline = createSmoothCurvedLine( // [stopItem.startLongitude, stopItem.startLatitude], // [stopItem.endLongitude, stopItem.endLatitude], // { // arcHeight: 0.8, // segments: 180 // } // ) return true } catch (error) { console.error(`创建数据源失败`, error) return false } } // 地图加载完成 const mapLoaded = (map: MapboxMap) => { baseMap.value = map // 批量创建线要素 // props.stationPathDto.forEach((stopItem, stopIndex) => { // if (stopItem?.startLatitude && stopItem?.endLongitude) { // createStopOdLine(map, stopItem, stopIndex) // } // }) } // 组件卸载时清理 onUnmounted(() => { // if (baseMap.value && baseMap.value.getStyle()) { // props.stationPathDto.forEach((stopItem) => { // const layerId = `pulse-lines-layer-${stopItem.id}` // const sourceId = `pulse-lines-${stopItem.id}` // if (baseMap.value.getLayer(layerId)) { // baseMap.value.removeLayer(layerId) // } // if (baseMap.value.getSource(sourceId)) { // baseMap.value.removeSource(sourceId) // } // }) // if (baseMap.value) { // baseMap.value.remove() // } // } }) onMounted(() => {}) watchEffect(() => { debugger console.log(props.stationPathDto) if (props.stationPathDto && baseMap.value) { } }) </script> <style lang="scss" scoped> $prefix-cls: #{$namespace}-stop-evaluate-map; .#{$prefix-cls} { &__legend { position: absolute; right: 482px; bottom: 14px; } } </style>在vue3项目中对于大批量的脉冲图如何使用使用deck.gl实现
最新发布
09-04
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山中涛大爷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值