Merge branch 'master' into rollup

This commit is contained in:
thinkinggis 2019-07-15 20:45:53 +08:00
commit 2585a202ed
9 changed files with 215 additions and 48 deletions

BIN
demos/assets/arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 B

BIN
demos/assets/right.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 B

100
demos/patternline.html Normal file
View File

@ -0,0 +1,100 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="geometry" content="diagram">
<link rel="stylesheet" href="./assets/common.css">
<title>city demo</title>
<style>
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
#timepannel {
background: white;
z-index: 10;
position: absolute;
right: 50px;
padding: 10px;
}
</style>
</head>
<body>
<div id='timepannel'>时间: 6时</div>
<div id="map">
</div>
<script src="https://webapi.amap.com/maps?v=1.4.8&key=f28fca5384129d180ad82915156a9baf&plugin=Map3D"></script>
<script src="./assets/jquery-3.2.1.min.js"></script>
<script src="../build/L7.js"></script>
<script>
var buildLayer = null;
const scene = new L7.Scene({
id: 'map',
mapStyle: 'amap://styles/c9f1d10cae34f8ab05e425462c5a58d7', // 样式URL
center: [120.102915, 30.261396],
pitch: 0,
zoom: 12,
minZoom: 5,
maxZoom: 18
});
scene.on('loaded', () => {
scene.image.addImage('arrow', '/demos/assets/arrow.png');
scene.image.addImage('right', '/demos/assets/right.png');
const mapData = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": { "type": 'right' },
"geometry": {
"type": "LineString",
"coordinates": [
[120.294931, 30.224459],
[120.194847, 30.224384],
[120.294847, 30.274384],
[120.344847, 30.34384],
[120.364847, 30.374384],
[120.364847, 30.074384],
]
}
}, {
"type": "Feature",
"properties": { "type": 'arrow' },
"geometry": {
"type": "LineString",
"coordinates": [
[120.394931, 30.324459],
[120.494847, 30.324384],
[120.494847, 30.374384],
]
}
}]
};
const linelayer = scene.LineLayer({
zIndex: 2
}).shape('line')
.size([10, 0])
.source(mapData)
.color('#fff')
.pattern('type', function (type) {
return type;
})
.style({
patternSpacing: 20
})
.render();
})
</script>
</body>
</html>

View File

