feat(point-layer): use 2d sdf functions

This commit is contained in:
xiaoiver 2019-06-18 18:23:51 +08:00
parent 1733971fcf
commit 6ec70396b9
10 changed files with 167 additions and 24 deletions

View File

@ -59,7 +59,14 @@ scene.on('loaded', () => {
.source(data,{ .source(data,{
isCluster:true isCluster:true
}) })
.shape('circle') // .shape('circle')
.shape('point_count', [ 'circle', 'triangle', 'hexagon' ])
// .shape('triangle')
// .shape('square')
// .shape('hexagon')
// .shape('octogon')
// .shape('hexagram')
// .shape('pentagon')
.size('point_count', [ 5, 40]) // default 1 .size('point_count', [ 5, 40]) // default 1
//.size('value', [ 10, 300]) // default 1 //.size('value', [ 10, 300]) // default 1
.active(true) .active(true)

View File

@ -1,13 +1,24 @@
import { packUint8ToFloat } from '../../../util/vertex-compress'; import { packUint8ToFloat } from '../../../util/vertex-compress';
import Global from '../../../global';
const { pointShape } = Global;
const LEFT_SHIFT18 = 262144.0; const LEFT_SHIFT17 = 131072.0;
const LEFT_SHIFT20 = 1048576.0; // const LEFT_SHIFT18 = 262144.0;
// const LEFT_SHIFT19 = 524288.0;
// const LEFT_SHIFT20 = 1048576.0;
const LEFT_SHIFT21 = 2097152.0;
// const LEFT_SHIFT22 = 4194304.0;
const LEFT_SHIFT23 = 8388608.0;
// const LEFT_SHIFT24 = 16777216.0;
export default function circleBuffer(layerData) { export default function circleBuffer(layerData) {
const index = []; const index = [];
const aPosition = []; const aPosition = [];
const aPackedData = []; const aPackedData = [];
layerData.forEach(({ size = 0, color, id, coordinates }, i) => {
layerData.forEach(({ size = 0, color, id, coordinates, shape }, i) => {
const shapeIndex = pointShape['2d'].indexOf(shape) || 0;
if (isNaN(size)) { if (isNaN(size)) {
size = 0; size = 0;
@ -26,10 +37,12 @@ export default function circleBuffer(layerData) {
[ 1, 1 ], [ 1, 1 ],
[ -1, 1 ] [ -1, 1 ]
].forEach(extrude => { ].forEach(extrude => {
// vec4(color, color, (4-bit extrude, 16-bit size), id) // vec4(color, color, (4-bit extrude, 4-bit shape, 16-bit size), id)
aPackedData.push( aPackedData.push(
...packedColor, ...packedColor,
(extrude[0] + 1) * LEFT_SHIFT20 + (extrude[1] + 1) * LEFT_SHIFT18 + size, (extrude[0] + 1) * LEFT_SHIFT23 + (extrude[1] + 1) * LEFT_SHIFT21
+ shapeIndex * LEFT_SHIFT17
+ size,
id id
); );
}); });

View File

@ -4,22 +4,57 @@ uniform float u_stroke_width : 1;
uniform vec4 u_stroke_color : [1, 1, 1, 1]; uniform vec4 u_stroke_color : [1, 1, 1, 1];
uniform float u_stroke_opacity : 1; uniform float u_stroke_opacity : 1;
varying vec3 v_data; varying vec4 v_data;
varying vec4 v_color; varying vec4 v_color;
varying float v_radius; varying float v_radius;
#pragma include "sdf_2d"
void main() { void main() {
float extrude_length = length(v_data.xy); int shape = int(floor(v_data.w + 0.5));
lowp float antialiasblur = v_data.z; lowp float antialiasblur = v_data.z;
float antialiased_blur = -max(u_blur, antialiasblur); float antialiased_blur = -max(u_blur, antialiasblur);
float r = v_radius / (v_radius + u_stroke_width);
float opacity_t = smoothstep(0.0, antialiased_blur, extrude_length - 1.0); float outer_df;
float inner_df;
// 'circle', 'triangle', 'square', 'pentagon', 'hexagon', 'octogon', 'hexagram', 'rhombus', 'vesica'
if (shape == 0) {
outer_df = sdCircle(v_data.xy, 1.0);
inner_df = sdCircle(v_data.xy, r);
} else if (shape == 1) {
outer_df = sdEquilateralTriangle(1.1 * v_data.xy);
inner_df = sdEquilateralTriangle(1.1 / r * v_data.xy);
} else if (shape == 2) {
outer_df = sdBox(v_data.xy, vec2(1.));
inner_df = sdBox(v_data.xy, vec2(r));
} else if (shape == 3) {
outer_df = sdPentagon(v_data.xy, 0.8);
inner_df = sdPentagon(v_data.xy, r * 0.8);
} else if (shape == 4) {
outer_df = sdHexagon(v_data.xy, 0.8);
inner_df = sdHexagon(v_data.xy, r * 0.8);
} else if (shape == 5) {
outer_df = sdOctogon(v_data.xy, 1.0);
inner_df = sdOctogon(v_data.xy, r);
} else if (shape == 6) {
outer_df = sdHexagram(v_data.xy, 0.52);
inner_df = sdHexagram(v_data.xy, r * 0.52);
} else if (shape == 7) {
outer_df = sdRhombus(v_data.xy, vec2(1.0));
inner_df = sdRhombus(v_data.xy, vec2(r));
} else if (shape == 8) {
outer_df = sdVesica(v_data.xy, 1.1, 0.8);
inner_df = sdVesica(v_data.xy, r * 1.1, r * 0.8);
}
float opacity_t = smoothstep(0.0, antialiased_blur, outer_df);
float color_t = u_stroke_width < 0.01 ? 0.0 : smoothstep( float color_t = u_stroke_width < 0.01 ? 0.0 : smoothstep(
antialiased_blur, antialiased_blur,
0.0, 0.0,
extrude_length - v_radius / (v_radius + u_stroke_width) inner_df
); );
gl_FragColor = opacity_t * mix(v_color * u_opacity, u_stroke_color * u_stroke_opacity, color_t); gl_FragColor = opacity_t * mix(v_color * u_opacity, u_stroke_color * u_stroke_opacity, color_t);

View File

@ -5,7 +5,7 @@ uniform float u_stroke_width : 2;
uniform float u_activeId : 0; uniform float u_activeId : 0;
uniform vec4 u_activeColor : [ 1.0, 0, 0, 1.0 ]; uniform vec4 u_activeColor : [ 1.0, 0, 0, 1.0 ];
varying vec3 v_data; varying vec4 v_data;
varying vec4 v_color; varying vec4 v_color;
varying float v_radius; varying float v_radius;
@ -22,14 +22,17 @@ void main() {
// extrude(4-bit) // extrude(4-bit)
vec2 extrude; vec2 extrude;
extrude.x = floor(compressed * SHIFT_RIGHT20); extrude.x = floor(compressed * SHIFT_RIGHT23);
compressed -= extrude.x * SHIFT_LEFT20; compressed -= extrude.x * SHIFT_LEFT23;
extrude.x = extrude.x - 1.; extrude.x = extrude.x - 1.;
extrude.y = floor(compressed * SHIFT_RIGHT18); extrude.y = floor(compressed * SHIFT_RIGHT21);
compressed -= extrude.y * SHIFT_LEFT18; compressed -= extrude.y * SHIFT_LEFT21;
extrude.y = extrude.y - 1.; extrude.y = extrude.y - 1.;
float shape_type = floor(compressed * SHIFT_RIGHT17);
compressed -= shape_type * SHIFT_LEFT17;
// radius(16-bit) // radius(16-bit)
float radius = compressed; float radius = compressed;
v_radius = radius; v_radius = radius;
@ -42,7 +45,7 @@ void main() {
float antialiasblur = 1.0 / (radius + u_stroke_width); float antialiasblur = 1.0 / (radius + u_stroke_width);
// construct point coords // construct point coords
v_data = vec3(extrude, antialiasblur); v_data = vec4(extrude, antialiasblur, shape_type);
// picking // picking
if(picking_id == u_activeId) { if(picking_id == u_activeId) {

View File

@ -52,11 +52,13 @@ import common from './common.glsl';
import { registerModule } from '../../util/shaderModule'; import { registerModule } from '../../util/shaderModule';
import pick_color from './shaderChunks/pick_color.glsl'; import pick_color from './shaderChunks/pick_color.glsl';
import decode from './shaderChunks/decode.glsl'; import decode from './shaderChunks/decode.glsl';
import sdf_2d from './shaderChunks/sdf_2d.glsl';
export function compileBuiltinModules() { export function compileBuiltinModules() {
registerModule('point', { vs: point_vert, fs: point_frag }); registerModule('point', { vs: point_vert, fs: point_frag });
registerModule('common', { vs: common, fs: common }); registerModule('common', { vs: common, fs: common });
registerModule('decode', { vs: decode, fs: '' }); registerModule('decode', { vs: decode, fs: '' });
registerModule('sdf_2d', { vs: '', fs: sdf_2d });
registerModule('pick_color', { vs: pick_color, fs: pick_color }); registerModule('pick_color', { vs: pick_color, fs: pick_color });
registerModule('circle', { vs: circle_vert, fs: circle_frag }); registerModule('circle', { vs: circle_vert, fs: circle_frag });
registerModule('polygon', { vs: polygon_vert, fs: polygon_frag }); registerModule('polygon', { vs: polygon_vert, fs: polygon_frag });

View File

@ -1,7 +1,20 @@
#define SHIFT_RIGHT17 1.0 / 131072.0
#define SHIFT_RIGHT18 1.0 / 262144.0 #define SHIFT_RIGHT18 1.0 / 262144.0
#define SHIFT_RIGHT19 1.0 / 524288.0
#define SHIFT_RIGHT20 1.0 / 1048576.0 #define SHIFT_RIGHT20 1.0 / 1048576.0
#define SHIFT_RIGHT21 1.0 / 2097152.0
#define SHIFT_RIGHT22 1.0 / 4194304.0
#define SHIFT_RIGHT23 1.0 / 8388608.0
#define SHIFT_RIGHT24 1.0 / 16777216.0
#define SHIFT_LEFT17 131072.0
#define SHIFT_LEFT18 262144.0 #define SHIFT_LEFT18 262144.0
#define SHIFT_LEFT19 524288.0
#define SHIFT_LEFT20 1048576.0 #define SHIFT_LEFT20 1048576.0
#define SHIFT_LEFT21 2097152.0
#define SHIFT_LEFT22 4194304.0
#define SHIFT_LEFT23 8388608.0
#define SHIFT_LEFT24 16777216.0
vec2 unpack_float(const float packedValue) { vec2 unpack_float(const float packedValue) {
int packedIntValue = int(packedValue); int packedIntValue = int(packedValue);

View File

@ -0,0 +1,74 @@
/**
* 2D signed distance field functions
* @see http://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
*/
float ndot(vec2 a, vec2 b ) { return a.x*b.x - a.y*b.y; }
float sdCircle(vec2 p, float r) {
return length(p) - r;
}
float sdEquilateralTriangle(vec2 p) {
const float k = sqrt(3.0);
p.x = abs(p.x) - 1.0;
p.y = p.y + 1.0/k;
if( p.x + k*p.y > 0.0 ) p = vec2(p.x-k*p.y,-k*p.x-p.y)/2.0;
p.x -= clamp( p.x, -2.0, 0.0 );
return -length(p)*sign(p.y);
}
float sdBox(vec2 p, vec2 b) {
vec2 d = abs(p)-b;
return length(max(d,vec2(0))) + min(max(d.x,d.y),0.0);
}
float sdPentagon(vec2 p, float r) {
const vec3 k = vec3(0.809016994,0.587785252,0.726542528);
p.x = abs(p.x);
p -= 2.0*min(dot(vec2(-k.x,k.y),p),0.0)*vec2(-k.x,k.y);
p -= 2.0*min(dot(vec2( k.x,k.y),p),0.0)*vec2( k.x,k.y);
p -= vec2(clamp(p.x,-r*k.z,r*k.z),r);
return length(p)*sign(p.y);
}
float sdHexagon(vec2 p, float r) {
const vec3 k = vec3(-0.866025404,0.5,0.577350269);
p = abs(p);
p -= 2.0*min(dot(k.xy,p),0.0)*k.xy;
p -= vec2(clamp(p.x, -k.z*r, k.z*r), r);
return length(p)*sign(p.y);
}
float sdOctogon(vec2 p, float r) {
const vec3 k = vec3(-0.9238795325, 0.3826834323, 0.4142135623 );
p = abs(p);
p -= 2.0*min(dot(vec2( k.x,k.y),p),0.0)*vec2( k.x,k.y);
p -= 2.0*min(dot(vec2(-k.x,k.y),p),0.0)*vec2(-k.x,k.y);
p -= vec2(clamp(p.x, -k.z*r, k.z*r), r);
return length(p)*sign(p.y);
}
float sdHexagram(vec2 p, float r) {
const vec4 k=vec4(-0.5,0.8660254038,0.5773502692,1.7320508076);
p = abs(p);
p -= 2.0*min(dot(k.xy,p),0.0)*k.xy;
p -= 2.0*min(dot(k.yx,p),0.0)*k.yx;
p -= vec2(clamp(p.x,r*k.z,r*k.w),r);
return length(p)*sign(p.y);
}
float sdRhombus(vec2 p, vec2 b) {
vec2 q = abs(p);
float h = clamp((-2.0*ndot(q,b)+ndot(b,b))/dot(b,b),-1.0,1.0);
float d = length( q - 0.5*b*vec2(1.0-h,1.0+h) );
return d * sign( q.x*b.y + q.y*b.x - b.x*b.y );
}
float sdVesica(vec2 p, float r, float d) {
p = abs(p);
float b = sqrt(r*r-d*d); // can delay this sqrt
return ((p.y-b)*d>p.x*b)
? length(p-vec2(0.0,b))
: length(p-vec2(-d,0.0))-r;
}

View File

@ -23,7 +23,7 @@ const Global = {
shape: 'circle', shape: 'circle',
snapArray: [ 0, 1, 2, 4, 5, 10 ], snapArray: [ 0, 1, 2, 4, 5, 10 ],
pointShape: { pointShape: {
'2d': [ 'circle', 'square', 'hexagon', 'triangle' ], '2d': [ 'circle', 'triangle', 'square', 'pentagon', 'hexagon', 'octogon', 'hexagram', 'rhombus', 'vesica' ],
'3d': [ 'cylinder', 'triangleColumn', 'hexagonColumn', 'squareColumn' ] '3d': [ 'cylinder', 'triangleColumn', 'hexagonColumn', 'squareColumn' ]
}, },
sdfHomeUrl: 'https://sdf.amap.com', sdfHomeUrl: 'https://sdf.amap.com',

View File

@ -30,13 +30,9 @@ export default class PointLayer extends Layer {
} }
// 2D circle 特殊处理 // 2D circle 特殊处理
if (shape === 'circle') { if (pointShape['2d'].indexOf(shape) !== -1) {
return 'circle'; return 'circle';
} } else if (pointShape['3d'].indexOf(shape) !== -1) {
if (
pointShape['2d'].indexOf(shape) !== -1 ||
pointShape['3d'].indexOf(shape) !== -1
) {
return 'fill'; return 'fill';
} else if (this.scene.image.imagesIds.indexOf(shape) !== -1) { } else if (this.scene.image.imagesIds.indexOf(shape) !== -1) {
return 'image'; return 'image';

View File

@ -1,5 +1,5 @@
/** /**
* 针对绘制圆形的优化 * 绘制 SDF不仅是圆形
* 手动构建点阵坐标系便于实现描边反走样效果 * 手动构建点阵坐标系便于实现描边反走样效果
*/ */
import * as THREE from '../../../core/three'; import * as THREE from '../../../core/three';