mirror of https://gitee.com/antv-l7/antv-l7
refactor(@l7/core): 重构 MultiPassRenderer & PostProcessor
不依赖具体 renderer 渲染服务接口,@l7/renderer 各渲染引擎只需要实现基础 WebGL 资源对象接口
This commit is contained in:
parent
31a3db93a1
commit
7059ef3186
|
@ -65,3 +65,5 @@ jspm_packages/
|
|||
# End of https://www.gitignore.io/api/node
|
||||
|
||||
lib/
|
||||
|
||||
.DS_Store
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
"@l7/source": "0.0.1",
|
||||
"eventemitter3": "^3.1.0",
|
||||
"gl-matrix": "^3.1.0",
|
||||
"hammerjs": "^2.0.8",
|
||||
"inversify": "^5.0.1",
|
||||
"inversify-inject-decorators": "^3.1.0",
|
||||
"lodash": "^4.17.15",
|
||||
|
@ -32,6 +33,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/gl-matrix": "^2.4.5",
|
||||
"@types/hammerjs": "^2.0.36",
|
||||
"@types/lodash": "^4.14.138",
|
||||
"@types/viewport-mercator-project": "^6.1.0"
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import container, { lazyInject } from './inversify.config';
|
||||
import ClearPass from './services/renderer/passes/ClearPass';
|
||||
import MultiPassRenderer from './services/renderer/passes/MultiPassRenderer';
|
||||
import PixelPickingPass from './services/renderer/passes/PixelPickingPass';
|
||||
import BlurHPass from './services/renderer/passes/post-processing/BlurHPass';
|
||||
import BlurVPass from './services/renderer/passes/post-processing/BlurVPass';
|
||||
import CopyPass from './services/renderer/passes/post-processing/CopyPass';
|
||||
|
@ -27,8 +29,10 @@ export {
|
|||
SceneService,
|
||||
packCircleVertex,
|
||||
/** pass */
|
||||
MultiPassRenderer,
|
||||
ClearPass,
|
||||
RenderPass,
|
||||
PixelPickingPass,
|
||||
BlurHPass,
|
||||
BlurVPass,
|
||||
CopyPass,
|
||||
|
|
|
@ -9,6 +9,7 @@ import { TYPES } from './types';
|
|||
import { ICameraService } from './services/camera/ICameraService';
|
||||
import { IGlobalConfigService } from './services/config/IConfigService';
|
||||
import { ICoordinateSystemService } from './services/coordinate/ICoordinateSystemService';
|
||||
import { IInteractionService } from './services/interaction/IInteractionService';
|
||||
import { ILayerService } from './services/layer/ILayerService';
|
||||
import { ILogService } from './services/log/ILogService';
|
||||
import { IShaderModuleService } from './services/shader/IShaderModuleService';
|
||||
|
@ -17,6 +18,7 @@ import { IShaderModuleService } from './services/shader/IShaderModuleService';
|
|||
import CameraService from './services/camera/CameraService';
|
||||
import GlobalConfigService from './services/config/ConfigService';
|
||||
import CoordinateSystemService from './services/coordinate/CoordinateSystemService';
|
||||
import InteractionService from './services/interaction/InteractionService';
|
||||
import LayerService from './services/layer/LayerService';
|
||||
import LayerStyleService from './services/layer/LayerStyleService';
|
||||
import LogService from './services/log/LogService';
|
||||
|
@ -52,6 +54,10 @@ container
|
|||
.bind<ILogService>(TYPES.ILogService)
|
||||
.to(LogService)
|
||||
.inSingletonScope();
|
||||
container
|
||||
.bind<IInteractionService>(TYPES.IInteractionService)
|
||||
.to(InteractionService)
|
||||
.inSingletonScope();
|
||||
|
||||
// @see https://github.com/inversify/InversifyJS/blob/master/wiki/inheritance.md#what-can-i-do-when-my-base-class-is-provided-by-a-third-party-module
|
||||
decorate(injectable(), EventEmitter);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
export interface IInteractionService {
|
||||
init(): void;
|
||||
destroy(): void;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
import Hammer from 'hammerjs';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { TYPES } from '../../types';
|
||||
import { ILogService } from '../log/ILogService';
|
||||
import { IRendererService } from '../renderer/IRendererService';
|
||||
import { IInteractionService } from './IInteractionService';
|
||||
|
||||
@injectable()
|
||||
export default class InteractionService implements IInteractionService {
|
||||
@inject(TYPES.IRendererService)
|
||||
private readonly rendererService: IRendererService;
|
||||
|
||||
@inject(TYPES.ILogService)
|
||||
private readonly logger: ILogService;
|
||||
|
||||
private hammertime: HammerManager;
|
||||
|
||||
public init() {
|
||||
const $containter = this.rendererService.getContainer();
|
||||
if ($containter) {
|
||||
const hammertime = new Hammer($containter);
|
||||
hammertime.get('pan').set({ direction: Hammer.DIRECTION_ALL });
|
||||
hammertime.get('pinch').set({ enable: true });
|
||||
|
||||
// hammertime.on('panstart', this.onPanstart);
|
||||
hammertime.on('panmove', this.onPanmove);
|
||||
// hammertime.on('panend', this.onPanend);
|
||||
// hammertime.on('pinch', this.onPinch);
|
||||
|
||||
// $containter.addEventListener('wheel', this.onMousewheel);
|
||||
this.hammertime = hammertime;
|
||||
}
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
if (this.hammertime) {
|
||||
this.hammertime.destroy();
|
||||
}
|
||||
const $containter = this.rendererService.getContainer();
|
||||
if ($containter) {
|
||||
// $containter.removeEventListener('wheel', this.onMousewheel);
|
||||
}
|
||||
}
|
||||
|
||||
private onPanmove = (e: HammerInput) => {
|
||||
// @ts-ignore
|
||||
// this.logger.info(e);
|
||||
// if (this.isMoving) {
|
||||
// this.deltaX = e.center.x - this.lastX;
|
||||
// this.deltaY = e.center.y - this.lastY;
|
||||
// this.lastX = e.center.x;
|
||||
// this.lastY = e.center.y;
|
||||
// this.emit(Mouse.MOVE_EVENT, {
|
||||
// deltaX: this.deltaX,
|
||||
// deltaY: this.deltaY,
|
||||
// deltaZ: this.deltaZ
|
||||
// });
|
||||
// }
|
||||
};
|
||||
}
|
|
@ -92,6 +92,7 @@ export interface ILayerPlugin {
|
|||
*/
|
||||
export interface ILayerInitializationOptions {
|
||||
enableMultiPassRenderer: boolean;
|
||||
enablePicking: boolean;
|
||||
passes: Array<string | [string, { [key: string]: unknown }]>;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,9 +31,6 @@ export interface IPostProcessingPass extends IPass {
|
|||
export interface IPostProcessor {
|
||||
getReadFBO(): IFramebuffer;
|
||||
getWriteFBO(): IFramebuffer;
|
||||
useScreenRenderTarget(renderCommand: () => void): void;
|
||||
useOffscreenRenderTarget(renderCommand: () => void): void;
|
||||
renderToPostProcessor(renderCommand: () => void): void;
|
||||
resize(viewportWidth: number, viewportHeight: number): void;
|
||||
add(pass: IPostProcessingPass, layer: ILayer): void;
|
||||
render(layer: ILayer): Promise<unknown>;
|
||||
|
|
|
@ -2,9 +2,13 @@ import { ILayer } from '../layer/ILayerService';
|
|||
import { IAttribute, IAttributeInitializationOptions } from './IAttribute';
|
||||
import { IBuffer, IBufferInitializationOptions } from './IBuffer';
|
||||
import { IElements, IElementsInitializationOptions } from './IElements';
|
||||
import { IFramebuffer } from './IFramebuffer';
|
||||
import {
|
||||
IFramebuffer,
|
||||
IFramebufferInitializationOptions,
|
||||
} from './IFramebuffer';
|
||||
import { IModel, IModelInitializationOptions } from './IModel';
|
||||
import { IMultiPassRenderer, IPass } from './IMultiPassRenderer';
|
||||
import { ITexture2D, ITexture2DInitializationOptions } from './ITexture2D';
|
||||
|
||||
export interface IRenderConfig {
|
||||
/**
|
||||
|
@ -32,7 +36,13 @@ export interface IRendererService {
|
|||
createAttribute(options: IAttributeInitializationOptions): IAttribute;
|
||||
createBuffer(options: IBufferInitializationOptions): IBuffer;
|
||||
createElements(options: IElementsInitializationOptions): IElements;
|
||||
createMultiPassRenderer(layer: ILayer): IMultiPassRenderer;
|
||||
createTexture2D(options: ITexture2DInitializationOptions): ITexture2D;
|
||||
createFramebuffer(options: IFramebufferInitializationOptions): IFramebuffer;
|
||||
renderToFramebuffer(
|
||||
framebuffer: IFramebuffer | null,
|
||||
drawCommands: () => void,
|
||||
): void;
|
||||
getViewportSize(): { width: number; height: number };
|
||||
getContainer(): HTMLElement | null;
|
||||
viewport(size: { x: number; y: number; width: number; height: number }): void;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
|
|||
protected readonly shaderModule: IShaderModuleService;
|
||||
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
protected readonly renderer: IRendererService;
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
protected config: Partial<InitializationOptions> | undefined;
|
||||
|
||||
|
@ -51,7 +51,7 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
|
|||
}
|
||||
|
||||
public init() {
|
||||
const { createAttribute, createBuffer, createModel } = this.renderer;
|
||||
const { createAttribute, createBuffer, createModel } = this.rendererService;
|
||||
const { vs, fs, uniforms } = this.setupShaders();
|
||||
|
||||
this.model = createModel({
|
||||
|
@ -81,19 +81,31 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
|
|||
|
||||
public render(layer: ILayer) {
|
||||
const postProcessor = layer.multiPassRenderer.getPostProcessor();
|
||||
const { renderToFramebuffer } = this.rendererService;
|
||||
|
||||
const useRenderTarget = (this.renderToScreen
|
||||
? postProcessor.useScreenRenderTarget
|
||||
: postProcessor.useOffscreenRenderTarget
|
||||
).bind(postProcessor);
|
||||
|
||||
useRenderTarget(async () => {
|
||||
renderToFramebuffer(
|
||||
this.renderToScreen ? null : postProcessor.getWriteFBO(),
|
||||
() => {
|
||||
this.model.draw({
|
||||
uniforms: {
|
||||
u_Texture: postProcessor.getReadFBO(),
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
// const useRenderTarget = (this.renderToScreen
|
||||
// ? postProcessor.useScreenRenderTarget
|
||||
// : postProcessor.useOffscreenRenderTarget
|
||||
// ).bind(postProcessor);
|
||||
|
||||
// useRenderTarget(async () => {
|
||||
// this.model.draw({
|
||||
// uniforms: {
|
||||
// u_Texture: postProcessor.getReadFBO(),
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
public isEnabled() {
|
||||
|
|
|
@ -1,45 +1,44 @@
|
|||
import { injectable } from 'inversify';
|
||||
import { ILayer } from '../../layer/ILayerService';
|
||||
import {
|
||||
ILayer,
|
||||
IMultiPassRenderer,
|
||||
IPass,
|
||||
IPostProcessingPass,
|
||||
IPostProcessor,
|
||||
PassType,
|
||||
} from '@l7/core';
|
||||
import regl from 'regl';
|
||||
import ReglPostProcessor from './ReglPostProcessor';
|
||||
} from '../IMultiPassRenderer';
|
||||
import PostProcessor from './PostProcessor';
|
||||
|
||||
/**
|
||||
* ported from Three.js EffectComposer
|
||||
* @example
|
||||
* const renderer = new MultiPassRenderer(gl, [
|
||||
* new ClearPass(gl),
|
||||
* new RenderPass(gl, {
|
||||
* const renderer = new MultiPassRenderer([
|
||||
* new ClearPass(),
|
||||
* new RenderPass({
|
||||
* models: [
|
||||
* new Model(),
|
||||
* new Model(),
|
||||
* ],
|
||||
* }),
|
||||
* new CopyPass(gl, {
|
||||
* new CopyPass({
|
||||
* renderToScreen: true,
|
||||
* }),
|
||||
* new TAAPass(gl),
|
||||
* new TAAPass(),
|
||||
* ]);
|
||||
* renderer.render();
|
||||
* @see https://yuque.antfin-inc.com/yuqi.pyq/fgetpa/apuvbf#dRM8W
|
||||
*/
|
||||
export default class ReglMultiPassRenderer implements IMultiPassRenderer {
|
||||
@injectable()
|
||||
export default class MultiPassRenderer implements IMultiPassRenderer {
|
||||
private passes: IPass[] = [];
|
||||
private postProcessor: IPostProcessor;
|
||||
|
||||
private reGl: regl.Regl;
|
||||
private layer: ILayer;
|
||||
private renderFlag: boolean;
|
||||
|
||||
constructor(reGl: regl.Regl, layer: ILayer) {
|
||||
this.reGl = reGl;
|
||||
constructor(layer: ILayer) {
|
||||
this.layer = layer;
|
||||
this.postProcessor = new ReglPostProcessor(reGl);
|
||||
this.postProcessor = new PostProcessor();
|
||||
}
|
||||
|
||||
public setRenderFlag(renderFlag: boolean) {
|
|
@ -0,0 +1,46 @@
|
|||
import { inject, injectable } from 'inversify';
|
||||
import { lazyInject } from '../../../index';
|
||||
import { TYPES } from '../../../types';
|
||||
import { ILayer, ILayerService } from '../../layer/ILayerService';
|
||||
import { gl } from '../gl';
|
||||
import { IFramebuffer } from '../IFramebuffer';
|
||||
import { IPass, PassType } from '../IMultiPassRenderer';
|
||||
import { IRendererService } from '../IRendererService';
|
||||
|
||||
/**
|
||||
* PixelPickingPass based on
|
||||
*/
|
||||
@injectable()
|
||||
export default class PixelPickingPass implements IPass {
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
private pickingFBO: IFramebuffer;
|
||||
|
||||
public getType() {
|
||||
return PassType.Normal;
|
||||
}
|
||||
|
||||
public init(layer: ILayer) {
|
||||
const { createTexture2D, createFramebuffer } = this.rendererService;
|
||||
this.pickingFBO = createFramebuffer({
|
||||
color: createTexture2D({
|
||||
width: 1,
|
||||
height: 1,
|
||||
wrapS: gl.CLAMP_TO_EDGE,
|
||||
wrapT: gl.CLAMP_TO_EDGE,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
public render(layer: ILayer) {
|
||||
const { getViewportSize, renderToFramebuffer } = this.rendererService;
|
||||
this.pickingFBO.resize(getViewportSize());
|
||||
|
||||
renderToFramebuffer(this.pickingFBO, () => {
|
||||
layer.multiPassRenderer.setRenderFlag(false);
|
||||
layer.render();
|
||||
layer.multiPassRenderer.setRenderFlag(true);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,32 +1,29 @@
|
|||
import {
|
||||
gl,
|
||||
IFramebuffer,
|
||||
ILayer,
|
||||
IPostProcessingPass,
|
||||
IPostProcessor,
|
||||
} from '@l7/core';
|
||||
import regl from 'regl';
|
||||
import ReglFramebuffer from './ReglFramebuffer';
|
||||
import ReglTexture2D from './ReglTexture2D';
|
||||
import { injectable } from 'inversify';
|
||||
import { lazyInject } from '../../../index';
|
||||
import { TYPES } from '../../../types';
|
||||
import { ILayer } from '../../layer/ILayerService';
|
||||
import { gl } from '../gl';
|
||||
import { IFramebuffer } from '../IFramebuffer';
|
||||
import { IPostProcessingPass, IPostProcessor } from '../IMultiPassRenderer';
|
||||
import { IRendererService } from '../IRendererService';
|
||||
|
||||
/**
|
||||
* ported from Three.js EffectComposer
|
||||
* 后处理负责 pingpong read/write framebuffer,最后一个 pass 默认输出到屏幕
|
||||
*/
|
||||
export default class ReglPostProcessor implements IPostProcessor {
|
||||
@injectable()
|
||||
export default class PostProcessor implements IPostProcessor {
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
private passes: IPostProcessingPass[] = [];
|
||||
private readFBO: IFramebuffer;
|
||||
private writeFBO: IFramebuffer;
|
||||
|
||||
private screenRenderTarget: regl.DrawCommand;
|
||||
private offscreenRenderTarget: regl.DrawCommand;
|
||||
private inputRenderTarget: regl.DrawCommand;
|
||||
|
||||
private reGl: regl.Regl;
|
||||
|
||||
constructor(reGl: regl.Regl) {
|
||||
this.reGl = reGl;
|
||||
this.readFBO = new ReglFramebuffer(reGl, {
|
||||
color: new ReglTexture2D(reGl, {
|
||||
constructor() {
|
||||
const { createFramebuffer, createTexture2D } = this.rendererService;
|
||||
this.readFBO = createFramebuffer({
|
||||
color: createTexture2D({
|
||||
width: 1,
|
||||
height: 1,
|
||||
wrapS: gl.CLAMP_TO_EDGE,
|
||||
|
@ -34,27 +31,14 @@ export default class ReglPostProcessor implements IPostProcessor {
|
|||
}),
|
||||
});
|
||||
|
||||
this.writeFBO = new ReglFramebuffer(reGl, {
|
||||
color: new ReglTexture2D(reGl, {
|
||||
this.writeFBO = createFramebuffer({
|
||||
color: createTexture2D({
|
||||
width: 1,
|
||||
height: 1,
|
||||
wrapS: gl.CLAMP_TO_EDGE,
|
||||
wrapT: gl.CLAMP_TO_EDGE,
|
||||
}),
|
||||
});
|
||||
|
||||
this.screenRenderTarget = reGl({
|
||||
framebuffer: null,
|
||||
});
|
||||
|
||||
this.offscreenRenderTarget = reGl({
|
||||
// since post-processor will swap read/write fbos, we must retrieve it dynamically
|
||||
framebuffer: () => (this.writeFBO as ReglFramebuffer).get(),
|
||||
});
|
||||
|
||||
this.inputRenderTarget = reGl({
|
||||
framebuffer: () => (this.readFBO as ReglFramebuffer).get(),
|
||||
});
|
||||
}
|
||||
|
||||
public getReadFBO() {
|
||||
|
@ -65,26 +49,6 @@ export default class ReglPostProcessor implements IPostProcessor {
|
|||
return this.writeFBO;
|
||||
}
|
||||
|
||||
public renderToPostProcessor(renderCommand: () => void) {
|
||||
this.inputRenderTarget(() => {
|
||||
this.reGl.clear({
|
||||
color: [0, 0, 0, 0],
|
||||
depth: 1,
|
||||
stencil: 0,
|
||||
framebuffer: (this.getReadFBO() as ReglFramebuffer).get(),
|
||||
});
|
||||
renderCommand();
|
||||
});
|
||||
}
|
||||
|
||||
public useScreenRenderTarget(callback: () => void) {
|
||||
this.screenRenderTarget({}, callback);
|
||||
}
|
||||
|
||||
public useOffscreenRenderTarget(callback: () => void) {
|
||||
this.offscreenRenderTarget({}, callback);
|
||||
}
|
||||
|
||||
public async render(layer: ILayer) {
|
||||
for (let i = 0; i < this.passes.length; i++) {
|
||||
const pass = this.passes[i];
|
|
@ -1,12 +1,18 @@
|
|||
import { inject, injectable } from 'inversify';
|
||||
import { ILayer, ILayerService } from '../../layer/ILayerService';
|
||||
import { injectable } from 'inversify';
|
||||
import { lazyInject } from '../../../index';
|
||||
import { TYPES } from '../../../types';
|
||||
import { ILayer } from '../../layer/ILayerService';
|
||||
import { IPass, PassType } from '../IMultiPassRenderer';
|
||||
import { IRendererService } from '../IRendererService';
|
||||
|
||||
/**
|
||||
* RenderPass,负责输出到后续 PostProcessor 的 readFBO 中
|
||||
*/
|
||||
@injectable()
|
||||
export default class RenderPass implements IPass {
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
public getType() {
|
||||
return PassType.Normal;
|
||||
}
|
||||
|
@ -16,7 +22,16 @@ export default class RenderPass implements IPass {
|
|||
}
|
||||
|
||||
public render(layer: ILayer) {
|
||||
layer.multiPassRenderer.getPostProcessor().renderToPostProcessor(() => {
|
||||
const { renderToFramebuffer, clear } = this.rendererService;
|
||||
const readFBO = layer.multiPassRenderer.getPostProcessor().getReadFBO();
|
||||
renderToFramebuffer(readFBO, () => {
|
||||
clear({
|
||||
color: [0, 0, 0, 0],
|
||||
depth: 1,
|
||||
stencil: 0,
|
||||
framebuffer: readFBO,
|
||||
});
|
||||
|
||||
// render to post processor
|
||||
layer.multiPassRenderer.setRenderFlag(false);
|
||||
layer.render();
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { injectable } from 'inversify';
|
||||
import { lazyInject } from '../../../../index';
|
||||
import blur from '../../../../shaders/post-processing/blur.glsl';
|
||||
import quad from '../../../../shaders/post-processing/quad.glsl';
|
||||
import { TYPES } from '../../../../types';
|
||||
import { IRendererService } from '../../IRendererService';
|
||||
import BasePostProcessingPass from '../BasePostProcessingPass';
|
||||
|
||||
export interface IBlurHPassConfig {
|
||||
|
@ -15,6 +18,9 @@ const defaultConfig: IBlurHPassConfig = {
|
|||
export default class BlurHPass extends BasePostProcessingPass<
|
||||
IBlurHPassConfig
|
||||
> {
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
public setupShaders() {
|
||||
this.shaderModule.registerModule('blur-pass', {
|
||||
vs: quad,
|
||||
|
@ -22,7 +28,7 @@ export default class BlurHPass extends BasePostProcessingPass<
|
|||
});
|
||||
|
||||
const { vs, fs, uniforms } = this.shaderModule.getModule('blur-pass');
|
||||
const { width, height } = this.renderer.getViewportSize();
|
||||
const { width, height } = this.rendererService.getViewportSize();
|
||||
|
||||
const { blurRadius } = {
|
||||
...defaultConfig,
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { injectable } from 'inversify';
|
||||
import { lazyInject } from '../../../../index';
|
||||
import blur from '../../../../shaders/post-processing/blur.glsl';
|
||||
import quad from '../../../../shaders/post-processing/quad.glsl';
|
||||
import { TYPES } from '../../../../types';
|
||||
import { IRendererService } from '../../IRendererService';
|
||||
import BasePostProcessingPass from '../BasePostProcessingPass';
|
||||
|
||||
export interface IBlurVPassConfig {
|
||||
|
@ -15,6 +18,9 @@ const defaultConfig: IBlurVPassConfig = {
|
|||
export default class BlurVPass extends BasePostProcessingPass<
|
||||
IBlurVPassConfig
|
||||
> {
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
public setupShaders() {
|
||||
this.shaderModule.registerModule('blur-pass', {
|
||||
vs: quad,
|
||||
|
@ -22,7 +28,7 @@ export default class BlurVPass extends BasePostProcessingPass<
|
|||
});
|
||||
|
||||
const { vs, fs, uniforms } = this.shaderModule.getModule('blur-pass');
|
||||
const { width, height } = this.renderer.getViewportSize();
|
||||
const { width, height } = this.rendererService.getViewportSize();
|
||||
|
||||
const { blurRadius } = {
|
||||
...defaultConfig,
|
||||
|
|
|
@ -5,6 +5,7 @@ import { TYPES } from '../../types';
|
|||
import { createRendererContainer } from '../../utils/dom';
|
||||
import { ICameraService, IViewport } from '../camera/ICameraService';
|
||||
import { IGlobalConfig, IGlobalConfigService } from '../config/IConfigService';
|
||||
import { IInteractionService } from '../interaction/IInteractionService';
|
||||
import { ILayer, ILayerService } from '../layer/ILayerService';
|
||||
import { ILogService } from '../log/ILogService';
|
||||
import { IMapCamera, IMapService } from '../map/IMapService';
|
||||
|
@ -38,6 +39,9 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
@inject(TYPES.ICameraService)
|
||||
private readonly cameraService: ICameraService;
|
||||
|
||||
@inject(TYPES.IInteractionService)
|
||||
private readonly interactionService: IInteractionService;
|
||||
|
||||
@inject(TYPES.IShaderModuleService)
|
||||
private readonly shaderModule: IShaderModuleService;
|
||||
|
||||
|
@ -110,6 +114,9 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
// 初始化 ShaderModule
|
||||
this.shaderModule.registerBuiltinModules();
|
||||
|
||||
// 初始化 container 上的交互
|
||||
this.interactionService.init();
|
||||
|
||||
// TODO:init renderer
|
||||
this.logger.info('renderer loaded');
|
||||
});
|
||||
|
@ -141,6 +148,7 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
this.inited = false;
|
||||
this.layerService.clean();
|
||||
this.configService.reset();
|
||||
this.interactionService.destroy();
|
||||
window.removeEventListener('resize', this.handleWindowResized, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ const TYPES = {
|
|||
IMapService: Symbol.for('IMapService'),
|
||||
IRendererService: Symbol.for('IRendererService'),
|
||||
IShaderModuleService: Symbol.for('IShaderModuleService'),
|
||||
IInteractionService: Symbol.for('IInteractionService'),
|
||||
|
||||
/** multi-pass */
|
||||
ClearPass: Symbol.for('ClearPass'),
|
||||
|
|
|
@ -77,6 +77,7 @@ export default class BaseLayer implements ILayer {
|
|||
this.buildModels();
|
||||
return this;
|
||||
}
|
||||
|
||||
public color(field: StyleAttributeField, values?: any) {
|
||||
this.createStyleAttribute(
|
||||
'color',
|
||||
|
@ -86,6 +87,7 @@ export default class BaseLayer implements ILayer {
|
|||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
public size(field: StyleAttributeField, values?: any) {
|
||||
this.createStyleAttribute(
|
||||
'size',
|
||||
|
@ -95,6 +97,7 @@ export default class BaseLayer implements ILayer {
|
|||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
public shape(field: StyleAttributeField, values?: any) {
|
||||
this.createStyleAttribute(
|
||||
'shape',
|
||||
|
@ -110,6 +113,10 @@ export default class BaseLayer implements ILayer {
|
|||
return this;
|
||||
}
|
||||
|
||||
public style(styleAttributes: any) {
|
||||
//
|
||||
}
|
||||
|
||||
public render(): ILayer {
|
||||
if (this.multiPassRenderer && this.multiPassRenderer.getRenderFlag()) {
|
||||
this.multiPassRenderer.render();
|
||||
|
|
|
@ -9,6 +9,8 @@ import {
|
|||
IPostProcessingPass,
|
||||
IRendererService,
|
||||
lazyInject,
|
||||
MultiPassRenderer,
|
||||
PixelPickingPass,
|
||||
RenderPass,
|
||||
TYPES,
|
||||
} from '@l7/core';
|
||||
|
@ -20,6 +22,20 @@ const builtinPostProcessingPassMap: {
|
|||
blurV: BlurVPass,
|
||||
};
|
||||
|
||||
/**
|
||||
* 'blurH' -> ['blurH', {}]
|
||||
*/
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 Layer 配置的 passes 创建 MultiPassRenderer 并渲染
|
||||
* @example
|
||||
|
@ -83,28 +99,23 @@ export default class MultiPassRendererPlugin implements ILayerPlugin {
|
|||
layer: ILayer,
|
||||
passes: Array<string | [string, { [key: string]: unknown }]>,
|
||||
) {
|
||||
const multiPassRenderer = this.rendererService.createMultiPassRenderer(
|
||||
layer,
|
||||
);
|
||||
// TODO: PickingPass
|
||||
multiPassRenderer.add(new ClearPass());
|
||||
multiPassRenderer.add(new RenderPass());
|
||||
const multiPassRenderer = new MultiPassRenderer(layer);
|
||||
|
||||
const normalizedPasses: Array<
|
||||
[string, { [key: string]: unknown }]
|
||||
> = passes.map((pass: string | [string, { [key: string]: unknown }]) => {
|
||||
if (typeof pass === 'string') {
|
||||
pass = [pass, {}];
|
||||
multiPassRenderer.add(new ClearPass());
|
||||
|
||||
if (layer.getInitializationOptions().enablePicking) {
|
||||
multiPassRenderer.add(new PixelPickingPass());
|
||||
}
|
||||
return pass;
|
||||
});
|
||||
multiPassRenderer.add(new RenderPass());
|
||||
|
||||
// post processing
|
||||
// TODO: pass initialization params
|
||||
normalizedPasses.forEach((pass: [string, { [key: string]: unknown }]) => {
|
||||
normalizePasses(passes).forEach(
|
||||
(pass: [string, { [key: string]: unknown }]) => {
|
||||
const PostProcessingPassClazz = builtinPostProcessingPassMap[pass[0]];
|
||||
multiPassRenderer.add(new PostProcessingPassClazz(pass[1]));
|
||||
});
|
||||
},
|
||||
);
|
||||
// 末尾为固定的 CopyPass
|
||||
multiPassRenderer.add(new CopyPass());
|
||||
|
||||
|
|
|
@ -19,14 +19,6 @@ export default class PolygonLayer extends BaseLayer {
|
|||
@lazyInject(TYPES.IRendererService)
|
||||
private readonly renderer: IRendererService;
|
||||
|
||||
public style(options: any) {
|
||||
// this.layerStyleService.update(options);
|
||||
// this.styleOptions = {
|
||||
// ...this.styleOptions,
|
||||
// ...options,
|
||||
// };
|
||||
}
|
||||
|
||||
protected renderModels() {
|
||||
this.models.forEach((model) =>
|
||||
model.draw({
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
import {
|
||||
IRenderbuffer,
|
||||
IRenderbufferInitializationOptions,
|
||||
} from '@l7/core';
|
||||
import { IRenderbuffer, IRenderbufferInitializationOptions } from '@l7/core';
|
||||
import regl from 'regl';
|
||||
import { formatMap } from './constants';
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* @see https://github.com/regl-project/regl/blob/gh-pages/API.md
|
||||
*/
|
||||
import {
|
||||
gl,
|
||||
IAttribute,
|
||||
IAttributeInitializationOptions,
|
||||
IBuffer,
|
||||
|
@ -11,20 +10,22 @@ import {
|
|||
IClearOptions,
|
||||
IElements,
|
||||
IElementsInitializationOptions,
|
||||
ILayer,
|
||||
IFramebuffer,
|
||||
IFramebufferInitializationOptions,
|
||||
IModel,
|
||||
IModelInitializationOptions,
|
||||
IMultiPassRenderer,
|
||||
IRendererService,
|
||||
ITexture2D,
|
||||
ITexture2DInitializationOptions,
|
||||
} from '@l7/core';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { injectable } from 'inversify';
|
||||
import regl from 'regl';
|
||||
import ReglAttribute from './ReglAttribute';
|
||||
import ReglBuffer from './ReglBuffer';
|
||||
import ReglElements from './ReglElements';
|
||||
import ReglFramebuffer from './ReglFramebuffer';
|
||||
import ReglModel from './ReglModel';
|
||||
import ReglMultiPassRenderer from './ReglMultiPassRenderer';
|
||||
import ReglTexture2D from './ReglTexture2D';
|
||||
|
||||
/**
|
||||
* regl renderer
|
||||
|
@ -32,8 +33,10 @@ import ReglMultiPassRenderer from './ReglMultiPassRenderer';
|
|||
@injectable()
|
||||
export default class ReglRendererService implements IRendererService {
|
||||
private gl: regl.Regl;
|
||||
private $container: HTMLDivElement | null;
|
||||
|
||||
public async init($container: HTMLDivElement): Promise<void> {
|
||||
this.$container = $container;
|
||||
// tslint:disable-next-line:typedef
|
||||
this.gl = await new Promise((resolve, reject) => {
|
||||
regl({
|
||||
|
@ -67,31 +70,43 @@ export default class ReglRendererService implements IRendererService {
|
|||
});
|
||||
}
|
||||
|
||||
public createModel = (options: IModelInitializationOptions): IModel => {
|
||||
return new ReglModel(this.gl, options);
|
||||
};
|
||||
public createModel = (options: IModelInitializationOptions): IModel =>
|
||||
new ReglModel(this.gl, options);
|
||||
|
||||
public createAttribute = (
|
||||
options: IAttributeInitializationOptions,
|
||||
): IAttribute => {
|
||||
return new ReglAttribute(this.gl, options);
|
||||
};
|
||||
): IAttribute => new ReglAttribute(this.gl, options);
|
||||
|
||||
public createBuffer = (options: IBufferInitializationOptions): IBuffer => {
|
||||
return new ReglBuffer(this.gl, options);
|
||||
};
|
||||
public createBuffer = (options: IBufferInitializationOptions): IBuffer =>
|
||||
new ReglBuffer(this.gl, options);
|
||||
|
||||
public createElements = (
|
||||
options: IElementsInitializationOptions,
|
||||
): IElements => {
|
||||
return new ReglElements(this.gl, options);
|
||||
): IElements => new ReglElements(this.gl, options);
|
||||
|
||||
public createTexture2D = (
|
||||
options: ITexture2DInitializationOptions,
|
||||
): ITexture2D => new ReglTexture2D(this.gl, options);
|
||||
|
||||
public createFramebuffer = (options: IFramebufferInitializationOptions) =>
|
||||
new ReglFramebuffer(this.gl, options);
|
||||
|
||||
public renderToFramebuffer = (
|
||||
framebuffer: IFramebuffer | null,
|
||||
drawCommands: () => void,
|
||||
) => {
|
||||
const useFramebuffer = this.gl({
|
||||
// since post-processor will swap read/write fbos, we must retrieve it dynamically
|
||||
framebuffer: framebuffer
|
||||
? () => (framebuffer as ReglFramebuffer).get()
|
||||
: null,
|
||||
});
|
||||
|
||||
// TODO: pass other options
|
||||
useFramebuffer({}, drawCommands);
|
||||
};
|
||||
|
||||
public createMultiPassRenderer = (layer: ILayer): IMultiPassRenderer => {
|
||||
return new ReglMultiPassRenderer(this.gl, layer);
|
||||
};
|
||||
|
||||
public clear(options: IClearOptions) {
|
||||
public clear = (options: IClearOptions) => {
|
||||
// @see https://github.com/regl-project/regl/blob/gh-pages/API.md#clear-the-draw-buffer
|
||||
const { color, depth, stencil, framebuffer = null } = options;
|
||||
const reglClearOptions: regl.ClearOptions = {
|
||||
|
@ -106,9 +121,9 @@ export default class ReglRendererService implements IRendererService {
|
|||
: (framebuffer as ReglFramebuffer).get();
|
||||
|
||||
this.gl.clear(reglClearOptions);
|
||||
}
|
||||
};
|
||||
|
||||
public viewport({
|
||||
public viewport = ({
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
|
@ -118,17 +133,21 @@ export default class ReglRendererService implements IRendererService {
|
|||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}) {
|
||||
}) => {
|
||||
// use WebGL context directly
|
||||
// @see https://github.com/regl-project/regl/blob/gh-pages/API.md#unsafe-escape-hatch
|
||||
this.gl._gl.viewport(x, y, width, height);
|
||||
this.gl._refresh();
|
||||
}
|
||||
};
|
||||
|
||||
public getViewportSize() {
|
||||
public getViewportSize = () => {
|
||||
return {
|
||||
width: this.gl._gl.drawingBufferWidth,
|
||||
height: this.gl._gl.drawingBufferHeight,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
public getContainer = () => {
|
||||
return this.$container;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ export default class Mapbox extends React.Component {
|
|||
},
|
||||
],
|
||||
],
|
||||
enablePicking: true,
|
||||
});
|
||||
|
||||
// TODO: new GeoJSONSource()
|
||||
|
@ -81,6 +82,17 @@ export default class Mapbox extends React.Component {
|
|||
this.scene = scene;
|
||||
|
||||
/*** 运行时修改样式属性 ***/
|
||||
// const gui = new dat.GUI();
|
||||
// this.gui = gui;
|
||||
// const pointFolder = gui.addFolder('Polygon 样式属性');
|
||||
// pointFolder
|
||||
// .add(layer.styleOptions, 'opacity')
|
||||
// .onChange((opacity: number) => {
|
||||
// layer.style({
|
||||
// opacity,
|
||||
// });
|
||||
// scene.render();
|
||||
// });
|
||||
}
|
||||
|
||||
public render() {
|
||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -2820,6 +2820,11 @@
|
|||
"@types/minimatch" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/hammerjs@^2.0.36":
|
||||
version "2.0.36"
|
||||
resolved "https://registry.yarnpkg.com/@types/hammerjs/-/hammerjs-2.0.36.tgz#17ce0a235e9ffbcdcdf5095646b374c2bf615a4c"
|
||||
integrity sha512-7TUK/k2/QGpEAv/BCwSHlYu3NXZhQ9ZwBYpzr9tjlPIL2C5BeGhH3DmVavRx3ZNyELX5TLC91JTz/cen6AAtIQ==
|
||||
|
||||
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
|
||||
|
@ -7497,6 +7502,11 @@ gzip-size@5.1.1:
|
|||
duplexer "^0.1.1"
|
||||
pify "^4.0.1"
|
||||
|
||||
hammerjs@^2.0.8:
|
||||
version "2.0.8"
|
||||
resolved "https://registry.yarnpkg.com/hammerjs/-/hammerjs-2.0.8.tgz#04ef77862cff2bb79d30f7692095930222bf60f1"
|
||||
integrity sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=
|
||||
|
||||
handle-thing@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754"
|
||||
|
|
Loading…
Reference in New Issue