feat: 渲染流程代码简化

This commit is contained in:
shihui 2022-12-04 22:59:21 +08:00
parent 99b10bf662
commit b450900f02
3 changed files with 138 additions and 357 deletions

View File

@ -17,12 +17,12 @@ export default class LayerModelPlugin implements ILayerPlugin {
}
public async prepareLayerModel(layer: ILayer) {
// 更新Model 配置项
layer.prepareBuildModel();
// clear layerModel resource
// 初始化 Model
await layer.buildModels();
// layer.layerModelNeedUpdate = false;
// // 更新Model 配置项
// layer.prepareBuildModel();
// // clear layerModel resource
// // 初始化 Model
// await layer.buildModels();
// // layer.layerModelNeedUpdate = false;
}
public apply(layer: ILayer) {

View File

@ -1,18 +1,10 @@
import {
AttributeType,
gl,
IEncodeFeature,
ILayer,
TYPES,
IRendererService,
} from '@antv/l7-core';
import StyleAttribute from '../../../../core/src/services/layer/StyleAttribute'
import { vert, frag } from './fillShader';
export default class FillModel {
protected layer: ILayer;
private attributes: any[] = [];
protected rendererService: IRendererService;
constructor(layer: ILayer) {
@ -21,253 +13,11 @@ export default class FillModel {
.getContainer()
.get<IRendererService>(TYPES.IRendererService);
this.registerBuiltinAttributes();
}
public createAttributesAndIndices(
features: IEncodeFeature[],
) {
function triangulation() {
const coordinates = [120, 30]
return {
vertices: [...coordinates, ...coordinates, ...coordinates, ...coordinates],
indices: [0, 1, 2, 2, 3, 0],
size: 2,
};
}
const descriptors = this.attributes.map((attr) => {
attr.resetDescriptor();
return attr.descriptor;
});
let verticesNum = 0;
let vecticesCount = 0; // 在不使用 element 的时候记录顶点、图层所有顶点的总数
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const vertices: number[] = [];
const indices: number[] = [];
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const normals: number[] = [];
let size = 3;
features.forEach((feature, featureIdx) => {
// 逐 feature 进行三角化
const {
indices: indicesForCurrentFeature,
vertices: verticesForCurrentFeature,
normals: normalsForCurrentFeature,
size: vertexSize,
indexes,
count,
} = triangulation(feature);
if (typeof count === 'number') {
vecticesCount += count;
}
indicesForCurrentFeature.forEach((i) => {
indices.push(i + verticesNum);
});
size = vertexSize;
const verticesNumForCurrentFeature =
verticesForCurrentFeature.length / vertexSize;
verticesNum += verticesNumForCurrentFeature;
// 根据 position 顶点生成其他顶点数据
for (
let vertexIdx = 0;
vertexIdx < verticesNumForCurrentFeature;
vertexIdx++
) {
const normal =
normalsForCurrentFeature?.slice(vertexIdx * 3, vertexIdx * 3 + 3) ||
[];
const vertice = verticesForCurrentFeature.slice(
vertexIdx * vertexSize,
vertexIdx * vertexSize + vertexSize,
);
let vertexIndex = 0;
if (indexes && indexes[vertexIdx] !== undefined) {
vertexIndex = indexes[vertexIdx];
}
descriptors.forEach((descriptor) => {
if (descriptor && descriptor.update) {
(descriptor.buffer.data as number[]).push(
...descriptor.update(
feature,
featureIdx,
vertice,
vertexIdx, // 当前顶点所在feature索引
normal,
vertexIndex,
// 传入顶点索引 vertexIdx
),
);
} // end if
}); // end for each
} // end for
}); // end features for Each
const {
createAttribute,
createBuffer,
createElements,
} = this.rendererService;
const attributes = {};
descriptors.forEach((descriptor) => {
if (descriptor) {
const { buffer, update, name, ...rest } = descriptor;
const vertexAttribute = createAttribute({
// IBuffer 参数透传
buffer: createBuffer(buffer),
...rest,
});
attributes[descriptor.name || ''] = vertexAttribute;
}
});
const elements = createElements({
data: indices,
type: gl.UNSIGNED_INT,
count: indices.length,
});
// console.log(attributes);
const a_posotion_data = {
data: [120, 30, 0, 120, 30, 0, 120, 30, 0, 120, 30, 0],
type: 5126
}
const a_extrude_data = {
data: [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 0],
type: 5126,
usage: 35048
}
const attributesAndIndices = {
attributes,
elements,
count: vecticesCount,
};
return attributesAndIndices;
}
public buildLayerModel() {
const uniforms = {
u_CameraPosition: [0, 0, 0],
u_CoordinateSystem: 0,
u_DevicePixelRatio: 0,
u_FocalDistance: 0,
u_ModelMatrix: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
u_Mvp: [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
}
const { createModel } = this.rendererService;
const { attributes, elements } =this.createAttributesAndIndices(
[{
coordinates: [120, 30],
id: 0,
}],
);
const modelOptions = {
attributes,
uniforms,
fs: frag,
vs: vert,
elements,
};
return createModel(modelOptions);
}
public buildModels() {
const model = this.buildLayerModel();
return [model];
}
public registerStyleAttribute(
options: any
) {
const attributeToUpdate = new StyleAttribute(options);
// console.log(options);
// console.log(attributeToUpdate);
this.attributes.push(attributeToUpdate);
}
protected registerBuiltinAttributes() {
this.registerStyleAttribute({
name: 'position',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Position',
buffer: {
data: [],
type: gl.FLOAT,
},
size: 3,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
) => {
return vertex.length === 2
? [vertex[0], vertex[1], 0]
: [vertex[0], vertex[1], vertex[2]];
},
},
});
this.registerStyleAttribute({
name: 'extrude',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Extrude',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 3,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
const extrude = [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 0];
const extrudeIndex = (attributeIdx % 4) * 3;
return [
extrude[extrudeIndex],
extrude[extrudeIndex + 1],
extrude[extrudeIndex + 2],
];
},
},
});
const { createModel } = this.rendererService;
const model = createModel();
return [model];
}
}

