refactor(@l7/core): 重构 MultiPassRenderer & PostProcessor

不依赖具体 renderer 渲染服务接口,@l7/renderer 各渲染引擎只需要实现基础 WebGL 资源对象接口
This commit is contained in:
yuqi.pyq 2019-10-12 10:39:40 +08:00
parent 587560c7f4
commit b4ad1afb65
27 changed files with 341 additions and 150 deletions

BIN
.DS_Store vendored

Binary file not shown.

2
.gitignore vendored
View File

@ -65,3 +65,5 @@ jspm_packages/
# End of https://www.gitignore.io/api/node
lib/
.DS_Store

View File

@ -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"
}

View File

@ -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,

View File

@ -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);

View File

@ -0,0 +1,4 @@
export interface IInteractionService {
init(): void;
destroy(): void;
}

View File

@ -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
// });
// }
};
}

View File

@ -92,6 +92,7 @@ export interface ILayerPlugin {
*/
export interface ILayerInitializationOptions {
enableMultiPassRenderer: boolean;
enablePicking: boolean;
passes: Array<string | [string, { [key: string]: unknown }]>;
}

View File

@ -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>;

View File

@ -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;
}

View File

@ -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);
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() {

View File

@ -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) {

View File

@ -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);
});
}
}

View File

@ -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];

View File

@ -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();

View File

@ -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,

View File

@ -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,

View File

@ -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();
// TODOinit 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);
}

View File

@ -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'),

View File

@ -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();

View File

@ -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, {}];
}
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());

View File

@ -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({

View File

@ -1,7 +1,4 @@
import {
IRenderbuffer,
IRenderbufferInitializationOptions,
} from '@l7/core';
import { IRenderbuffer, IRenderbufferInitializationOptions } from '@l7/core';
import regl from 'regl';
import { formatMap } from './constants';

View File

@ -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;
};
}

View File

@ -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() {

View File

@ -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"