From ad49acd4d16b2c2d50d6a9d7bcf7db4f80865905 Mon Sep 17 00:00:00 2001 From: "yuqi.pyq" Date: Tue, 19 Dec 2023 16:05:11 +0800 Subject: [PATCH 1/3] fix: single mask --- __tests__/e2e/tests.ts | 6 +- dev-demos/features/mask/demos/singleMask.tsx | 18 +-- packages/layers/src/utils/stencil.ts | 7 +- packages/renderer/src/device/DeviceModel.ts | 131 ++++++++++--------- packages/renderer/src/device/constants.ts | 15 +++ packages/renderer/src/regl/ReglModel.ts | 9 +- 6 files changed, 101 insertions(+), 85 deletions(-) diff --git a/__tests__/e2e/tests.ts b/__tests__/e2e/tests.ts index 11bfab846b..5934bdec0c 100644 --- a/__tests__/e2e/tests.ts +++ b/__tests__/e2e/tests.ts @@ -9,9 +9,7 @@ export const tests = { 'point-normal-device': 'features/point/point-normal-device', 'citybuilding-amap1': 'features/citybuilding/amap1', 'line-arc-plane': 'features/line/line-arc-plane', + 'mask-single-mask': 'features/mask/single-mask', }; -export const testList = [ - 'PointFill', - 'PointImage' -] \ No newline at end of file +export const testList = ['PointFill', 'PointImage']; diff --git a/dev-demos/features/mask/demos/singleMask.tsx b/dev-demos/features/mask/demos/singleMask.tsx index e361b1f5b2..e969895ca5 100644 --- a/dev-demos/features/mask/demos/singleMask.tsx +++ b/dev-demos/features/mask/demos/singleMask.tsx @@ -1,5 +1,5 @@ // @ts-ignore -import { PointLayer, Scene } from '@antv/l7'; +import { PointLayer, PolygonLayer, Scene } from '@antv/l7'; // @ts-ignore import { GaodeMap, Map } from '@antv/l7-maps'; import React, { useEffect } from 'react'; @@ -43,15 +43,15 @@ export default () => { }; scene.on('loaded', () => { - // const polygonLayer = new PolygonLayer() - // .source(maskData) - // .shape('fill') - // .color('#f00') - // .style({ opacity: 0.5 }); + const polygonLayer = new PolygonLayer() + .source(maskData) + .shape('fill') + .color('#f00') + .style({ opacity: 0.5 }); let point1 = new PointLayer({ zIndex: 1, - // maskLayers: [polygonLayer], + maskLayers: [polygonLayer], }) .source( [ @@ -77,7 +77,7 @@ export default () => { .active(true); let point2 = new PointLayer({ - // maskLayers: [polygonLayer], + maskLayers: [polygonLayer], }) .source( [ @@ -101,7 +101,7 @@ export default () => { .active(true); scene.addLayer(point1); - // scene.addLayer(polygonLayer); + scene.addLayer(polygonLayer); scene.addLayer(point2); // scene.startAnimate(); }); diff --git a/packages/layers/src/utils/stencil.ts b/packages/layers/src/utils/stencil.ts index 0bcbc982cd..dfa8bd6dfa 100644 --- a/packages/layers/src/utils/stencil.ts +++ b/packages/layers/src/utils/stencil.ts @@ -1,12 +1,9 @@ import type { IRenderOptions, IStencilOptions, - MaskOperationType} from '@antv/l7-core'; -import { - gl, - MaskOperation, - StencilType, + MaskOperationType, } from '@antv/l7-core'; +import { MaskOperation, StencilType, gl } from '@antv/l7-core'; // 掩膜配置 export function getStencil( mask: boolean, diff --git a/packages/renderer/src/device/DeviceModel.ts b/packages/renderer/src/device/DeviceModel.ts index d863083507..bbf0a1edd4 100644 --- a/packages/renderer/src/device/DeviceModel.ts +++ b/packages/renderer/src/device/DeviceModel.ts @@ -14,6 +14,7 @@ import { CompareFunction, CullMode, Format, + StencilOp, TransparentBlack, VertexStepMode, } from '@antv/g-device-api'; @@ -38,6 +39,8 @@ import { depthFuncMap, primitiveMap, sizeFormatMap, + stencilFuncMap, + stencilOpMap, } from './constants'; const { isPlainObject, isTypedArray } = lodashUtil; @@ -132,7 +135,7 @@ export default class DeviceModel implements IModel { } private createPipeline(options: IModelInitializationOptions, pick?: boolean) { - const { primitive = gl.TRIANGLES, depth, cull, blend } = options; + const { primitive = gl.TRIANGLES, depth, cull, blend, stencil } = options; const depthParams = this.initDepthDrawParams({ depth }); const depthEnabled = !!(depthParams && depthParams.enable); @@ -142,6 +145,9 @@ export default class DeviceModel implements IModel { const blendParams = this.getBlendDrawParams({ blend }); const blendEnabled = !!(blendParams && blendParams.enable); + const stencilParams = this.getStencilDrawParams({ stencil }); + const stencilEnabled = !!(stencilParams && stencilParams.enable); + return this.device.createRenderPipeline({ inputLayout: this.inputLayout, program: this.program, @@ -165,7 +171,11 @@ export default class DeviceModel implements IModel { }, } : { - channelWriteMask: ChannelWriteMask.ALL, + channelWriteMask: + stencilEnabled && + stencilParams.opFront.zpass === StencilOp.REPLACE + ? ChannelWriteMask.NONE + : ChannelWriteMask.ALL, rgbBlendState: { blendMode: (blendEnabled && blendParams.equation.rgb) || BlendMode.ADD, @@ -194,7 +204,19 @@ export default class DeviceModel implements IModel { depthCompare: (depthEnabled && depthParams.func) || CompareFunction.LESS, cullMode: (cullEnabled && cullParams.face) || CullMode.NONE, - stencilWrite: false, + stencilWrite: stencilEnabled, + stencilFront: { + compare: stencilEnabled + ? stencilParams.func.cmp + : CompareFunction.ALWAYS, + passOp: stencilParams.opFront.zpass, + }, + stencilBack: { + compare: stencilEnabled + ? stencilParams.func.cmp + : CompareFunction.ALWAYS, + passOp: stencilParams.opBack.zpass, + }, }, }); } @@ -227,7 +249,6 @@ export default class DeviceModel implements IModel { ...options, }; const { - depth: { enable: depthEnabled } = {}, count = 0, instances, elements, @@ -253,6 +274,7 @@ export default class DeviceModel implements IModel { currentFramebuffer?.['height'] || height, ); renderPass.setPipeline(this.pipeline); + renderPass.setStencilReference(1); renderPass.setVertexInput( this.inputLayout, this.vertexBuffers.map((buffer) => ({ @@ -355,63 +377,50 @@ export default class DeviceModel implements IModel { }; } - // /** - // * @see https://github.com/regl-project/regl/blob/gh-pages/API.md#stencil - // */ - // private getStencilDrawParams({ - // stencil, - // }: Pick) { - // const { - // enable, - // mask = -1, - // func = { - // cmp: gl.ALWAYS, - // ref: 0, - // mask: -1, - // }, - // opFront = { - // fail: gl.KEEP, - // zfail: gl.KEEP, - // zpass: gl.KEEP, - // }, - // opBack = { - // fail: gl.KEEP, - // zfail: gl.KEEP, - // zpass: gl.KEEP, - // }, - // } = stencil || {}; - // return { - // enable: !!enable, - // mask, - // func: { - // ...func, - // cmp: stencilFuncMap[func.cmp], - // }, - // opFront: { - // fail: stencilOpMap[opFront.fail], - // zfail: stencilOpMap[opFront.zfail], - // zpass: stencilOpMap[opFront.zpass], - // }, - // opBack: { - // fail: stencilOpMap[opBack.fail], - // zfail: stencilOpMap[opBack.zfail], - // zpass: stencilOpMap[opBack.zpass], - // }, - // }; - // } - - // private getColorMaskDrawParams( - // { stencil }: Pick, - // pick: boolean, - // ) { - // // TODO: 重构相关参数 - // // 掩膜模式下,颜色通道全部关闭 - // const colorMask = - // stencil?.enable && stencil.opFront && !pick - // ? [false, false, false, false] - // : [true, true, true, true]; // 非掩码模式下,颜色通道全部开启 - // return colorMask; - // } + /** + * @see https://github.com/regl-project/regl/blob/gh-pages/API.md#stencil + */ + private getStencilDrawParams({ + stencil, + }: Pick) { + const { + enable, + mask = -1, + func = { + cmp: gl.ALWAYS, + ref: 0, + mask: -1, + }, + opFront = { + fail: gl.KEEP, + zfail: gl.KEEP, + zpass: gl.KEEP, + }, + opBack = { + fail: gl.KEEP, + zfail: gl.KEEP, + zpass: gl.KEEP, + }, + } = stencil || {}; + return { + enable: !!enable, + mask, + func: { + ...func, + cmp: stencilFuncMap[func.cmp], + }, + opFront: { + fail: stencilOpMap[opFront.fail], + zfail: stencilOpMap[opFront.zfail], + zpass: stencilOpMap[opFront.zpass], + }, + opBack: { + fail: stencilOpMap[opBack.fail], + zfail: stencilOpMap[opBack.zfail], + zpass: stencilOpMap[opBack.zpass], + }, + }; + } /** * @see https://github.com/regl-project/regl/blob/gh-pages/API.md#culling diff --git a/packages/renderer/src/device/constants.ts b/packages/renderer/src/device/constants.ts index ff8f5a8f95..a9dc0e28c7 100644 --- a/packages/renderer/src/device/constants.ts +++ b/packages/renderer/src/device/constants.ts @@ -7,6 +7,7 @@ import { CullMode, Format, PrimitiveTopology, + StencilOp, } from '@antv/g-device-api'; import { gl } from '@antv/l7-core'; import type { TypedArray } from './utils/typedarray'; @@ -109,6 +110,20 @@ export const blendFuncMap: { [gl.SRC_ALPHA_SATURATE]: BlendFactor.SRC_ALPHA_SATURATE, }; +export const stencilOpMap: { + [key: string]: StencilOp; +} = { + [gl.REPLACE]: StencilOp.REPLACE, + [gl.KEEP]: StencilOp.KEEP, +}; + +export const stencilFuncMap: { + [key: string]: CompareFunction; +} = { + [gl.ALWAYS]: CompareFunction.ALWAYS, + [gl.EQUAL]: CompareFunction.EQUAL, +}; + // export const filterMap: { // [key: string]: FilterMode; // } = { diff --git a/packages/renderer/src/regl/ReglModel.ts b/packages/renderer/src/regl/ReglModel.ts index 4a82a3c0f3..35a95b4ce5 100644 --- a/packages/renderer/src/regl/ReglModel.ts +++ b/packages/renderer/src/regl/ReglModel.ts @@ -10,11 +10,9 @@ import type { IModel, IModelDrawOptions, IModelInitializationOptions, - IUniform} from '@antv/l7-core'; -import { - gl, - removeDuplicateUniforms, + IUniform, } from '@antv/l7-core'; +import { gl, removeDuplicateUniforms } from '@antv/l7-core'; import { lodashUtil } from '@antv/l7-utils'; import type regl from 'regl'; import { @@ -94,9 +92,8 @@ export default class ReglModel implements IModel { const vert = removeDuplicateUniforms( preprocessShader_GLSL(vendorInfo, 'vert', vs, null, false), - ) + ); - const drawParams: regl.DrawConfig = { attributes: reglAttributes, frag, From d283fdddfee28aee376d2e9cf063cd62a2a892ed Mon Sep 17 00:00:00 2001 From: "yuqi.pyq" Date: Tue, 19 Dec 2023 19:01:34 +0800 Subject: [PATCH 2/3] fix: add more stencil constants --- dev-demos/features/mask/demos/heatmap.tsx | 47 ++--- dev-demos/features/mask/demos/hexgon.tsx | 17 +- dev-demos/features/mask/demos/image.tsx | 20 +- dev-demos/features/mask/demos/raster.tsx | 27 +-- .../features/mask/demos/raster_point.tsx | 190 ++++++++---------- dev-demos/features/mask/demos/text.tsx | 16 +- dev-demos/features/mask/demos/wind.tsx | 14 +- dev-demos/features/point/demos/fill-image.tsx | 4 +- dev-demos/features/point/pointFillImage.md | 75 +------ packages/renderer/src/device/constants.ts | 12 ++ 10 files changed, 178 insertions(+), 244 deletions(-) diff --git a/dev-demos/features/mask/demos/heatmap.tsx b/dev-demos/features/mask/demos/heatmap.tsx index 854ebef320..5354fc86de 100644 --- a/dev-demos/features/mask/demos/heatmap.tsx +++ b/dev-demos/features/mask/demos/heatmap.tsx @@ -1,15 +1,15 @@ // @ts-ignore -import { Scene, HeatmapLayer, PolygonLayer } from '@antv/l7'; +import { HeatmapLayer, PolygonLayer, Scene } from '@antv/l7'; // @ts-ignore -import { GaodeMap } from '@antv/l7-maps'; +import { GaodeMap, Map } from '@antv/l7-maps'; import React, { useEffect } from 'react'; export default () => { useEffect(() => { const scene = new Scene({ id: 'map', - - map: new GaodeMap({ + renderer: process.env.renderer, + map: new (process.env.CI ? Map : GaodeMap)({ center: [120.165, 30.26], pitch: 0, zoom: 2, @@ -49,20 +49,20 @@ export default () => { ], }; - scene.on('loaded', () => { - - fetch( 'https://gw.alipayobjects.com/os/basement_prod/d3564b06-670f-46ea-8edb-842f7010a7c6.json', ) .then((res) => res.json()) .then((data) => { - const polygonLayer = new PolygonLayer({visible:true}).source(maskData).shape('fill').color('#f00').style({opacity:0.4}); + const polygonLayer = new PolygonLayer({ visible: true }) + .source(maskData) + .shape('fill') + .color('#f00') + .style({ opacity: 0.4 }); const heatmapLayer = new HeatmapLayer({ maskLayers: [polygonLayer], - mask:false, - + // mask: false, }) .source(data) .shape('heatmap') // heatmap3D heatmap @@ -83,23 +83,20 @@ export default () => { positions: [0, 0.2, 0.4, 0.6, 0.8, 1.0], }, }); - scene.addLayer(polygonLayer); - scene.addLayer(heatmapLayer); - - setTimeout(()=>{ - console.log('add mask'); - // heatmapLayer.addMask(polygonLayer); - // scene.render(); - - console.log('disable mask'); - // heatmapLayer.disableMask(); - // scene.render(); - heatmapLayer.enableMask(); - scene.render(); + scene.addLayer(polygonLayer); + scene.addLayer(heatmapLayer); + // setTimeout(() => { + // console.log('add mask'); + // // heatmapLayer.addMask(polygonLayer); + // // scene.render(); - },2000) - + // console.log('disable mask'); + // // heatmapLayer.disableMask(); + // // scene.render(); + // heatmapLayer.enableMask(); + // scene.render(); + // }, 2000); }); }); }, []); diff --git a/dev-demos/features/mask/demos/hexgon.tsx b/dev-demos/features/mask/demos/hexgon.tsx index 27b99f0316..0c269051d9 100644 --- a/dev-demos/features/mask/demos/hexgon.tsx +++ b/dev-demos/features/mask/demos/hexgon.tsx @@ -1,15 +1,15 @@ // @ts-ignore -import { Scene, HeatmapLayer,PolygonLayer } from '@antv/l7'; +import { HeatmapLayer, PolygonLayer, Scene } from '@antv/l7'; // @ts-ignore -import { GaodeMap } from '@antv/l7-maps'; +import { GaodeMap, Map } from '@antv/l7-maps'; import React, { useEffect } from 'react'; export default () => { useEffect(() => { const scene = new Scene({ id: 'map', - - map: new GaodeMap({ + renderer: process.env.renderer, + map: new (process.env.CI ? Map : GaodeMap)({ center: [120.165, 30.26], pitch: 0, zoom: 6, @@ -54,10 +54,13 @@ export default () => { ) .then((res) => res.text()) .then((data) => { - const polygonLayer = new PolygonLayer().source(maskData).shape('fill').color('#f00').style({opacity:0.5}); + const polygonLayer = new PolygonLayer() + .source(maskData) + .shape('fill') + .color('#f00') + .style({ opacity: 0.5 }); const layer = new HeatmapLayer({ - maskLayers: [polygonLayer] - + maskLayers: [polygonLayer], }) .source(data, { parser: { diff --git a/dev-demos/features/mask/demos/image.tsx b/dev-demos/features/mask/demos/image.tsx index fcd96516dc..5e75e8c387 100644 --- a/dev-demos/features/mask/demos/image.tsx +++ b/dev-demos/features/mask/demos/image.tsx @@ -1,15 +1,15 @@ // @ts-ignore -import { Scene, ImageLayer,PolygonLayer } from '@antv/l7'; +import { ImageLayer, PolygonLayer, Scene } from '@antv/l7'; // @ts-ignore -import { GaodeMap } from '@antv/l7-maps'; +import { GaodeMap, Map } from '@antv/l7-maps'; import React, { useEffect } from 'react'; export default () => { useEffect(() => { const scene = new Scene({ id: 'map', - - map: new GaodeMap({ + renderer: process.env.renderer, + map: new (process.env.CI ? Map : GaodeMap)({ center: [120.165, 30.26], pitch: 0, zoom: 15, @@ -51,9 +51,13 @@ export default () => { }; scene.on('loaded', () => { - const polygonLayer = new PolygonLayer().source(maskData).shape('fill').color('#f00').style({opacity:0.5}); + const polygonLayer = new PolygonLayer() + .source(maskData) + .shape('fill') + .color('#f00') + .style({ opacity: 0.5 }); const layer = new ImageLayer({ - maskLayers:[polygonLayer], + maskLayers: [polygonLayer], }); layer.source( 'https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*4UApTKmeiy4AAAAAAAAAAAAAARQnAQ', @@ -61,9 +65,7 @@ export default () => { parser: { type: 'image', extent: [ - 120.14802932739258, - 30.262773970881057, - 120.17669677734374, + 120.14802932739258, 30.262773970881057, 120.17669677734374, 30.25239466884559, ], }, diff --git a/dev-demos/features/mask/demos/raster.tsx b/dev-demos/features/mask/demos/raster.tsx index b946a5a118..2f89e6db0a 100644 --- a/dev-demos/features/mask/demos/raster.tsx +++ b/dev-demos/features/mask/demos/raster.tsx @@ -1,7 +1,7 @@ // @ts-ignore -import { Scene, RasterLayer,PolygonLayer } from '@antv/l7'; +import { PolygonLayer, RasterLayer, Scene } from '@antv/l7'; // @ts-ignore -import { GaodeMap } from '@antv/l7-maps'; +import { GaodeMap, Map } from '@antv/l7-maps'; import React, { useEffect } from 'react'; import * as GeoTIFF from 'geotiff'; @@ -28,11 +28,11 @@ async function getTiffData() { export default () => { // @ts-ignore - useEffect( async () => { + useEffect(async () => { const scene = new Scene({ id: 'map', - - map: new GaodeMap({ + renderer: process.env.renderer, + map: new (process.env.CI ? Map : GaodeMap)({ center: [120.165, 30.26], pitch: 0, zoom: 2, @@ -52,11 +52,15 @@ export default () => { .then((res) => res.json()) .then((maskData) => { const polygonLayer = new PolygonLayer({ - visible:false - }).source(maskData).shape('fill').color('#f00').style({opacity:0.5}); + visible: false, + }) + .source(maskData) + .shape('fill') + .color('#f00') + .style({ opacity: 0.5 }); const layer = new RasterLayer({ - maskLayers: [polygonLayer] - }); + maskLayers: [polygonLayer], + }); const mindata = -0; const maxdata = 8000; layer @@ -66,10 +70,7 @@ export default () => { width: tiffdata.width, height: tiffdata.height, extent: [ - 73.482190241, - 3.82501784112, - 135.106618732, - 57.6300459963, + 73.482190241, 3.82501784112, 135.106618732, 57.6300459963, ], }, }) diff --git a/dev-demos/features/mask/demos/raster_point.tsx b/dev-demos/features/mask/demos/raster_point.tsx index 4ee6ca8084..508133594c 100644 --- a/dev-demos/features/mask/demos/raster_point.tsx +++ b/dev-demos/features/mask/demos/raster_point.tsx @@ -1,7 +1,7 @@ // @ts-ignore -import { Scene, RasterLayer,PolygonLayer,PointLayer } from '@antv/l7'; +import { PointLayer, RasterLayer, Scene } from '@antv/l7'; // @ts-ignore -import { GaodeMap } from '@antv/l7-maps'; +import { GaodeMap, Map } from '@antv/l7-maps'; import React, { useEffect } from 'react'; import * as GeoTIFF from 'geotiff'; @@ -28,11 +28,11 @@ async function getTiffData() { export default () => { // @ts-ignore - useEffect( async () => { + useEffect(async () => { const scene = new Scene({ id: 'map', - - map: new GaodeMap({ + renderer: process.env.renderer, + map: new (process.env.CI ? Map : GaodeMap)({ center: [120.165, 30.26], pitch: 0, zoom: 2, @@ -47,109 +47,93 @@ export default () => { const tiffdata = await getTiffData(); const maskPointData = { - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "properties": {}, - "geometry": { - "coordinates": [ - 110.64070700180974, - 38.725170221383365 - ], - "type": "Point" - } + type: 'FeatureCollection', + features: [ + { + type: 'Feature', + properties: {}, + geometry: { + coordinates: [110.64070700180974, 38.725170221383365], + type: 'Point', }, - { - "type": "Feature", - "properties": {}, - "geometry": { - "coordinates": [ - 117.05859241946035, - 41.44428218345186 - ], - "type": "Point" - } + }, + { + type: 'Feature', + properties: {}, + geometry: { + coordinates: [117.05859241946035, 41.44428218345186], + type: 'Point', }, - { - "type": "Feature", - "properties": {}, - "geometry": { - "coordinates": [ - 114.98363698367831, - 37.113784885036424 - ], - "type": "Point" - } + }, + { + type: 'Feature', + properties: {}, + geometry: { + coordinates: [114.98363698367831, 37.113784885036424], + type: 'Point', }, - { - "type": "Feature", - "properties": {}, - "geometry": { - "coordinates": [ - 118.77967948635097, - 37.47208097958061 - ], - "type": "Point" - } + }, + { + type: 'Feature', + properties: {}, + geometry: { + coordinates: [118.77967948635097, 37.47208097958061], + type: 'Point', }, - { - "type": "Feature", - "properties": {}, - "geometry": { - "coordinates": [ - 113.729012766695, - 39.22535473120385 - ], - "type": "Point" - } - } - ] - } - + }, + { + type: 'Feature', + properties: {}, + geometry: { + coordinates: [113.729012766695, 39.22535473120385], + type: 'Point', + }, + }, + ], + }; - const maskPoint = new PointLayer({ - visible:false - }).source(maskPointData).shape('circle').size(100000).color('#f00').style({ - opacity:0.5, - unit:'meter', - }); - const layer = new RasterLayer({ - maskLayers: [maskPoint] - }); - const mindata = -0; - const maxdata = 8000; - layer - .source(tiffdata.data, { - parser: { - type: 'raster', - width: tiffdata.width, - height: tiffdata.height, - extent: [ - 73.482190241, - 3.82501784112, - 135.106618732, - 57.6300459963, - ], - }, - }) - .style({ - opacity: 0.8, - domain: [mindata, maxdata], - clampLow: true, - rampColors: { - colors: [ - 'rgb(166,97,26)', - 'rgb(223,194,125)', - 'rgb(245,245,245)', - 'rgb(128,205,193)', - 'rgb(1,133,113)', - ], - positions: [0, 0.25, 0.5, 0.75, 1.0], - }, - }); - scene.addLayer(layer); - scene.addLayer(maskPoint); + const maskPoint = new PointLayer({ + visible: false, + }) + .source(maskPointData) + .shape('circle') + .size(100000) + .color('#f00') + .style({ + opacity: 0.5, + unit: 'meter', + }); + const layer = new RasterLayer({ + maskLayers: [maskPoint], + }); + const mindata = -0; + const maxdata = 8000; + layer + .source(tiffdata.data, { + parser: { + type: 'raster', + width: tiffdata.width, + height: tiffdata.height, + extent: [73.482190241, 3.82501784112, 135.106618732, 57.6300459963], + }, + }) + .style({ + opacity: 0.8, + domain: [mindata, maxdata], + clampLow: true, + rampColors: { + colors: [ + 'rgb(166,97,26)', + 'rgb(223,194,125)', + 'rgb(245,245,245)', + 'rgb(128,205,193)', + 'rgb(1,133,113)', + ], + positions: [0, 0.25, 0.5, 0.75, 1.0], + }, + }); + scene.addLayer(layer); + scene.addLayer(maskPoint); }, []); return (
{ useEffect(() => { const scene = new Scene({ id: 'map', - - map: new GaodeMap({ + renderer: process.env.renderer, + map: new (process.env.CI ? Map : GaodeMap)({ center: [105, 32], pitch: 0, zoom: 4, @@ -53,9 +53,13 @@ export default () => { ) .then((res) => res.json()) .then((data) => { - const polygonLayer = new PolygonLayer().source(maskData).shape('fill').color('#f00').style({opacity:0.5}); + const polygonLayer = new PolygonLayer() + .source(maskData) + .shape('fill') + .color('#f00') + .style({ opacity: 0.5 }); const pointLayer = new PointLayer({ - maskLayers: [polygonLayer] + maskLayers: [polygonLayer], }) .source(data.list, { parser: { diff --git a/dev-demos/features/mask/demos/wind.tsx b/dev-demos/features/mask/demos/wind.tsx index 874ce0e2c2..5b750c62e1 100644 --- a/dev-demos/features/mask/demos/wind.tsx +++ b/dev-demos/features/mask/demos/wind.tsx @@ -1,15 +1,15 @@ // @ts-ignore -import { Scene, WindLayer,PolygonLayer } from '@antv/l7'; +import { PolygonLayer, Scene, WindLayer } from '@antv/l7'; // @ts-ignore -import { GaodeMap } from '@antv/l7-maps'; +import { GaodeMap, Map } from '@antv/l7-maps'; import React, { useEffect } from 'react'; export default () => { useEffect(() => { const scene = new Scene({ id: 'map', - - map: new GaodeMap({ + renderer: process.env.renderer, + map: new (process.env.CI ? Map : GaodeMap)({ center: [105.732421875, 32.24997445586331], pitch: 0, style: 'light', @@ -49,7 +49,11 @@ export default () => { scene.on('loaded', () => { const polygonLayer = new PolygonLayer({ visible: false, - }).source(maskData).shape('fill').color('#f00').style({opacity:0.3}); + }) + .source(maskData) + .shape('fill') + .color('#f00') + .style({ opacity: 0.3 }); const layer = new WindLayer({ maskLayers: [polygonLayer], zIndex: 2, diff --git a/dev-demos/features/point/demos/fill-image.tsx b/dev-demos/features/point/demos/fill-image.tsx index 89726e2031..b2fee82a86 100644 --- a/dev-demos/features/point/demos/fill-image.tsx +++ b/dev-demos/features/point/demos/fill-image.tsx @@ -62,7 +62,7 @@ export default () => { ) .shape('marker') .size(36) - // .active(true) + .active(true) .style({ rotation: 90, }); @@ -70,7 +70,7 @@ export default () => { scene.on('loaded', () => { scene.addLayer(pointLayer); scene.addLayer(pointLayer2); - scene.startAnimate(); + // scene.startAnimate(); }); }, []); return ( diff --git a/dev-demos/features/point/pointFillImage.md b/dev-demos/features/point/pointFillImage.md index 720888034b..1bd373ed73 100644 --- a/dev-demos/features/point/pointFillImage.md +++ b/dev-demos/features/point/pointFillImage.md @@ -1,76 +1,3 @@ ### point - fillImage -```tsx -import { PointLayer, Scene } from '@antv/l7'; -import { GaodeMap, Mapbox } from '@antv/l7-maps'; -import React, { useEffect } from 'react'; -export default () => { - useEffect(() => { - - const scene = new Scene({ - id: 'point_fillImage', - renderer: process.env.renderer, - map: new GaodeMap({ - style: 'light', - center: [120, 30], - pitch: 60, - zoom: 14 - }), - }); - - scene.addImage( - 'marker', - 'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*BJ6cTpDcuLcAAAAAAAAAAABkARQnAQ' - ); - - const pointLayer = new PointLayer({ layerType: 'fillImage' }) - .source([{ - lng: 120, lat: 30, name: 'marker' - }], { - parser: { - type: 'json', - x: 'lng', - y: 'lat', - }, - }) - .style({ - unit:'meter' - }) - .shape('marker') - .size(36) - - const pointLayer2 = new PointLayer({ layerType: 'fillImage' }) - .source([{ - lng: 120, lat: 30, name: 'marker' - }], { - parser: { - type: 'json', - x: 'lng', - y: 'lat', - }, - }) - .shape('marker') - .size(36) - // .active(true) - .style({ - rotation: 90 - }) - - - scene.on('loaded', () => { - scene.addLayer(pointLayer); - scene.addLayer(pointLayer2); - scene.startAnimate(); - }) - }, []) - return ( -
- ); -} -``` \ No newline at end of file + diff --git a/packages/renderer/src/device/constants.ts b/packages/renderer/src/device/constants.ts index a9dc0e28c7..1dfa6a4941 100644 --- a/packages/renderer/src/device/constants.ts +++ b/packages/renderer/src/device/constants.ts @@ -115,6 +115,12 @@ export const stencilOpMap: { } = { [gl.REPLACE]: StencilOp.REPLACE, [gl.KEEP]: StencilOp.KEEP, + [gl.ZERO]: StencilOp.ZERO, + [gl.INVERT]: StencilOp.INVERT, + [gl.INCR]: StencilOp.INCREMENT_CLAMP, + [gl.DECR]: StencilOp.DECREMENT_CLAMP, + [gl.INCR_WRAP]: StencilOp.INCREMENT_WRAP, + [gl.DECR_WRAP]: StencilOp.DECREMENT_WRAP, }; export const stencilFuncMap: { @@ -122,6 +128,12 @@ export const stencilFuncMap: { } = { [gl.ALWAYS]: CompareFunction.ALWAYS, [gl.EQUAL]: CompareFunction.EQUAL, + [gl.GEQUAL]: CompareFunction.GEQUAL, + [gl.GREATER]: CompareFunction.GREATER, + [gl.LEQUAL]: CompareFunction.LEQUAL, + [gl.LESS]: CompareFunction.LESS, + [gl.NEVER]: CompareFunction.NEVER, + [gl.NOTEQUAL]: CompareFunction.NOTEQUAL, }; // export const filterMap: { From d32454deef32ac65228a9157417b4c51e36332f0 Mon Sep 17 00:00:00 2001 From: "yuqi.pyq" Date: Wed, 20 Dec 2023 15:08:29 +0800 Subject: [PATCH 3/3] fix: mask layer --- __tests__/e2e/snapshots/mask-single-mask.png | Bin 0 -> 7069 bytes dev-demos/features/mask/demos/heatmapgrid.tsx | 8 +- .../features/mask/demos/heatmapgrid3d.tsx | 8 +- .../core/src/services/layer/ILayerService.ts | 3 + .../core/src/services/layer/LayerService.ts | 7 +- packages/layers/src/core/BaseLayer.ts | 2 + packages/layers/src/core/BaseModel.ts | 91 ++++++++++-------- packages/layers/src/heatmap/index.ts | 9 ++ packages/layers/src/heatmap/models/heatmap.ts | 27 +++--- packages/layers/src/mask/models/fill.ts | 27 ++++-- .../layers/src/mask/shaders/mask_vert.glsl | 7 +- packages/layers/src/shader/minify_frag.glsl | 12 ++- 12 files changed, 125 insertions(+), 76 deletions(-) create mode 100644 __tests__/e2e/snapshots/mask-single-mask.png diff --git a/__tests__/e2e/snapshots/mask-single-mask.png b/__tests__/e2e/snapshots/mask-single-mask.png new file mode 100644 index 0000000000000000000000000000000000000000..d4d232f5b8b4a6ae43dbd0b2884620e7dbb134a1 GIT binary patch literal 7069 zcmeHMX;@QNw?4E*TZi&}#fmcJs*zwBqEJA_ID*UyUMYeg3W-7h4Khg}c&+*%AW8%b zkVH$7OBI43U}S7j;4se+8U4ucpq2?vA zQw`&@QRt(y6H~`v6#QKPEGp4zh>+dwp_Ol)?AjW8*3J~;?aJhXGg>$#<|k(*~Xq=vxaBqcNa4PJU<@WnPNA4aOdlWT`A=vjeq~JcrLN0 zu0dj1<-1K;kymNtl!S)_?C_ee@ z7SoKr;>V@rjMF8L`+n`)1WXTLb7tl{Pxn1f4-ag8xVl)Ib#Y77(V*?07N6#uK#(2p)$t&=pmn9|pr{yi<&nTu)9a_Hh&u?%>eij9 z>p8t{HPq`!yio0ey0YnSeMT1y-uGmhtb&S94&JiOt{}iU$TJT_x#|i>&Z))!wSNWb zOrM7GNXY5thow*5gZg?hdom9eC_y8dIgr9L$g>-X6$xP3RkDWii_2@HQgC!@vvO8* zg#hRSxr(aTt{nBgH2okF00561@+Fkjsavb!vF6mhg|E|gTWhE#FeY?aQ21tC<8{ENVq z{|Wq0KKVS-c#vplA#Rmb>kw8t7bq_0`iX<0wx=eI!H)YcG1qgfX!0^&3IBx+EnIkOE=rPlKmO8&`+N+}4byyA1D z@%@A?(AeTKQlS4;Q7*`Bl^~x#ld?+Gu}LB@Em)=0pZ$Xvkpn?XYuKOlyDn5)-}N~q zk`hlq@v~i@BPDJD+q3Lek!G%_ucI4mA6%|pwc{tAjSzw98lbEOT?k_3ey+#`I>_FP z?JE3LMb-`W1Jlqnq^AM(FW2dK(7+G?y5M(lh0)s)nVFQ{oHgA5+Tvf`W4Zef$-sS5 z)@u5G7vNB)k5535DYfs9`cr>jEC08*=_1%FOVw}u2PJ3#T^L}3W3spsZF!#GxVkcQ zR&_ruL+l~mD6LU+Bvj5!6W*^{vRWIA3K24U%B}-jm9=) zl+4NZ)-NyM8r8%L6s>x1#6HT(PV9&i(Y-58lGxut@%v`Nq$I}D$$_tct?7##b2_$4 z!qIQP>HP33=<4s;!bc$(->g! z;Ot7X)ekl8Ip#IEl@C3oPx<%gj%?EnS;s&O>%vXdNPI0nDgZR_(1p*-w)}@F4LR@K zl{Q|N!RiB_w%6XnTUQ^D3i)qziAIQ@lkkyZ^_As7ug6Ag&DH-s@J8V_D<(Z7!p1W9 z)pJ5xi4poYogX7`GT}a9oW+XKKnm{+hqPlg-aJxhgf+_a-ZHGiY~%IXn^uC22*Qiy zcA?H}^%cxhd16=?ZAAPIiDf7+%y&vw?nl)HP{zsvexSUY!xX<~7kzUdRR0<-)0I1; zR;P0uRC8Sf-b*gp$ZV~)t9zgaN~ucOk7`blp}dS=YS#Y*^77z;6Fl1NDwx6E+6Oed z*LJG;kt{Mrc7%`m`uuMo{1(|28yZg994SaA)NKRg+;&(IE58&sS~HNv$=!=bs@-wY zR*I2^ieutJJn$(umWlKjZ%n5!a2YrePOGtC^qcd)fWwl4+xukR@+=1J>&LHU; z!UnS@e>q-$R^G{yPgN=e)B^0S%};?fbs?XORyaQV~! z{p)H@<;@^HxX#z!#hU4DljUum;pB{=y2IR)Mr;#WwgZ3Kern->(dD_(-B_|Qd?dBk zUqFZHHP}5l#8V!u!e8$v+y}C&RWWS}ijsG76^s3FX^{P*Tk*?Gr&hEVo|@0`4>YB{ zp$V<-YF_P6b6Tok+P5)VLcN?F>?5>X=7*Um|A2tqlQcnCfYf2+azikuEZ8FSrk+P3 z|IvCBd}E_pn7}e<>$h#ZUZ1P8PTCaNAbV;gMupICU?~ptmG`o^-{Yk0c5aM;_L(Nt z6kJ+DLIQd0`ZQeV6~XV_nqtTsVvD78CnqOv+2B^As$dJKHcLQCE%3`x=b5yOrnO8t zxL|cqA9ulz7E_HJn$mwI+Ut~~K^h9bgwum_xD9d_5}(bLvM?!2Zp8|Qzr<2}T03SA z_O6I9Fg7-p^3CG(mRU7N+=|ywjHi&0Yi}%PZrfi5H;`uH)#9`WP7RfdHS@-eFKG`RG)i7xdV5YgmYYDHshi#i&D0m@nA5o&G-{JZuP)0k z&`Z>byDRgh;AlhXWT7jXnnOmZ!dgt{Q-x?1857RcgB#?hjozfAxJ{z8?5MXVZ9dRa z0!SnyEF*3Y#+A`l9UDV3PS0R*vql#RysNI7)x)_wBiNpvZXr$?i4(!C_Ywj(;C z+i<5p9$&`G55>`2hzNo+&Lp(GWAS;v9YpV(q4)}$OwCG6G~X<>L2+0##cT|X5&7z< z`L>+>1ua>E{hu3{%YPD0D$Lk|F!*gduT)>#lCiWX!2=9{o!qfUQcY`;{^I;398PGj z&K`Hfh;HZS8?d8h-E?$xiX*2PLQaKcKi%fTIV6x+)C=6`!iUiok%+_>NCcLy*3>5+ z9!6$0xD>0oD4%D~=MM4JzU98mvAe@7tc&EfKEHIy5INZn6}^+SpE7l5>g8ga5LaYo zm!jF+U^9CU+)!FxqubHuG0g^?ea5P$WhX)o?1A%am{v>4Ts?(;w7@QPLd%{ZRe`BB zsZVt{G5gumVo!FaHz&gNG36Z!BO#m8bfXQB6RSX$jj{ArnlT}4ri08N|I5@edSgnQtj=5_lImlzVAV^ES5LNOE375_ z@3B=;Ix4uipF%2PcYwc9A(VzkPR`ECP}EWzCi(|hBwykfsozLuao4pD(<>!4$6Rda zB8Rn67VV$Q$_A ztdoliULmjYw0e2pqa|dNakXJGx_xn~*>buX(NfspceJh3uixT_O}+`dgRQ!osD|aq*kbdj!9z$(iZSr@Y3r|InMH`_AOMl4=m{QSz! zhOH@txVHxi&s3!6o^L3*bjc<(7x>`ks2gQYx`}9xQ%WZZpTinoh5X z;C2Ly*->xZ3N0z}L!gNZ>QK=XM0z0OiFO%AC9yhQd3hw!t9(Q>7?w|A&r2Aq?xfpg+5i8w@`6bDb^n+t>y>H#sA*r%IB2`jA}0Z2gYYV z?TMa;*wXXNnbzb?&_^c+%LT6z+>stEm43-4N1GFTET~KC=lQLdq+KKzh83NPaTRdk zZu4l-l|p@AnCF;L0?aBRCR<=?UU8&i1WD@zx?P8sN#8tv@qYhXhAT!QFXaC2YhNvA zrKa(??DeTC@@w2eSMJSh9A$?Z*1KgSwj4h(Fslzp99)j&zI4y?X}Py65s;vc{h@Ez z(_;QmnX{{)v;Ys%*`MYn@{X|qqmENU2`%&jMSZ=ip_rl=0X4@?P6$Y6LnvTuh;5xi zhcn%DM6wb)(e2*e-b$HBIuyQe2br3Hx#ltRJWY$||A5B$XY57ZsgoNw`jL}G7EVs+ z8bK&JC2o&24GcHdZuf3@TK=BxmuPn<01y{!MViOp$mPB3zZEuzSA=kAtk@4`r1pxb zwm%+8Wqh-mv|w>}G&0N0DRQZI%7Hm9BCiQbaVK&WwM#-O2%Y>W*8Xg zh^TvUG{$#iQ~4B!j?A+s1%-utpy*ajT*S^2%Q6B`j-cJQah@}&1ci)jv^Si5lV;$T z4FcBMpG_8RgcagQmdME`bqes%Gfj0w%BM_Qb@*5UIJ)N zU$e1Xn~e6#du(K4l6D4YGWp}je(lCruZ~pr1GmViu$&^>Y0C<3g^?$2Xj<)O!ti$> z%iazoGz>^q7p1}5yddshqC9?C-yEF&dV^ufadb69}k^ZhX>c=qHAa- UI(onla1dmF)a6Lwp|k(>KOXtwbN~PV literal 0 HcmV?d00001 diff --git a/dev-demos/features/mask/demos/heatmapgrid.tsx b/dev-demos/features/mask/demos/heatmapgrid.tsx index da0987941d..7d1d9da67a 100644 --- a/dev-demos/features/mask/demos/heatmapgrid.tsx +++ b/dev-demos/features/mask/demos/heatmapgrid.tsx @@ -1,15 +1,15 @@ // @ts-ignore -import { Scene, HeatmapLayer } from '@antv/l7'; +import { HeatmapLayer, Scene } from '@antv/l7'; // @ts-ignore -import { GaodeMap } from '@antv/l7-maps'; +import { GaodeMap, Map } from '@antv/l7-maps'; import React, { useEffect } from 'react'; export default () => { useEffect(() => { const scene = new Scene({ id: 'map', - - map: new GaodeMap({ + // renderer: process.env.renderer, + map: new (process.env.CI ? Map : GaodeMap)({ center: [120.165, 30.26], pitch: 0, zoom: 2, diff --git a/dev-demos/features/mask/demos/heatmapgrid3d.tsx b/dev-demos/features/mask/demos/heatmapgrid3d.tsx index 2f6e1e8c13..26e9184027 100644 --- a/dev-demos/features/mask/demos/heatmapgrid3d.tsx +++ b/dev-demos/features/mask/demos/heatmapgrid3d.tsx @@ -1,15 +1,15 @@ // @ts-ignore -import { Scene, HeatmapLayer } from '@antv/l7'; +import { HeatmapLayer, Scene } from '@antv/l7'; // @ts-ignore -import { GaodeMap } from '@antv/l7-maps'; +import { GaodeMap, Map } from '@antv/l7-maps'; import React, { useEffect } from 'react'; export default () => { useEffect(() => { const scene = new Scene({ id: 'map', - - map: new GaodeMap({ + renderer: process.env.renderer, + map: new (process.env.CI ? Map : GaodeMap)({ style: 'light', pitch: 56.499, center: [114.07737552216226, 22.542656745583486], diff --git a/packages/core/src/services/layer/ILayerService.ts b/packages/core/src/services/layer/ILayerService.ts index 4608485199..f1c2ee4ec5 100644 --- a/packages/core/src/services/layer/ILayerService.ts +++ b/packages/core/src/services/layer/ILayerService.ts @@ -100,6 +100,8 @@ export interface ILayerModel { initModels(): Promise; needUpdate(): Promise; clearModels(refresh?: boolean): void; + + prerender(): void; render(renderOptions?: Partial): void; // canvasLayer @@ -499,6 +501,7 @@ export interface ILayer { passes?: Array, ): ILayer; renderLayers(): void; + prerender(): void; render(options?: Partial): ILayer; renderMultiPass(): any; diff --git a/packages/core/src/services/layer/LayerService.ts b/packages/core/src/services/layer/LayerService.ts index 057cb1f739..f6a0418bad 100644 --- a/packages/core/src/services/layer/LayerService.ts +++ b/packages/core/src/services/layer/LayerService.ts @@ -141,6 +141,11 @@ export default class LayerService this.alreadyInRendering = true; this.clear(); + for (const layer of this.layerList) { + layer.prerender(); + } + + // The main render pass, all layers in a whole. this.renderService.beginFrame(); for (const layer of this.layerList) { const { enableMask } = layer.getLayerConfig(); @@ -152,7 +157,7 @@ export default class LayerService // multiPassRender 不是同步渲染完成的 await layer.renderMultiPass(); } else { - await layer.render(); + layer.render(); } } this.renderService.endFrame(); diff --git a/packages/layers/src/core/BaseLayer.ts b/packages/layers/src/core/BaseLayer.ts index d3601bb25f..75a803cd2e 100644 --- a/packages/layers/src/core/BaseLayer.ts +++ b/packages/layers/src/core/BaseLayer.ts @@ -779,6 +779,8 @@ export default class BaseLayer this.rendering = false; } + prerender() {} + public render(options: Partial = {}): ILayer { if (this.tileLayer) { // 瓦片图层执行单独的 render 渲染队列 diff --git a/packages/layers/src/core/BaseModel.ts b/packages/layers/src/core/BaseModel.ts index ff347c76f0..9d0b63eaf8 100644 --- a/packages/layers/src/core/BaseModel.ts +++ b/packages/layers/src/core/BaseModel.ts @@ -1,4 +1,3 @@ - import type { IAnimateOption, IAttribute, @@ -25,7 +24,8 @@ import type { IStyleAttributeService, ITexture2D, ITexture2DInitializationOptions, - Triangulation} from '@antv/l7-core'; + Triangulation, +} from '@antv/l7-core'; import { BlendType, lazyInject, @@ -36,12 +36,12 @@ import { import { rgb2arr } from '@antv/l7-utils'; import { BlendTypes } from '../utils/blend'; import { getStencil, getStencilMask } from '../utils/stencil'; -import { DefaultUniformStyleType, DefaultUniformStyleValue } from './constant' -import { MultipleOfFourNumber } from './utils' import { getCommonStyleAttributeOptions, ShaderLocation, } from './CommonStyleAttribute'; +import { DefaultUniformStyleType, DefaultUniformStyleValue } from './constant'; +import { MultipleOfFourNumber } from './utils'; export type styleSingle = | number | string @@ -77,7 +77,8 @@ const shaderLocationMap: Record = { // eslint-disable-next-line @typescript-eslint/no-unused-vars export default class BaseModel - implements ILayerModel { + implements ILayerModel +{ public triangulation: Triangulation; public uniformBuffers: IBuffer[] = []; public textures: ITexture2D[] = []; @@ -202,12 +203,16 @@ export default class BaseModel const commoninfo = this.getCommonUniformsInfo(); const attributeInfo = this.getUniformsBufferInfo(this.getStyleAttribute()); this.updateStyleUnifoms(); - const result = { + const result = { ...attributeInfo.uniformsOption, - ...commoninfo.uniformsOption - } + ...commoninfo.uniformsOption, + }; //如果是regl渲染 需要在uniform中带上u_texture 暂时用this.rendererService.device判断 - if(!this.rendererService.hasOwnProperty('device')&&this.textures&&this.textures.length===1){ + if ( + !this.rendererService.hasOwnProperty('device') && + this.textures && + this.textures.length === 1 + ) { result['u_texture'] = this.textures[0]; } return result; @@ -239,6 +244,7 @@ export default class BaseModel } { throw new Error('Method not implemented.'); } + public prerender(): void {} // eslint-disable-next-line @typescript-eslint/no-unused-vars public render(renderOptions?: Partial): void { throw new Error('Method not implemented.'); @@ -272,19 +278,21 @@ export default class BaseModel const uniforms: string[] = []; // 支持数据映射的类型 this.layer.enableShaderEncodeStyles.forEach((key: string) => { - if (encodeStyleAttribute[key]) { // 配置了数据映射的类型 + if (encodeStyleAttribute[key]) { + // 配置了数据映射的类型 str += `#define USE_ATTRIBUTE_${key.toUpperCase()} 0.0; \n\n`; } else { uniforms.push(` ${DefaultUniformStyleType[key]} u_${key};`); } let location = shaderLocationMap[key]; - if(!location&&key==='THETA_OFFSET'){ + if (!location && key === 'THETA_OFFSET') { location = 15; } str += ` #ifdef USE_ATTRIBUTE_${key.toUpperCase()} - layout(location = ${shaderLocationMap[key]}) in ${DefaultUniformStyleType[key] - } a_${key.charAt(0).toUpperCase() + key.slice(1)}; + layout(location = ${shaderLocationMap[key]}) in ${ + DefaultUniformStyleType[key] + } a_${key.charAt(0).toUpperCase() + key.slice(1)}; #endif\n `; }); @@ -301,8 +309,9 @@ ${uniforms.join('\n')} this.layer.enableShaderEncodeStyles.forEach((key) => { innerStr += `\n #ifdef USE_ATTRIBUTE_${key.toUpperCase()} - ${DefaultUniformStyleType[key]} ${key} = a_${key.charAt(0).toUpperCase() + key.slice(1) - }; + ${DefaultUniformStyleType[key]} ${key} = a_${ + key.charAt(0).toUpperCase() + key.slice(1) + }; #else ${DefaultUniformStyleType[key]} ${key} = u_${key}; #endif\n @@ -327,7 +336,9 @@ ${uniforms.join('\n')} const keyValue = this.layer.getLayerConfig()[key]; let value = - typeof keyValue === 'undefined' ? DefaultUniformStyleValue[key] : keyValue; + typeof keyValue === 'undefined' + ? DefaultUniformStyleValue[key] + : keyValue; if (key === 'stroke') { value = rgb2arr(value); } @@ -358,19 +369,22 @@ ${uniforms.join('\n')} const commonUniforms = this.getCommonUniformsInfo(); if (attrUniforms.uniformsLength !== 0) { this.attributeUnifoms = this.rendererService.createBuffer({ - data: new Float32Array(MultipleOfFourNumber(attrUniforms.uniformsLength)).fill(0), // 长度需要大于等于 4 + data: new Float32Array( + MultipleOfFourNumber(attrUniforms.uniformsLength), + ).fill(0), // 长度需要大于等于 4 isUBO: true, }); this.uniformBuffers.push(this.attributeUnifoms); } if (commonUniforms.uniformsLength !== 0) { this.commonUnifoms = this.rendererService.createBuffer({ - data: new Float32Array(MultipleOfFourNumber(commonUniforms.uniformsLength)).fill(0), + data: new Float32Array( + MultipleOfFourNumber(commonUniforms.uniformsLength), + ).fill(0), isUBO: true, }); this.uniformBuffers.push(this.commonUnifoms); } - } // 获取数据映射 uniform 信息 protected getUniformsBufferInfo(uniformsOption: { [key: string]: any }) { @@ -380,48 +394,47 @@ ${uniforms.join('\n')} if (Array.isArray(value)) { uniformsArray.push(...value); uniformsLength += value.length; - } else if (typeof value === 'number' ) { // 排除纹理 + } else if (typeof value === 'number') { + // 排除纹理 uniformsArray.push(value); uniformsLength += 1; - } else if(typeof value ==='boolean') { + } else if (typeof value === 'boolean') { uniformsArray.push(Number(value)); uniformsLength += 1; } - }) + }); return { uniformsOption, uniformsLength, - uniformsArray - } - + uniformsArray, + }; } - protected getCommonUniformsInfo(): { uniformsArray: number[]; uniformsLength: number; uniformsOption: { [key: string]: any } } { + protected getCommonUniformsInfo(): { + uniformsArray: number[]; + uniformsLength: number; + uniformsOption: { [key: string]: any }; + } { return { uniformsLength: 0, uniformsArray: [], - uniformsOption: {} - } + uniformsOption: {}, + }; } // 更新支持数据映射的uniform public updateStyleUnifoms() { - const { uniformsArray } = this.getUniformsBufferInfo(this.getStyleAttribute()); + const { uniformsArray } = this.getUniformsBufferInfo( + this.getStyleAttribute(), + ); const { uniformsArray: commonUniformsArray } = this.getCommonUniformsInfo(); this.attributeUnifoms?.subData({ offset: 0, - data: new Uint8Array( - new Float32Array(uniformsArray).buffer, - ), + data: new Uint8Array(new Float32Array(uniformsArray).buffer), }); this.commonUnifoms?.subData({ offset: 0, - data: new Uint8Array( - new Float32Array(commonUniformsArray).buffer, - ), - } - ); - + data: new Uint8Array(new Float32Array(commonUniformsArray).buffer), + }); } - } diff --git a/packages/layers/src/heatmap/index.ts b/packages/layers/src/heatmap/index.ts index 0b50bb13f0..e8ba739508 100644 --- a/packages/layers/src/heatmap/index.ts +++ b/packages/layers/src/heatmap/index.ts @@ -12,6 +12,15 @@ export default class HeatMapLayer extends BaseLayer { await this.initLayerModels(); } + public prerender() { + const shape = this.getModelType(); + if (shape === 'heatmap') { + if (this.layerModel) { + this.layerModel.prerender(); // 独立的渲染流程 + } + } + } + public renderModels(options: Partial = {}) { const shape = this.getModelType(); if (shape === 'heatmap') { diff --git a/packages/layers/src/heatmap/models/heatmap.ts b/packages/layers/src/heatmap/models/heatmap.ts index 201dbebf2f..a38fb6ac0a 100644 --- a/packages/layers/src/heatmap/models/heatmap.ts +++ b/packages/layers/src/heatmap/models/heatmap.ts @@ -5,19 +5,11 @@ import type { IModel, IModelUniform, IRenderOptions, - ITexture2D} from '@antv/l7-core'; -import { - AttributeType, - gl, - TextureUsage, + ITexture2D, } from '@antv/l7-core'; -import type { - IColorRamp} from '@antv/l7-utils'; -import { - generateColorRamp, - getCullFace, - lodashUtil, -} from '@antv/l7-utils'; +import { AttributeType, TextureUsage, gl } from '@antv/l7-core'; +import type { IColorRamp } from '@antv/l7-utils'; +import { generateColorRamp, getCullFace, lodashUtil } from '@antv/l7-utils'; import { mat4 } from 'gl-matrix'; import { injectable } from 'inversify'; import 'reflect-metadata'; @@ -49,10 +41,8 @@ export default class HeatMapModel extends BaseModel { private colorModelUniformBuffer: IBuffer[] = []; private heat3DModelUniformBuffer: IBuffer[] = []; - public render(options: Partial) { + public prerender() { const { clear, useFramebuffer } = this.rendererService; - const { rampColors } = - this.layer.getLayerConfig() as IHeatMapLayerStyleOptions; useFramebuffer(this.heatmapFramerBuffer, () => { clear({ color: [0, 0, 0, 0], @@ -62,6 +52,12 @@ export default class HeatMapModel extends BaseModel { }); this.drawIntensityMode(); // 密度图 }); + } + + public render(options: Partial) { + const { rampColors } = + this.layer.getLayerConfig() as IHeatMapLayerStyleOptions; + if (!isEqual(this.preRampColors, rampColors)) { this.updateColorTexture(); } @@ -413,7 +409,6 @@ export default class HeatMapModel extends BaseModel { }); } - private updateColorTexture() { const { createTexture2D } = this.rendererService; if (this.texture) { diff --git a/packages/layers/src/mask/models/fill.ts b/packages/layers/src/mask/models/fill.ts index 7fa2895015..43687b43fb 100644 --- a/packages/layers/src/mask/models/fill.ts +++ b/packages/layers/src/mask/models/fill.ts @@ -1,19 +1,33 @@ import type { IModel } from '@antv/l7-core'; -import { lodashUtil, rgb2arr } from '@antv/l7-utils'; +import { rgb2arr } from '@antv/l7-utils'; import BaseModel from '../../core/BaseModel'; -import type { IMaskLayerStyleOptions } from '../../core/interface'; import { polygonTriangulation } from '../../core/triangulation'; import mask_frag from '../../shader/minify_frag.glsl'; import mask_vert from '../shaders/mask_vert.glsl'; -const { isNumber } = lodashUtil; export default class MaskModel extends BaseModel { public getUninforms() { - const { opacity = 1, color = '#000' } = - this.layer.getLayerConfig() as IMaskLayerStyleOptions; + const commoninfo = this.getCommonUniformsInfo(); + const attributeInfo = this.getUniformsBufferInfo(this.getStyleAttribute()); + this.updateStyleUnifoms(); return { - u_opacity: isNumber(opacity) ? opacity : 0.0, + ...commoninfo.uniformsOption, + ...attributeInfo.uniformsOption, + }; + } + + protected getCommonUniformsInfo(): { + uniformsArray: number[]; + uniformsLength: number; + uniformsOption: { [key: string]: any }; + } { + const { opacity = 1, color = '#000' } = this.layer.getLayerConfig() as any; + const commonOptions = { u_color: rgb2arr(color), + u_opacity: opacity || 1, }; + + const commonBufferInfo = this.getUniformsBufferInfo(commonOptions); + return commonBufferInfo; } public async initModels(): Promise { @@ -21,6 +35,7 @@ export default class MaskModel extends BaseModel { } public async buildModels(): Promise { + this.initUniformsBuffer(); const model = await this.layer.buildLayerModel({ moduleName: 'mask', vertexShader: mask_vert, diff --git a/packages/layers/src/mask/shaders/mask_vert.glsl b/packages/layers/src/mask/shaders/mask_vert.glsl index 05b0fba16f..4a6b6b749b 100644 --- a/packages/layers/src/mask/shaders/mask_vert.glsl +++ b/packages/layers/src/mask/shaders/mask_vert.glsl @@ -1,6 +1,9 @@ -attribute vec3 a_Position; -uniform mat4 u_ModelMatrix; +layout(location = 0) in vec3 a_Position; +layout(std140) uniform commonUniorm { + vec4 u_color; + float u_opacity; +}; #pragma include "projection" diff --git a/packages/layers/src/shader/minify_frag.glsl b/packages/layers/src/shader/minify_frag.glsl index 6fb20cb940..58408b454d 100644 --- a/packages/layers/src/shader/minify_frag.glsl +++ b/packages/layers/src/shader/minify_frag.glsl @@ -1,7 +1,11 @@ -uniform float u_opacity : 1.0; -uniform vec4 u_color; +layout(std140) uniform commonUniorm { + vec4 u_color; + float u_opacity; +}; + +out vec4 outputColor; void main() { - gl_FragColor = u_color; - gl_FragColor.a *= u_opacity; + outputColor = u_color; + outputColor.a *= u_opacity; }