From ac0e64cf6a707450be05cdcb27889b9abd40ed53 Mon Sep 17 00:00:00 2001 From: "yuqi.pyq" Date: Tue, 2 Jan 2024 17:25:29 +0800 Subject: [PATCH] fix: heatmap grid3d in webgpu --- examples/demos/webgpu/heatmap_grid.ts | 59 +++++++++++++++++ examples/demos/webgpu/heatmap_grid3d.ts | 64 +++++++++++++++++++ examples/demos/webgpu/index.ts | 2 + .../core/src/services/renderer/ITexture2D.ts | 6 ++ packages/layers/src/heatmap/models/grid.ts | 29 ++++----- packages/layers/src/heatmap/models/grid3d.ts | 29 ++++----- packages/layers/src/heatmap/models/heatmap.ts | 4 +- .../heatmap/shaders/grid3d/grid_3d_frag.glsl | 9 +++ .../heatmap/shaders/grid3d/grid_3d_vert.glsl | 12 ++-- .../heatmap/shaders/heatmap/heatmap_vert.glsl | 3 + .../renderer/src/device/DeviceTexture2D.ts | 3 +- 11 files changed, 178 insertions(+), 42 deletions(-) create mode 100644 examples/demos/webgpu/heatmap_grid.ts create mode 100644 examples/demos/webgpu/heatmap_grid3d.ts diff --git a/examples/demos/webgpu/heatmap_grid.ts b/examples/demos/webgpu/heatmap_grid.ts new file mode 100644 index 0000000000..d4fc4ed19c --- /dev/null +++ b/examples/demos/webgpu/heatmap_grid.ts @@ -0,0 +1,59 @@ +import { HeatmapLayer, Scene } from '@antv/l7'; +import * as allMap from '@antv/l7-maps'; + +export function MapRender(option: { map: string; renderer: string }) { + const scene = new Scene({ + id: 'map', + renderer: option.renderer === 'device' ? 'device' : 'regl', + enableWebGPU: true, + shaderCompilerPath: '/glsl_wgsl_compiler_bg.wasm', + map: new allMap[option.map || 'Map']({ + style: 'light', + center: [121.434765, 31.256735], + zoom: 14.83, + }), + }); + + scene.on('loaded', () => { + fetch( + 'https://gw.alipayobjects.com/os/basement_prod/513add53-dcb2-4295-8860-9e7aa5236699.json', + ) + .then((res) => res.json()) + .then((data) => { + const layer = new HeatmapLayer({ autoFit: true }) + .source(data, { + transforms: [ + { + type: 'hexagon', + size: 100, + field: 'h12', + method: 'sum', + }, + ], + }) + .size('sum', [0, 60]) + .shape('squareColumn') + .style({ + opacity: 1, + }) + .color( + 'sum', + [ + '#094D4A', + '#146968', + '#1D7F7E', + '#289899', + '#34B6B7', + '#4AC5AF', + '#5FD3A6', + '#7BE39E', + '#A1EDB8', + '#CEF8D6', + ].reverse(), + ); + scene.startAnimate(); + scene.addLayer(layer); + scene.render(); + }); + }); +} diff --git a/examples/demos/webgpu/heatmap_grid3d.ts b/examples/demos/webgpu/heatmap_grid3d.ts new file mode 100644 index 0000000000..e56f7d15d9 --- /dev/null +++ b/examples/demos/webgpu/heatmap_grid3d.ts @@ -0,0 +1,64 @@ +import { HeatmapLayer, Scene } from '@antv/l7'; +import * as allMap from '@antv/l7-maps'; + +export function MapRender(option: { map: string; renderer: string }) { + const scene = new Scene({ + id: 'map', + renderer: option.renderer === 'device' ? 'device' : 'regl', + enableWebGPU: true, + shaderCompilerPath: '/glsl_wgsl_compiler_bg.wasm', + map: new allMap[option.map || 'Map']({ + style: 'light', + center: [121.434765, 31.256735], + zoom: 14.83, + }), + }); + + scene.on('loaded', () => { + fetch( + 'https://gw.alipayobjects.com/os/basement_prod/d3564b06-670f-46ea-8edb-842f7010a7c6.json', + ) + .then((res) => res.json()) + .then((data) => { + const layer = new HeatmapLayer({ autoFit: true }) + .source(data, { + transforms: [ + { + type: 'grid', + size: 150000, + field: 'mag', + method: 'sum', + }, + ], + }) + .size('sum', (sum) => { + return sum * 2000; + }) + .shape('hexagonColumn') + .style({ + coverage: 0.8, + angle: 0, + }) + .color( + 'count', + [ + '#0B0030', + '#100243', + '#100243', + '#1B048B', + '#051FB7', + '#0350C1', + '#0350C1', + '#0072C4', + '#0796D3', + '#2BA9DF', + '#30C7C4', + '#6BD5A0', + '#A7ECB2', + '#D0F4CA', + ].reverse(), + ); + scene.addLayer(layer); + }); + }); +} diff --git a/examples/demos/webgpu/index.ts b/examples/demos/webgpu/index.ts index 66fcb42be7..808006894c 100644 --- a/examples/demos/webgpu/index.ts +++ b/examples/demos/webgpu/index.ts @@ -2,6 +2,8 @@ export { MapRender as boids } from './boids'; export { MapRender as compute_texture } from './compute_texture'; export { MapRender as WebGL_IDW } from './idw'; // export { MapRender as line_normal } from './line_normal'; +export { MapRender as heatmap_grid } from './heatmap_grid'; +export { MapRender as heatmap_grid3d } from './heatmap_grid3d'; export { MapRender as heatmap_normal } from './heatmap_normal'; export { MapRender as point_column } from './point_column'; export { MapRender as point_fill } from './point_fill'; diff --git a/packages/core/src/services/renderer/ITexture2D.ts b/packages/core/src/services/renderer/ITexture2D.ts index 2c0b144b7b..3f695dc683 100644 --- a/packages/core/src/services/renderer/ITexture2D.ts +++ b/packages/core/src/services/renderer/ITexture2D.ts @@ -71,6 +71,12 @@ export interface ITexture2DInitializationOptions { wrapT?: gl.REPEAT | gl.CLAMP_TO_EDGE | gl.MIRRORED_REPEAT; aniso?: number; + /** + * unorm means unsigned normalized which is fancy way of saying + * the value will be converted from an unsigned byte with values from (0 to 255) to a floating point value with values (0.0 to 1.0). + */ + unorm?: boolean; + /** * 以下为 gl.pixelStorei 参数 * @see https://developer.mozilla.org/zh-CN/docs/Web/API/WebGLRenderingContext/pixelStorei diff --git a/packages/layers/src/heatmap/models/grid.ts b/packages/layers/src/heatmap/models/grid.ts index 66e3dafbf4..d82ecf43ab 100644 --- a/packages/layers/src/heatmap/models/grid.ts +++ b/packages/layers/src/heatmap/models/grid.ts @@ -1,16 +1,10 @@ -import type { - IEncodeFeature, - IModel, - IModelUniform} from '@antv/l7-core'; -import { - AttributeType, - gl -} from '@antv/l7-core'; +import type { IEncodeFeature, IModel, IModelUniform } from '@antv/l7-core'; +import { AttributeType, gl } from '@antv/l7-core'; import BaseModel from '../../core/BaseModel'; import type { IHeatMapLayerStyleOptions } from '../../core/interface'; import { HeatmapGridTriangulation } from '../../core/triangulation'; -import grid_vert from '../shaders/grid/grid_vert.glsl'; import grid_frag from '../shaders/grid/grid_frag.glsl'; +import grid_vert from '../shaders/grid/grid_vert.glsl'; export default class GridModel extends BaseModel { public getUninforms(): IModelUniform { const commoninfo = this.getCommonUniformsInfo(); @@ -19,10 +13,14 @@ export default class GridModel extends BaseModel { return { ...commoninfo.uniformsOption, ...attributeInfo.uniformsOption, - } + }; } - protected getCommonUniformsInfo(): { uniformsArray: number[]; uniformsLength: number; uniformsOption: { [key: string]: any; }; } { + protected getCommonUniformsInfo(): { + uniformsArray: number[]; + uniformsLength: number; + uniformsOption: { [key: string]: any }; + } { const { opacity, coverage, angle } = this.layer.getLayerConfig() as IHeatMapLayerStyleOptions; const commonOptions = { @@ -34,10 +32,9 @@ export default class GridModel extends BaseModel { u_coverage: coverage || 0.9, u_angle: angle || 0, }; - - const commonBufferInfo = this.getUniformsBufferInfo(commonOptions); - return commonBufferInfo; - + + const commonBufferInfo = this.getUniformsBufferInfo(commonOptions); + return commonBufferInfo; } public async initModels(): Promise { @@ -61,7 +58,7 @@ export default class GridModel extends BaseModel { name: 'pos', // 顶点经纬度位置 type: AttributeType.Attribute, descriptor: { - shaderLocation:10, + shaderLocation: 10, name: 'a_Pos', buffer: { usage: gl.DYNAMIC_DRAW, diff --git a/packages/layers/src/heatmap/models/grid3d.ts b/packages/layers/src/heatmap/models/grid3d.ts index a9c26e6044..1c438c659b 100644 --- a/packages/layers/src/heatmap/models/grid3d.ts +++ b/packages/layers/src/heatmap/models/grid3d.ts @@ -1,17 +1,11 @@ -import type { - IEncodeFeature, - IModel, - IModelUniform} from '@antv/l7-core'; -import { - AttributeType, - gl -} from '@antv/l7-core'; +import type { IEncodeFeature, IModel, IModelUniform } from '@antv/l7-core'; +import { AttributeType, gl } from '@antv/l7-core'; import BaseModel from '../../core/BaseModel'; +import { ShaderLocation } from '../../core/CommonStyleAttribute'; import type { IHeatMapLayerStyleOptions } from '../../core/interface'; import { PointExtrudeTriangulation } from '../../core/triangulation'; -import grid_3d_vert from '../shaders/grid3d/grid_3d_vert.glsl'; import grid_3d_frag from '../shaders/grid3d/grid_3d_frag.glsl'; -import { ShaderLocation } from '../../core/CommonStyleAttribute'; +import grid_3d_vert from '../shaders/grid3d/grid_3d_vert.glsl'; export default class Grid3DModel extends BaseModel { public getUninforms(): IModelUniform { const commoninfo = this.getCommonUniformsInfo(); @@ -20,10 +14,14 @@ export default class Grid3DModel extends BaseModel { return { ...commoninfo.uniformsOption, ...attributeInfo.uniformsOption, - } + }; } - protected getCommonUniformsInfo(): { uniformsArray: number[]; uniformsLength: number; uniformsOption: { [key: string]: any; }; } { + protected getCommonUniformsInfo(): { + uniformsArray: number[]; + uniformsLength: number; + uniformsOption: { [key: string]: any }; + } { const { opacity, coverage, angle } = this.layer.getLayerConfig() as IHeatMapLayerStyleOptions; const commonOptions = { @@ -35,10 +33,9 @@ export default class Grid3DModel extends BaseModel { u_coverage: coverage || 0.9, u_angle: angle || 0, }; - - const commonBufferInfo = this.getUniformsBufferInfo(commonOptions); - return commonBufferInfo; - + + const commonBufferInfo = this.getUniformsBufferInfo(commonOptions); + return commonBufferInfo; } public async initModels(): Promise { diff --git a/packages/layers/src/heatmap/models/heatmap.ts b/packages/layers/src/heatmap/models/heatmap.ts index 6d86b6a91c..3e4de5f1b6 100644 --- a/packages/layers/src/heatmap/models/heatmap.ts +++ b/packages/layers/src/heatmap/models/heatmap.ts @@ -421,7 +421,8 @@ export default class HeatMapModel extends BaseModel { this.layer.getLayerConfig() as IHeatMapLayerStyleOptions; const imageData = generateColorRamp(rampColors as IColorRamp); this.colorTexture = createTexture2D({ - data: new Uint8Array(imageData.data), + data: imageData.data, + usage: TextureUsage.SAMPLED, width: imageData.width, height: imageData.height, wrapS: gl.CLAMP_TO_EDGE, @@ -429,6 +430,7 @@ export default class HeatMapModel extends BaseModel { min: gl.NEAREST, mag: gl.NEAREST, flipY: false, + unorm: true, }); this.preRampColors = rampColors; diff --git a/packages/layers/src/heatmap/shaders/grid3d/grid_3d_frag.glsl b/packages/layers/src/heatmap/shaders/grid3d/grid_3d_frag.glsl index c0a9667efe..53e1df7a98 100644 --- a/packages/layers/src/heatmap/shaders/grid3d/grid_3d_frag.glsl +++ b/packages/layers/src/heatmap/shaders/grid3d/grid_3d_frag.glsl @@ -1,6 +1,15 @@ in vec4 v_color; +layout(std140) uniform commonUniforms { + vec2 u_radius; + float u_opacity; + float u_coverage; + float u_angle; +}; + +#pragma include "scene_uniforms" #pragma include "picking" + out vec4 outputColor; void main() { outputColor = v_color; diff --git a/packages/layers/src/heatmap/shaders/grid3d/grid_3d_vert.glsl b/packages/layers/src/heatmap/shaders/grid3d/grid_3d_vert.glsl index 33001b01df..8225f654ce 100644 --- a/packages/layers/src/heatmap/shaders/grid3d/grid_3d_vert.glsl +++ b/packages/layers/src/heatmap/shaders/grid3d/grid_3d_vert.glsl @@ -5,10 +5,10 @@ layout(location = 10) in vec3 a_Pos; layout(location = 13) in vec3 a_Normal; layout(std140) uniform commonUniforms { - vec2 u_radius; - float u_opacity; - float u_coverage; - float u_angle; + vec2 u_radius; + float u_opacity; + float u_coverage; + float u_angle; }; out vec4 v_color; @@ -18,12 +18,10 @@ out vec4 v_color; #pragma include "light" #pragma include "picking" - void main() { mat2 rotationMatrix = mat2(cos(u_angle), sin(u_angle), -sin(u_angle), cos(u_angle)); vec2 offset =(vec2(a_Position.xy * u_radius * rotationMatrix * u_coverage)); - if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x vec2 lnglat = unProjectFlat(a_Pos.xy + offset); // 经纬度 @@ -44,7 +42,5 @@ void main() { gl_Position = project_common_position_to_clipspace(project_pos); } - - setPickingColor(a_PickingColor); } diff --git a/packages/layers/src/heatmap/shaders/heatmap/heatmap_vert.glsl b/packages/layers/src/heatmap/shaders/heatmap/heatmap_vert.glsl index 797aa5ebcd..88fc503845 100644 --- a/packages/layers/src/heatmap/shaders/heatmap/heatmap_vert.glsl +++ b/packages/layers/src/heatmap/shaders/heatmap/heatmap_vert.glsl @@ -14,6 +14,9 @@ layout(std140) uniform commonUniforms { out vec2 v_texCoord; void main() { v_texCoord = a_Uv; + #ifdef VIEWPORT_ORIGIN_TL + v_texCoord.y = 1.0 - v_texCoord.y; + #endif gl_Position = vec4(a_Position.xy, 0, 1.); } diff --git a/packages/renderer/src/device/DeviceTexture2D.ts b/packages/renderer/src/device/DeviceTexture2D.ts index 728c6b4e81..6bdd37c5a4 100644 --- a/packages/renderer/src/device/DeviceTexture2D.ts +++ b/packages/renderer/src/device/DeviceTexture2D.ts @@ -40,6 +40,7 @@ export default class DeviceTexture2D implements ITexture2D { // premultiplyAlpha = false, mag = gl.NEAREST, min = gl.NEAREST, + unorm = false, // colorSpace = gl.BROWSER_DEFAULT_WEBGL, // x = 0, // y = 0, @@ -50,7 +51,7 @@ export default class DeviceTexture2D implements ITexture2D { let pixelFormat: Format = Format.U8_RGBA_RT; if (type === gl.UNSIGNED_BYTE && format === gl.RGBA) { - pixelFormat = Format.U8_RGBA_RT; + pixelFormat = unorm ? Format.U8_RGBA_NORM : Format.U8_RGBA_RT; } else if (type === gl.UNSIGNED_BYTE && format === gl.LUMINANCE) { pixelFormat = Format.U8_LUMINANCE; } else if (type === gl.FLOAT && format === gl.RGB) {