feat: try to replace regl with g-webgl (#1563)

* feat: try to replace regl with g-webgl

* fix: pass uniforms when re-render
This commit is contained in:
xiaoiver 2023-01-16 14:26:20 +08:00 committed by GitHub
parent 6dabb4a0c9
commit de77a82ba4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 369 additions and 155 deletions

View File

@ -37,7 +37,6 @@ export default class Scene extends EventEmitter implements ISceneService {
@inject(TYPES.SceneID)
private readonly id: string;
@inject(TYPES.IControlService)
private readonly controlService: IControlService;
@ -62,7 +61,6 @@ export default class Scene extends EventEmitter implements ISceneService {
@inject(TYPES.IInteractionService)
private readonly interactionService: IInteractionService;
@inject(TYPES.IShaderModuleService)
private readonly shaderModuleService: IShaderModuleService;
@ -86,7 +84,7 @@ export default class Scene extends EventEmitter implements ISceneService {
private markerContainer: HTMLElement;
private gl: any
private gl: any;
private hooks: {
init: AsyncSeriesHook;
@ -112,7 +110,6 @@ export default class Scene extends EventEmitter implements ISceneService {
// 初始化 ShaderModule
this.shaderModuleService.registerBuiltinModules();
/**
*
*/
@ -123,7 +120,6 @@ export default class Scene extends EventEmitter implements ISceneService {
this.cameraService.init();
this.cameraService.update(viewport);
resolve();
});
this.map.init();
});
@ -166,9 +162,7 @@ export default class Scene extends EventEmitter implements ISceneService {
) as HTMLCanvasElement;
this.setCanvas();
this.gl = this.rendererService.init(
this.canvas,
);
this.gl = await this.rendererService.init(this.canvas);
this.initContainer();
@ -184,20 +178,17 @@ export default class Scene extends EventEmitter implements ISceneService {
} else {
console.error('容器 id 不存在');
}
});
this.render();
}
public addLayer(layer: ILayer) {
this.layerService.sceneService = this;
this.layerService.add(layer);
}
public async render() {
// 首次初始化,或者地图的容器被强制销毁的需要重新初始化
if (!this.inited) {
// 还未初始化完成需要等待
@ -208,22 +199,17 @@ export default class Scene extends EventEmitter implements ISceneService {
}
// FIXME: 初始化 marker 容器,可以放到 map 初始化方法中?
await this.layerService.initLayers();
this.layerService.renderLayers();
this.controlService.addControls();
this.loaded = true;
this.emit('loaded');
this.inited = true;
} else {
this.layerService.renderLayers();
}
}
public getSceneContainer(): HTMLDivElement {
return this.$container as HTMLDivElement;
}
@ -275,8 +261,6 @@ export default class Scene extends EventEmitter implements ISceneService {
?.removeListener(this.handleWindowResized);
}
this.layerService.destroy();
// this.rendererService.destroy();
@ -284,9 +268,6 @@ export default class Scene extends EventEmitter implements ISceneService {
this.interactionService.destroy();
this.controlService.destroy();
this.markerService.destroy();
this.removeAllListeners();
this.inited = false;
@ -300,7 +281,7 @@ export default class Scene extends EventEmitter implements ISceneService {
// Tip: 把这一部分销毁放到写下一个事件循环中执行,兼容 L7React 中 scene 和 layer 同时销毁的情况
this.rendererService.destroy();
});
// 销毁 container 容器
// 销毁 container 容器
this.$container?.parentNode?.removeChild(this.$container);
this.emit('destroy');
}
@ -326,7 +307,7 @@ export default class Scene extends EventEmitter implements ISceneService {
canvas.width = w * pixelRatio;
canvas.height = h * pixelRatio;
}
// set view port
// this.gl._gl.viewport(0, 0, pixelRatio * w, pixelRatio * h);
}

View File

@ -0,0 +1,8 @@
import { ILayer, ILayerPlugin, IModel } from '@antv/l7-core';
import { injectable } from 'inversify';
import 'reflect-metadata';
@injectable()
export default class LayerAnimateStylePlugin implements ILayerPlugin {
public apply(layer: ILayer) {}
}

View File

