diff --git a/.changeset/polite-apples-rule.md b/.changeset/polite-apples-rule.md new file mode 100644 index 0000000000..d158d296d4 --- /dev/null +++ b/.changeset/polite-apples-rule.md @@ -0,0 +1,5 @@ +--- +'@antv/l7-core': patch +--- + +fix: 在 WebGL2 拾取事件冒泡延迟问题 diff --git a/packages/core/src/services/interaction/PickingService.ts b/packages/core/src/services/interaction/PickingService.ts index 130acd02ec..9090c42b6e 100644 --- a/packages/core/src/services/interaction/PickingService.ts +++ b/packages/core/src/services/interaction/PickingService.ts @@ -177,7 +177,7 @@ export default class PickingService implements IPickingService { { x, y, lngLat, type, target }: IInteractionTarget, ) => { let isPicked = false; - const { readPixelsAsync, getViewportSize } = this.rendererService; + const { readPixels, readPixelsAsync, getViewportSize, queryVerdorInfo } = this.rendererService; const { width, height } = getViewportSize(); const { enableHighlight, enableSelect } = layer.getLayerConfig(); const xInDevicePixel = x * DOM.DPR; @@ -190,15 +190,33 @@ export default class PickingService implements IPickingService { ) { return false; } - const pickedColors: Uint8Array | undefined = await readPixelsAsync({ - x: Math.floor(xInDevicePixel / this.pickBufferScale), - // 视口坐标系原点在左上,而 WebGL 在左下,需要翻转 Y 轴 - y: Math.floor((height - (y + 1) * DOM.DPR) / this.pickBufferScale), - width: 1, - height: 1, - data: new Uint8Array(1 * 1 * 4), - framebuffer: this.pickingFBO, - }); + + let pickedColors: Uint8Array | undefined; + + // readPixelsAsync 比 readPixels 慢,会造成拾取事件冒泡延迟,优先使用 readPixelsAsync,WebGPU 只支持 readPixelsAsync API + const isWebGPU = queryVerdorInfo() === 'WebGPU'; + if (isWebGPU) { + pickedColors = await readPixelsAsync({ + x: Math.floor(xInDevicePixel / this.pickBufferScale), + // 视口坐标系原点在左上,而 WebGL 在左下,需要翻转 Y 轴 + y: Math.floor((height - (y + 1) * DOM.DPR) / this.pickBufferScale), + width: 1, + height: 1, + data: new Uint8Array(1 * 1 * 4), + framebuffer: this.pickingFBO, + }); + } else { + pickedColors = readPixels({ + x: Math.floor(xInDevicePixel / this.pickBufferScale), + // 视口坐标系原点在左上,而 WebGL 在左下,需要翻转 Y 轴 + y: Math.floor((height - (y + 1) * DOM.DPR) / this.pickBufferScale), + width: 1, + height: 1, + data: new Uint8Array(1 * 1 * 4), + framebuffer: this.pickingFBO, + }); + } + this.pickedColors = pickedColors; if (pickedColors[0] !== 0 || pickedColors[1] !== 0 || pickedColors[2] !== 0) { diff --git a/packages/core/src/services/renderer/passes/PixelPickingPass.ts b/packages/core/src/services/renderer/passes/PixelPickingPass.ts index d46ade8555..750b6d3c7c 100644 --- a/packages/core/src/services/renderer/passes/PixelPickingPass.ts +++ b/packages/core/src/services/renderer/passes/PixelPickingPass.ts @@ -11,6 +11,8 @@ import BaseNormalPass from './BaseNormalPass'; /** * color-based PixelPickingPass * @see https://github.com/antvis/L7/blob/next/dev-docs/PixelPickingEngine.md + * @deprecated + * 目前未使用 */ export default class PixelPickingPass< InitializationOptions = {}, diff --git a/packages/renderer/src/device/index.ts b/packages/renderer/src/device/index.ts index 3095bd0060..b0e37912dc 100644 --- a/packages/renderer/src/device/index.ts +++ b/packages/renderer/src/device/index.ts @@ -302,7 +302,19 @@ export default class DeviceRendererService implements IRendererService { height, new Uint8Array(width * height * 4), ) as Uint8Array; + + // Since we use U8_RGBA_RT format in render target, need to change bgranorm -> rgba here. + if (this.viewportOrigin !== ViewportOrigin.LOWER_LEFT) { + for (let j = 0; j < result.length; j += 4) { + // Switch b and r components. + const t = result[j]; + result[j] = result[j + 2]; + result[j + 2] = t; + } + } + readback.destroy(); + return result; };