* feat: bloom 效果优化

* style: lint style

* docs: 在 readme 添加最新官网地址

* feat: 增加 multiPass 状态开关方法 setMultiPass

* feat: 优化 setMultiPass 方法

* style: lint style
This commit is contained in:
YiQianYao 2022-03-07 11:30:41 +08:00 committed by GitHub
parent b72aef9a28
commit ebef919f64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 250 additions and 130 deletions

View File

@ -13,6 +13,8 @@ Powered by WebGL, the rendering technology of L7 supports fast and efficient ren
L7 focuses on geographic data expressivenessinteraction and design of geographic visualization layers. The basemaps on the platform are powered by third-party services
[website](https://l7.antv.vision/zh)
## 🌄 L7 visualization demos
![L7 demo](https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*S-73QpO8d0YAAAAAAAAAAABkARQnAQ)

View File

@ -12,6 +12,8 @@
L7 是由蚂蚁金服 AntV 数据可视化团队推出的基于 WebGL 的开源大规模地理空间数据可视分析开发框架。L7 中的 L 代表 Location7 代表世界七大洲寓意能为全球位置数据提供可视分析的能力。L7 专注数据可视化化表达,通过颜色、大小、纹理,方向,体积等视觉变量设置实现从数据到信息清晰,有效的表达。
[官网地址](https://l7.antv.vision/zh)
L7 能够满足常见的地图图表BI 系统的可视化分析、以及 GIS交通电力国土农业城市等领域的空间信息管理分析等应用系统开发需求。
![L7 demo](https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*S-73QpO8d0YAAAAAAAAAAABkARQnAQ)

View File

@ -214,6 +214,11 @@ export interface ILayer {
get(name: string): number;
setBlend(type: keyof typeof BlendType): ILayer;
// animate(field: string, option: any): ILayer;
setMultiPass(
multipass: boolean,
passes?: Array<string | [string, { [key: string]: unknown }]>,
): ILayer;
renderLayers(): void;
render(): ILayer;

View File

@ -28,14 +28,6 @@ float luminance(vec4 color) {
void main() {
// vec4 baseColor = texture2D(u_Texture, v_UV);
// float lum = luminance(baseColor);
// baseColor.a *= lum;
// gl_FragColor = baseColor;
// if(u_BloomFinal > 0.0) { //
// gl_FragColor = baseColor; //--
// }
float r = sqrt(u_radius);
@ -55,64 +47,11 @@ void main() {
if(u_BloomFinal > 0.0) {
vec4 baseColor = texture2D(u_Texture2, v_UV);
float baselum = luminance(baseColor);
// float lum = luminance(inbloomColor);
// vec4 bloom = vec4(lum);
// inbloomColor.a *= lum;
// gl_FragColor = inbloomColor * u_intensity + texture2D(u_Texture2, v_UV);
// gl_FragColor = inbloomColor * 0.5 + texture2D(u_Texture2, v_UV);
// gl_FragColor = baseColor;
// gl_FragColor = inbloomColor;
// vec4 mixColor = mix(baseColor, inbloomColor, max(u_intensity - 0.3, 0.0));
// mixColor.a = max(baseColor.a, mixColor.a);
gl_FragColor = mix(inbloomColor, baseColor, max(1.0 - u_intensity, u_baseRadio));
// gl_FragColor = mixColor;
// gl_FragColor = baseColor;
if(baselum <= 0.0) {
// float lum = luminance(inbloomColor);
// inbloomColor.rgb *= lum;
gl_FragColor += inbloomColor * u_intensity;
gl_FragColor = mix(inbloomColor, baseColor, u_baseRadio);
if(baselum <= 0.2) {
gl_FragColor = inbloomColor * u_intensity;
}
// gl_FragColor = inbloomColor * baseColor + baseColor;
// gl_FragColor = baseColor + bloom * 0.5;
} else {
gl_FragColor = inbloomColor;
}
// gl_FragColor = inbloomColor;
// float h = 0.01;
// vec4 color11 = texture2D( u_Texture, vec2( v_UV.x - 1.0 * h, v_UV.y + 1.0 * h) );
// vec4 color12 = texture2D( u_Texture, vec2( v_UV.x - 0.0 * h, v_UV.y + 1.0 * h) );
// vec4 color13 = texture2D( u_Texture, vec2( v_UV.x + 1.0 * h, v_UV.y + 1.0 * h) );
// vec4 color21 = texture2D( u_Texture, vec2( v_UV.x - 1.0 * h, v_UV.y) );
// vec4 color23 = texture2D( u_Texture, vec2( v_UV.x + 1.0 * h, v_UV.y) );
// vec4 color31 = texture2D( u_Texture, vec2( v_UV.x - 1.0 * h, v_UV.y-1.0*h) );
// vec4 color32 = texture2D( u_Texture, vec2( v_UV.x - 0.0 * h, v_UV.y-1.0*h) );
// vec4 color33 = texture2D( u_Texture, vec2( v_UV.x + 1.0 * h, v_UV.y-1.0*h) );
// vec4 bloomColor =
// color11 +
// color12 +
// color13 +
// color21 +
// color21 +
// color23 +
// color31 +
// color32 +
// color33;
// if(baseColor.a > 0.0) {
// gl_FragColor.r = min(bloomColor.r, baseColor.r);
// gl_FragColor.g = min(bloomColor.g, baseColor.g);
// gl_FragColor.b = min(bloomColor.b, baseColor.b);
// gl_FragColor.a = min(bloomColor.a, baseColor.a);
// gl_FragColor = mix(inbloomColor, gl_FragColor, 0.7);
// } else {
// gl_FragColor = bloomColor/9.0;
// }
}

View File

@ -51,9 +51,12 @@ import { encodePickingColor } from '@antv/l7-utils';
import { EventEmitter } from 'eventemitter3';
import { Container } from 'inversify';
import { isFunction, isObject, isUndefined } from 'lodash';
import { normalizePasses } from '../plugins/MultiPassRendererPlugin';
import { BlendTypes } from '../utils/blend';
import { handleStyleDataMapping } from '../utils/dataMappingStyle';
import {
createMultiPassRenderer,
normalizePasses,
} from '../utils/multiPassRender';
import { updateShape } from '../utils/updateShape';
/**
* layer id
@ -766,6 +769,35 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
return !!visible && zoom >= minZoom && zoom <= maxZoom;
}
public setMultiPass(
enableMultiPass: boolean,
currentPasses?: Array<string | [string, { [key: string]: unknown }]>,
) {
this.updateLayerConfig({
enableMultiPassRenderer: enableMultiPass,
});
if (currentPasses) {
this.updateLayerConfig({
passes: currentPasses,
});
}
if (enableMultiPass) {
const { passes = [] } = this.getLayerConfig();
this.multiPassRenderer = createMultiPassRenderer(
this,
passes,
this.postProcessingPassFactory,
this.normalPassFactory,
);
this.multiPassRenderer.setRenderFlag(true);
const { width, height } = this.rendererService.getViewportSize();
this.multiPassRenderer.resize(width, height);
}
return this;
}
public setMinZoom(minZoom: number): ILayer {
this.updateLayerConfig({
minZoom,

View File

@ -9,20 +9,7 @@ import {
} from '@antv/l7-core';
import { inject, injectable } from 'inversify';
import 'reflect-metadata';
/**
* 'blurH' -> ['blurH', {}]
*/
export function normalizePasses(
passes: Array<string | [string, { [key: string]: unknown }]>,
) {
return passes.map((pass: string | [string, { [key: string]: unknown }]) => {
if (typeof pass === 'string') {
pass = [pass, {}];
}
return pass;
});
}
import { createMultiPassRenderer } from '../utils/multiPassRender';
/**
* 线
@ -66,7 +53,7 @@ export default class MultiPassRendererPlugin implements ILayerPlugin {
// 根据 LayerConfig passes 配置项初始化
if (this.enabled) {
layer.multiPassRenderer = this.createMultiPassRenderer(
layer.multiPassRenderer = createMultiPassRenderer(
layer,
passes,
postProcessingPassFactory,
@ -84,47 +71,4 @@ export default class MultiPassRendererPlugin implements ILayerPlugin {
}
});
}
/**
* ClearPassRenderPass
* PostProcessing CopyPass
*/
private createMultiPassRenderer(
layer: ILayer,
passes: Array<string | [string, { [key: string]: unknown }]>,
postProcessingPassFactory: (name: string) => IPostProcessingPass<unknown>,
normalPassFactory: (name: string) => IPass<unknown>,
) {
const multiPassRenderer = layer.multiPassRenderer;
const { enablePicking, enableTAA } = layer.getLayerConfig();
// picking pass if enabled
// if (enablePicking) {
// multiPassRenderer.add(normalPassFactory('pixelPicking'));
// }
// use TAA pass if enabled instead of render pass
if (enableTAA) {
multiPassRenderer.add(normalPassFactory('taa'));
} else {
// render all layers in this pass
multiPassRenderer.add(normalPassFactory('render'));
}
// post processing
normalizePasses(passes).forEach(
(pass: [string, { [key: string]: unknown }]) => {
const [passName, initializationOptions] = pass;
multiPassRenderer.add(
postProcessingPassFactory(passName),
initializationOptions,
);
},
);
// 末尾为固定的 CopyPass
multiPassRenderer.add(postProcessingPassFactory('copy'));
return multiPassRenderer;
}
}

View File

@ -0,0 +1,66 @@
import {
IGlobalConfigService,
ILayer,
ILayerPlugin,
IPass,
IPostProcessingPass,
IRendererService,
TYPES,
} from '@antv/l7-core';
/**
* 'blurH' -> ['blurH', {}]
*/
export function normalizePasses(
passes: Array<string | [string, { [key: string]: unknown }]>,
) {
return passes.map((pass: string | [string, { [key: string]: unknown }]) => {
if (typeof pass === 'string') {
pass = [pass, {}];
}
return pass;
});
}
/**
* ClearPassRenderPass
* PostProcessing CopyPass
*/
export function createMultiPassRenderer(
layer: ILayer,
passes: Array<string | [string, { [key: string]: unknown }]>,
postProcessingPassFactory: (name: string) => IPostProcessingPass<unknown>,
normalPassFactory: (name: string) => IPass<unknown>,
) {
const multiPassRenderer = layer.multiPassRenderer;
const { enablePicking, enableTAA } = layer.getLayerConfig();
// picking pass if enabled
// if (enablePicking) {
// multiPassRenderer.add(normalPassFactory('pixelPicking'));
// }
// use TAA pass if enabled instead of render pass
if (enableTAA) {
multiPassRenderer.add(normalPassFactory('taa'));
} else {
// render all layers in this pass
multiPassRenderer.add(normalPassFactory('render'));
}
// post processing
normalizePasses(passes).forEach(
(pass: [string, { [key: string]: unknown }]) => {
const [passName, initializationOptions] = pass;
multiPassRenderer.add(
postProcessingPassFactory(passName),
initializationOptions,
);
},
);
// 末尾为固定的 CopyPass
multiPassRenderer.add(postProcessingPassFactory('copy'));
return multiPassRenderer;
}

View File

@ -1,6 +1,7 @@
import { storiesOf } from '@storybook/react';
import * as React from 'react';
import Bloom from './components/Bloom';
import BloomClick from './components/BloomClick';
import Blur from './components/Blur';
import ColorHalftone from './components/ColorHalftone';
import CustomPostProcessing from './components/CustomPostProcessing';
@ -15,6 +16,7 @@ storiesOf('MultiPassRenderer', module)
.add('HexagonalPixelate', () => <HexagonalPixelate />)
.add('Ink', () => <Ink />)
.add('Bloom', () => <Bloom />)
.add('BloomClick', () => <BloomClick/>)
.add('Blur', () => <Blur />)
.add('Noise', () => <Noise />)
.add('Sepia', () => <Sepia />)

View File

@ -28,7 +28,7 @@ export default class Bloom extends React.Component {
map: new Mapbox({
style: 'mapbox://styles/mapbox/streets-v9',
// style: 'blank',
center: [110.19382669582967, 50.258134],
center: [122, 30],
pitch: 0,
zoom: 3,
}),
@ -43,15 +43,13 @@ export default class Bloom extends React.Component {
[
'bloom',
{
// bloomBaseRadio: 0.5,
bloomRadius: 25,
bloomBaseRadio: 0.5,
bloomRadius: 20,
bloomIntensity: 1,
},
],
],
});
layer
})
.source(data)
.size('name', [0, 10000, 50000, 30000, 100000])
.color('name', [
@ -70,7 +68,21 @@ export default class Bloom extends React.Component {
scene.addLayer(layer);
let pointLayer = new PointLayer({ zIndex: 1 })
// console.log('layer', layer)
let pointLayer = new PointLayer({
zIndex: 1,
enableMultiPassRenderer: false,
// passes: [
// [
// 'bloom',
// {
// bloomRadius: 10,
// bloomIntensity: 1,
// },
// ],
// ],
})
.source([{ lng: 122, lat: 30 }], {
parser: {
type: 'json',
@ -83,6 +95,21 @@ export default class Bloom extends React.Component {
.color('red');
scene.addLayer(pointLayer);
setTimeout(() => {
layer.setMultiPass(false);
pointLayer.setMultiPass(true, [
[
'bloom',
{
bloomRadius: 10,
bloomIntensity: 1,
},
],
]);
scene.render();
}, 1000);
this.scene = scene;
}

View File

@ -0,0 +1,101 @@
import { PolygonLayer, PointLayer, Scene } from '@antv/l7';
import { Mapbox } from '@antv/l7-maps';
import * as dat from 'dat.gui';
import * as React from 'react';
export default class Bloom extends React.Component {
private gui: dat.GUI;
private $stats: Node;
private scene: Scene;
public componentWillUnmount() {
if (this.gui) {
this.gui.destroy();
}
if (this.$stats) {
document.body.removeChild(this.$stats);
}
this.scene.destroy();
}
public async componentDidMount() {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/d2e0e930-fd44-4fca-8872-c1037b0fee7b.json',
);
const data = await response.json();
const scene = new Scene({
id: 'map',
map: new Mapbox({
style: 'mapbox://styles/mapbox/streets-v9',
// style: 'blank',
center: [122, 30],
pitch: 0,
zoom: 3,
}),
});
// @ts-ignore
let selectLayer = null;
for (let i = 0; i < 10; i++) {
let pointLayer = new PointLayer({
zIndex: 1,
enableMultiPassRenderer: false,
passes: [
[
'bloom',
{
bloomBaseRadio: 0.95,
bloomRadius: 4,
bloomIntensity: 1.1,
},
],
],
})
.source(
[{ lng: 120 + Math.random() * 10, lat: 20 + Math.random() * 10 }],
{
parser: {
type: 'json',
x: 'lng',
y: 'lat',
},
},
)
.shape('circle')
.size(20)
.color('red');
scene.addLayer(pointLayer);
}
scene.on('loaded', () => {
scene.getLayers().map((layer) => {
layer.on('click', () => {
// @ts-ignore
if (selectLayer) {
// @ts-ignore
selectLayer.setMultiPass(false);
}
selectLayer = layer;
layer.setMultiPass(true);
});
});
});
this.scene = scene;
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
}