feat(point-layer): optimize 2d circle

This commit is contained in:
yuqi.pyq 2019-05-29 14:22:07 +08:00
parent dd8fcfab7a
commit e8704a1e7e
10 changed files with 146 additions and 0 deletions

View File

@ -99,6 +99,7 @@
"@antv/geo-coord": "^1.0.8",
"@antv/util": "~2.0.1",
"@mapbox/tiny-sdf": "^1.1.0",
"@mapbox/vector-tile": "^1.3.1",
"@turf/bbox": "^6.0.1",
"@turf/clean-coords": "^6.0.1",
"@turf/invariant": "^6.1.2",
@ -110,6 +111,7 @@
"gl-matrix": "^2.4.1",
"gl-vec2": "^1.3.0",
"lodash": "^4.17.5",
"pbf": "^3.2.0",
"polyline-miter-util": "^1.0.1",
"rbush": "^2.0.2",
"simple-statistics": "^7.0.1",

View File

@ -0,0 +1,25 @@
export default function circleBuffer(layerData) {
const index = [];
const aExtrude = [];
const aRadius = [];
const aColor = [];
const aPickingId = [];
const aPosition = [];
layerData.forEach(({ size = 0, color, id, coordinates }, i) => {
// construct point coords
aExtrude.push(-1, -1, 1, -1, 1, 1, -1, 1);
aRadius.push(size, size, size, size);
aColor.push(...color, ...color, ...color, ...color);
aPickingId.push(id, id, id, id);
aPosition.push(...coordinates, ...coordinates, ...coordinates, ...coordinates);
index.push(...[ 0, 1, 2, 0, 2, 3 ].map(n => n + i * 4));
});
return {
aExtrude,
aRadius,
aColor,
aPickingId,
aPosition,
index
};
}

View File

@ -2,3 +2,4 @@ export { default as FillBuffer } from './fillBuffer';
export { default as StrokeBuffer } from './strokeBuffer';
export { default as ImageBuffer } from './imageBuffer';
export { default as NormalBuffer } from './normalBuffer';
export { default as CircleBuffer } from './circleBuffer';

View File

@ -0,0 +1,16 @@
import Material from './material';
import { getModule, wrapUniforms } from '../../util/shaderModule';
import merge from '@antv/util/lib/deep-mix';
export default class CircleMaterial extends Material {
constructor(_uniforms, _defines, parameters) {
super(parameters);
const { vs, fs, uniforms } = getModule('circle');
this.uniforms = wrapUniforms(merge(uniforms, _uniforms));
this.defines = _defines;
this.type = 'CircleMaterial';
this.vertexShader = vs;
this.fragmentShader = fs;
this.transparent = true;
}
}

View File

@ -0,0 +1,26 @@
uniform float u_blur : 0;
uniform float u_opacity : 1;
uniform float u_stroke_width : 1;
uniform vec4 u_stroke_color : [1, 1, 1, 1];
uniform float u_stroke_opacity : 1;
varying vec3 v_data;
varying vec4 v_color;
varying float v_radius;
void main() {
float extrude_length = length(v_data.xy);
lowp float antialiasblur = v_data.z;
float antialiased_blur = -max(u_blur, antialiasblur);
float opacity_t = smoothstep(0.0, antialiased_blur, extrude_length - 1.0);
float color_t = u_stroke_width < 0.01 ? 0.0 : smoothstep(
antialiased_blur,
0.0,
extrude_length - v_radius / (v_radius + u_stroke_width)
);
gl_FragColor = opacity_t * mix(v_color * u_opacity, u_stroke_color * u_stroke_opacity, color_t);
}

View File

