From 0785dc763160bc0010a5b56d1e849ae87df75715 Mon Sep 17 00:00:00 2001 From: "izzy.cz" Date: Fri, 12 Jul 2019 20:38:20 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BA=BF=E6=94=AF=E6=8C=81pattern?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demos/assets/arrow.png | Bin 0 -> 811 bytes demos/assets/right.png | Bin 0 -> 647 bytes demos/patternline.html | 100 ++++++++++++++++++++++++++ src/geom/buffer/line.js | 15 +++- src/geom/shader/meshline_frag.glsl | 32 +++++++-- src/geom/shader/meshline_vert.glsl | 32 +++++++-- src/geom/shape/line.js | 19 ++--- src/layer/render/line/drawMeshLine.js | 18 ++++- src/util/polyline-normals.js | 47 ++++++------ 9 files changed, 215 insertions(+), 48 deletions(-) create mode 100644 demos/assets/arrow.png create mode 100755 demos/assets/right.png create mode 100644 demos/patternline.html diff --git a/demos/assets/arrow.png b/demos/assets/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..f4b715fc6beea9db20fe1cd8d81d9cad35efacb0 GIT binary patch literal 811 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^T}FfdWk9dNvV1jxdlK~3=B3ERzPNMYDuC(MQ%=Bu~mhw5?F;5kPQ;nS5g2gDap1~ zitr6kaLzAERWQ{v(KAr8<5EyiuqjGOvkG!?gK7uzY?U%fN(!v>^~=l4^~#O)@{7{- z4J|D#^$m>ljf`}GDs+o0^GXscbn}XpA%?)raY-#sF3Kz@$;{7F0GXSZlwVq6tE2?7 z2o50bEXhnm*pycc^%l^B`XCv7Lp=k1xYR3{W_A=fnk--Pt2=BMvI)ss)(%rCdu z+W7t14V<1UugGqj*!{mrciBGID?02ezuk_xpnUm3Ml*TVfaX{Nng^IPOHPRps2-=kESmI@R4> z!ljhw?3qW*J4=7OxKeVj#ozDTucwOZVUiu5*VASnaGUFQ4?D zH`BoDx~9p-qtQiIPb_r$A|Buu(fX^yCp~c9C%>Z-SB*22y3L=Y$)?_7%8G6-yw6#g z?WV-H@%^bpfS l)|^-?zIITu_H^}gS?83{1OR0dG;#m{ literal 0 HcmV?d00001 diff --git a/demos/assets/right.png b/demos/assets/right.png new file mode 100755 index 0000000000000000000000000000000000000000..7d419a4f687ba12415fcf88b8e797cda56ae9f27 GIT binary patch literal 647 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S1|*9D%+3HQ#^NA%Cx&(BWL^Tz9|8>y;bpKhp88yV>WRp=I1=9MH?=;jqGLkxkLnOgw2D6bgmE1>`MD-sLz4fPE4v1uyFOhY&iMHfg0q7CdTh-Egwps{i;N=+=u zFAB-e&#`j^g`I+DZen_BP-YFDw}3qIva2PL8@ol+#IKsypNw&WN?RE5W3N{?0{efM~}jp?bn_xe(9GFih^g$hOB~*~`bso$B?(^JC18I4-v!>93mR@8H%flh03{huS3j3^P6 + + + + + + + + + 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; }