View File

@ -1,16 +1,94 @@
/**
* render w/ regl
* @see https://github.com/regl-project/regl/blob/gh-pages/API.md
*/
import {
IAttributeInitializationOptions,
IBufferInitializationOptions,
IClearOptions,
IElementsInitializationOptions,
IExtensions,
IModel,
IModelInitializationOptions,
} from '@antv/l7-core';
const vert = `
#define TILE_SIZE 512.0
#define PI 3.1415926536
#define WORLD_SCALE TILE_SIZE / (PI * 2.0)
#define COORDINATE_SYSTEM_P20 5.0 // amap
#define COORDINATE_SYSTEM_P20_OFFSET 6.0 // amap offset
attribute vec3 a_Position;
attribute vec3 a_Extrude;
uniform mat4 u_ViewProjectionMatrix;
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;
vec2 project_mercator(vec2 lnglat) {
float x = lnglat.x;
return vec2(
radians(x) + PI,
PI - log(tan(PI * 0.25 + radians(lnglat.y) * 0.5))
);
}
// offset coords -> world coords 偏移坐标转成世界坐标
vec4 project_offset(vec4 offset) {
float dy = offset.y;
dy = clamp(dy, -1., 1.);
vec3 pixels_per_unit = u_PixelsPerDegree + u_PixelsPerDegree2 * dy;
return vec4(offset.xy * pixels_per_unit.xy, 0.0, 1.0);
}
// 投影方法 - 将经纬度转化为平面坐标xy 平面)
vec4 project_position(vec4 position) {
if (u_CoordinateSystem == COORDINATE_SYSTEM_P20_OFFSET) {
float X = position.x - u_ViewportCenter.x;
float Y = position.y - u_ViewportCenter.y;
return project_offset(vec4(X, Y, 0.0, 1.0));
}
if (u_CoordinateSystem == COORDINATE_SYSTEM_P20) {
return vec4(
(project_mercator(position.xy) * WORLD_SCALE * u_ZoomScale - vec2(215440491., 106744817.)) * vec2(1., -1.),
0.0,
1.0
);
}
return position;
}
vec2 project_pixel(vec2 pixel) {
// P20 坐标系下,为了和 Web 墨卡托坐标系统一zoom 默认减1
return pixel * pow(2.0, (19.0 - u_Zoom));
}
void main() {
vec2 offset = a_Extrude.xy * 10.0;
offset = project_pixel(offset);
vec4 project_pos = project_position(vec4(a_Position.xy, 0.0, 1.0));
vec4 worldPos = u_ViewProjectionMatrix * vec4(project_pos.xy + offset, 0.0, 1.0) + u_ViewportCenterProjection;
gl_Position = worldPos;
}
`;
const frag = `
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
import { injectable } from 'inversify';
import regl from 'l7regl';
import 'reflect-metadata';
@ -20,87 +98,25 @@ import 'reflect-metadata';
*/
@injectable()
export default class ReglRendererService {
public extensionObject: IExtensions;
private gl: regl.Regl;
public init(
canvas: HTMLCanvasElement,
) {
this.gl = regl({
// creates a full screen canvas element and WebGLRenderingContext
// var regl = require('regl')()
canvas: canvas,
attributes: {
alpha: true,
antialias: true,
premultipliedAlpha: true,
preserveDrawingBuffer: false,
stencil: false,
},
// TODO: use extensions
extensions: [
'OES_element_index_uint',
'OES_standard_derivatives', // wireframe
'ANGLE_instanced_arrays', // VSM shadow map
],
optionalExtensions: [
'oes_texture_float_linear',
'OES_texture_float',
'EXT_texture_filter_anisotropic',
'EXT_blend_minmax',
'WEBGL_depth_texture',
],
profile: true,
this.gl = regl({
canvas,
});
return this.gl;
}
public createModel = (options: IModelInitializationOptions): IModel =>
new ReglModel(this.gl, options);
public createModel = () =>
new ReglModel(this.gl);
public createAttribute = (
options: IAttributeInitializationOptions,
) => {
const { buffer, offset, stride, normalized, size, divisor } = options;
const attribute = {
buffer,
offset: offset || 0,
stride: stride || 0,
normalized: normalized || false,
divisor: divisor || 0,
};
if (size) {
attribute.size = size;
}
return attribute;
}
public createBuffer = (options: IBufferInitializationOptions) => {
const { data } = options;
return this.gl.buffer({
data,
usage: 'static',
});
}
public createElements = (
options: IElementsInitializationOptions,
) => {
const { data, count } = options;
return this.gl.elements({
data,
usage: "static",
count,
});
};
public clear = (options: IClearOptions) => {
public clear = (options: any) => {
const { color, depth, stencil } = options;
const reglClearOptions: regl.ClearOptions = {
const reglClearOptions: any = {
color,
depth,
stencil,
@ -113,36 +129,51 @@ class ReglModel {
private drawCommand: any;
private uniforms: any = {};
constructor(reGl: any, options: any) {
const {
vs,
fs,
attributes,
uniforms,
elements,
} = options;
constructor(reGl: any) {
const reglUniforms: any = {};
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_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
}
this.uniforms = this.extractUniforms(uniforms);
Object.keys(uniforms).forEach((uniformName) => {
// pass data into regl
reglUniforms[uniformName] = reGl.prop(uniformName);
});
const reglAttributes: any = {};
Object.keys(attributes).forEach((name: string) => {
reglAttributes[name] = attributes[name];
});
// [{
// coordinates: [120, 30],
// id: 0,
// }],
const drawParams: any = {
attributes: reglAttributes,
frag: fs,
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],
},
frag,
uniforms: reglUniforms,
vert: vs,
vert,
primitive: 'triangles'
};
drawParams.elements = elements;
drawParams.elements = [0, 1, 2, 2, 3, 0];
this.drawCommand = reGl(drawParams);
}