@ -0,0 +1,109 @@
import { ILayer, ILayerPlugin } from '@antv/l7-core';
import { injectable } from 'inversify';
import 'reflect-metadata';
const lightTypeUniformMap = {
directional: {
lights: 'u_DirectionalLights',
num: 'u_NumOfDirectionalLights',
},
spot: {
lights: 'u_SpotLights',
num: 'u_NumOfSpotLights',
},
};
interface IDirectionalLight {
type: 'directional';
direction: [number, number, number];
ambient: [number, number, number];
diffuse: [number, number, number];
specular: [number, number, number];
}
interface ISpotLight {
type: 'spot';
position: [number, number, number];
direction: [number, number, number];
ambient: [number, number, number];
diffuse: [number, number, number];
specular: [number, number, number];
constant: number;
linear: number;
quadratic: number;
angle: number;
exponent: number;
blur: number;
}
const DEFAULT_LIGHT: IDirectionalLight = {
type: 'directional',
direction: [1, 10.5, 12],
ambient: [0.2, 0.2, 0.2],
diffuse: [0.6, 0.6, 0.6],
specular: [0.1, 0.1, 0.1],
};
const DEFAULT_DIRECTIONAL_LIGHT = {
direction: [0, 0, 0],
ambient: [0, 0, 0],
diffuse: [0, 0, 0],
specular: [0, 0, 0],
};
const DEFAULT_SPOT_LIGHT = {
position: [0, 0, 0],
direction: [0, 0, 0],
ambient: [0, 0, 0],
diffuse: [0, 0, 0],
specular: [0, 0, 0],
constant: 1,
linear: 0,
quadratic: 0,
angle: 14,
exponent: 40,
blur: 5,
};
export function generateLightingUniforms(
lights?: Array<Partial<IDirectionalLight | ISpotLight>>,
) {
const lightsMap: {
u_DirectionalLights: Array<Omit<IDirectionalLight, 'type'>>;
u_NumOfDirectionalLights: number;
u_SpotLights: Array<Omit<ISpotLight, 'type'>>;
u_NumOfSpotLights: number;
} = {
u_DirectionalLights: new Array(3).fill({ ...DEFAULT_DIRECTIONAL_LIGHT }),
u_NumOfDirectionalLights: 0,
u_SpotLights: new Array(3).fill({ ...DEFAULT_SPOT_LIGHT }),
u_NumOfSpotLights: 0,
};
if (!lights || !lights.length) {
lights = [DEFAULT_LIGHT];
}
lights.forEach(({ type = 'directional', ...rest }) => {
const lightsUniformName = lightTypeUniformMap[type].lights;
const lightsNumUniformName = lightTypeUniformMap[type].num;
// @ts-ignore
const num = lightsMap[lightsNumUniformName];
// @ts-ignore
lightsMap[lightsUniformName][num] = {
// @ts-ignore
...lightsMap[lightsUniformName][num],
...rest,
};
// @ts-ignore
lightsMap[lightsNumUniformName]++;
});
return lightsMap;
}
/**
* & Shadow
*/
@injectable()
export default class LightingPlugin implements ILayerPlugin {
public apply(layer: ILayer) {}
}

View File

@ -0,0 +1,36 @@
import {
CameraUniform,
CoordinateUniform,
ICameraService,
ICoordinateSystemService,
ILayer,
ILayerPlugin,
IMapService,
IRendererService,
TYPES,
} from '@antv/l7-core';
import { inject, injectable } from 'inversify';
import 'reflect-metadata';
/**
* Shader Uniform
* 1. View & ProjectionMatrix
* 2.
* @see https://yuque.antfin-inc.com/yuqi.pyq/fgetpa/doml91
* 3. Layer
*/
@injectable()
export default class ShaderUniformPlugin implements ILayerPlugin {
@inject(TYPES.ICameraService)
private readonly cameraService: ICameraService;
@inject(TYPES.ICoordinateSystemService)
private readonly coordinateSystemService: ICoordinateSystemService;
@inject(TYPES.IRendererService)
private readonly rendererService: IRendererService;
public apply(layer: ILayer) {
layer.hooks.beforeRender.tap('ShaderUniformPlugin', () => {});
}
}

View File

@ -0,0 +1,10 @@
import { ILayer, ILayerPlugin } from '@antv/l7-core';
import { injectable } from 'inversify';
import 'reflect-metadata';
/**
* Model
*/
@injectable()
export default class UpdateModelPlugin implements ILayerPlugin {
public apply(layer: ILayer) {}
}

