feat: 渲染流程清理

This commit is contained in:
shihui 2022-12-02 11:51:33 +08:00
parent 383ba2df7e
commit f519a6dce0
10 changed files with 128 additions and 406 deletions

View File

@ -1302,17 +1302,13 @@ export default class BaseLayer<ChildLayerStyleOptions = {}>
}
public renderModels(isPicking?: boolean) {
// TODO: this.getEncodedData().length > 0 这个判断是为了解决在 2.5.x 引入数据纹理后产生的 空数据渲染导致 texture 超出上限问题
if (this.encodeDataLength <= 0 && !this.forceRender) {
return this;
}
this.hooks.beforeRender.call();
this.models.forEach((model) => {
model.draw(
{
uniforms: {},
},
isPicking,
}
);
});
this.hooks.afterRender.call();

View File

@ -48,54 +48,6 @@ export default class DataMappingPlugin implements ILayerPlugin {
return true;
},
);
// remapping before render
layer.hooks.beforeRender.tap('DataMappingPlugin', () => {
const source = layer.getSource();
if (layer.layerModelNeedUpdate || !source || !source.inited) {
return;
}
const attributes = styleAttributeService.getLayerStyleAttributes() || [];
const filter = styleAttributeService.getLayerStyleAttribute('filter');
const { dataArray } = source.data;
// TODO 数据为空的情况
if (Array.isArray(dataArray) && dataArray.length === 0) {
return;
}
const attributesToRemapping = attributes.filter(
(attribute) => attribute.needRemapping, // 如果filter变化
);
let filterData = dataArray;
// 数据过滤完 再执行数据映射
if (filter?.needRemapping && filter?.scale) {
filterData = dataArray.filter((record: IParseDataItem) => {
return this.applyAttributeMapping(filter, record)[0];
});
}
if (attributesToRemapping.length) {
// 过滤数据
if (filter?.needRemapping) {
const encodeData = this.mapping(
layer,
attributes,
filterData,
undefined,
);
layer.setEncodedData(encodeData);
filter.needRemapping = false;
} else {
const encodeData = this.mapping(
layer,
attributesToRemapping,
filterData,
layer.getEncodedData(),
);
layer.setEncodedData(encodeData);
}
}
});
}
private generateMaping(
layer: ILayer,

View File

@ -78,27 +78,6 @@ export default class FeatureScalePlugin implements ILayerPlugin {
return true;
},
);
layer.hooks.beforeRender.tap('FeatureScalePlugin', () => {
if (layer.layerModelNeedUpdate) {
return;
}
this.scaleOptions = layer.getScaleOptions();
const attributes = styleAttributeService.getLayerStyleAttributes();
const dataArray = layer.getSource().data.dataArray;
if (Array.isArray(dataArray) && dataArray.length === 0) {
return;
}
if (attributes) {
const attributesToRescale = attributes.filter(
(attribute) => attribute.needRescale,
);
if (attributesToRescale.length) {
this.caculateScalesForAttributes(attributesToRescale, dataArray);
}
}
});
}
private isNumber(n: any) {
return !isNaN(parseFloat(n)) && isFinite(n);

View File

@ -5,16 +5,5 @@ import 'reflect-metadata';
@injectable()
export default class LayerAnimateStylePlugin implements ILayerPlugin {
public apply(layer: ILayer) {
layer.hooks.beforeRender.tap('LayerAnimateStylePlugin', () => {
// @ts-ignore
const animateStatus = layer.animateStatus;
if (animateStatus) {
layer.models.forEach((model: IModel) => {
model.addUniforms({
...layer.layerModel.getAnimateUniforms(),
});
});
}
});
}
}

View File

@ -106,16 +106,6 @@ export function generateLightingUniforms(
@injectable()
export default class LightingPlugin implements ILayerPlugin {
public apply(layer: ILayer) {
layer.hooks.beforeRender.tap('LightingPlugin', () => {
const { enableLighting } = layer.getLayerConfig();
if (enableLighting) {
layer.models.forEach((model) =>
// @ts-ignore
model.addUniforms({
...generateLightingUniforms(),
}),
);
}
});
}
}

View File

@ -57,13 +57,5 @@ export default class MultiPassRendererPlugin implements ILayerPlugin {
layer.multiPassRenderer.setRenderFlag(true);
}
});
layer.hooks.beforeRender.tap('MultiPassRendererPlugin', () => {
if (this.enabled) {
// 渲染前根据 viewport 调整 FBO size
const { width, height } = rendererService.getViewportSize();
layer.multiPassRenderer.resize(width, height);
}
});
}
}

