From fe894bc660ac5e47c339a1ed3aebb7b01cf1f890 Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Wed, 30 Oct 2019 14:53:18 +0800 Subject: [PATCH 1/6] feat(layers): add arclayer --- packages/layers/src/core/triangulation.ts | 38 +++++++ packages/layers/src/index.ts | 2 + packages/layers/src/line/arc.ts | 107 ++++++++++++++++++ .../src/line/shaders/line_arc_frag.glsl | 10 ++ .../src/line/shaders/line_arc_vert.glsl | 66 +++++++++++ .../src/polygon/shaders/polygon_vert.glsl | 2 +- stories/Layers/Layers.stories.tsx | 2 + stories/Layers/components/Arcline.tsx | 56 +++++++++ stories/Layers/components/Line.tsx | 2 +- 9 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 packages/layers/src/line/arc.ts create mode 100644 packages/layers/src/line/shaders/line_arc_frag.glsl create mode 100644 packages/layers/src/line/shaders/line_arc_vert.glsl create mode 100644 stories/Layers/components/Arcline.tsx diff --git a/packages/layers/src/core/triangulation.ts b/packages/layers/src/core/triangulation.ts index e6d219000c..dc52a9d5db 100644 --- a/packages/layers/src/core/triangulation.ts +++ b/packages/layers/src/core/triangulation.ts @@ -137,6 +137,44 @@ export function RasterImageTriangulation(feature: IEncodeFeature) { }; } +export function LineArcTriangulation(feature: IEncodeFeature, segNum = 30) { + const coordinates = feature.coordinates as IPosition[]; + const positions = []; + const indexArray = []; + for (let i = 0; i < segNum; i++) { + // 上线两个顶点 + // [ x, y, z, sx,sy, tx,ty] + positions.push( + i, + 1, + i, + coordinates[0][0], + coordinates[0][1], + coordinates[1][0], + coordinates[1][1], + i, + -1, + i, + coordinates[0][0], + coordinates[0][1], + coordinates[1][0], + coordinates[1][1], + ); + if (i !== segNum - 1) { + indexArray.push( + ...[0, 1, 2, 1, 3, 2].map((v) => { + return i * 2 + v; + }), + ); + } + } + return { + vertices: positions, + indices: indexArray, + size: 7, + }; +} + /** * 点图层3d geomerty * @param shape 3D形状 diff --git a/packages/layers/src/index.ts b/packages/layers/src/index.ts index f1b752992c..79bfc5e97a 100644 --- a/packages/layers/src/index.ts +++ b/packages/layers/src/index.ts @@ -2,6 +2,7 @@ import { container, ILayerPlugin, TYPES } from '@l7/core'; import BaseLayer from './core/BaseLayer'; import HeatMapGridLayer from './heatmap/grid'; import LineLayer from './line/index'; +import ArcLineLayer from './line/arc'; import Point3dLayer from './point/extrude'; import PointImageLayer from './point/image'; import PointLayer from './point/index'; @@ -72,6 +73,7 @@ export { Polygon3DLayer, ImageLayer, HeatMapGridLayer, + ArcLineLayer, // Line, // ImageLayer, // HeatMapLayer, diff --git a/packages/layers/src/line/arc.ts b/packages/layers/src/line/arc.ts new file mode 100644 index 0000000000..5813156a68 --- /dev/null +++ b/packages/layers/src/line/arc.ts @@ -0,0 +1,107 @@ +import { AttributeType, gl, IEncodeFeature, ILayer } from '@l7/core'; +import BaseLayer from '../core/BaseLayer'; +import { LineArcTriangulation } from '../core/triangulation'; +import line_arc_frag from './shaders/line_arc_frag.glsl'; +import line_arc_vert from './shaders/line_arc_vert.glsl'; +interface IArcLayerStyleOptions { + opacity: number; + segmentNumber: number; +} +export default class ArcLineLayer extends BaseLayer { + public name: string = 'LineLayer'; + + protected getConfigSchema() { + return { + properties: { + opacity: { + type: 'number', + minimum: 0, + maximum: 1, + }, + }, + }; + } + + protected renderModels() { + const { opacity } = this.getStyleOptions(); + this.models.forEach((model) => + model.draw({ + uniforms: { + u_Opacity: opacity || 1, + segmentNumber: 30, + }, + }), + ); + return this; + } + + protected buildModels() { + this.registerBuiltinAttributes(this); + this.models = [ + this.buildLayerModel({ + moduleName: 'arcline', + vertexShader: line_arc_vert, + fragmentShader: line_arc_frag, + triangulation: LineArcTriangulation, + blend: { + enable: true, + func: { + srcRGB: gl.ONE, + srcAlpha: 1, + dstRGB: gl.ONE, + dstAlpha: 1, + }, + }, + }), + ]; + } + + private registerBuiltinAttributes(layer: ILayer) { + // point layer size; + layer.styleAttributeService.registerStyleAttribute({ + name: 'size', + type: AttributeType.Attribute, + descriptor: { + name: 'a_Size', + buffer: { + // give the WebGL driver a hint that this buffer may change + usage: gl.DYNAMIC_DRAW, + data: [], + type: gl.FLOAT, + }, + size: 1, + update: ( + feature: IEncodeFeature, + featureIdx: number, + vertex: number[], + attributeIdx: number, + ) => { + const { size } = feature; + return Array.isArray(size) ? [size[0]] : [size as number]; + }, + }, + }); + + layer.styleAttributeService.registerStyleAttribute({ + name: 'instance', // 弧线起始点信息 + type: AttributeType.Attribute, + descriptor: { + name: 'a_Instance', + buffer: { + usage: gl.STATIC_DRAW, + data: [], + type: gl.FLOAT, + }, + size: 4, + update: ( + feature: IEncodeFeature, + featureIdx: number, + vertex: number[], + attributeIdx: number, + ) => { + return [vertex[3], vertex[4], vertex[5], vertex[6]]; + }, + }, + }); + } +} diff --git a/packages/layers/src/line/shaders/line_arc_frag.glsl b/packages/layers/src/line/shaders/line_arc_frag.glsl new file mode 100644 index 0000000000..b8f0e5bbb4 --- /dev/null +++ b/packages/layers/src/line/shaders/line_arc_frag.glsl @@ -0,0 +1,10 @@ + precision mediump float; + uniform float u_Opacity; + varying vec4 v_color; + + void main() { + + gl_FragColor = v_color; + gl_FragColor.a = v_color.a * u_Opacity; + + } diff --git a/packages/layers/src/line/shaders/line_arc_vert.glsl b/packages/layers/src/line/shaders/line_arc_vert.glsl new file mode 100644 index 0000000000..abefcf54bd --- /dev/null +++ b/packages/layers/src/line/shaders/line_arc_vert.glsl @@ -0,0 +1,66 @@ +precision mediump float; +attribute vec3 a_Position; +attribute vec4 a_Instance; +attribute vec4 a_Color; +attribute float a_Size; + + +uniform mat4 u_ModelMatrix; +uniform float segmentNumber; +varying vec4 v_color; +#pragma include "projection" + +float maps (float value, float start1, float stop1, float start2, float stop2) { + return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1)); +} + +float getSegmentRatio(float index) { + return smoothstep(0.0, 1.0, index / (segmentNumber - 1.0)); +} + +float paraboloid(vec2 source, vec2 target, float ratio) { + vec2 x = mix(source, target, ratio); + vec2 center = mix(source, target, 0.5); + float dSourceCenter = distance(source, center); + float dXCenter = distance(x, center); + return (dSourceCenter + dXCenter) * (dSourceCenter - dXCenter); +} + +vec3 getPos(vec2 source, vec2 target, float segmentRatio) { + float vertex_height = paraboloid(source, target, segmentRatio); + + return vec3( + mix(source, target, segmentRatio), + sqrt(max(0.0, vertex_height)) + ); +} +vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction) { + // normalized direction of the line + vec2 dir_screenspace = normalize(line_clipspace); + // rotate by 90 degrees + dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x); + + vec2 offset = dir_screenspace * offset_direction * a_Size / 2.0; + + return offset; +} + + +void main() { + v_color = a_Color; + vec2 source = project_position(vec4(a_Instance.rg, 0, 0)).xy; + vec2 target = project_position(vec4(a_Instance.ba, 0, 0)).xy; + float segmentIndex = a_Position.x; + float segmentRatio = getSegmentRatio(segmentIndex); + float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0)); + + float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir); + vec3 curr = getPos(source, target, segmentRatio); + vec3 next = getPos(source, target, nextSegmentRatio); + vec2 offset = getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y); + + // vec4 project_pos = project_position(vec4(curr, 1.0)); + + gl_Position = project_common_position_to_clipspace(vec4(curr.xy + project_pixel(offset), curr.z, 1.0)); + +} diff --git a/packages/layers/src/polygon/shaders/polygon_vert.glsl b/packages/layers/src/polygon/shaders/polygon_vert.glsl index 710449f147..03094f786f 100644 --- a/packages/layers/src/polygon/shaders/polygon_vert.glsl +++ b/packages/layers/src/polygon/shaders/polygon_vert.glsl @@ -11,7 +11,7 @@ varying vec4 v_Color; void main() { v_Color =a_Color; - vec4 project_pos = project_position(vec4(a_Position 1.0)); + vec4 project_pos = project_position(vec4(a_Position,1.0)); gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0)); setPickingColor(a_PickingColor); diff --git a/stories/Layers/Layers.stories.tsx b/stories/Layers/Layers.stories.tsx index a019f80220..6946fffa22 100644 --- a/stories/Layers/Layers.stories.tsx +++ b/stories/Layers/Layers.stories.tsx @@ -1,5 +1,6 @@ import { storiesOf } from '@storybook/react'; import * as React from 'react'; +import ArcLineDemo from './components/Arcline'; import GridHeatMap from './components/heatMapgrid'; import LineLayer from './components/Line'; import PointDemo from './components/Point'; @@ -15,5 +16,6 @@ storiesOf('图层', module) .add('图片标注', () => ) .add('面3d图层', () => ) .add('线图层', () => ) + .add('弧线', () => ) .add('网格热力图', () => ) .add('图片', () => ); diff --git a/stories/Layers/components/Arcline.tsx b/stories/Layers/components/Arcline.tsx new file mode 100644 index 0000000000..42333b66bb --- /dev/null +++ b/stories/Layers/components/Arcline.tsx @@ -0,0 +1,56 @@ +import { ArcLineLayer } from '@l7/layers'; +import { Scene } from '@l7/scene'; +import * as React from 'react'; + +export default class ArxLineDemo extends React.Component { + private scene: Scene; + + public componentWillUnmount() { + this.scene.destroy(); + } + + public async componentDidMount() { + const response = await fetch( + 'https://gw.alipayobjects.com/os/rmsportal/UEXQMifxtkQlYfChpPwT.txt', + ); + const scene = new Scene({ + center: [116.2825, 39.9], + id: 'map', + pitch: 0, + type: 'mapbox', + style: 'mapbox://styles/mapbox/dark-v9', + zoom: 2, + }); + const lineLayer = new ArcLineLayer({}) + .source(await response.text(), { + parser: { + type: 'csv', + x: 'lng1', + y: 'lat1', + x1: 'lng2', + y1: 'lat2', + }, + }) + .size(0.5) + .shape('arc') + .color('rgb(13,64,140)'); + scene.addLayer(lineLayer); + scene.render(); + this.scene = scene; + } + + public render() { + return ( +
+ ); + } +} diff --git a/stories/Layers/components/Line.tsx b/stories/Layers/components/Line.tsx index ad2e84487f..55dd4d5bcb 100644 --- a/stories/Layers/components/Line.tsx +++ b/stories/Layers/components/Line.tsx @@ -2,7 +2,7 @@ import { LineLayer } from '@l7/layers'; import { Scene } from '@l7/scene'; import * as React from 'react'; -export default class Point3D extends React.Component { +export default class LineDemo extends React.Component { private scene: Scene; public componentWillUnmount() { From 37d67994220926a1cf0e470bb76c89280b8c0739 Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Wed, 30 Oct 2019 16:38:59 +0800 Subject: [PATCH 2/6] feat(layer): add arc2d layer --- packages/layers/src/core/triangulation.ts | 6 +- packages/layers/src/index.ts | 4 +- packages/layers/src/line/arc2d.ts | 108 ++++++++++++++++++ .../src/line/shaders/line_arc2d_vert.glsl | 89 +++++++++++++++ .../layers/src/line/shaders/line_vert.glsl | 1 + stories/Layers/Layers.stories.tsx | 4 +- stories/Layers/components/Arc2DLine.tsx | 56 +++++++++ stories/Layers/components/Arcline.tsx | 2 +- 8 files changed, 266 insertions(+), 4 deletions(-) create mode 100644 packages/layers/src/line/arc2d.ts create mode 100644 packages/layers/src/line/shaders/line_arc2d_vert.glsl create mode 100644 stories/Layers/components/Arc2DLine.tsx diff --git a/packages/layers/src/core/triangulation.ts b/packages/layers/src/core/triangulation.ts index dc52a9d5db..84cf8e6b47 100644 --- a/packages/layers/src/core/triangulation.ts +++ b/packages/layers/src/core/triangulation.ts @@ -136,7 +136,11 @@ export function RasterImageTriangulation(feature: IEncodeFeature) { size: 5, }; } - +/** + * 计算3D弧线顶点 + * @param feature 映射数据 + * @param segNum 弧线线段数 + */ export function LineArcTriangulation(feature: IEncodeFeature, segNum = 30) { const coordinates = feature.coordinates as IPosition[]; const positions = []; diff --git a/packages/layers/src/index.ts b/packages/layers/src/index.ts index 79bfc5e97a..2c83d5b7ff 100644 --- a/packages/layers/src/index.ts +++ b/packages/layers/src/index.ts @@ -1,8 +1,9 @@ import { container, ILayerPlugin, TYPES } from '@l7/core'; import BaseLayer from './core/BaseLayer'; import HeatMapGridLayer from './heatmap/grid'; -import LineLayer from './line/index'; import ArcLineLayer from './line/arc'; +import Arc2DLineLayer from './line/arc2d'; +import LineLayer from './line/index'; import Point3dLayer from './point/extrude'; import PointImageLayer from './point/image'; import PointLayer from './point/index'; @@ -74,6 +75,7 @@ export { ImageLayer, HeatMapGridLayer, ArcLineLayer, + Arc2DLineLayer, // Line, // ImageLayer, // HeatMapLayer, diff --git a/packages/layers/src/line/arc2d.ts b/packages/layers/src/line/arc2d.ts new file mode 100644 index 0000000000..18e3c7a16d --- /dev/null +++ b/packages/layers/src/line/arc2d.ts @@ -0,0 +1,108 @@ +import { AttributeType, gl, IEncodeFeature, ILayer } from '@l7/core'; +import BaseLayer from '../core/BaseLayer'; +import { LineArcTriangulation } from '../core/triangulation'; +import line_arc2d_vert from './shaders/line_arc2d_vert.glsl'; +import line_arc_frag from './shaders/line_arc_frag.glsl'; +interface IArcLayerStyleOptions { + opacity: number; + segmentNumber: number; +} +export default class Arc2DLineLayer extends BaseLayer { + public name: string = 'LineLayer'; + + protected getConfigSchema() { + return { + properties: { + opacity: { + type: 'number', + minimum: 0, + maximum: 1, + }, + }, + }; + } + + protected renderModels() { + const { opacity } = this.getStyleOptions(); + this.models.forEach((model) => + model.draw({ + uniforms: { + u_Opacity: opacity || 1, + segmentNumber: 30, + }, + }), + ); + return this; + } + + protected buildModels() { + this.registerBuiltinAttributes(this); + this.models = [ + this.buildLayerModel({ + moduleName: 'arc2dline', + vertexShader: line_arc2d_vert, + fragmentShader: line_arc_frag, + triangulation: LineArcTriangulation, + depth: { enable: false }, + blend: { + enable: true, + func: { + srcRGB: gl.ONE, + srcAlpha: 1, + dstRGB: gl.ONE, + dstAlpha: 1, + }, + }, + }), + ]; + } + + private registerBuiltinAttributes(layer: ILayer) { + // point layer size; + layer.styleAttributeService.registerStyleAttribute({ + name: 'size', + type: AttributeType.Attribute, + descriptor: { + name: 'a_Size', + buffer: { + // give the WebGL driver a hint that this buffer may change + usage: gl.DYNAMIC_DRAW, + data: [], + type: gl.FLOAT, + }, + size: 1, + update: ( + feature: IEncodeFeature, + featureIdx: number, + vertex: number[], + attributeIdx: number, + ) => { + const { size } = feature; + return Array.isArray(size) ? [size[0]] : [size as number]; + }, + }, + }); + + layer.styleAttributeService.registerStyleAttribute({ + name: 'instance', // 弧线起始点信息 + type: AttributeType.Attribute, + descriptor: { + name: 'a_Instance', + buffer: { + usage: gl.STATIC_DRAW, + data: [], + type: gl.FLOAT, + }, + size: 4, + update: ( + feature: IEncodeFeature, + featureIdx: number, + vertex: number[], + attributeIdx: number, + ) => { + return [vertex[3], vertex[4], vertex[5], vertex[6]]; + }, + }, + }); + } +} diff --git a/packages/layers/src/line/shaders/line_arc2d_vert.glsl b/packages/layers/src/line/shaders/line_arc2d_vert.glsl new file mode 100644 index 0000000000..360aed1ee5 --- /dev/null +++ b/packages/layers/src/line/shaders/line_arc2d_vert.glsl @@ -0,0 +1,89 @@ +precision mediump float; +attribute vec4 a_Color; +attribute vec3 a_Position; +attribute vec4 a_Instance; +attribute float a_Size; +uniform mat4 u_ModelMatrix; +uniform float segmentNumber; +varying vec4 v_color; + +#pragma include "projection" + +float maps (float value, float start1, float stop1, float start2, float stop2) { + return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1)); +} + +float getSegmentRatio(float index) { + return smoothstep(0.0, 1.0, index / (segmentNumber - 1.)); +} + +float paraboloid(vec2 source, vec2 target, float ratio) { + vec2 x = mix(source, target, ratio); + vec2 center = mix(source, target, 0.5); + float dSourceCenter = distance(source, center); + float dXCenter = distance(x, center); + return (dSourceCenter + dXCenter) * (dSourceCenter - dXCenter); +} + +vec3 getPos(vec2 source, vec2 target, float segmentRatio) { + float vertex_height = paraboloid(source, target, segmentRatio); + + return vec3( + mix(source, target, segmentRatio), + sqrt(max(0.0, vertex_height)) + ); +} +vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction) { + // normalized direction of the line + vec2 dir_screenspace = normalize(line_clipspace); + // rotate by 90 degrees + dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x); + vec2 offset = dir_screenspace * offset_direction * a_Size / 2.0; + return offset; +} +float getAngularDist (vec2 source, vec2 target) { + vec2 delta = source - target; + vec2 sin_half_delta = sin(delta / 2.0); + float a = + sin_half_delta.y * sin_half_delta.y + + cos(source.y) * cos(target.y) * + sin_half_delta.x * sin_half_delta.x; + return 2.0 * atan(sqrt(a), sqrt(1.0 - a)); +} +vec2 interpolate (vec2 source, vec2 target, float angularDist, float t) { + // if the angularDist is PI, linear interpolation is applied. otherwise, use spherical interpolation + if(abs(angularDist - PI) < 0.001) { + return (1.0 - t) * source + t * target; + } + float a = sin((1.0 - t) * angularDist) / sin(angularDist); + float b = sin(t * angularDist) / sin(angularDist); + vec2 sin_source = sin(source); + vec2 cos_source = cos(source); + vec2 sin_target = sin(target); + vec2 cos_target = cos(target); + float x = a * cos_source.y * cos_source.x + b * cos_target.y * cos_target.x; + float y = a * cos_source.y * sin_source.x + b * cos_target.y * sin_target.x; + float z = a * sin_source.y + b * sin_target.y; + return vec2(atan(y, x), atan(z, sqrt(x * x + y * y))); +} + + +void main() { + v_color = a_Color; + vec2 source = radians(a_Instance.rg); + vec2 target = radians(a_Instance.ba); + float angularDist = getAngularDist(source, target); + float segmentIndex = a_Position.x; + float segmentRatio = getSegmentRatio(segmentIndex); + float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0)); + float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir); + + vec4 curr = project_position(vec4(degrees(interpolate(source, target, angularDist, segmentRatio)), 0.0, 1.0)); + vec4 next = project_position(vec4(degrees(interpolate(source, target, angularDist, nextSegmentRatio)), 0.0, 1.0)); + + vec2 offset = getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y); + + // vec4 project_pos = project_position(vec4(curr.xy, 0, 1.0)); + gl_Position = project_common_position_to_clipspace(vec4(curr.xy + offset, 0, 1.0)); +} + diff --git a/packages/layers/src/line/shaders/line_vert.glsl b/packages/layers/src/line/shaders/line_vert.glsl index 3cc4620ea4..75f3992525 100644 --- a/packages/layers/src/line/shaders/line_vert.glsl +++ b/packages/layers/src/line/shaders/line_vert.glsl @@ -12,6 +12,7 @@ uniform mat4 u_ModelMatrix; varying vec4 v_color; varying float v_dash_array; varying vec3 v_normal; + #pragma include "projection" void main() { v_normal = a_Normal; diff --git a/stories/Layers/Layers.stories.tsx b/stories/Layers/Layers.stories.tsx index 6946fffa22..4a105d43ee 100644 --- a/stories/Layers/Layers.stories.tsx +++ b/stories/Layers/Layers.stories.tsx @@ -1,5 +1,6 @@ import { storiesOf } from '@storybook/react'; import * as React from 'react'; +import Arc2DLineDemo from './components/Arc2DLine'; import ArcLineDemo from './components/Arcline'; import GridHeatMap from './components/heatMapgrid'; import LineLayer from './components/Line'; @@ -16,6 +17,7 @@ storiesOf('图层', module) .add('图片标注', () => ) .add('面3d图层', () => ) .add('线图层', () => ) - .add('弧线', () => ) + .add('3D弧线', () => ) + .add('2D弧线', () => ) .add('网格热力图', () => ) .add('图片', () => ); diff --git a/stories/Layers/components/Arc2DLine.tsx b/stories/Layers/components/Arc2DLine.tsx new file mode 100644 index 0000000000..8629a3f8e8 --- /dev/null +++ b/stories/Layers/components/Arc2DLine.tsx @@ -0,0 +1,56 @@ +import { Arc2DLineLayer } from '@l7/layers'; +import { Scene } from '@l7/scene'; +import * as React from 'react'; + +export default class Arc2DLineDemo extends React.Component { + private scene: Scene; + + public componentWillUnmount() { + this.scene.destroy(); + } + + public async componentDidMount() { + const response = await fetch( + 'https://gw.alipayobjects.com/os/rmsportal/UEXQMifxtkQlYfChpPwT.txt', + ); + const scene = new Scene({ + center: [116.2825, 39.9], + id: 'map', + pitch: 0, + type: 'mapbox', + style: 'mapbox://styles/mapbox/dark-v9', + zoom: 2, + }); + const lineLayer = new Arc2DLineLayer({}) + .source(await response.text(), { + parser: { + type: 'csv', + x: 'lng1', + y: 'lat1', + x1: 'lng2', + y1: 'lat2', + }, + }) + .size(0.5) + .shape('arc') + .color('rgb(13,64,140)'); + scene.addLayer(lineLayer); + scene.render(); + this.scene = scene; + } + + public render() { + return ( +
+ ); + } +} diff --git a/stories/Layers/components/Arcline.tsx b/stories/Layers/components/Arcline.tsx index 42333b66bb..0ffe2e4439 100644 --- a/stories/Layers/components/Arcline.tsx +++ b/stories/Layers/components/Arcline.tsx @@ -2,7 +2,7 @@ import { ArcLineLayer } from '@l7/layers'; import { Scene } from '@l7/scene'; import * as React from 'react'; -export default class ArxLineDemo extends React.Component { +export default class ArcLineDemo extends React.Component { private scene: Scene; public componentWillUnmount() { From 9b8d3c8f5d2e42bfd7784bdc35fbb2a8c7634e02 Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Sat, 2 Nov 2019 00:42:30 +0800 Subject: [PATCH 3/6] feat(layers): add heatmap 3d layer --- packages/layers/src/core/BaseLayer.ts | 1 + packages/layers/src/heatmap/heatmap.ts | 12 ++++++- .../src/heatmap/shaders/heatmap_3d_frag.glsl | 2 +- .../src/heatmap/shaders/heatmap_3d_vert.glsl | 33 +++++++++++++++---- stories/Layers/Layers.stories.tsx | 18 +++++----- stories/Layers/components/heatMap.tsx | 9 +++-- 6 files changed, 54 insertions(+), 21 deletions(-) diff --git a/packages/layers/src/core/BaseLayer.ts b/packages/layers/src/core/BaseLayer.ts index abd212c7df..750e43d302 100644 --- a/packages/layers/src/core/BaseLayer.ts +++ b/packages/layers/src/core/BaseLayer.ts @@ -1,4 +1,5 @@ import { + ICameraService, IEncodeFeature, IFontService, IGlobalConfigService, diff --git a/packages/layers/src/heatmap/heatmap.ts b/packages/layers/src/heatmap/heatmap.ts index 19d134b1b5..ddd039c596 100644 --- a/packages/layers/src/heatmap/heatmap.ts +++ b/packages/layers/src/heatmap/heatmap.ts @@ -1,6 +1,7 @@ import { AttributeType, gl, + ICameraService, IEncodeFeature, IFramebuffer, ILayer, @@ -12,6 +13,7 @@ import { lazyInject, TYPES, } from '@l7/core'; +import { mat4 } from 'gl-matrix'; import BaseLayer from '../core/BaseLayer'; import { HeatmapTriangulation } from '../core/triangulation'; import { generateColorRamp, IColorRamp } from '../utils/color'; @@ -34,6 +36,8 @@ export default class HeatMapLayer extends BaseLayer { public name: string = 'HeatMapLayer'; protected texture: ITexture2D; protected colorTexture: ITexture2D; + @lazyInject(TYPES.ICameraService) + protected readonly camera: ICameraService; protected heatmapFramerBuffer: IFramebuffer; private intensityModel: IModel; private colorModel: IModel; @@ -72,7 +76,7 @@ export default class HeatMapLayer extends BaseLayer { this.intensityModel = this.buildHeatMapIntensity(); this.models = [this.intensityModel]; // this.colorModel = this.buildHeatmapColor(); - this.colorModel = this.buildHeatmapColor(); + this.colorModel = this.build3dHeatMap(); this.models.push(this.colorModel); const { rampColors } = this.getStyleOptions(); const imageData = generateColorRamp(rampColors as IColorRamp); @@ -251,12 +255,18 @@ export default class HeatMapLayer extends BaseLayer { private draw3DHeatMap() { const { opacity } = this.getStyleOptions(); const mapbounds = this.map.getBounds(); + const invert = mat4.invert( + mat4.create(), + // @ts-ignore + mat4.fromValues(...this.camera.getViewProjectionMatrix()), + ) as mat4; this.colorModel.draw({ uniforms: { u_Opacity: opacity || 1.0, u_colorTexture: this.colorTexture, u_texture: this.heatmapFramerBuffer, u_extent: [-179.9476, -60.0959, 179.9778, 79.5651], + u_InverseViewProjectionMatrix: [...invert], }, }); } diff --git a/packages/layers/src/heatmap/shaders/heatmap_3d_frag.glsl b/packages/layers/src/heatmap/shaders/heatmap_3d_frag.glsl index f3f83b7c2a..f2c35866d3 100644 --- a/packages/layers/src/heatmap/shaders/heatmap_3d_frag.glsl +++ b/packages/layers/src/heatmap/shaders/heatmap_3d_frag.glsl @@ -11,6 +11,6 @@ void main(){ // vec4 color = texture2D(u_colorTexture,vec2(0.5,1.0-intensity)); vec4 color = texture2D(u_colorTexture,ramp_pos); gl_FragColor = color; - gl_FragColor.a = color.a * smoothstep(0.1,0.5,intensity) * u_Opacity; + // gl_FragColor.a = color.a * smoothstep(0.0,0.12,intensity) * u_Opacity; } diff --git a/packages/layers/src/heatmap/shaders/heatmap_3d_vert.glsl b/packages/layers/src/heatmap/shaders/heatmap_3d_vert.glsl index a7093f2215..087e4328bd 100644 --- a/packages/layers/src/heatmap/shaders/heatmap_3d_vert.glsl +++ b/packages/layers/src/heatmap/shaders/heatmap_3d_vert.glsl @@ -5,19 +5,38 @@ uniform sampler2D u_texture; uniform vec4 u_extent; varying vec2 v_texCoord; uniform mat4 u_ModelMatrix; +uniform mat4 u_InverseViewProjectionMatrix; #pragma include "projection" void main() { - v_texCoord = a_Uv; - vec2 minxy = project_position(vec4(u_extent.xy, 0, 1.0)).xy; - vec2 maxxy = project_position(vec4(u_extent.zw, 0, 1.0)).xy; + v_texCoord = a_Uv; - vec2 step = (maxxy - minxy); + vec2 pos = a_Uv * vec2(2.0) - vec2(1.0); - vec2 pos = minxy + (vec2(a_Position.x, a_Position.y ) + vec2(1.0)) / vec2(2.0) * step; + vec4 n_0 = vec4(pos, 0.0, 1.0) - u_ViewportCenterProjection; + vec4 n_1 = vec4(pos, 1.0, 1.0) - u_ViewportCenterProjection; + + vec4 m_0 = u_InverseViewProjectionMatrix * n_0 ; + vec4 m_1 = u_InverseViewProjectionMatrix * n_1; + m_0 = m_0 / m_0.w; + m_1 = m_1 / m_1.w; + + float zPos = (0.0 - m_0.z) / (m_1.z - m_0.z); + vec4 mapCoord = m_0 + zPos * (m_1 - m_0); + + // vec4 p = u_InverseViewProjectionMatrix * (vec4(pos,0,1) - u_ViewportCenterProjection); + // p = p /p.w; + // pos.y = 1.0 -pos.y; + // vec2 minxy = project_position(vec4(u_extent.xy, 0, 1.0)).xy; + // vec2 maxxy = project_position(vec4(u_extent.zw, 0, 1.0)).xy; + + // vec2 step = (maxxy - minxy); + + // vec2 pos = minxy + (vec2(a_Position.x, a_Position.y ) + vec2(1.0)) / vec2(2.0) * step; float intensity = texture2D(u_texture, v_texCoord).r; - gl_Position = project_common_position_to_clipspace(vec4(pos.xy, 0, 1.0)); - v_texCoord = (gl_Position.xy + vec2(1.0)) / vec2(2.0) * gl_Position.w; + gl_Position = project_common_position_to_clipspace(vec4(mapCoord.xy, intensity * 100., 1.0)); + // gl_Position = vec4(pos,0.,1.0); + // v_texCoord = (gl_Position.xy + vec2(1.0)) / vec2(2.0) / gl_Position.w; // v_texCoord.y = 1.0 - v_texCoord.y; } diff --git a/stories/Layers/Layers.stories.tsx b/stories/Layers/Layers.stories.tsx index e4d6f3ba92..1625fe47f2 100644 --- a/stories/Layers/Layers.stories.tsx +++ b/stories/Layers/Layers.stories.tsx @@ -14,14 +14,14 @@ import RasterLayerDemo from './components/RasterLayer'; // @ts-ignore storiesOf('图层', module) - // .add('点图层', () => ) - // .add('3D点', () => ) - // .add('图片标注', () => ) - // .add('面3d图层', () => ) - // .add('线图层', () => ) - // .add('3D弧线', () => ) - // .add('2D弧线', () => ) - // .add('网格热力图', () => ) + .add('点图层', () => ) + .add('3D点', () => ) + .add('图片标注', () => ) + .add('面3d图层', () => ) + .add('线图层', () => ) + .add('3D弧线', () => ) + .add('2D弧线', () => ) + .add('网格热力图', () => ) .add('热力图', () => ) - // .add('栅格', () => ) + .add('栅格', () => ) .add('图片', () => ); diff --git a/stories/Layers/components/heatMap.tsx b/stories/Layers/components/heatMap.tsx index 9ca24173d2..4dc2c55241 100644 --- a/stories/Layers/components/heatMap.tsx +++ b/stories/Layers/components/heatMap.tsx @@ -22,16 +22,19 @@ export default class HeatMapLayerDemo extends React.Component { style: 'mapbox://styles/mapbox/dark-v10', zoom: 2, }); - const layer = new HeatMapLayer({}); + const layer = new HeatMapLayer({ + enableTAA: true, + }); layer .source(await response.json()) .size('mag', [0, 1]) // weight映射通道 .style({ intensity: 2, radius: 20, - opacity: 1, + opacity: 0.5, rampColors: { colors: [ + 'rgba(0,0,0,0)', '#2E8AE6', '#69D1AB', '#DAF291', @@ -39,7 +42,7 @@ export default class HeatMapLayerDemo extends React.Component { '#FF7A45', '#CF1D49', ], - positions: [0, 0.2, 0.4, 0.6, 0.8, 1.0], + positions: [0, 0.1, 0.2, 0.4, 0.6, 0.8, 1.0], }, }); scene.addLayer(layer); From de276d7512ffbd2f5c9cb5cac9ed06153d42facb Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Mon, 4 Nov 2019 11:19:45 +0800 Subject: [PATCH 4/6] fix(raster layer): update raster triangle --- .../services/layer/IStyleAttributeService.ts | 2 - .../services/layer/StyleAttributeService.ts | 3 +- packages/layers/src/core/BaseLayer.ts | 1 - .../src/raster/buffers/triangulation.ts | 5 +- packages/layers/src/raster/raster.ts | 64 +++++++++++++------ 5 files changed, 46 insertions(+), 29 deletions(-) diff --git a/packages/core/src/services/layer/IStyleAttributeService.ts b/packages/core/src/services/layer/IStyleAttributeService.ts index c5ba434ee2..03f8b69533 100644 --- a/packages/core/src/services/layer/IStyleAttributeService.ts +++ b/packages/core/src/services/layer/IStyleAttributeService.ts @@ -131,7 +131,6 @@ export interface IStyleAttribute extends IStyleAttributeInitializationOptions { export type Triangulation = ( feature: IEncodeFeature, - parserData: IParseDataItem, ) => { vertices: number[]; indices: number[]; @@ -161,7 +160,6 @@ export interface IStyleAttributeService { createAttributesAndIndices( encodedFeatures: IEncodeFeature[], triangulation: Triangulation, - parserData: IParseDataItem[], ): { attributes: { [attributeName: string]: IAttribute; diff --git a/packages/core/src/services/layer/StyleAttributeService.ts b/packages/core/src/services/layer/StyleAttributeService.ts index a40647dc69..42cdfaac59 100644 --- a/packages/core/src/services/layer/StyleAttributeService.ts +++ b/packages/core/src/services/layer/StyleAttributeService.ts @@ -167,7 +167,6 @@ export default class StyleAttributeService implements IStyleAttributeService { public createAttributesAndIndices( features: IEncodeFeature[], triangulation: Triangulation, - parserData: IParseDataItem[], ): { attributes: { [attributeName: string]: IAttribute; @@ -188,7 +187,7 @@ export default class StyleAttributeService implements IStyleAttributeService { vertices: verticesForCurrentFeature, normals: normalsForCurrentFeature, size: vertexSize, - } = triangulation(feature, parserData[featureIdx]); + } = triangulation(feature); indices.push(...indicesForCurrentFeature.map((i) => i + verticesNum)); vertices.push(...verticesForCurrentFeature); if (normalsForCurrentFeature) { diff --git a/packages/layers/src/core/BaseLayer.ts b/packages/layers/src/core/BaseLayer.ts index 750e43d302..13d60d574d 100644 --- a/packages/layers/src/core/BaseLayer.ts +++ b/packages/layers/src/core/BaseLayer.ts @@ -351,7 +351,6 @@ export default class BaseLayer implements ILayer { } = this.styleAttributeService.createAttributesAndIndices( this.encodedData, triangulation, - parserData, ); return createModel({ attributes, diff --git a/packages/layers/src/raster/buffers/triangulation.ts b/packages/layers/src/raster/buffers/triangulation.ts index 5fe8f48f60..2d15ce9c0f 100644 --- a/packages/layers/src/raster/buffers/triangulation.ts +++ b/packages/layers/src/raster/buffers/triangulation.ts @@ -1,10 +1,7 @@ import { IEncodeFeature, IParseDataItem } from '@l7/core'; // @ts-ignore import Martini from '@mapbox/martini'; -export function RasterTriangulation( - feature: IEncodeFeature, - parserData: IParseDataItem, -) { +export function RasterTriangulation(parserData: IParseDataItem) { const { coordinates, data, min, max, width, height } = parserData; const maxlength = Math.max(width, height); const gridSize = Math.pow(2, Math.ceil(Math.log2(maxlength))) + 1; diff --git a/packages/layers/src/raster/raster.ts b/packages/layers/src/raster/raster.ts index 941497947c..011eaef5bd 100644 --- a/packages/layers/src/raster/raster.ts +++ b/packages/layers/src/raster/raster.ts @@ -24,8 +24,8 @@ interface IRasterLayerStyleOptions { rampColors: IColorRamp; } -export default class ImageLayer extends BaseLayer { - public name: string = 'RasterLayer'; +export default class RasterLayer extends BaseLayer { + public name: string = 'e'; protected texture: ITexture2D; protected colorTexture: ITexture2D; @@ -81,24 +81,48 @@ export default class ImageLayer extends BaseLayer { height: imageData.height, flipY: true, }); - this.models = [ - this.buildLayerModel({ - moduleName: 'Raster', - vertexShader: rasterVert, - fragmentShader: rasterFrag, - triangulation: RasterTriangulation, - primitive: gl.TRIANGLES, - depth: { enable: false }, - blend: { - enable: true, - func: { - srcRGB: gl.SRC_ALPHA, - srcAlpha: 1, - dstRGB: gl.ONE_MINUS_SRC_ALPHA, - dstAlpha: 1, - }, - }, + this.models = [this.buildRasterModel()]; + } + private buildRasterModel() { + const source = this.getSource(); + const sourceFeature = source.data.dataArray[0]; + const triangulation = RasterTriangulation(sourceFeature); + this.shaderModuleService.registerModule('raster', { + vs: rasterVert, + fs: rasterFrag, + }); + + const { vs, fs, uniforms } = this.shaderModuleService.getModule('raster'); + const { + createAttribute, + createElements, + createBuffer, + createModel, + } = this.rendererService; + return createModel({ + vs, + fs, + attributes: { + a_Position: createAttribute({ + buffer: createBuffer({ + data: triangulation.vertices, + type: gl.FLOAT, + }), + size: 2, + }), + }, + primitive: gl.TRIANGLES, + uniforms: { + ...uniforms, + }, + depth: { + enable: true, + }, + elements: createElements({ + data: triangulation.indices, + type: gl.UNSIGNED_INT, + count: triangulation.indices.length, }), - ]; + }); } } From 755ef1aa2d237d9a2984883c8901fdac54347428 Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Mon, 4 Nov 2019 11:33:38 +0800 Subject: [PATCH 5/6] fix(raster layer): raster layer triangle --- packages/layers/src/raster/buffers/triangulation.ts | 2 +- packages/layers/src/raster/shaders/raster_vert.glsl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/layers/src/raster/buffers/triangulation.ts b/packages/layers/src/raster/buffers/triangulation.ts index 2d15ce9c0f..be96cf697b 100644 --- a/packages/layers/src/raster/buffers/triangulation.ts +++ b/packages/layers/src/raster/buffers/triangulation.ts @@ -13,7 +13,7 @@ export function RasterTriangulation(parserData: IParseDataItem) { } const martini = new Martini(gridSize); const tile = martini.createTile(terrain); - const mesh = tile.getMesh(1024); + const mesh = tile.getMesh(gridSize / 2); return { vertices: Array.from(mesh.vertices) as number[], indices: Array.from(mesh.triangles) as number[], diff --git a/packages/layers/src/raster/shaders/raster_vert.glsl b/packages/layers/src/raster/shaders/raster_vert.glsl index 486b2394cd..f2e93eae62 100644 --- a/packages/layers/src/raster/shaders/raster_vert.glsl +++ b/packages/layers/src/raster/shaders/raster_vert.glsl @@ -35,6 +35,6 @@ void main() { // vec2 range = u_extent.zw - u_extent.xy; // vec4 project_pos = project_position(vec4(pos, 0, 1.0)); - gl_Position = project_common_position_to_clipspace(vec4(pos.xy, project_scale(value) * 50., 1.0)); + gl_Position = project_common_position_to_clipspace(vec4(pos.xy, project_scale(value) * 10., 1.0)); } From 591f19dad8fdda71120d0952577c091107e9f240 Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Mon, 4 Nov 2019 13:41:09 +0800 Subject: [PATCH 6/6] fix(travis): travis nodejs version --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0e18395982..26f13a34b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,10 @@ sudo: false language: node_js node_js: -- '8' +- '12' branches: only: - next script: - yarn test -- yarn coveralls \ No newline at end of file +- yarn coveralls