mirror of https://gitee.com/antv-l7/antv-l7
Shihui (#994)
* feat: bloom 效果优化 * style: lint style * docs: 在 readme 添加最新官网地址 * feat: 增加 multiPass 状态开关方法 setMultiPass * feat: 优化 setMultiPass 方法 * style: lint style
This commit is contained in:
parent
b72aef9a28
commit
ebef919f64
|
@ -13,6 +13,8 @@ Powered by WebGL, the rendering technology of L7 supports fast and efficient ren
|
|||
|
||||
L7 focuses on geographic data expressiveness,interaction 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)
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
L7 是由蚂蚁金服 AntV 数据可视化团队推出的基于 WebGL 的开源大规模地理空间数据可视分析开发框架。L7 中的 L 代表 Location,7 代表世界七大洲,寓意能为全球位置数据提供可视分析的能力。L7 专注数据可视化化表达,通过颜色、大小、纹理,方向,体积等视觉变量设置实现从数据到信息清晰,有效的表达。
|
||||
|
||||
[官网地址](https://l7.antv.vision/zh)
|
||||
|
||||
L7 能够满足常见的地图图表,BI 系统的可视化分析、以及 GIS,交通,电力,国土,农业,城市等领域的空间信息管理,分析等应用系统开发需求。
|
||||
|
||||
![L7 demo](https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*S-73QpO8d0YAAAAAAAAAAABkARQnAQ)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
// }
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认添加 ClearPass、RenderPass
|
||||
* 以及 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认添加 ClearPass、RenderPass
|
||||
* 以及 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;
|
||||
}
|
|
@ -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 />)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue