mirror of https://gitee.com/antv-l7/antv-l7
Shihui (#1019)
* feat: planeGeometry 支持地形(地形贴图偏移) * style: lint style * feat: 增加 terrain clip * style: lint sytle * style: lint style
This commit is contained in:
parent
5746ad3227
commit
23595672c1
|
@ -5,6 +5,7 @@ import {
|
|||
IModelUniform,
|
||||
ITexture2D,
|
||||
} from '@antv/l7-core';
|
||||
import { Version } from '@antv/l7-maps';
|
||||
import { getMask, isMini } from '@antv/l7-utils';
|
||||
// import { mat4, vec3 } from 'gl-matrix';
|
||||
import BaseModel from '../../core/BaseModel';
|
||||
|
@ -12,7 +13,13 @@ import { IGeometryLayerStyleOptions } from '../../core/interface';
|
|||
import planeFrag from '../shaders/plane_frag.glsl';
|
||||
import planeVert from '../shaders/plane_vert.glsl';
|
||||
|
||||
function initPlane(
|
||||
export default class PlaneModel extends BaseModel {
|
||||
protected texture: ITexture2D;
|
||||
protected mapTexture: string | undefined;
|
||||
protected positions: number[];
|
||||
protected indices: number[];
|
||||
|
||||
public initPlane(
|
||||
width = 1,
|
||||
height = 1,
|
||||
widthSegments = 1,
|
||||
|
@ -41,8 +48,16 @@ function initPlane(
|
|||
|
||||
for (let ix = 0; ix < gridX1; ix++) {
|
||||
const x = ix * segmentWidth - widthHalf;
|
||||
|
||||
if (this.mapService.version === Version['GAODE2.x']) {
|
||||
// @ts-ignore
|
||||
const [a, b] = this.mapService.lngLatToCoord([x + lng, -y + lat]) as [
|
||||
number,
|
||||
number,
|
||||
];
|
||||
positions.push(a, b, 0);
|
||||
} else {
|
||||
positions.push(x + lng, -y + lat, 0);
|
||||
}
|
||||
|
||||
positions.push(ix / gridX);
|
||||
positions.push(1 - iy / gridY);
|
||||
|
@ -64,9 +79,6 @@ function initPlane(
|
|||
return { indices, positions };
|
||||
}
|
||||
|
||||
export default class PlaneModel extends BaseModel {
|
||||
protected texture: ITexture2D;
|
||||
protected mapTexture: string | undefined;
|
||||
public planeGeometryTriangulation = () => {
|
||||
const {
|
||||
width = 1,
|
||||
|
@ -74,25 +86,44 @@ export default class PlaneModel extends BaseModel {
|
|||
widthSegments = 1,
|
||||
heightSegments = 1,
|
||||
center = [120, 30],
|
||||
terrainTexture,
|
||||
} = this.layer.getLayerConfig() as IGeometryLayerStyleOptions;
|
||||
const { indices, positions } = initPlane(
|
||||
|
||||
const { indices, positions } = this.initPlane(
|
||||
width,
|
||||
height,
|
||||
widthSegments,
|
||||
heightSegments,
|
||||
...center,
|
||||
);
|
||||
this.positions = positions;
|
||||
this.indices = indices;
|
||||
|
||||
if (terrainTexture) {
|
||||
// 存在地形贴图的时候会根据地形贴图对顶点进行偏移
|
||||
this.loadTerrainTexture();
|
||||
}
|
||||
|
||||
return {
|
||||
vertices: positions,
|
||||
indices,
|
||||
size: 5,
|
||||
};
|
||||
};
|
||||
public planeGeometryUpdateTriangulation = () => {
|
||||
return {
|
||||
vertices: this.positions,
|
||||
indices: this.indices,
|
||||
size: 5,
|
||||
};
|
||||
};
|
||||
|
||||
public getUninforms(): IModelUniform {
|
||||
const {
|
||||
opacity,
|
||||
mapTexture,
|
||||
terrainClipHeight = 0,
|
||||
terrainTexture,
|
||||
} = this.layer.getLayerConfig() as IGeometryLayerStyleOptions;
|
||||
if (this.mapTexture !== mapTexture) {
|
||||
this.mapTexture = mapTexture;
|
||||
|
@ -102,7 +133,7 @@ export default class PlaneModel extends BaseModel {
|
|||
return {
|
||||
u_opacity: opacity || 1,
|
||||
u_mapFlag: mapTexture ? 1 : 0,
|
||||
|
||||
u_terrainClipHeight: terrainTexture ? terrainClipHeight : -1,
|
||||
u_texture: this.texture,
|
||||
// u_ModelMatrix: mat4.translate(mat4.create(), mat4.create(), [1, 0, 0])
|
||||
// u_ModelMatrix: mat4.rotateZ(mat4.create(), mat4.create(), 10)
|
||||
|
@ -111,17 +142,6 @@ export default class PlaneModel extends BaseModel {
|
|||
};
|
||||
}
|
||||
|
||||
// public rotateZ(): mat4 {
|
||||
// const res = mat4.create()
|
||||
// const roZero = mat4.translate(mat4.create(), mat4.create(), [-120, 0, -30])
|
||||
// const rotate = mat4.rotateZ(mat4.create(), mat4.create(), 10)
|
||||
// const roOrigin = mat4.translate(mat4.create(), mat4.create(), [120, 0, 30])
|
||||
// mat4.multiply(res, res, roZero)
|
||||
// mat4.multiply(res, res, rotate)
|
||||
// mat4.multiply(res, res, roOrigin)
|
||||
// return res
|
||||
// }
|
||||
|
||||
public clearModels(): void {
|
||||
this.texture.destroy();
|
||||
}
|
||||
|
@ -149,13 +169,89 @@ export default class PlaneModel extends BaseModel {
|
|||
fragmentShader: planeFrag,
|
||||
triangulation: this.planeGeometryTriangulation,
|
||||
primitive: gl.TRIANGLES,
|
||||
// primitive: gl.POINTS,
|
||||
depth: { enable: false },
|
||||
depth: { enable: true },
|
||||
blend: this.getBlend(),
|
||||
stencil: getMask(mask, maskInside),
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
public getImageData(img: HTMLImageElement) {
|
||||
const canvas: HTMLCanvasElement = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
|
||||
const { width, height } = img;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
ctx.drawImage(img, 0, 0, width, height);
|
||||
const imageData = ctx.getImageData(0, 0, width, height);
|
||||
|
||||
return imageData;
|
||||
}
|
||||
|
||||
/**
|
||||
* load terrain texture & offset attribute z
|
||||
*/
|
||||
public loadTerrainTexture(): void {
|
||||
const {
|
||||
mask = false,
|
||||
maskInside = true,
|
||||
widthSegments = 1,
|
||||
heightSegments = 1,
|
||||
terrainTexture,
|
||||
rgb2height = (r: number, g: number, b: number) => r + g + b,
|
||||
} = this.layer.getLayerConfig() as IGeometryLayerStyleOptions;
|
||||
const terrainImage = new Image();
|
||||
terrainImage.crossOrigin = 'anonymous';
|
||||
terrainImage.onload = () => {
|
||||
const imgWidth = terrainImage.width;
|
||||
const imgHeight = terrainImage.height;
|
||||
|
||||
const imageData = this.getImageData(terrainImage).data;
|
||||
|
||||
const gridX = Math.floor(widthSegments);
|
||||
const gridY = Math.floor(heightSegments);
|
||||
|
||||
const gridX1 = gridX + 1;
|
||||
const gridY1 = gridY + 1;
|
||||
|
||||
const widthStep = imgWidth / gridX;
|
||||
const heihgtStep = imgHeight / gridY;
|
||||
|
||||
for (let iy = 0; iy < gridY1; iy++) {
|
||||
const imgIndexY = Math.floor(iy * heihgtStep);
|
||||
const imgLen = imgIndexY * imgWidth;
|
||||
|
||||
for (let ix = 0; ix < gridX1; ix++) {
|
||||
const imgIndexX = Math.floor(ix * widthStep);
|
||||
const imgDataIndex = (imgLen + imgIndexX) * 4;
|
||||
|
||||
const r = imageData[imgDataIndex];
|
||||
const g = imageData[imgDataIndex + 1];
|
||||
const b = imageData[imgDataIndex + 2];
|
||||
|
||||
const z = (iy * gridX1 + ix) * 5 + 2;
|
||||
this.positions[z] = rgb2height(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
this.layer.models = [
|
||||
this.layer.buildLayerModel({
|
||||
moduleName: 'geometry_plane',
|
||||
vertexShader: planeVert,
|
||||
fragmentShader: planeFrag,
|
||||
triangulation: this.planeGeometryUpdateTriangulation,
|
||||
primitive: gl.TRIANGLES,
|
||||
depth: { enable: true },
|
||||
blend: this.getBlend(),
|
||||
stencil: getMask(mask, maskInside),
|
||||
}),
|
||||
];
|
||||
this.layerService.renderLayers();
|
||||
};
|
||||
terrainImage.src = terrainTexture as string;
|
||||
}
|
||||
|
||||
public buildModels() {
|
||||
return this.initModels();
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ uniform float u_opacity;
|
|||
|
||||
varying vec3 v_Color;
|
||||
varying vec2 v_uv;
|
||||
varying float v_clip;
|
||||
|
||||
#pragma include "picking"
|
||||
void main() {
|
||||
|
@ -12,10 +13,10 @@ void main() {
|
|||
if(u_mapFlag > 0.0) {
|
||||
gl_FragColor = texture2D(u_texture, vec2(v_uv.x, 1.0 - v_uv.y));
|
||||
gl_FragColor.a *= u_opacity;
|
||||
|
||||
} else {
|
||||
// gl_FragColor = vec4(v_uv, 0.0, u_opacity);
|
||||
gl_FragColor = vec4(v_Color, u_opacity);
|
||||
}
|
||||
gl_FragColor.a *= v_clip;
|
||||
gl_FragColor = filterColor(gl_FragColor);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ precision highp float;
|
|||
uniform mat4 u_ModelMatrix;
|
||||
|
||||
uniform mat4 u_Mvp;
|
||||
uniform float u_opacity;
|
||||
uniform float u_terrainClipHeight;
|
||||
|
||||
attribute vec3 a_Position;
|
||||
attribute vec2 a_Uv;
|
||||
|
@ -9,6 +11,7 @@ attribute vec3 a_Color;
|
|||
|
||||
varying vec3 v_Color;
|
||||
varying vec2 v_uv;
|
||||
varying float v_clip;
|
||||
|
||||
#pragma include "projection"
|
||||
#pragma include "picking"
|
||||
|
@ -17,6 +20,12 @@ void main() {
|
|||
v_uv = a_Uv;
|
||||
|
||||
vec4 project_pos = project_position(vec4(a_Position, 1.0));
|
||||
|
||||
v_clip = 1.0;
|
||||
if(a_Position.z < u_terrainClipHeight) {
|
||||
v_clip = 0.0;
|
||||
}
|
||||
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy,0., 1.0));
|
||||
|
||||
// float x = 1.0;
|
||||
|
@ -35,12 +44,10 @@ void main() {
|
|||
// );
|
||||
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
gl_Position = u_Mvp * (vec4(project_pos.xy, 0., 1.0));
|
||||
gl_Position = u_Mvp * (vec4(project_pos.xy, a_Position.z, 1.0));
|
||||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy, 0., 1.0));
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy, a_Position.z, 1.0));
|
||||
}
|
||||
|
||||
setPickingColor(a_PickingColor);
|
||||
|
||||
gl_PointSize = 10.0;
|
||||
}
|
||||
|
|
|
@ -106,6 +106,7 @@ export interface IGeometryLayerStyleOptions {
|
|||
maskInside?: boolean;
|
||||
|
||||
mapTexture?: string;
|
||||
terrainTexture?: string;
|
||||
|
||||
// planeGeometry
|
||||
center?: [number, number];
|
||||
|
@ -114,6 +115,9 @@ export interface IGeometryLayerStyleOptions {
|
|||
|
||||
widthSegments?: number;
|
||||
heightSegments?: number;
|
||||
|
||||
terrainClipHeight?: number;
|
||||
rgb2height?: (r: number, g: number, b: number) => number;
|
||||
}
|
||||
|
||||
export enum CanvasUpdateType {
|
||||
|
|
|
@ -180,7 +180,7 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
|||
// TODO: 避免经纬度被重复计算导致坐标位置偏移
|
||||
.filter((d) => !d.originCoordinates)
|
||||
.map((d) => {
|
||||
d.version = 'GAODE2.x';
|
||||
d.version = Version['GAODE2.x'];
|
||||
// @ts-ignore
|
||||
d.originCoordinates = cloneDeep(d.coordinates); // 为了兼容高德1.x 需要保存一份原始的经纬度坐标数据(许多上层逻辑依赖经纬度数据)
|
||||
// @ts-ignore
|
||||
|
@ -193,7 +193,7 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
|||
// TODO: 避免经纬度被重复计算导致坐标位置偏移
|
||||
.filter((d) => !d.originCoordinates)
|
||||
.map((d) => {
|
||||
d.version = 'GAODE2.x';
|
||||
d.version = Version['GAODE2.x'];
|
||||
// @ts-ignore
|
||||
d.originCoordinates = cloneDeep(d.coordinates); // 为了兼容高德1.x 需要保存一份原始的经纬度坐标数据(许多上层逻辑依赖经纬度数据)
|
||||
// @ts-ignore
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { GeometryLayer, Scene, IMapService } from '@antv/l7';
|
||||
import { GaodeMap, Mapbox } from '@antv/l7-maps';
|
||||
import { GaodeMap, GaodeMapV2, Mapbox } from '@antv/l7-maps';
|
||||
import * as React from 'react';
|
||||
|
||||
export default class Demo extends React.Component {
|
||||
|
@ -13,7 +13,8 @@ export default class Demo extends React.Component {
|
|||
public async componentDidMount() {
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
// map: new GaodeMap({
|
||||
map: new GaodeMapV2({
|
||||
// map: new Mapbox({
|
||||
pitch: 0,
|
||||
// style: 'dark',
|
||||
|
@ -49,16 +50,16 @@ export default class Demo extends React.Component {
|
|||
scene.on('loaded', () => {
|
||||
scene.addLayer(layer);
|
||||
|
||||
setTimeout(() => {
|
||||
// setTimeout(() => {
|
||||
// // layer.style({
|
||||
// // mapTexture: ""
|
||||
// // })
|
||||
// layer.style({
|
||||
// mapTexture: ""
|
||||
// })
|
||||
layer.style({
|
||||
mapTexture:
|
||||
'https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*GJhASbfQTK8AAAAAAAAAAAAAARQnAQ',
|
||||
});
|
||||
scene.render();
|
||||
}, 2000);
|
||||
// mapTexture:
|
||||
// 'https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*GJhASbfQTK8AAAAAAAAAAAAAARQnAQ',
|
||||
// });
|
||||
// scene.render();
|
||||
// }, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
import { GeometryLayer, Scene, IMapService } from '@antv/l7';
|
||||
import { GaodeMap, Mapbox, GaodeMapV2 } from '@antv/l7-maps';
|
||||
import * as React from 'react';
|
||||
|
||||
export default class Demo extends React.Component {
|
||||
// @ts-ignore
|
||||
private scene: Scene;
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.scene.destroy();
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
// map: new GaodeMapV2({
|
||||
// map: new Mapbox({
|
||||
pitch: 60,
|
||||
center: [120.1025, 30.2594],
|
||||
rotation: 220,
|
||||
zoom: 14,
|
||||
}),
|
||||
});
|
||||
this.scene = scene;
|
||||
|
||||
let layer = new GeometryLayer()
|
||||
.style({
|
||||
width: 0.074,
|
||||
height: 0.061,
|
||||
center: [120.1025, 30.2594],
|
||||
widthSegments: 200,
|
||||
heightSegments: 200,
|
||||
terrainClipHeight: 1,
|
||||
mapTexture:
|
||||
'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*gA0NRbuOF5cAAAAAAAAAAAAAARQnAQ',
|
||||
terrainTexture:
|
||||
'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*eYFaRYlnnOUAAAAAAAAAAAAAARQnAQ',
|
||||
rgb2height: (r: number, g: number, b: number) => {
|
||||
let h =
|
||||
-10000.0 +
|
||||
(r * 255.0 * 256.0 * 256.0 + g * 255.0 * 256.0 + b * 255.0) * 0.1;
|
||||
h = h / 20 - 127600;
|
||||
h = Math.max(0, h);
|
||||
return h;
|
||||
},
|
||||
})
|
||||
.color('#ff0');
|
||||
|
||||
scene.on('loaded', () => {
|
||||
scene.addLayer(layer);
|
||||
// setTimeout(() => {
|
||||
// // layer.style({
|
||||
// // mapTexture: ""
|
||||
// // })
|
||||
// layer.style({
|
||||
// mapTexture:
|
||||
// 'https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*GJhASbfQTK8AAAAAAAAAAAAAARQnAQ',
|
||||
// });
|
||||
// scene.render();
|
||||
// }, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import Taifong from './components/taifeng'
|
|||
import Radar from './components/radar';
|
||||
import CanvasDemo from './components/canvas';
|
||||
import Plane from './components/plane';
|
||||
import PlaneTerrain from './components/planeTerrain';
|
||||
|
||||
storiesOf('Object', module)
|
||||
.add('water', () => <Water />)
|
||||
|
@ -14,3 +15,4 @@ storiesOf('Object', module)
|
|||
.add('Radar', () => <Radar/>)
|
||||
.add('CanvasDemo', () => <CanvasDemo/>)
|
||||
.add('Plane', () => <Plane/>)
|
||||
.add('PlaneTerrain', () => <PlaneTerrain/>)
|
Loading…
Reference in New Issue