View File

@ -2,46 +2,49 @@
"name": "@antv/l7-renderer",
"version": "2.11.4",
"description": "",
"license": "ISC",
"author": "xiaoiver",
"sideEffects": false,
"main": "lib/index.js",
"module": "es/index.js",
"types": "es/index.d.ts",
"sideEffects": false,
"files": [
"lib",
"es",
"README.md"
],
"scripts": {
"tsc": "tsc --project tsconfig.build.json",
"clean": "rimraf dist; rimraf es; rimraf lib;",
"build": "father build",
"build:cjs": "BABEL_ENV=cjs babel src --root-mode upward --out-dir lib --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments",
"build:esm": "BABEL_ENV=esm babel src --root-mode upward --out-dir es --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments",
"watch": "BABEL_ENV=cjs babel src --watch --root-mode upward --out-dir lib --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments",
"clean": "rimraf dist; rimraf es; rimraf lib;",
"sync": "tnpm sync",
"test": "umi-test --passWithNoTests",
"test-live": "umi-test --watch"
"test-live": "umi-test --watch",
"tsc": "tsc --project tsconfig.build.json",
"watch": "BABEL_ENV=cjs babel src --watch --root-mode upward --out-dir lib --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments"
},
"dependencies": {
"@antv/g": "latest",
"@antv/g-plugin-3d": "latest",
"@antv/g-webgl": "latest",
"@antv/l7-core": "2.11.4",
"@antv/l7-utils": "2.11.4",
"@babel/runtime": "^7.7.7",
"@luma.gl/engine": "^8.5.18",
"@luma.gl/gltools": "^8.5.18",
"@luma.gl/webgl": "^8.5.18",
"inversify": "^5.0.1",
"l7regl": "^0.0.20",
"lodash": "^4.17.15",
"reflect-metadata": "^0.1.13"
},
"author": "xiaoiver",
"license": "ISC",
"devDependencies": {
"@antv/l7-test-utils": "2.11.4",
"gl": "^5.0.3"
},
"dependencies": {
"@antv/l7-core": "2.11.4",
"@antv/l7-utils": "2.11.4",
"@babel/runtime": "^7.7.7",
"inversify": "^5.0.1",
"l7regl": "^0.0.20",
"lodash": "^4.17.15",
"reflect-metadata": "^0.1.13",
"@luma.gl/engine": "^8.5.18",
"@luma.gl/webgl": "^8.5.18",
"@luma.gl/gltools": "^8.5.18"
},
"gitHead": "684ba4eb806a798713496d3fc0b4d1e17517dc31",
"publishConfig": {
"access": "public"
}
},
"gitHead": "684ba4eb806a798713496d3fc0b4d1e17517dc31"
}

View File