@ -76,6 +76,7 @@ export default class LineBuffer extends BufferBase {
_getMeshLineAttributes() { _getMeshLineAttributes() {
const layerData = this.get('layerData'); const layerData = this.get('layerData');
const { dashArray } = this.get('style'); const { dashArray } = this.get('style');
const imagePos = this.get('imagePos');
const positions = []; const positions = [];
const pickingIds = []; const pickingIds = [];
const normal = []; const normal = [];
@ -85,10 +86,16 @@ export default class LineBuffer extends BufferBase {
const sizes = []; const sizes = [];
const attrDistance = []; const attrDistance = [];
const attrDashArray = []; const attrDashArray = [];
const textureCoord = [];
const totalDistance = [];
layerData.forEach(item => { layerData.forEach(item => {
const props = item; const props = item;
const positionCount = positions.length / 3; 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); positions.push(...attr.positions);
normal.push(...attr.normal); normal.push(...attr.normal);
miter.push(...attr.miter); miter.push(...attr.miter);
@ -98,6 +105,8 @@ export default class LineBuffer extends BufferBase {
attrDistance.push(...attr.attrDistance); attrDistance.push(...attr.attrDistance);
pickingIds.push(...attr.pickingIds); pickingIds.push(...attr.pickingIds);
attrDashArray.push(...attr.dashArray); attrDashArray.push(...attr.dashArray);
textureCoord.push(...attr.textureCoordArray);
totalDistance.push(...attr.totalDistances);
}); });
return { return {
positions, positions,
@ -108,7 +117,9 @@ export default class LineBuffer extends BufferBase {
pickingIds, pickingIds,
sizes, sizes,
attrDistance, attrDistance,
attrDashArray attrDashArray,
textureCoord,
totalDistance
}; };
} }

View File

@ -6,22 +6,42 @@ uniform float u_dash_ratio : 0.0;
uniform float u_blur : 0.9; uniform float u_blur : 0.9;
varying vec4 v_color; varying vec4 v_color;
varying float v_distance; #ifdef DASHLINE
varying float v_distance_ratio;
#endif
varying float v_dash_array; varying float v_dash_array;
varying float v_time; varying float v_time;
varying vec2 v_normal; 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() { void main() {
gl_FragColor = v_color; #ifdef TEXTURE
#ifdef DASHLINE float texture_y_fract = fract(v_texture_y);
gl_FragColor.a *= u_opacity * ceil(mod(v_distance + u_dash_offset, v_dash_array) - (v_dash_array * u_dash_ratio)); 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 #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 #endif
#ifdef ANIMATE #ifdef ANIMATE
gl_FragColor.a *= v_time; gl_FragColor.a *= v_time;
#endif #endif
// anti-alias // anti-alias
float blur = 1. - smoothstep(u_blur, 1., length(v_normal)); float blur = 1. - smoothstep(u_blur, 1., length(v_normal));
gl_FragColor.a *= blur; gl_FragColor.a *= blur;

View File

@ -3,6 +3,7 @@ attribute vec4 a_color;
attribute float a_size; attribute float a_size;
attribute float a_distance; attribute float a_distance;
attribute float a_dash_array; attribute float a_dash_array;
attribute float a_total_distance;
uniform float u_zoom; uniform float u_zoom;
uniform float u_time : 0; uniform float u_time : 0;
@ -11,9 +12,11 @@ uniform vec4 u_activeColor : [ 1.0, 0, 0, 1.0 ];
varying float v_time; varying float v_time;
varying vec4 v_color; varying vec4 v_color;
varying float v_distance;
varying float v_dash_array; varying float v_dash_array;
varying vec2 v_normal; varying vec2 v_normal;
#ifdef DASHLINE
varying float v_distance_ratio;
#endif
#ifdef ANIMATE #ifdef ANIMATE
uniform float u_duration : 2.0; uniform float u_duration : 2.0;
@ -21,22 +24,41 @@ uniform float u_interval : 1.0;
uniform float u_trailLength : 0.2; uniform float u_trailLength : 0.2;
#endif #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() { void main() {
// extrude along normal
float extrude_scale = pow(2.0, 20.0 - u_zoom);
v_color = a_color; v_color = a_color;
v_distance = a_distance;
v_dash_array = a_dash_array; 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 // anti-alias
v_normal = vec2(normal * sign(a_miter)); 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); 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 = projectionMatrix * modelViewMatrix * vec4(position.xy + offset.xy, 0., 1.0);
// gl_Position.z -=0.8 * gl_Position.w; // gl_Position.z -=0.8 * gl_Position.w;
#ifdef ANIMATE #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; alpha = (alpha + u_trailLength -1.0) / u_trailLength;
v_time = clamp(alpha,0.,1.); v_time = clamp(alpha,0.,1.);
#endif #endif

View File

@ -66,7 +66,7 @@ export function defaultLine(geo, index) {
} }
// mesh line // 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])) { if (Array.isArray(path[0][0])) {
path = path[0]; // 面坐标转线坐标 path = path[0]; // 面坐标转线坐标
} }
@ -76,21 +76,23 @@ export function Line(path, props, positionsIndex, lengthPerDashSegment = 200) {
const miter = []; const miter = [];
const colors = []; const colors = [];
const dashArray = []; const dashArray = [];
const textureCoordArray = [];
const { normals, attrIndex, attrPos, attrDistance } = getNormals(path, false, positionsIndex); const { normals, attrIndex, attrPos, attrDistance } = getNormals(path, false, positionsIndex);
const sizes = []; const sizes = [];
const totalDistances = [];
let { size, color, id } = props; let { size, color, id } = props;
!Array.isArray(size) && (size = [ size ]); !Array.isArray(size) && (size = [ size ]);
const totalLength = attrDistance[attrDistance.length - 1];
attrPos.forEach(point => { attrPos.forEach(point => {
colors.push(...color); colors.push(...color);
pickingIds.push(id); pickingIds.push(id);
sizes.push(size[0]); sizes.push(size[0]);
point[2] = size[1] || 0; point[2] = size[1] || 0;
positions.push(...point); positions.push(...point);
textureCoordArray.push(textureCoord.x, textureCoord.y);
totalDistances.push(totalLength);
}); });
const totalLength = attrDistance[attrDistance.length - 1];
const ratio = lengthPerDashSegment / totalLength; const ratio = lengthPerDashSegment / totalLength;
normals.forEach(n => { normals.forEach(n => {
const norm = n[0]; const norm = n[0];
@ -100,6 +102,7 @@ export function Line(path, props, positionsIndex, lengthPerDashSegment = 200) {
dashArray.push(ratio); dashArray.push(ratio);
}); });
return { return {
positions, positions,
normal, normal,
@ -108,10 +111,10 @@ export function Line(path, props, positionsIndex, lengthPerDashSegment = 200) {
colors, colors,
sizes, sizes,
pickingIds, pickingIds,
attrDistance: attrDistance.map(d => { attrDistance,
return d / totalLength; dashArray,
}), textureCoordArray,
dashArray totalDistances
}; };
} }

View File

@ -1,15 +1,22 @@
import * as THREE from '../../../core/three'; import * as THREE from '../../../core/three';
import LineBuffer from '../../../geom/buffer/line'; import LineBuffer from '../../../geom/buffer/line';
import { MeshLineMaterial } from '../../../geom/material/lineMaterial'; import { MeshLineMaterial } from '../../../geom/material/lineMaterial';
export default function DrawLine(layerData, layer) { export default function DrawLine(layerData, layer) {
const style = layer.get('styleOptions'); const style = layer.get('styleOptions');
const animateOptions = layer.get('animateOptions'); const animateOptions = layer.get('animateOptions');
const activeOption = layer.get('activedOptions'); 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({ const { attributes } = new LineBuffer({
layerData, layerData,
shapeType: 'line', shapeType: 'line',
style style,
imagePos: layer.scene.image.imagePos
}); });
const geometry = new THREE.BufferGeometry(); const geometry = new THREE.BufferGeometry();
geometry.setIndex(attributes.indexArray); 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_miter', new THREE.Float32BufferAttribute(attributes.miter, 1));
geometry.addAttribute('a_distance', new THREE.Float32BufferAttribute(attributes.attrDistance, 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_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({ const lineMaterial = new MeshLineMaterial({
u_opacity: style.opacity, u_opacity: style.opacity,
@ -28,11 +37,14 @@ export default function DrawLine(layerData, layer) {
u_time: 0, u_time: 0,
u_dash_offset: style.dashOffset, u_dash_offset: style.dashOffset,
u_dash_ratio: style.dashRatio, 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, SHAPE: false,
ANIMATE: false, ANIMATE: false,
DASHLINE: style.lineType === 'dash' DASHLINE: style.lineType === 'dash',
TEXTURE: hasPattern
}); });
lineMaterial.setBending(style.blending); lineMaterial.setBending(style.blending);
const lineMesh = new THREE.Mesh(geometry, lineMaterial); const lineMesh = new THREE.Mesh(geometry, lineMaterial);

View File

@ -67,7 +67,7 @@ export default function(points, closed, indexOffset) {
extrusions(attrPos, out, last, _normal, 1); 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 // no miter, simple segment
if (!next) { if (!next) {
@ -75,9 +75,7 @@ export default function(points, closed, indexOffset) {
normal(_normal, lineA); normal(_normal, lineA);
extrusions(attrPos, out, cur, _normal, 1); extrusions(attrPos, out, cur, _normal, 1);
attrDistance.push(d, d); attrDistance.push(d, d);
attrIndex.push( attrIndex.push([ index + 1, index + 2, index + 3 ]);
_lastFlip === 1 ? [ index + 1, index + 3, index + 2 ] : [ index, index + 2, index + 3 ]);
count += 2; count += 2;
} else { } else {
// get unit dir of next line // get unit dir of next line
@ -87,7 +85,7 @@ export default function(points, closed, indexOffset) {
let miterLen = computeMiter(tangent, miter, lineA, lineB, 1); let miterLen = computeMiter(tangent, miter, lineA, lineB, 1);
// get orientation // get orientation
let flip = (dot(tangent, _normal) < 0) ? -1 : 1; const flip = (dot(tangent, _normal) < 0) ? -1 : 1;
const bevel = Math.abs(miterLen) > miterLimit; const bevel = Math.abs(miterLen) > miterLimit;
// 处理前后两条线段重合的情况这种情况不需要使用任何接头miter/bevel // 处理前后两条线段重合的情况这种情况不需要使用任何接头miter/bevel
@ -114,38 +112,39 @@ export default function(points, closed, indexOffset) {
miterLen = miterLimit; miterLen = miterLimit;
// next two points in our first segment // next two points in our first segment
addNext(out, _normal, -flip); extrusions(attrPos, out, cur, _normal, 1);
attrPos.push(cur);
addNext(out, miter, miterLen * flip);
attrPos.push(cur);
attrIndex.push(_lastFlip !== -flip attrIndex.push([ index + 1, index + 2, index + 3 ]);
? [ index + 1, index + 3, index + 2 ] : [ index, index + 2, index + 3 ]);
// now add the bevel triangle // 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); normal(tmp, lineB);
copy(_normal, tmp); // store normal for next round copy(_normal, tmp); // store normal for next round
addNext(out, _normal, -flip); extrusions(attrPos, out, cur, _normal, 1);
attrPos.push(cur); attrDistance.push(d, d, d, d);
attrDistance.push(d, d, d);
// the miter is now the normal for our next join // the miter is now the normal for our next join
count += 3; count += 4;
} else { } else {
// next two points for our miter join // next two points in our first segment
extrusions(attrPos, out, cur, miter, miterLen); extrusions(attrPos, out, cur, _normal, 1);
attrDistance.push(d, d); attrIndex.push([ index + 1, index + 2, index + 3 ]);
attrIndex.push(_lastFlip === 1
? [ index + 1, index + 3, index + 2 ] : [ index, 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 // the miter is now the normal for our next join
copy(_normal, miter); count += 5;
count += 2;
} }
_lastFlip = flip; _lastFlip = flip;
} }