@ -0,0 +1,34 @@
attribute float a_radius;
attribute vec2 a_shape;
attribute vec4 a_color;
uniform float u_zoom : 1;
uniform float u_stroke_width : 2;
uniform float u_activeId : 0;
uniform vec4 u_activeColor : [ 1.0, 0, 0, 1.0 ];
varying vec3 v_data;
varying vec4 v_color;
varying float v_radius;
void main() {
v_color = a_color;
v_radius = a_radius;
// extrude
float zoom_scale = pow(2., 20. - u_zoom);
vec2 offset = a_shape * (a_radius + u_stroke_width) * zoom_scale;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position.xy + offset, 0.0, 1.0);
// anti-alias
float antialiasblur = 1.0 / (a_radius + u_stroke_width);
// construct point coords
v_data = vec3(a_shape, antialiasblur);
// picking
if(pickingId == u_activeId) {
v_color = u_activeColor;
}
worldId = id_toPickColor(pickingId);
}

View File

@ -6,6 +6,8 @@ import grid_frag from '../shader/grid_frag.glsl';
import grid_vert from '../shader/grid_vert.glsl';
import hexagon_frag from '../shader/hexagon_frag.glsl';
import hexagon_vert from '../shader/hexagon_vert.glsl';
import circle_frag from './circle_frag.glsl';
import circle_vert from './circle_vert.glsl';
// 点的边线
import point_line_frag from '../shader/point_meshLine_frag.glsl';
@ -53,6 +55,7 @@ export function compileBuiltinModules() {
registerModule('point', { vs: point_vert, fs: point_frag });
registerModule('common', { vs: common, fs: common });
registerModule('pick_color', { vs: pick_color, fs: pick_color });
registerModule('circle', { vs: circle_vert, fs: circle_frag });
registerModule('polygon', { vs: polygon_vert, fs: polygon_frag });
registerModule('grid', { vs: grid_vert, fs: grid_frag });
registerModule('hexagon', { vs: hexagon_vert, fs: hexagon_frag });

View File

@ -28,6 +28,11 @@ export default class PointLayer extends Layer {
break;
}
}
// 2D circle 特殊处理
if (shape === 'circle') {
return 'circle';
}
if (
pointShape['2d'].indexOf(shape) !== -1 ||
pointShape['3d'].indexOf(shape) !== -1

View File

@ -22,12 +22,14 @@ import DrawPointImage from './point/drawImage';
import DrawPointNormal from './point/drawNormal';
import DrawPointStroke from './point/drawStroke';
import DrawPointText from './point/drawText';
import DrawPointCircle from './point/drawCircle';
registerRender('point', 'fill', DrawPointFill);
registerRender('point', 'image', DrawPointImage);
registerRender('point', 'normal', DrawPointNormal);
registerRender('point', 'stroke', DrawPointStroke);
registerRender('point', 'text', DrawPointText);
registerRender('point', 'circle', DrawPointCircle);
// heatmap

View File

@ -0,0 +1,32 @@
/**
* 针对绘制圆形的优化
* 手动构建点阵坐标系便于实现描边反走样效果
*/
import * as THREE from '../../../core/three';
import * as PointBuffer from '../../../geom/buffer/point/index';
import CircleMaterial from '../../../geom/material/circleMaterial';
export default function drawCircle(layerData, layer) {
const style = layer.get('styleOptions');
const activeOption = layer.get('activedOptions');
const { aColor, aExtrude, aPickingId, aPosition, index, aRadius } = PointBuffer.CircleBuffer(layerData, style);
const geometry = new THREE.BufferGeometry();
geometry.setIndex(index);
geometry.addAttribute('position', new THREE.Float32BufferAttribute(aPosition, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(aColor, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(aPickingId, 1));
geometry.addAttribute('a_shape', new THREE.Float32BufferAttribute(aExtrude, 2));
geometry.addAttribute('a_radius', new THREE.Float32BufferAttribute(aRadius, 1));
const material = new CircleMaterial({
u_opacity: style.opacity,
u_activeColor: activeOption.fill,
u_zoom: layer.scene.getZoom(),
u_stroke_color: style.stroke,
u_stroke_width: style.strokeWidth,
u_stroke_opacity: style.strokeOpacity
});
material.depthTest = false;
const fillMesh = new THREE.Mesh(geometry, material);
return fillMesh;
}