View File

@ -7,9 +7,5 @@ import 'reflect-metadata';
@injectable()
export default class UpdateModelPlugin implements ILayerPlugin {
public apply(layer: ILayer) {
layer.hooks.beforeRender.tap('UpdateModelPlugin', () => {});
layer.hooks.afterRender.tap('UpdateModelPlugin', () => {
layer.layerModelNeedUpdate = false;
});
}
}

View File

@ -16,42 +16,6 @@ export default class UpdateStyleAttributePlugin implements ILayerPlugin {
layer.hooks.init.tapPromise('UpdateStyleAttributePlugin', () => {
this.initStyleAttribute(layer, { styleAttributeService });
});
layer.hooks.beforeRender.tap('UpdateStyleAttributePlugin', () => {
if (layer.layerModelNeedUpdate) {
return;
}
if (layer.inited) {
this.updateStyleAttribute(layer, { styleAttributeService });
}
});
}
private updateStyleAttribute(
layer: ILayer,
{
styleAttributeService,
}: { styleAttributeService: IStyleAttributeService },
) {
const attributes = styleAttributeService.getLayerStyleAttributes() || [];
const filter = styleAttributeService.getLayerStyleAttribute('filter');
if (filter && filter.needRegenerateVertices) {
layer.layerModelNeedUpdate = true;
attributes.forEach((attr) => (attr.needRegenerateVertices = false));
return;
}
attributes
.filter((attribute) => attribute.needRegenerateVertices)
.forEach((attribute) => {
// 精确更新某个/某些 feature(s),需要传入 featureIdx d
styleAttributeService.updateAttributeByFeatureRange(
attribute.name,
layer.getEncodedData(), // 获取经过 mapping 最新的数据
attribute.featureRange.startIndex,
attribute.featureRange.endIndex,
layer,
);
attribute.needRegenerateVertices = false;
});
}
private initStyleAttribute(

View File

@ -0,0 +1,117 @@
export 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_ModelMatrix;
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;
uniform vec3 u_PixelsPerMeter;
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))
);
}
float project_scale(float meters) {
return meters * u_PixelsPerMeter.z;
}
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.xyz * pixels_per_unit, offset.w);
}
vec4 project_position(vec4 position) {
if (u_CoordinateSystem == COORDINATE_SYSTEM_P20) {
return vec4(
(project_mercator(position.xy) * WORLD_SCALE * u_ZoomScale - vec2(215440491., 106744817.)) * vec2(1., -1.),
project_scale(position.z),
position.w
);
}
return position;
}
vec2 project_pixel(vec2 pixel) {
if (u_CoordinateSystem == COORDINATE_SYSTEM_P20 || u_CoordinateSystem == COORDINATE_SYSTEM_P20_OFFSET) {
return pixel * pow(2.0, (19.0 - u_Zoom));
}
return pixel * -1.;
}
vec4 project_common_position_to_clipspace(vec4 position, mat4 viewProjectionMatrix, vec4 center) {
return viewProjectionMatrix * position + center;
}
vec4 project_common_position_to_clipspace(vec4 position) {
return project_common_position_to_clipspace(
position,
u_ViewProjectionMatrix,
u_ViewportCenterProjection
);
}
vec4 unproject_clipspace_to_position(vec4 clipspacePos, mat4 u_InverseViewProjectionMatrix) {
vec4 pos = u_InverseViewProjectionMatrix * (clipspacePos - u_ViewportCenterProjection);
return pos;
}
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));
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, 0.0, 1.0));
}
`;
export 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);
}
`;

View File

