From 7059ef31867a97c3d28b4d6c8a6c7d57940149c5 Mon Sep 17 00:00:00 2001 From: "yuqi.pyq" Date: Sat, 12 Oct 2019 10:39:40 +0800 Subject: [PATCH] =?UTF-8?q?refactor(@l7/core):=20=E9=87=8D=E6=9E=84=20Mult?= =?UTF-8?q?iPassRenderer=20&=20PostProcessor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 不依赖具体 renderer 渲染服务接口,@l7/renderer 各渲染引擎只需要实现基础 WebGL 资源对象接口 --- .DS_Store | Bin 6148 -> 10244 bytes .gitignore | 2 + packages/core/package.json | 2 + packages/core/src/index.ts | 4 + packages/core/src/inversify.config.ts | 6 ++ .../interaction/IInteractionService.ts | 4 + .../interaction/InteractionService.ts | 60 ++++++++++++++ .../core/src/services/layer/ILayerService.ts | 1 + .../services/renderer/IMultiPassRenderer.ts | 3 - .../src/services/renderer/IRendererService.ts | 14 +++- .../renderer/passes/BasePostProcessingPass.ts | 38 ++++++--- .../renderer/passes/MultiPassRenderer.ts} | 27 +++---- .../services/renderer/passes/PickingPass.ts | 0 .../renderer/passes/PixelPickingPass.ts | 46 +++++++++++ .../renderer/passes/PostProcessor.ts} | 76 +++++------------- .../services/renderer/passes/RenderPass.ts | 21 ++++- .../passes/post-processing/BlurHPass.ts | 8 +- .../passes/post-processing/BlurVPass.ts | 8 +- .../core/src/services/scene/SceneService.ts | 8 ++ packages/core/src/types.ts | 1 + packages/layers/src/core/BaseLayer.ts | 7 ++ .../src/plugins/MultiPassRendererPlugin.ts | 47 ++++++----- packages/layers/src/polygon/index.ts | 8 -- .../renderer/src/regl/ReglRenderbuffer.ts | 5 +- packages/renderer/src/regl/index.ts | 73 ++++++++++------- stories/MapAdaptor/components/Polygon.tsx | 12 +++ yarn.lock | 10 +++ 27 files changed, 341 insertions(+), 150 deletions(-) create mode 100644 packages/core/src/services/interaction/IInteractionService.ts create mode 100644 packages/core/src/services/interaction/InteractionService.ts rename packages/{renderer/src/regl/ReglMultiPassRenderer.ts => core/src/services/renderer/passes/MultiPassRenderer.ts} (73%) delete mode 100644 packages/core/src/services/renderer/passes/PickingPass.ts create mode 100644 packages/core/src/services/renderer/passes/PixelPickingPass.ts rename packages/{renderer/src/regl/ReglPostProcessor.ts => core/src/services/renderer/passes/PostProcessor.ts} (50%) diff --git a/.DS_Store b/.DS_Store index eb77dd9d28a1ff4ab47759cb0b3a7c57cb1fdf56..cc07750f66c7ae18d00eaa34b2253a227ff1110c 100644 GIT binary patch literal 10244 zcmeHMU2GIp6h5aEdS_bNX$9KZ0$nK;l&!S^6t#zaM<7<`bV@rMT=^u2_-C`mkO5)sP?z#7z zd+yJ7znPPJ2LP}$r?vxx0f5oNrBp@PEQ#CsQWw9>14V#9 zfIxsifIxsifWX6m0L5&cSfwX}JU}2oAV8pq0RKLO>ESZw%SlhVpAO30BLK;AQoD)D z5-*Sp`!eRsNl%i65_+yAJy-OP80fi^KJ2%P`Et^eo;#p__&|ST^iL@0j!ylD-R6KX zPX>8_K!89g0{rY=4o|``=-^B{zYl;78e}P74H-BI$4QQXMVe!z%YXuDvacp-f{34Y~7FyT^ z?o?tl?0lDpLfIAc&Q6Z=bj`Db?j^al0~(ZkhI8Eo+lZN;NhC(wDZ(-C2#> z2h*038#V2uRGU_ebk0y5ZM$K_^;4QX6s=7J6pYSvt z{iv>Gg<6aV2~!!>rWVyVNODMCd@nC1HM5~yN@5*YFt5Z^S&HNQBWies%87oY1HIY_POdO*Pmu$h)w67860Ygb?hNKG2 zZPXDJ<-xp%q_oplZmtvMp|mwRN=vax#}_TfssDzt-&OG)tF3!v!NR4@D_hq@x5SFuIb;9s=8;Puj~^~?3cPSP zaXJx+&~m6zTyif$4-oCN6O6wBQpJ=^9BB%NLJ}tsbF0f+s9Ht@XZ+=m#V114Qen~@ zw;Eb4wlm_WG}p7P6FUTAu~hC^H;S7XkyV=KcD1!p6eS>v^I?RRkVxOMe@wtP;R?JD zpAq$L!PoFT{0Kk8?}%7|wOEf0*ocd9DXzfBaTP|e6+3VPZo=T<}goGd=Agx*&-ERCMv#;Z+HwV60g^1oGgfLH=n=Xl9S08DJJ2gF=8nfIxsifIxsifWZADFvoKZ^ZWmvd;kBx{{aHe0D%C3 zhaLee?~ZqO(liTa?3pv>ckN+%j?lvsZ#U^l*M&0PgzMewc&hO0c=w)xbcG8BZjbrx XCOt_SO8@%LfZ+Teod5sl=l?$eM!p4O delta 122 zcmZn(XfcprU|?W$DortDU=RQ@Ie-{MGjUEV6q~50$jG)aU^gQp+h!gCSw_y3;^ds9 z{QMlojfGcP7PE732r>iJ0)YTGkZ=WQ+gSLWc{0C>Bgk9^Mg|5J5X}TJ7%a9qo@Wj- E03UP{fB*mh diff --git a/.gitignore b/.gitignore index 79052bd45d..a5542c8ad0 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,5 @@ jspm_packages/ # End of https://www.gitignore.io/api/node lib/ + +.DS_Store diff --git a/packages/core/package.json b/packages/core/package.json index 2813d705f4..ca6fb3029d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -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" } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index ede8adfc89..ec38942f22 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -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, diff --git a/packages/core/src/inversify.config.ts b/packages/core/src/inversify.config.ts index 2645d7a932..4ddb94071b 100644 --- a/packages/core/src/inversify.config.ts +++ b/packages/core/src/inversify.config.ts @@ -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(TYPES.ILogService) .to(LogService) .inSingletonScope(); +container + .bind(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); diff --git a/packages/core/src/services/interaction/IInteractionService.ts b/packages/core/src/services/interaction/IInteractionService.ts new file mode 100644 index 0000000000..d1b20a01e9 --- /dev/null +++ b/packages/core/src/services/interaction/IInteractionService.ts @@ -0,0 +1,4 @@ +export interface IInteractionService { + init(): void; + destroy(): void; +} diff --git a/packages/core/src/services/interaction/InteractionService.ts b/packages/core/src/services/interaction/InteractionService.ts new file mode 100644 index 0000000000..b8fd4435f2 --- /dev/null +++ b/packages/core/src/services/interaction/InteractionService.ts @@ -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 + // }); + // } + }; +} diff --git a/packages/core/src/services/layer/ILayerService.ts b/packages/core/src/services/layer/ILayerService.ts index 49ce82b515..9b079c9117 100644 --- a/packages/core/src/services/layer/ILayerService.ts +++ b/packages/core/src/services/layer/ILayerService.ts @@ -92,6 +92,7 @@ export interface ILayerPlugin { */ export interface ILayerInitializationOptions { enableMultiPassRenderer: boolean; + enablePicking: boolean; passes: Array; } diff --git a/packages/core/src/services/renderer/IMultiPassRenderer.ts b/packages/core/src/services/renderer/IMultiPassRenderer.ts index e8d7d8a166..7481ed3820 100644 --- a/packages/core/src/services/renderer/IMultiPassRenderer.ts +++ b/packages/core/src/services/renderer/IMultiPassRenderer.ts @@ -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; diff --git a/packages/core/src/services/renderer/IRendererService.ts b/packages/core/src/services/renderer/IRendererService.ts index 9f2a7b3118..b0b15786f3 100644 --- a/packages/core/src/services/renderer/IRendererService.ts +++ b/packages/core/src/services/renderer/IRendererService.ts @@ -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; } diff --git a/packages/core/src/services/renderer/passes/BasePostProcessingPass.ts b/packages/core/src/services/renderer/passes/BasePostProcessingPass.ts index 40c8f1896f..952400bfa1 100644 --- a/packages/core/src/services/renderer/passes/BasePostProcessingPass.ts +++ b/packages/core/src/services/renderer/passes/BasePostProcessingPass.ts @@ -23,7 +23,7 @@ export default class BasePostProcessingPass protected readonly shaderModule: IShaderModuleService; @lazyInject(TYPES.IRendererService) - protected readonly renderer: IRendererService; + protected readonly rendererService: IRendererService; protected config: Partial | undefined; @@ -51,7 +51,7 @@ export default class BasePostProcessingPass } 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 public render(layer: ILayer) { const postProcessor = layer.multiPassRenderer.getPostProcessor(); + const { renderToFramebuffer } = this.rendererService; - const useRenderTarget = (this.renderToScreen - ? postProcessor.useScreenRenderTarget - : postProcessor.useOffscreenRenderTarget - ).bind(postProcessor); + renderToFramebuffer( + this.renderToScreen ? null : postProcessor.getWriteFBO(), + () => { + this.model.draw({ + uniforms: { + u_Texture: postProcessor.getReadFBO(), + }, + }); + }, + ); - useRenderTarget(async () => { - 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() { diff --git a/packages/renderer/src/regl/ReglMultiPassRenderer.ts b/packages/core/src/services/renderer/passes/MultiPassRenderer.ts similarity index 73% rename from packages/renderer/src/regl/ReglMultiPassRenderer.ts rename to packages/core/src/services/renderer/passes/MultiPassRenderer.ts index d3b55dfbc8..e28b046f64 100644 --- a/packages/renderer/src/regl/ReglMultiPassRenderer.ts +++ b/packages/core/src/services/renderer/passes/MultiPassRenderer.ts @@ -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) { diff --git a/packages/core/src/services/renderer/passes/PickingPass.ts b/packages/core/src/services/renderer/passes/PickingPass.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/core/src/services/renderer/passes/PixelPickingPass.ts b/packages/core/src/services/renderer/passes/PixelPickingPass.ts new file mode 100644 index 0000000000..bbf7f7286e --- /dev/null +++ b/packages/core/src/services/renderer/passes/PixelPickingPass.ts @@ -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); + }); + } +} diff --git a/packages/renderer/src/regl/ReglPostProcessor.ts b/packages/core/src/services/renderer/passes/PostProcessor.ts similarity index 50% rename from packages/renderer/src/regl/ReglPostProcessor.ts rename to packages/core/src/services/renderer/passes/PostProcessor.ts index 84068685fa..f93e071175 100644 --- a/packages/renderer/src/regl/ReglPostProcessor.ts +++ b/packages/core/src/services/renderer/passes/PostProcessor.ts @@ -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]; diff --git a/packages/core/src/services/renderer/passes/RenderPass.ts b/packages/core/src/services/renderer/passes/RenderPass.ts index 1ca8e43613..4a4b770cb7 100644 --- a/packages/core/src/services/renderer/passes/RenderPass.ts +++ b/packages/core/src/services/renderer/passes/RenderPass.ts @@ -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(); diff --git a/packages/core/src/services/renderer/passes/post-processing/BlurHPass.ts b/packages/core/src/services/renderer/passes/post-processing/BlurHPass.ts index 52856499b7..d999a9927e 100644 --- a/packages/core/src/services/renderer/passes/post-processing/BlurHPass.ts +++ b/packages/core/src/services/renderer/passes/post-processing/BlurHPass.ts @@ -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, diff --git a/packages/core/src/services/renderer/passes/post-processing/BlurVPass.ts b/packages/core/src/services/renderer/passes/post-processing/BlurVPass.ts index 584d4b50e7..b707fbed39 100644 --- a/packages/core/src/services/renderer/passes/post-processing/BlurVPass.ts +++ b/packages/core/src/services/renderer/passes/post-processing/BlurVPass.ts @@ -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, diff --git a/packages/core/src/services/scene/SceneService.ts b/packages/core/src/services/scene/SceneService.ts index 0ae413816a..4a7206f067 100644 --- a/packages/core/src/services/scene/SceneService.ts +++ b/packages/core/src/services/scene/SceneService.ts @@ -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); } diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 19901f97a2..efeaa99a5a 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -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'), diff --git a/packages/layers/src/core/BaseLayer.ts b/packages/layers/src/core/BaseLayer.ts index fbbfcaf7f8..0b429cd837 100644 --- a/packages/layers/src/core/BaseLayer.ts +++ b/packages/layers/src/core/BaseLayer.ts @@ -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(); diff --git a/packages/layers/src/plugins/MultiPassRendererPlugin.ts b/packages/layers/src/plugins/MultiPassRendererPlugin.ts index b83333aee4..fac1623412 100644 --- a/packages/layers/src/plugins/MultiPassRendererPlugin.ts +++ b/packages/layers/src/plugins/MultiPassRendererPlugin.ts @@ -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, +) { + 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, ) { - 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, {}]; - } - return pass; - }); + multiPassRenderer.add(new ClearPass()); + + if (layer.getInitializationOptions().enablePicking) { + multiPassRenderer.add(new PixelPickingPass()); + } + multiPassRenderer.add(new RenderPass()); // post processing // TODO: pass initialization params - normalizedPasses.forEach((pass: [string, { [key: string]: unknown }]) => { - const PostProcessingPassClazz = builtinPostProcessingPassMap[pass[0]]; - multiPassRenderer.add(new PostProcessingPassClazz(pass[1])); - }); + normalizePasses(passes).forEach( + (pass: [string, { [key: string]: unknown }]) => { + const PostProcessingPassClazz = builtinPostProcessingPassMap[pass[0]]; + multiPassRenderer.add(new PostProcessingPassClazz(pass[1])); + }, + ); // 末尾为固定的 CopyPass multiPassRenderer.add(new CopyPass()); diff --git a/packages/layers/src/polygon/index.ts b/packages/layers/src/polygon/index.ts index dd90ab97fb..b2f05d7a7e 100644 --- a/packages/layers/src/polygon/index.ts +++ b/packages/layers/src/polygon/index.ts @@ -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({ diff --git a/packages/renderer/src/regl/ReglRenderbuffer.ts b/packages/renderer/src/regl/ReglRenderbuffer.ts index 7e68fc5d1b..0040cd9bd9 100644 --- a/packages/renderer/src/regl/ReglRenderbuffer.ts +++ b/packages/renderer/src/regl/ReglRenderbuffer.ts @@ -1,7 +1,4 @@ -import { - IRenderbuffer, - IRenderbufferInitializationOptions, -} from '@l7/core'; +import { IRenderbuffer, IRenderbufferInitializationOptions } from '@l7/core'; import regl from 'regl'; import { formatMap } from './constants'; diff --git a/packages/renderer/src/regl/index.ts b/packages/renderer/src/regl/index.ts index a22b73c608..a03f46baf4 100644 --- a/packages/renderer/src/regl/index.ts +++ b/packages/renderer/src/regl/index.ts @@ -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 { + 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; + }; } diff --git a/stories/MapAdaptor/components/Polygon.tsx b/stories/MapAdaptor/components/Polygon.tsx index 19a1a95cda..e8b4665c56 100644 --- a/stories/MapAdaptor/components/Polygon.tsx +++ b/stories/MapAdaptor/components/Polygon.tsx @@ -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() { diff --git a/yarn.lock b/yarn.lock index f5436fbf7d..0522495639 100644 --- a/yarn.lock +++ b/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"