diff --git a/demos/assets/arrow.png b/demos/assets/arrow.png
new file mode 100644
index 0000000000..f4b715fc6b
Binary files /dev/null and b/demos/assets/arrow.png differ
diff --git a/demos/assets/right.png b/demos/assets/right.png
new file mode 100755
index 0000000000..7d419a4f68
Binary files /dev/null and b/demos/assets/right.png differ
diff --git a/demos/patternline.html b/demos/patternline.html
new file mode 100644
index 0000000000..09119de91e
--- /dev/null
+++ b/demos/patternline.html
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+ city demo
+
+
+
+
+ 时间: 6时
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/geom/buffer/line.js b/src/geom/buffer/line.js
index e5b3ed7932..680829d3e1 100644
--- a/src/geom/buffer/line.js
+++ b/src/geom/buffer/line.js
@@ -76,6 +76,7 @@ export default class LineBuffer extends BufferBase {
_getMeshLineAttributes() {
const layerData = this.get('layerData');
const { dashArray } = this.get('style');
+ const imagePos = this.get('imagePos');
const positions = [];
const pickingIds = [];
const normal = [];
@@ -85,10 +86,16 @@ export default class LineBuffer extends BufferBase {
const sizes = [];
const attrDistance = [];
const attrDashArray = [];
+ const textureCoord = [];
+ const totalDistance = [];
layerData.forEach(item => {
const props = item;
const positionCount = positions.length / 3;
- const attr = lineShape.Line(item.coordinates, props, positionCount, dashArray);
+ let patternPos = { x: 0, y: 0 };
+ if (item.pattern && imagePos[item.pattern]) {
+ patternPos = imagePos[item.pattern];
+ }
+ const attr = lineShape.Line(item.coordinates, props, positionCount, dashArray, patternPos);
positions.push(...attr.positions);
normal.push(...attr.normal);
miter.push(...attr.miter);
@@ -98,6 +105,8 @@ export default class LineBuffer extends BufferBase {
attrDistance.push(...attr.attrDistance);
pickingIds.push(...attr.pickingIds);
attrDashArray.push(...attr.dashArray);
+ textureCoord.push(...attr.textureCoordArray);
+ totalDistance.push(...attr.totalDistances);
});
return {
positions,
@@ -108,7 +117,9 @@ export default class LineBuffer extends BufferBase {
pickingIds,
sizes,
attrDistance,
- attrDashArray
+ attrDashArray,
+ textureCoord,
+ totalDistance
};
}
diff --git a/src/geom/shader/meshline_frag.glsl b/src/geom/shader/meshline_frag.glsl
index bb96ae0092..f07301978e 100644
--- a/src/geom/shader/meshline_frag.glsl
+++ b/src/geom/shader/meshline_frag.glsl
@@ -6,22 +6,42 @@ uniform float u_dash_ratio : 0.0;
uniform float u_blur : 0.9;
varying vec4 v_color;
-varying float v_distance;
+#ifdef DASHLINE
+varying float v_distance_ratio;
+#endif
varying float v_dash_array;
varying float v_time;
varying vec2 v_normal;
+#ifdef TEXTURE
+uniform sampler2D u_texture;
+varying vec2 v_uv;
+varying float v_texture_y;
+varying float v_texture_percent;
+#endif
+
void main() {
- gl_FragColor = v_color;
- #ifdef DASHLINE
- gl_FragColor.a *= u_opacity * ceil(mod(v_distance + u_dash_offset, v_dash_array) - (v_dash_array * u_dash_ratio));
+ #ifdef TEXTURE
+ float texture_y_fract = fract(v_texture_y);
+ if (texture_y_fract <= v_texture_percent) {
+ vec4 tex_color = texture2D(u_texture, vec2(v_uv.x, 1.0 - 0.125 - v_uv.y + (texture_y_fract / v_texture_percent) * 0.125));
+ // tex_color = texture2D(u_texture, vec2(v_uv.x, v_uv.y));
+ gl_FragColor = vec4(mix(v_color.rgb, tex_color.rgb, tex_color.a), v_color.a);
+ } else {
+ gl_FragColor = v_color;
+ }
#else
- gl_FragColor.a = v_color.a * u_opacity;
+ gl_FragColor = v_color;
+ #endif
+
+ #ifdef DASHLINE
+ gl_FragColor.a *= u_opacity * ceil(mod(v_distance_ratio + u_dash_offset, v_dash_array) - (v_dash_array * u_dash_ratio));
+ #else
+ gl_FragColor.a *= u_opacity;
#endif
#ifdef ANIMATE
gl_FragColor.a *= v_time;
#endif
-
// anti-alias
float blur = 1. - smoothstep(u_blur, 1., length(v_normal));
gl_FragColor.a *= blur;
diff --git a/src/geom/shader/meshline_vert.glsl b/src/geom/shader/meshline_vert.glsl
index 65b64f5d98..3087744f61 100644
--- a/src/geom/shader/meshline_vert.glsl
+++ b/src/geom/shader/meshline_vert.glsl
@@ -3,6 +3,7 @@ attribute vec4 a_color;
attribute float a_size;
attribute float a_distance;
attribute float a_dash_array;
+attribute float a_total_distance;
uniform float u_zoom;
uniform float u_time : 0;
@@ -11,9 +12,11 @@ uniform vec4 u_activeColor : [ 1.0, 0, 0, 1.0 ];
varying float v_time;
varying vec4 v_color;
-varying float v_distance;
varying float v_dash_array;
varying vec2 v_normal;
+#ifdef DASHLINE
+varying float v_distance_ratio;
+#endif
#ifdef ANIMATE
uniform float u_duration : 2.0;
@@ -21,22 +24,41 @@ uniform float u_interval : 1.0;
uniform float u_trailLength : 0.2;
#endif
+#ifdef TEXTURE
+attribute vec2 a_texture_coord;
+uniform float u_pattern_spacing : 0.0;
+varying vec2 v_uv;
+varying float v_texture_y;
+varying float v_texture_percent;
+#endif
void main() {
+ // extrude along normal
+ float extrude_scale = pow(2.0, 20.0 - u_zoom);
v_color = a_color;
- v_distance = a_distance;
v_dash_array = a_dash_array;
+ float distance_ratio = a_distance / a_total_distance;
+ #ifdef DASHLINE
+ v_distance_ratio = distance_ratio;
+ #endif
+ #ifdef TEXTURE
+ v_uv = vec2(a_texture_coord.x + 0.125, a_texture_coord.y);
+ if (a_miter > 0.0) {
+ v_uv.x = a_texture_coord.x;
+ }
+ v_texture_y = a_distance / extrude_scale / (a_size + u_pattern_spacing);
+ v_texture_percent = a_size / (a_size + u_pattern_spacing);
+ #endif
// anti-alias
v_normal = vec2(normal * sign(a_miter));
- // extrude along normal
- float extrude_scale = pow(2.0, 20.0 - u_zoom);
+
vec3 offset = vec3(normal * a_size * extrude_scale / 2.0 * a_miter);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position.xy + offset.xy, 0., 1.0);
// gl_Position.z -=0.8 * gl_Position.w;
#ifdef ANIMATE
- float alpha =1.0 - fract( mod(1.0- a_distance,u_interval)* (1.0/u_interval) + u_time / u_duration);
+ float alpha =1.0 - fract( mod(1.0- distance_ratio,u_interval)* (1.0/u_interval) + u_time / u_duration);
alpha = (alpha + u_trailLength -1.0) / u_trailLength;
v_time = clamp(alpha,0.,1.);
#endif
diff --git a/src/geom/shape/line.js b/src/geom/shape/line.js
index 461abdb7fd..2cd461ca3c 100644
--- a/src/geom/shape/line.js
+++ b/src/geom/shape/line.js
@@ -66,7 +66,7 @@ export function defaultLine(geo, index) {
}
// mesh line
-export function Line(path, props, positionsIndex, lengthPerDashSegment = 200) {
+export function Line(path, props, positionsIndex, lengthPerDashSegment = 200, textureCoord) {
if (Array.isArray(path[0][0])) {
path = path[0]; // 面坐标转线坐标
}
@@ -76,21 +76,23 @@ export function Line(path, props, positionsIndex, lengthPerDashSegment = 200) {
const miter = [];
const colors = [];
const dashArray = [];
-
+ const textureCoordArray = [];
const { normals, attrIndex, attrPos, attrDistance } = getNormals(path, false, positionsIndex);
-
const sizes = [];
+ const totalDistances = [];
let { size, color, id } = props;
!Array.isArray(size) && (size = [ size ]);
+ const totalLength = attrDistance[attrDistance.length - 1];
attrPos.forEach(point => {
colors.push(...color);
pickingIds.push(id);
sizes.push(size[0]);
point[2] = size[1] || 0;
positions.push(...point);
+ textureCoordArray.push(textureCoord.x, textureCoord.y);
+ totalDistances.push(totalLength);
});
- const totalLength = attrDistance[attrDistance.length - 1];
const ratio = lengthPerDashSegment / totalLength;
normals.forEach(n => {
const norm = n[0];
@@ -100,6 +102,7 @@ export function Line(path, props, positionsIndex, lengthPerDashSegment = 200) {
dashArray.push(ratio);
});
+
return {
positions,
normal,
@@ -108,10 +111,10 @@ export function Line(path, props, positionsIndex, lengthPerDashSegment = 200) {
colors,
sizes,
pickingIds,
- attrDistance: attrDistance.map(d => {
- return d / totalLength;
- }),
- dashArray
+ attrDistance,
+ dashArray,
+ textureCoordArray,
+ totalDistances
};
}
diff --git a/src/layer/render/line/drawMeshLine.js b/src/layer/render/line/drawMeshLine.js
index 1b955faef7..6b9db4c8cb 100644
--- a/src/layer/render/line/drawMeshLine.js
+++ b/src/layer/render/line/drawMeshLine.js
@@ -1,15 +1,22 @@
import * as THREE from '../../../core/three';
import { LineBuffer } from '../../../geom/buffer/index';
import { MeshLineMaterial } from '../../../geom/material/lineMaterial';
+
export default function DrawLine(layerData, layer) {
const style = layer.get('styleOptions');
const animateOptions = layer.get('animateOptions');
const activeOption = layer.get('activedOptions');
+ // const pattern = style.pattern;
+ // const texture = layer.scene.image.singleImages[pattern];
+ const hasPattern = layerData.some(layer => {
+ return layer.pattern;
+ });
const { attributes } = new LineBuffer({
layerData,
shapeType: 'line',
- style
+ style,
+ imagePos: layer.scene.image.imagePos
});
const geometry = new THREE.BufferGeometry();
geometry.setIndex(attributes.indexArray);
@@ -21,6 +28,8 @@ export default function DrawLine(layerData, layer) {
geometry.addAttribute('a_miter', new THREE.Float32BufferAttribute(attributes.miter, 1));
geometry.addAttribute('a_distance', new THREE.Float32BufferAttribute(attributes.attrDistance, 1));
geometry.addAttribute('a_dash_array', new THREE.Float32BufferAttribute(attributes.attrDashArray, 1));
+ geometry.addAttribute('a_texture_coord', new THREE.Float32BufferAttribute(attributes.textureCoord, 2));
+ geometry.addAttribute('a_total_distance', new THREE.Float32BufferAttribute(attributes.totalDistance, 1));
const lineMaterial = new MeshLineMaterial({
u_opacity: style.opacity,
@@ -28,11 +37,14 @@ export default function DrawLine(layerData, layer) {
u_time: 0,
u_dash_offset: style.dashOffset,
u_dash_ratio: style.dashRatio,
- activeColor: activeOption.fill
+ activeColor: activeOption.fill,
+ u_pattern_spacing: style.patternSpacing || 0,
+ u_texture: hasPattern ? layer.scene.image.texture : null
}, {
SHAPE: false,
ANIMATE: false,
- DASHLINE: style.lineType === 'dash'
+ DASHLINE: style.lineType === 'dash',
+ TEXTURE: hasPattern
});
const lineMesh = new THREE.Mesh(geometry, lineMaterial);
diff --git a/src/util/polyline-normals.js b/src/util/polyline-normals.js
index dc6f2452ba..1be6aa15fe 100644
--- a/src/util/polyline-normals.js
+++ b/src/util/polyline-normals.js
@@ -67,7 +67,7 @@ export default function(points, closed, indexOffset) {
extrusions(attrPos, out, last, _normal, 1);
}
- attrIndex.push([ index + 0, index + 3, index + 1 ]);
+ attrIndex.push([ index + 0, index + 2, index + 1 ]);
// no miter, simple segment
if (!next) {
@@ -75,9 +75,7 @@ export default function(points, closed, indexOffset) {
normal(_normal, lineA);
extrusions(attrPos, out, cur, _normal, 1);
attrDistance.push(d, d);
- attrIndex.push(
- _lastFlip === 1 ? [ index + 1, index + 3, index + 2 ] : [ index, index + 2, index + 3 ]);
-
+ attrIndex.push([ index + 1, index + 2, index + 3 ]);
count += 2;
} else {
// get unit dir of next line
@@ -87,7 +85,7 @@ export default function(points, closed, indexOffset) {
let miterLen = computeMiter(tangent, miter, lineA, lineB, 1);
// get orientation
- let flip = (dot(tangent, _normal) < 0) ? -1 : 1;
+ const flip = (dot(tangent, _normal) < 0) ? -1 : 1;
const bevel = Math.abs(miterLen) > miterLimit;
// 处理前后两条线段重合的情况,这种情况不需要使用任何接头(miter/bevel)。
@@ -114,38 +112,39 @@ export default function(points, closed, indexOffset) {
miterLen = miterLimit;
// next two points in our first segment
- addNext(out, _normal, -flip);
- attrPos.push(cur);
- addNext(out, miter, miterLen * flip);
- attrPos.push(cur);
+ extrusions(attrPos, out, cur, _normal, 1);
- attrIndex.push(_lastFlip !== -flip
- ? [ index + 1, index + 3, index + 2 ] : [ index, index + 2, index + 3 ]);
+ attrIndex.push([ index + 1, index + 2, index + 3 ]);
// now add the bevel triangle
- attrIndex.push([ index + 2, index + 3, index + 4 ]);
+ attrIndex.push(flip === 1 ? [ index + 2, index + 4, index + 5 ] : [ index + 4, index + 5, index + 3 ]);
normal(tmp, lineB);
copy(_normal, tmp); // store normal for next round
- addNext(out, _normal, -flip);
- attrPos.push(cur);
- attrDistance.push(d, d, d);
+ extrusions(attrPos, out, cur, _normal, 1);
+ attrDistance.push(d, d, d, d);
// the miter is now the normal for our next join
- count += 3;
+ count += 4;
} else {
- // next two points for our miter join
- extrusions(attrPos, out, cur, miter, miterLen);
- attrDistance.push(d, d);
- attrIndex.push(_lastFlip === 1
- ? [ index + 1, index + 3, index + 2 ] : [ index, index + 2, index + 3 ]);
+ // next two points in our first segment
+ extrusions(attrPos, out, cur, _normal, 1);
+ attrIndex.push([ index + 1, index + 2, index + 3 ]);
- flip = -1;
+ // now add the miter triangles
+ addNext(out, miter, miterLen * -flip);
+ attrPos.push(cur);
+ attrIndex.push([ index + 2, index + 4, index + 3 ]);
+ attrIndex.push([ index + 4, index + 5, index + 6 ]);
+ normal(tmp, lineB);
+ copy(_normal, tmp); // store normal for next round
+
+ extrusions(attrPos, out, cur, _normal, 1);
+ attrDistance.push(d, d, d, d, d);
// the miter is now the normal for our next join
- copy(_normal, miter);
- count += 2;
+ count += 5;
}
_lastFlip = flip;
}