Skip to content

Commit

Permalink
feat(point-layer): use 2d sdf functions
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoiver committed Jun 18, 2019
1 parent 1733971 commit 6ec7039
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 24 deletions.
9 changes: 8 additions & 1 deletion demos/01_point_circle.html
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,14 @@
.source(data,{
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('value', [ 10, 300]) // default 1
.active(true)
Expand Down
23 changes: 18 additions & 5 deletions src/geom/buffer/point/circleBuffer.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import { packUint8ToFloat } from '../../../util/vertex-compress';
import Global from '../../../global';
const { pointShape } = Global;

const LEFT_SHIFT18 = 262144.0;
const LEFT_SHIFT20 = 1048576.0;
const LEFT_SHIFT17 = 131072.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) {
const index = [];
const aPosition = [];
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)) {
size = 0;
Expand All @@ -26,10 +37,12 @@ export default function circleBuffer(layerData) {
[ 1, 1 ],
[ -1, 1 ]
].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(
...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
);
});
Expand Down
43 changes: 39 additions & 4 deletions src/geom/shader/circle_frag.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,57 @@ 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_data;
varying vec4 v_color;
varying float v_radius;

#pragma include "sdf_2d"

void main() {
float extrude_length = length(v_data.xy);
int shape = int(floor(v_data.w + 0.5));

lowp float antialiasblur = v_data.z;
float antialiased_blur = -max(u_blur, antialiasblur);
float r = v_radius / (v_radius + u_stroke_width);

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, extrude_length - 1.0);
float opacity_t = smoothstep(0.0, antialiased_blur, outer_df);

float color_t = u_stroke_width < 0.01 ? 0.0 : smoothstep(
antialiased_blur,
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);
Expand Down
15 changes: 9 additions & 6 deletions src/geom/shader/circle_vert.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ 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_data;
varying vec4 v_color;
varying float v_radius;

Expand All @@ -22,14 +22,17 @@ void main() {

// extrude(4-bit)
vec2 extrude;
extrude.x = floor(compressed * SHIFT_RIGHT20);
compressed -= extrude.x * SHIFT_LEFT20;
extrude.x = floor(compressed * SHIFT_RIGHT23);
compressed -= extrude.x * SHIFT_LEFT23;
extrude.x = extrude.x - 1.;

extrude.y = floor(compressed * SHIFT_RIGHT18);
compressed -= extrude.y * SHIFT_LEFT18;
extrude.y = floor(compressed * SHIFT_RIGHT21);
compressed -= extrude.y * SHIFT_LEFT21;
extrude.y = extrude.y - 1.;

float shape_type = floor(compressed * SHIFT_RIGHT17);
compressed -= shape_type * SHIFT_LEFT17;

// radius(16-bit)
float radius = compressed;
v_radius = radius;
Expand All @@ -42,7 +45,7 @@ void main() {
float antialiasblur = 1.0 / (radius + u_stroke_width);

// construct point coords
v_data = vec3(extrude, antialiasblur);
v_data = vec4(extrude, antialiasblur, shape_type);

// picking
if(picking_id == u_activeId) {
Expand Down
2 changes: 2 additions & 0 deletions src/geom/shader/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@ import common from './common.glsl';
import { registerModule } from '../../util/shaderModule';
import pick_color from './shaderChunks/pick_color.glsl';
import decode from './shaderChunks/decode.glsl';
import sdf_2d from './shaderChunks/sdf_2d.glsl';

export function compileBuiltinModules() {
registerModule('point', { vs: point_vert, fs: point_frag });
registerModule('common', { vs: common, fs: common });
registerModule('decode', { vs: decode, fs: '' });
registerModule('sdf_2d', { vs: '', fs: sdf_2d });
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 });
Expand Down
13 changes: 13 additions & 0 deletions src/geom/shader/shaderChunks/decode.glsl
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
#define SHIFT_RIGHT17 1.0 / 131072.0
#define SHIFT_RIGHT18 1.0 / 262144.0
#define SHIFT_RIGHT19 1.0 / 524288.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_LEFT19 524288.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) {
int packedIntValue = int(packedValue);
Expand Down
74 changes: 74 additions & 0 deletions src/geom/shader/shaderChunks/sdf_2d.glsl
Original file line number Diff line number Diff line change
@@ -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;
}
2 changes: 1 addition & 1 deletion src/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const Global = {
shape: 'circle',
snapArray: [ 0, 1, 2, 4, 5, 10 ],
pointShape: {
'2d': [ 'circle', 'square', 'hexagon', 'triangle' ],
'2d': [ 'circle', 'triangle', 'square', 'pentagon', 'hexagon', 'octogon', 'hexagram', 'rhombus', 'vesica' ],
'3d': [ 'cylinder', 'triangleColumn', 'hexagonColumn', 'squareColumn' ]
},
sdfHomeUrl: 'https://sdf.amap.com',
Expand Down
8 changes: 2 additions & 6 deletions src/layer/pointLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,9 @@ export default class PointLayer extends Layer {
}

// 2D circle 特殊处理
if (shape === 'circle') {
if (pointShape['2d'].indexOf(shape) !== -1) {
return 'circle';
}
if (
pointShape['2d'].indexOf(shape) !== -1 ||
pointShape['3d'].indexOf(shape) !== -1
) {
} else if (pointShape['3d'].indexOf(shape) !== -1) {
return 'fill';
} else if (this.scene.image.imagesIds.indexOf(shape) !== -1) {
return 'image';
Expand Down
2 changes: 1 addition & 1 deletion src/layer/render/point/drawCircle.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* 针对绘制圆形的优化
* 绘制 SDF,不仅是圆形
* 手动构建点阵坐标系,便于实现描边、反走样效果
*/
import * as THREE from '../../../core/three';
Expand Down

0 comments on commit 6ec7039

Please sign in to comment.