@ -6,24 +6,32 @@ const vert = `
#define COORDINATE_SYSTEM_P20 5.0 // amap
#define COORDINATE_SYSTEM_P20_OFFSET 6.0 // amap offset
attribute vec3 a_Position;
attribute vec3 a_Extrude;
layout(std140) uniform ub_SceneParams {
mat4 u_ProjectionMatrix;
mat4 u_ViewMatrix;
vec3 u_CameraPosition;
float u_DevicePixelRatio;
vec2 u_Viewport;
float u_IsOrtho;
};
uniform mat4 u_ViewProjectionMatrix;
layout(std140) uniform ub_MaterialParams {
mat4 u_ViewProjectionMatrix;
vec4 u_ViewportCenterProjection;
vec3 u_PixelsPerDegree;
float u_Zoom;
vec3 u_PixelsPerDegree2;
float u_ZoomScale;
vec2 u_ViewportCenter;
float u_CoordinateSystem;
};
uniform float u_Zoom;
uniform float u_ZoomScale;
uniform float u_CoordinateSystem;
uniform vec2 u_ViewportCenter;
uniform vec4 u_ViewportCenterProjection;
uniform vec3 u_PixelsPerDegree;
uniform vec3 u_PixelsPerDegree2;
layout(location = ${VertexAttributeLocation.MODEL_MATRIX0}) in vec4 a_ModelMatrix0;
layout(location = ${VertexAttributeLocation.MODEL_MATRIX1}) in vec4 a_ModelMatrix1;
layout(location = ${VertexAttributeLocation.MODEL_MATRIX2}) in vec4 a_ModelMatrix2;
layout(location = ${VertexAttributeLocation.MODEL_MATRIX3}) in vec4 a_ModelMatrix3;
layout(location = ${VertexAttributeLocation.POSITION}) in vec3 a_Position;
layout(location = ${VertexAttributeLocation.MAX}) in vec3 a_Extrude;
vec2 project_mercator(vec2 lnglat) {
float x = lnglat.x;
@ -78,132 +86,169 @@ void main() {
}
`;
const frag = `
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
layout(std140) uniform ub_SceneParams {
mat4 u_ProjectionMatrix;
mat4 u_ViewMatrix;
vec3 u_CameraPosition;
float u_DevicePixelRatio;
vec2 u_Viewport;
float u_IsOrtho;
};
layout(std140) uniform ub_MaterialParams {
mat4 u_ViewProjectionMatrix;
vec4 u_ViewportCenterProjection;
vec3 u_PixelsPerDegree;
float u_Zoom;
vec3 u_PixelsPerDegree2;
float u_ZoomScale;
vec2 u_ViewportCenter;
float u_CoordinateSystem;
};
out vec4 outputColor;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
outputColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
import { Canvas } from '@antv/g';
import {
BufferGeometry,
Format,
Mesh,
Plugin,
ShaderMaterial,
VertexAttributeBufferIndex,
VertexAttributeLocation,
VertexBufferFrequency,
} from '@antv/g-plugin-3d';
import { Renderer } from '@antv/g-webgl';
import { injectable } from 'inversify';
import regl from 'l7regl';
import 'reflect-metadata';
// import {polyfillContext} from '@luma.gl/gltools';
/**
*
* 使 luma
https://luma.gl/docs/getting-started/hello-instancing-low
import { Model} from '@luma.gl/engine';
import {Buffer, clear} from '@luma.gl/webgl';
const positionBuffer = new Buffer(gl, new Float32Array([
-0.5, -0.5,
0.5, -0.5,
0.0, 0.5
]));
const model = new Model(gl, {
vs,
fs,
attributes: {
position: positionBuffer,
color: colorBuffer
},
vertexCount: 3,
uniforms: {
uTexture: texture
}
});
clear(gl, {color: [0, 0, 0, 1]});
model.setUniforms({uMVP: mvpMatrix})
model.draw();
*/
@injectable()
export default class ReglRendererService {
private gl: regl.Regl;
private canvas: Canvas;
private device: Device;
public init(canvas: HTMLCanvasElement) {
this.gl = regl({
public async init(canvas: HTMLCanvasElement) {
const renderer = new Renderer();
renderer.registerPlugin(new Plugin());
this.canvas = new Canvas({
canvas,
renderer,
});
return this.gl;
/**
* Wait for canvas ready.
* @see https://g.antv.antgroup.com/api/canvas/scenegraph-lifecycle#ready
*/
await this.canvas.ready;
const plugin = renderer.getPlugin('device-renderer');
/**
* Use device to create BufferGeometry & ShaderMaterial.
* @see https://g.antv.antgroup.com/plugins/device-renderer#device
*/
this.device = plugin.getDevice();
}
public createModel = () => new ReglModel(this.gl);
public createModel = () => {
return new ReglModel(this.canvas, this.device);
};
public clear = () => {
const reglClearOptions: any = {
color: [0, 0, 0, 0],
depth: 1,
stencil: 0,
};
this.gl?.clear(reglClearOptions);
// const reglClearOptions: any = {
// color: [0, 0, 0, 0],
// depth: 1,
// stencil: 0,
// };
// this.gl?.clear(reglClearOptions);
};
}
// 程序对象
class ReglModel {
private drawCommand: any;
private uniforms: any = {};
private shaderMaterial: ShaderMaterial;
constructor(reGl: any) {
const reglUniforms: any = {};
constructor(canvas: Canvas, device: Device) {
const uniforms = {
u_CameraPosition: [0, 0, 0],
u_CoordinateSystem: 0,
u_DevicePixelRatio: 0,
u_ModelMatrix: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
u_ViewProjectionMatrix: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
u_PixelsPerDegree: [0, 0, 0],
u_PixelsPerDegree2: [0, 0, 0],
u_PixelsPerMeter: [0, 0, 0],
u_ProjectionMatrix: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
u_ViewMatrix: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
u_ViewProjectionMatrix: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
u_ViewportCenter: [0, 0],
u_ViewportCenterProjection: [0, 0, 0, 0],
u_ViewportSize: [0, 0],
u_Zoom: 1,
u_ZoomScale: 1,
u_ViewportCenter: [0, 0],
u_ViewportCenterProjection: [0, 0, 0, 0],
};
this.uniforms = this.extractUniforms(uniforms);
Object.keys(uniforms).forEach((uniformName) => {
// pass data into regl
reglUniforms[uniformName] = reGl.prop(uniformName);
/**
* @see https://g.antv.antgroup.com/api/3d/material
*/
const shaderMaterial = new ShaderMaterial(device, {
vertexShader: vert,
fragmentShader: frag,
});
// @see https://g.antv.antgroup.com/api/3d/material#setuniforms
shaderMaterial.setUniforms(uniforms);
this.shaderMaterial = shaderMaterial;
// [{
// coordinates: [120, 30],
// id: 0,
// }],
console.log(reglUniforms);
/**
* @see https://g.antv.antgroup.com/api/3d/geometry
*/
const bufferGeometry = new BufferGeometry(device);
bufferGeometry.setVertexBuffer({
bufferIndex: VertexAttributeBufferIndex.POSITION,
byteStride: 4 * 3,
frequency: VertexBufferFrequency.PerVertex,
attributes: [
{
format: Format.F32_RGB,
bufferByteOffset: 4 * 0,
location: VertexAttributeLocation.POSITION,
},
],
// use 6 vertices
data: Float32Array.from([
120, 30, 0, 120, 30, 0, 120, 30, 0, 120, 30, 0, 120, 30, 0, 120, 30, 0,
]),
});
bufferGeometry.setVertexBuffer({
bufferIndex: VertexAttributeBufferIndex.MAX,
byteStride: 4 * 3,
frequency: VertexBufferFrequency.PerVertex,
attributes: [
{
format: Format.F32_RGB,
bufferByteOffset: 4 * 0,
location: VertexAttributeLocation.MAX,
},
],
// use 6 vertices
data: Float32Array.from([
1, 1, 0, -1, 1, 0, -1, -1, 0, -1, -1, 0, 1, -1, 0, 1, 1, 0,
]),
});
// draw 6 vertices
bufferGeometry.vertexCount = 6;
const drawParams: any = {
attributes: {
a_Extrude: [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 0],
a_Position: [120, 30, 0, 120, 30, 0, 120, 30, 0, 120, 30, 0],
/**
* @see https://g.antv.antgroup.com/api/3d/mesh
*/
const mesh = new Mesh({
style: {
fill: '#1890FF',
opacity: 1,
geometry: bufferGeometry,
material: shaderMaterial,
},
frag,
uniforms: reglUniforms,
vert,
// primitive: 'triangles'
};
drawParams.elements = [0, 1, 2, 2, 3, 0];
this.drawCommand = reGl(drawParams);
});
canvas.appendChild(mesh);
}
public addUniforms(uniforms: any) {
@ -214,11 +259,33 @@ class ReglModel {
}
public draw(options: any) {
this.drawCommand(this.uniforms);
console.log(this.uniforms);
const {
u_CoordinateSystem,
u_ViewProjectionMatrix,
u_PixelsPerDegree,
u_PixelsPerDegree2,
u_Zoom,
u_ZoomScale,
u_ViewportCenter,
u_ViewportCenterProjection,
} = this.uniforms;
this.shaderMaterial.setUniforms({
u_CoordinateSystem,
u_ViewProjectionMatrix,
u_PixelsPerDegree,
u_PixelsPerDegree2,
u_Zoom,
u_ZoomScale,
u_ViewportCenter,
u_ViewportCenterProjection,
});
}
private extractUniforms(uniforms: any): any {
const extractedUniforms = {};
const extractedUniforms: Record<string, any> = {};
Object.keys(uniforms).forEach((uniformName) => {
extractedUniforms[uniformName] = uniforms[uniformName];
});