diff --git a/demos/01_point_circle.html b/demos/01_point_circle.html
index 88efe97d33..a013fe9dc0 100644
--- a/demos/01_point_circle.html
+++ b/demos/01_point_circle.html
@@ -59,7 +59,14 @@ scene.on('loaded', () => {
.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)
diff --git a/src/geom/buffer/point/circleBuffer.js b/src/geom/buffer/point/circleBuffer.js
index 165a655e89..1a477b2dee 100644
--- a/src/geom/buffer/point/circleBuffer.js
+++ b/src/geom/buffer/point/circleBuffer.js
@@ -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;
@@ -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
);
});
diff --git a/src/geom/shader/circle_frag.glsl b/src/geom/shader/circle_frag.glsl
index db81ca186f..82b8a77362 100644
--- a/src/geom/shader/circle_frag.glsl
+++ b/src/geom/shader/circle_frag.glsl
@@ -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 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(
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);
diff --git a/src/geom/shader/circle_vert.glsl b/src/geom/shader/circle_vert.glsl
index e6320e7f7e..f9382ad0aa 100644
--- a/src/geom/shader/circle_vert.glsl
+++ b/src/geom/shader/circle_vert.glsl
@@ -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;
@@ -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;
@@ -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) {
diff --git a/src/geom/shader/index.js b/src/geom/shader/index.js
index a23f341538..2b17a38656 100644
--- a/src/geom/shader/index.js
+++ b/src/geom/shader/index.js
@@ -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 });
diff --git a/src/geom/shader/shaderChunks/decode.glsl b/src/geom/shader/shaderChunks/decode.glsl
index afa198e6e4..07818873f9 100644
--- a/src/geom/shader/shaderChunks/decode.glsl
+++ b/src/geom/shader/shaderChunks/decode.glsl
@@ -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);
diff --git a/src/geom/shader/shaderChunks/sdf_2d.glsl b/src/geom/shader/shaderChunks/sdf_2d.glsl
new file mode 100644
index 0000000000..4498415879
--- /dev/null
+++ b/src/geom/shader/shaderChunks/sdf_2d.glsl
@@ -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;
+}
\ No newline at end of file
diff --git a/src/global.js b/src/global.js
index b6f5e5341e..c0a2c994f2 100644
--- a/src/global.js
+++ b/src/global.js
@@ -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',
diff --git a/src/layer/pointLayer.js b/src/layer/pointLayer.js
index 8439ccaf79..2fc8038ca8 100644
--- a/src/layer/pointLayer.js
+++ b/src/layer/pointLayer.js
@@ -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';
diff --git a/src/layer/render/point/drawCircle.js b/src/layer/render/point/drawCircle.js
index 6f8df6f48b..9f938d2802 100644
--- a/src/layer/render/point/drawCircle.js
+++ b/src/layer/render/point/drawCircle.js
@@ -1,5 +1,5 @@
/**
- * 针对绘制圆形的优化
+ * 绘制 SDF,不仅是圆形
* 手动构建点阵坐标系,便于实现描边、反走样效果
*/
import * as THREE from '../../../core/three';