From 069f581e9c5963b2b35a9cdb4f7290f8ff30e2a1 Mon Sep 17 00:00:00 2001 From: YiQianYao <42212176+2912401452@users.noreply.github.com> Date: Tue, 29 Mar 2022 14:22:47 +0800 Subject: [PATCH] Shihui (#1024) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 增加各个图层的纹理销毁的容错判断 * feat: 增加挤出几何体顶面纹理贴图的能力 * feat: 增加挤出几何体侧面颜色配置渐变 * style: lint style --- packages/layers/src/Geometry/models/plane.ts | 4 +- packages/layers/src/core/interface.ts | 3 + packages/layers/src/point/models/fillmage.ts | 2 +- packages/layers/src/polygon/models/extrude.ts | 149 +++++++++++++++++- packages/layers/src/polygon/models/ocean.ts | 2 +- packages/layers/src/polygon/models/water.ts | 4 +- .../{ => extrude}/polygon_extrude_frag.glsl | 0 .../polygon_extrude_picklight_frag.glsl | 0 .../polygon_extrude_picklight_vert.glsl | 0 .../{ => extrude}/polygon_extrude_vert.glsl | 0 .../extrude/polygon_extrudetex_frag.glsl | 28 ++++ .../extrude/polygon_extrudetex_vert.glsl | 92 +++++++++++ packages/renderer/src/regl/ReglTexture2D.ts | 2 +- stories/Map/components/polygon_extrudeTex.tsx | 68 ++++++++ stories/Map/map.stories.tsx | 3 +- 15 files changed, 343 insertions(+), 14 deletions(-) rename packages/layers/src/polygon/shaders/{ => extrude}/polygon_extrude_frag.glsl (100%) rename packages/layers/src/polygon/shaders/{ => extrude}/polygon_extrude_picklight_frag.glsl (100%) rename packages/layers/src/polygon/shaders/{ => extrude}/polygon_extrude_picklight_vert.glsl (100%) rename packages/layers/src/polygon/shaders/{ => extrude}/polygon_extrude_vert.glsl (100%) create mode 100644 packages/layers/src/polygon/shaders/extrude/polygon_extrudetex_frag.glsl create mode 100644 packages/layers/src/polygon/shaders/extrude/polygon_extrudetex_vert.glsl create mode 100644 stories/Map/components/polygon_extrudeTex.tsx diff --git a/packages/layers/src/Geometry/models/plane.ts b/packages/layers/src/Geometry/models/plane.ts index 1afb6578b4..3344b4969e 100644 --- a/packages/layers/src/Geometry/models/plane.ts +++ b/packages/layers/src/Geometry/models/plane.ts @@ -127,7 +127,7 @@ export default class PlaneModel extends BaseModel { } = this.layer.getLayerConfig() as IGeometryLayerStyleOptions; if (this.mapTexture !== mapTexture) { this.mapTexture = mapTexture; - this.texture.destroy(); + this.texture?.destroy(); this.updateTexture(mapTexture); } return { @@ -143,7 +143,7 @@ export default class PlaneModel extends BaseModel { } public clearModels(): void { - this.texture.destroy(); + this.texture?.destroy(); } public initModels() { diff --git a/packages/layers/src/core/interface.ts b/packages/layers/src/core/interface.ts index 94fe97ea4c..45881e2223 100644 --- a/packages/layers/src/core/interface.ts +++ b/packages/layers/src/core/interface.ts @@ -83,7 +83,10 @@ export interface IPolygonLayerStyleOptions { dir: string; }; + mapTexture?: string; // 挤出几何体顶面贴图 raisingHeight?: number; // 挤出几何体抬升高度 + sourceColor?: string; // 可选参数、设置渐变色的起始颜色(all) + targetColor?: string; // 可选参数、设置渐变色的终点颜色(all) heightfixed?: boolean; // 挤出几何体高度是否固定(不随 zoom 发生变化) pickLight: boolean; diff --git a/packages/layers/src/point/models/fillmage.ts b/packages/layers/src/point/models/fillmage.ts index 3609ee9004..ddbe9ffbba 100644 --- a/packages/layers/src/point/models/fillmage.ts +++ b/packages/layers/src/point/models/fillmage.ts @@ -232,7 +232,7 @@ export default class FillImageModel extends BaseModel { public clearModels() { this.iconService.off('imageUpdate', this.updateTexture); - this.texture.destroy(); + this.texture?.destroy(); this.dataTexture?.destroy(); } diff --git a/packages/layers/src/polygon/models/extrude.ts b/packages/layers/src/polygon/models/extrude.ts index 1c620c6be3..710ea41283 100644 --- a/packages/layers/src/polygon/models/extrude.ts +++ b/packages/layers/src/polygon/models/extrude.ts @@ -1,19 +1,35 @@ -import { AttributeType, gl, IEncodeFeature, IModel } from '@antv/l7-core'; -import { getMask } from '@antv/l7-utils'; +import { + AttributeType, + gl, + IEncodeFeature, + IModel, + ITexture2D, +} from '@antv/l7-core'; +import { getMask, rgb2arr } from '@antv/l7-utils'; import { isNumber } from 'lodash'; import BaseModel from '../../core/BaseModel'; import { IPolygonLayerStyleOptions } from '../../core/interface'; import { PolygonExtrudeTriangulation } from '../../core/triangulation'; -import polygonExtrudeFrag from '../shaders/polygon_extrude_frag.glsl'; -import polygonExtrudePickLightFrag from '../shaders/polygon_extrude_picklight_frag.glsl'; -import polygonExtrudePickLightVert from '../shaders/polygon_extrude_picklight_vert.glsl'; -import polygonExtrudeVert from '../shaders/polygon_extrude_vert.glsl'; +import polygonExtrudeFrag from '../shaders/extrude/polygon_extrude_frag.glsl'; +// extrude +import polygonExtrudeVert from '../shaders/extrude/polygon_extrude_vert.glsl'; +import polygonExtrudeTexFrag from '../shaders/extrude/polygon_extrudetex_frag.glsl'; +// texture +import polygonExtrudeTexVert from '../shaders/extrude/polygon_extrudetex_vert.glsl'; +// extrude picking + +import polygonExtrudePickLightFrag from '../shaders/extrude/polygon_extrude_picklight_frag.glsl'; +import polygonExtrudePickLightVert from '../shaders/extrude/polygon_extrude_picklight_vert.glsl'; + export default class ExtrudeModel extends BaseModel { + protected texture: ITexture2D; public getUninforms() { const { opacity = 1, heightfixed = false, raisingHeight = 0, + sourceColor, + targetColor, } = this.layer.getLayerConfig() as IPolygonLayerStyleOptions; if (this.dataTextureTest && this.dataTextureNeedUpdate({ opacity })) { @@ -46,16 +62,28 @@ export default class ExtrudeModel extends BaseModel { }); } + // 转化渐变色 + let sourceColorArr = [1, 1, 1, 1]; + let targetColorArr = [1, 1, 1, 1]; + if (sourceColor && targetColor) { + sourceColorArr = rgb2arr(sourceColor); + targetColorArr = rgb2arr(targetColor); + } + return { u_heightfixed: Number(heightfixed), u_dataTexture: this.dataTexture, // 数据纹理 - 有数据映射的时候纹理中带数据,若没有任何数据映射时纹理是 [1] u_cellTypeLayout: this.getCellTypeLayout(), u_raisingHeight: Number(raisingHeight), u_opacity: isNumber(opacity) ? opacity : 1.0, + u_sourceColor: sourceColorArr, + u_targetColor: targetColorArr, + u_texture: this.texture, }; } public initModels(): IModel[] { + this.loadTexture(); return this.buildModels(); } @@ -74,6 +102,10 @@ export default class ExtrudeModel extends BaseModel { fragmentShader: frag, triangulation: PolygonExtrudeTriangulation, stencil: getMask(mask, maskInside), + cull: { + enable: true, + face: gl.BACK, // gl.FRONT | gl.BACK; + }, }), ]; } @@ -81,7 +113,15 @@ export default class ExtrudeModel extends BaseModel { public getShaders() { const { pickLight, + mapTexture, } = this.layer.getLayerConfig() as IPolygonLayerStyleOptions; + if (mapTexture) { + return { + frag: polygonExtrudeTexFrag, + vert: polygonExtrudeTexVert, + type: 'polygonExtrudeTexture', + }; + } if (pickLight) { return { frag: polygonExtrudePickLightFrag, @@ -99,9 +139,75 @@ export default class ExtrudeModel extends BaseModel { public clearModels() { this.dataTexture?.destroy(); + this.texture?.destroy(); } protected registerBuiltinAttributes() { + const { + mapTexture, + } = this.layer.getLayerConfig() as IPolygonLayerStyleOptions; + + if (mapTexture) { + const bbox = this.layer.getSource().extent; + const [minLng, minLat, maxLng, maxLat] = bbox; + const lngLen = maxLng - minLng; + const latLen = maxLat - minLat; + // this.styleAttributeService.registerStyleAttribute({ + // name: 'extrudeTopUv', + // type: AttributeType.Attribute, + // descriptor: { + // name: 'a_uv', + // buffer: { + // // give the WebGL driver a hint that this buffer may change + // usage: gl.STATIC_DRAW, + // data: [], + // type: gl.FLOAT, + // }, + // size: 2, + // update: ( + // feature: IEncodeFeature, + // featureIdx: number, + // vertex: number[], + // attributeIdx: number, + // normal: number[], + // ) => { + // const lng = vertex[0]; + // const lat = vertex[1]; + // return [(lng - minLng) / lngLen, (lat - minLat) / latLen]; + // }, + // }, + // }); + // 计算出来只有侧边值有效 + this.styleAttributeService.registerStyleAttribute({ + name: 'uvs', + type: AttributeType.Attribute, + descriptor: { + name: 'a_uvs', + buffer: { + // give the WebGL driver a hint that this buffer may change + usage: gl.STATIC_DRAW, + data: [], + type: gl.FLOAT, + }, + size: 3, + update: ( + feature: IEncodeFeature, + featureIdx: number, + vertex: number[], + attributeIdx: number, + normal: number[], + ) => { + const lng = vertex[0]; + const lat = vertex[1]; + return [ + (lng - minLng) / lngLen, + (lat - minLat) / latLen, + vertex[4], + ]; + }, + }, + }); + } // point layer size; this.styleAttributeService.registerStyleAttribute({ name: 'normal', @@ -151,4 +257,35 @@ export default class ExtrudeModel extends BaseModel { }, }); } + + private loadTexture() { + const { + mapTexture, + } = this.layer.getLayerConfig() as IPolygonLayerStyleOptions; + + const { createTexture2D } = this.rendererService; + this.texture = createTexture2D({ + height: 0, + width: 0, + }); + if (mapTexture) { + const image = new Image(); + image.crossOrigin = ''; + image.src = mapTexture; + + image.onload = () => { + this.texture = createTexture2D({ + data: image, + width: image.width, + height: image.height, + wrapS: gl.CLAMP_TO_EDGE, + wrapT: gl.CLAMP_TO_EDGE, + min: gl.LINEAR, + mag: gl.LINEAR, + }); + this.layerService.updateLayerRenderList(); + this.layerService.renderLayers(); + }; + } + } } diff --git a/packages/layers/src/polygon/models/ocean.ts b/packages/layers/src/polygon/models/ocean.ts index cd9adb3493..3a3a82920b 100644 --- a/packages/layers/src/polygon/models/ocean.ts +++ b/packages/layers/src/polygon/models/ocean.ts @@ -107,7 +107,7 @@ export default class OceanModel extends BaseModel { const latLen = maxLat - minLat; this.styleAttributeService.registerStyleAttribute({ - name: 'linear', + name: 'oceanUv', type: AttributeType.Attribute, descriptor: { name: 'a_uv', diff --git a/packages/layers/src/polygon/models/water.ts b/packages/layers/src/polygon/models/water.ts index 720e3c7688..1c854c7c47 100644 --- a/packages/layers/src/polygon/models/water.ts +++ b/packages/layers/src/polygon/models/water.ts @@ -88,7 +88,7 @@ export default class WaterModel extends BaseModel { } public clearModels() { - this.texture.destroy(); + this.texture?.destroy(); this.dataTexture?.destroy(); } @@ -99,7 +99,7 @@ export default class WaterModel extends BaseModel { const latLen = maxLat - minLat; this.styleAttributeService.registerStyleAttribute({ - name: 'linear', + name: 'waterUv', type: AttributeType.Attribute, descriptor: { name: 'a_uv', diff --git a/packages/layers/src/polygon/shaders/polygon_extrude_frag.glsl b/packages/layers/src/polygon/shaders/extrude/polygon_extrude_frag.glsl similarity index 100% rename from packages/layers/src/polygon/shaders/polygon_extrude_frag.glsl rename to packages/layers/src/polygon/shaders/extrude/polygon_extrude_frag.glsl diff --git a/packages/layers/src/polygon/shaders/polygon_extrude_picklight_frag.glsl b/packages/layers/src/polygon/shaders/extrude/polygon_extrude_picklight_frag.glsl similarity index 100% rename from packages/layers/src/polygon/shaders/polygon_extrude_picklight_frag.glsl rename to packages/layers/src/polygon/shaders/extrude/polygon_extrude_picklight_frag.glsl diff --git a/packages/layers/src/polygon/shaders/polygon_extrude_picklight_vert.glsl b/packages/layers/src/polygon/shaders/extrude/polygon_extrude_picklight_vert.glsl similarity index 100% rename from packages/layers/src/polygon/shaders/polygon_extrude_picklight_vert.glsl rename to packages/layers/src/polygon/shaders/extrude/polygon_extrude_picklight_vert.glsl diff --git a/packages/layers/src/polygon/shaders/polygon_extrude_vert.glsl b/packages/layers/src/polygon/shaders/extrude/polygon_extrude_vert.glsl similarity index 100% rename from packages/layers/src/polygon/shaders/polygon_extrude_vert.glsl rename to packages/layers/src/polygon/shaders/extrude/polygon_extrude_vert.glsl diff --git a/packages/layers/src/polygon/shaders/extrude/polygon_extrudetex_frag.glsl b/packages/layers/src/polygon/shaders/extrude/polygon_extrudetex_frag.glsl new file mode 100644 index 0000000000..61bd9b63e0 --- /dev/null +++ b/packages/layers/src/polygon/shaders/extrude/polygon_extrudetex_frag.glsl @@ -0,0 +1,28 @@ +uniform sampler2D u_texture; +uniform float u_opacity: 1.0; +uniform vec4 u_sourceColor; +uniform vec4 u_targetColor; +// varying vec4 v_Color; +varying mat4 styleMappingMat; // 传递从片元中传递的映射数据 +#pragma include "picking" + +void main() { + float opacity = styleMappingMat[0][0]; + float isSide = styleMappingMat[0][3]; + + float topU = styleMappingMat[2][2]; + float topV = styleMappingMat[2][3]; + + float sidey = styleMappingMat[3][0]; + if(isSide < 1.0) { + gl_FragColor = mix(u_targetColor, u_sourceColor, sidey); + } else { + gl_FragColor = texture2D(u_texture, vec2(topU, topV)); + } + + // gl_FragColor = v_Color; + + + gl_FragColor.a *= opacity; + gl_FragColor = filterColor(gl_FragColor); +} diff --git a/packages/layers/src/polygon/shaders/extrude/polygon_extrudetex_vert.glsl b/packages/layers/src/polygon/shaders/extrude/polygon_extrudetex_vert.glsl new file mode 100644 index 0000000000..5074160dbc --- /dev/null +++ b/packages/layers/src/polygon/shaders/extrude/polygon_extrudetex_vert.glsl @@ -0,0 +1,92 @@ +precision highp float; + +#define ambientRatio 0.5 +#define diffuseRatio 0.3 +#define specularRatio 0.2 + +attribute vec4 a_Color; +attribute vec3 a_Position; +attribute vec3 a_Normal; +attribute float a_Size; +attribute vec3 a_uvs; +uniform mat4 u_ModelMatrix; +uniform mat4 u_Mvp; + +// varying vec4 v_Color; +uniform float u_heightfixed: 0.0; // 默认不固定 +uniform float u_raisingHeight: 0.0; +uniform float u_opacity: 1.0; +varying mat4 styleMappingMat; // 用于将在顶点着色器中计算好的样式值传递给片元 + +#pragma include "styleMapping" +#pragma include "styleMappingCalOpacity" + +#pragma include "projection" +#pragma include "light" +#pragma include "picking" + +void main() { + // cal style mapping - 数据纹理映射部分的计算 + styleMappingMat = mat4( + 0.0, 0.0, 0.0, 0.0, // opacity - strokeOpacity - strokeWidth - a_Position.z(judge side by a_Position.z) + 0.0, 0.0, 0.0, 0.0, // strokeR - strokeG - strokeB - strokeA + 0.0, 0.0, 0.0, 0.0, // offsets[0] - offsets[1] - u - v + 0.0, 0.0, 0.0, 0.0 // sidey + ); + + styleMappingMat[0][3] = a_Position.z; + styleMappingMat[2][2] = a_uvs[0]; + styleMappingMat[2][3] = 1.0 - a_uvs[1]; + styleMappingMat[3][0] = a_uvs[2]; + + + float rowCount = u_cellTypeLayout[0][0]; // 当前的数据纹理有几行 + float columnCount = u_cellTypeLayout[0][1]; // 当看到数据纹理有几列 + float columnWidth = 1.0/columnCount; // 列宽 + float rowHeight = 1.0/rowCount; // 行高 + float cellCount = calCellCount(); // opacity - strokeOpacity - strokeWidth - stroke - offsets + float id = a_vertexId; // 第n个顶点 + float cellCurrentRow = floor(id * cellCount / columnCount) + 1.0; // 起始点在第几行 + float cellCurrentColumn = mod(id * cellCount, columnCount) + 1.0; // 起始点在第几列 + + // cell 固定顺序 opacity -> strokeOpacity -> strokeWidth -> stroke ... + // 按顺序从 cell 中取值、若没有则自动往下取值 + float textureOffset = 0.0; // 在 cell 中取值的偏移量 + + vec2 opacityAndOffset = calOpacityAndOffset(cellCurrentRow, cellCurrentColumn, columnCount, textureOffset, columnWidth, rowHeight); + styleMappingMat[0][0] = opacityAndOffset.r; + textureOffset = opacityAndOffset.g; + // cal style mapping - 数据纹理映射部分的计算 + + vec4 pos = vec4(a_Position.xy, a_Position.z * a_Size, 1.0); + vec4 project_pos = project_position(pos); + + if(u_heightfixed > 0.0) { // 判断几何体是否固定高度 + project_pos.z = a_Position.z * a_Size; + project_pos.z += u_raisingHeight; + + if(u_CoordinateSystem == COORDINATE_SYSTEM_LNGLAT || u_CoordinateSystem == COORDINATE_SYSTEM_LNGLAT_OFFSET) { + float mapboxZoomScale = 4.0/pow(2.0, 21.0 - u_Zoom); + project_pos.z *= mapboxZoomScale; + project_pos.z += u_raisingHeight * mapboxZoomScale; + } + } + + // project_pos.z += 500000.0; // amap1 + + // project_pos.z += (500000.0 * 4.0)/pow(2.0, 21.0 - u_Zoom); // mapbox + // gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0)); + + if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x + // gl_Position = u_Mvp * (vec4(project_pos.xyz * vec3(1.0, 1.0, -1.0), 1.0)); + gl_Position = u_Mvp * (vec4(project_pos.xyz, 1.0)); + } else { + gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0)); + } + + // float lightWeight = calc_lighting(pos); + // v_Color = a_Color; + // v_Color = vec4(a_Color.rgb * lightWeight, a_Color.w); + + setPickingColor(a_PickingColor); +} diff --git a/packages/renderer/src/regl/ReglTexture2D.ts b/packages/renderer/src/regl/ReglTexture2D.ts index 28fcbfd424..0089afc455 100644 --- a/packages/renderer/src/regl/ReglTexture2D.ts +++ b/packages/renderer/src/regl/ReglTexture2D.ts @@ -99,7 +99,7 @@ export default class ReglTexture2D implements ITexture2D { public destroy() { if (!this.isDistroy) { - this.texture.destroy(); + this.texture?.destroy(); } this.isDistroy = true; } diff --git a/stories/Map/components/polygon_extrudeTex.tsx b/stories/Map/components/polygon_extrudeTex.tsx new file mode 100644 index 0000000000..0204882af8 --- /dev/null +++ b/stories/Map/components/polygon_extrudeTex.tsx @@ -0,0 +1,68 @@ +import { PolygonLayer, Scene, LineLayer, PointLayer } from '@antv/l7'; +import { GaodeMap, GaodeMapV2, Mapbox } from '@antv/l7-maps'; +import * as React from 'react'; + +export default class Amap2demo_polygon_extrude extends React.Component { + private gui: dat.GUI; + private $stats: Node; + // @ts-ignore + private scene: Scene; + + public componentWillUnmount() { + this.scene.destroy(); + } + + public async componentDidMount() { + const scene = new Scene({ + id: 'map', + map: new GaodeMap({ + style: 'dark', + center: [120, 29.732983], + zoom: 6.2, + pitch: 60, + }), + }); + this.scene = scene; + + fetch('https://geo.datav.aliyun.com/areas_v3/bound/330000.json') + .then((res) => res.json()) + .then((data) => { + const provincelayer = new PolygonLayer({}) + .source(data) + .size(150000) + .shape('extrude') + .color('#0DCCFF') + // .active({ + // color: 'rgb(100,230,255)', + // }) + .style({ + heightfixed: true, + pickLight: true, + raisingHeight: 200000, + mapTexture: + 'https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*SOUKQJpw1FYAAAAAAAAAAAAAARQnAQ', + // mapTexture: 'https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*EojwT4VzSiYAAAAAAAAAAAAAARQnAQ' + // opacity: 0.8, + sourceColor: '#f00', + targetColor: '#ff0', + }); + + scene.addLayer(provincelayer); + }); + } + + public render() { + return ( +
+ ); + } +} diff --git a/stories/Map/map.stories.tsx b/stories/Map/map.stories.tsx index bcf92ea2bc..1f34093653 100644 --- a/stories/Map/map.stories.tsx +++ b/stories/Map/map.stories.tsx @@ -78,6 +78,7 @@ import Cluster from './components/cluster' import Hot from './components/hot' import Hot2 from './components/hot2' import Mask from './components/mask' +import PolygonExteudeTex from './components/polygon_extrudeTex'; import BugFix from './components/bugfix' // @ts-ignore @@ -161,5 +162,5 @@ storiesOf('地图方法', module) .add('Hot1', () => ) .add('Hot2', () => ) .add('Mask', () => ) - + .add('PolygonExteudeTex', () => ) .add('BugFix', () => )