@ -8,29 +8,19 @@ import {
IUniform,
} from '@antv/l7-core';
import regl from 'l7regl';
import { cloneDeep, isPlainObject, isTypedArray } from 'lodash';
import { isPlainObject, isTypedArray } from 'lodash';
import {
blendEquationMap,
blendFuncMap,
cullFaceMap,
depthFuncMap,
primitiveMap,
stencilFuncMap,
stencilOpMap,
} from './constants';
import ReglAttribute from './ReglAttribute';
import ReglElements from './ReglElements';
import ReglFramebuffer from './ReglFramebuffer';
import ReglTexture2D from './ReglTexture2D';
/**
* adaptor for regl.DrawCommand
*/
export default class ReglModel implements IModel {
private reGl: regl.Regl;
private destroyed: boolean = false;
private drawCommand: regl.DrawCommand;
private drawPickCommand: regl.DrawCommand;
private drawParams: regl.DrawConfig;
private options: IModelInitializationOptions;
private uniforms: {
@ -40,22 +30,16 @@ export default class ReglModel implements IModel {
constructor(reGl: regl.Regl, options: IModelInitializationOptions) {
this.reGl = reGl;
const {
pick = true,
vs,
fs,
attributes,
uniforms,
primitive,
count,
elements,
depth,
blend,
stencil,
cull,
instances,
} = options;
const reglUniforms: { [key: string]: IUniform } = {};
this.options = options;
if (uniforms) {
this.uniforms = this.extractUniforms(uniforms);
Object.keys(uniforms).forEach((uniformName) => {
@ -64,6 +48,7 @@ export default class ReglModel implements IModel {
reglUniforms[uniformName] = reGl.prop(uniformName);
});
}
const reglAttributes: { [key: string]: regl.Attribute } = {};
Object.keys(attributes).forEach((name: string) => {
@ -78,80 +63,9 @@ export default class ReglModel implements IModel {
primitive:
primitiveMap[primitive === undefined ? gl.TRIANGLES : primitive],
};
if (instances) {
drawParams.instances = instances;
}
// Tip:
// elements 中可能包含 count此时不应传入
// count 和 elements 相比、count 优先
if (count) {
drawParams.count = count;
} else if (elements) {
drawParams.elements = (elements as ReglElements).get();
}
this.initDepthDrawParams({ depth }, drawParams);
this.initBlendDrawParams({ blend }, drawParams);
this.initStencilDrawParams({ stencil }, drawParams);
this.initCullDrawParams({ cull }, drawParams);
drawParams.elements = (elements as ReglElements).get();
this.drawCommand = reGl(drawParams);
if (pick) {
const pickDrawParams = cloneDeep(drawParams);
pickDrawParams.blend = {
...pickDrawParams.blend,
enable: false,
};
this.drawPickCommand = reGl(pickDrawParams);
}
this.drawParams = drawParams;
}
public updateAttributesAndElements(
attributes: { [key: string]: IAttribute },
elements: IElements,
) {
const reglAttributes: { [key: string]: regl.Attribute } = {};
Object.keys(attributes).forEach((name: string) => {
reglAttributes[name] = (attributes[name] as ReglAttribute).get();
});
this.drawParams.attributes = reglAttributes;
this.drawParams.elements = (elements as ReglElements).get();
this.drawCommand = this.reGl(this.drawParams);
if (this.options.pick) {
const pickDrawParams = cloneDeep(this.drawParams);
pickDrawParams.blend = {
...pickDrawParams.blend,
enable: false,
};
this.drawPickCommand = this.reGl(pickDrawParams);
}
}
public updateAttributes(attributes: { [key: string]: IAttribute }) {
const reglAttributes: { [key: string]: regl.Attribute } = {};
Object.keys(attributes).forEach((name: string) => {
reglAttributes[name] = (attributes[name] as ReglAttribute).get();
});
this.drawParams.attributes = reglAttributes;
this.drawCommand = this.reGl(this.drawParams);
if (this.options.pick) {
const pickDrawParams = cloneDeep(this.drawParams);
pickDrawParams.blend = {
...pickDrawParams.blend,
enable: false,
};
this.drawPickCommand = this.reGl(pickDrawParams);
}
}
public addUniforms(uniforms: { [key: string]: IUniform }) {
@ -161,178 +75,11 @@ export default class ReglModel implements IModel {
};
}
public draw(options: IModelDrawOptions, pick?: boolean) {
// console.log('options', this.drawParams)
if (
this.drawParams.attributes &&
Object.keys(this.drawParams.attributes).length === 0
) {
return;
}
const uniforms: {
[key: string]: IUniform;
} = {
...this.uniforms,
...this.extractUniforms(options.uniforms || {}),
};
const reglDrawProps: {
[key: string]:
| regl.Framebuffer
| regl.Texture2D
| number
| number[]
| boolean;
} = {};
Object.keys(uniforms).forEach((uniformName: string) => {
const type = typeof uniforms[uniformName];
if (
type === 'boolean' ||
type === 'number' ||
Array.isArray(uniforms[uniformName]) ||
// @ts-ignore
uniforms[uniformName].BYTES_PER_ELEMENT
) {
reglDrawProps[uniformName] = uniforms[uniformName] as
| number
| number[]
| boolean;
} else {
reglDrawProps[uniformName] = (
uniforms[uniformName] as ReglFramebuffer | ReglTexture2D
).get();
}
});
// 在进行拾取操作的绘制中,不应该使用叠加模式 - picking 根据拾取的颜色作为判断的输入,而叠加模式会产生新的,在 id 序列中不存在的颜色
if (!pick) {
this.drawCommand(reglDrawProps);
} else {
if (this.drawPickCommand) {
this.drawPickCommand(reglDrawProps);
}
}
// this.drawCommand(reglDrawProps);
// this.drawPickCommand(reglDrawProps);
}
public draw(options: IModelDrawOptions) {
public destroy() {
// @ts-ignore
this.drawParams?.elements?.destroy();
if (this.options.attributes) {
Object.values(this.options.attributes).forEach((attr: any) => {
// @ts-ignore
(attr as ReglAttribute)?.destroy();
});
}
this.destroyed = true;
}
/**
* @see https://github.com/regl-project/regl/blob/gh-pages/API.md#depth-buffer
*/
private initDepthDrawParams(
{ depth }: Pick<IModelInitializationOptions, 'depth'>,
drawParams: regl.DrawConfig,
) {
if (depth) {
drawParams.depth = {
enable: depth.enable === undefined ? true : !!depth.enable,
mask: depth.mask === undefined ? true : !!depth.mask,
func: depthFuncMap[depth.func || gl.LESS],
range: depth.range || [0, 1],
};
}
}
/**
* @see https://github.com/regl-project/regl/blob/gh-pages/API.md#blending
*/
private initBlendDrawParams(
{ blend }: Pick<IModelInitializationOptions, 'blend'>,
drawParams: regl.DrawConfig,
) {
if (blend) {
const { enable, func, equation, color = [0, 0, 0, 0] } = blend;
// @ts-ignore
drawParams.blend = {
enable: !!enable,
func: {
srcRGB: blendFuncMap[(func && func.srcRGB) || gl.SRC_ALPHA],
srcAlpha: blendFuncMap[(func && func.srcAlpha) || gl.SRC_ALPHA],
dstRGB: blendFuncMap[(func && func.dstRGB) || gl.ONE_MINUS_SRC_ALPHA],
dstAlpha:
blendFuncMap[(func && func.dstAlpha) || gl.ONE_MINUS_SRC_ALPHA],
},
equation: {
rgb: blendEquationMap[(equation && equation.rgb) || gl.FUNC_ADD],
alpha: blendEquationMap[(equation && equation.alpha) || gl.FUNC_ADD],
},
color,
};
}
}
/**
* @see https://github.com/regl-project/regl/blob/gh-pages/API.md#stencil
*/
private initStencilDrawParams(
{ stencil }: Pick<IModelInitializationOptions, 'stencil'>,
drawParams: regl.DrawConfig,
) {
if (stencil) {
const {
enable,
mask = -1,
func = {
cmp: gl.ALWAYS,
ref: 0,
mask: -1,
},
opFront = {
fail: gl.KEEP,
zfail: gl.KEEP,
zpass: gl.KEEP,
},
opBack = {
fail: gl.KEEP,
zfail: gl.KEEP,
zpass: gl.KEEP,
},
} = stencil;
drawParams.stencil = {
enable: !!enable,
mask,
func: {
...func,
cmp: stencilFuncMap[func.cmp],
},
opFront: {
fail: stencilOpMap[opFront.fail],
zfail: stencilOpMap[opFront.zfail],
zpass: stencilOpMap[opFront.zpass],
},
opBack: {
fail: stencilOpMap[opBack.fail],
zfail: stencilOpMap[opBack.zfail],
zpass: stencilOpMap[opBack.zpass],
},
};
}
}
/**
* @see https://github.com/regl-project/regl/blob/gh-pages/API.md#culling
*/
private initCullDrawParams(
{ cull }: Pick<IModelInitializationOptions, 'cull'>,
drawParams: regl.DrawConfig,
) {
if (cull) {
const { enable, face = gl.BACK } = cull;
drawParams.cull = {
enable: !!enable,
face: cullFaceMap[face],
};
}
this.drawCommand(this.uniforms);
}
/**