From 3da2676b0e6807d1ebccdab3b8c672d3ef4f2b5a Mon Sep 17 00:00:00 2001 From: 2912401452 <2912401452@qq.com> Date: Sat, 18 Sep 2021 16:02:27 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A1=A5=E5=85=A8=E9=AB=98=E5=BE=B7?= =?UTF-8?q?=E5=9C=B0=E5=9B=BE=202.0=20=E7=9A=84=E6=A8=A1=E5=9E=8B=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E8=83=BD=E5=8A=9B=EF=BC=8C=E5=A2=9E=E5=8A=A0=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E7=9A=84=E7=BB=8F=E7=BA=AC=E5=BA=A6=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/maps/src/amap/map.ts | 6 ++ packages/maps/src/amap2/map.ts | 6 +- packages/maps/src/mapbox/map.ts | 12 +++ packages/three/src/core/IThreeJSLayer.ts | 33 +++++++++ packages/three/src/core/baseLayer.ts | 60 ++++++++++++--- packages/three/src/index.ts | 7 +- stories/3D_Model/Components/amap2_three.tsx | 77 ++++++++++++-------- stories/3D_Model/Components/amap_three.tsx | 28 ++++++- stories/3D_Model/Components/mapbox_three.tsx | 19 ++++- 9 files changed, 198 insertions(+), 50 deletions(-) create mode 100644 packages/three/src/core/IThreeJSLayer.ts diff --git a/packages/maps/src/amap/map.ts b/packages/maps/src/amap/map.ts index 4cc64e9a16..68b59e357f 100644 --- a/packages/maps/src/amap/map.ts +++ b/packages/maps/src/amap/map.ts @@ -275,6 +275,12 @@ export default class AMapService }; } + public lngLatToCoord(lnglat: [number, number]): any { + // @ts-ignore + let { x, y } = this.map.lngLatToGeodeticCoord(lnglat) + return [x, -y] + } + public lngLatToMercator( lnglat: [number, number], altitude: number, diff --git a/packages/maps/src/amap2/map.ts b/packages/maps/src/amap2/map.ts index 547b1914ec..f9155490e3 100644 --- a/packages/maps/src/amap2/map.ts +++ b/packages/maps/src/amap2/map.ts @@ -370,7 +370,10 @@ export default class AMapService scale: [number, number, number] = [1, 1, 1], origin: IMercator = { x: 0, y: 0, z: 0 }, ): number[] { - const flat = this.viewport.projectFlat(lnglat); + + // const flat = this.viewport.projectFlat(lnglat); + // @ts-ignore + const flat = this.map.customCoords.lngLatToCoord(lnglat) // @ts-ignore const modelMatrix = mat4.create(); @@ -379,6 +382,7 @@ export default class AMapService modelMatrix, vec3.fromValues(flat[0], flat[1], altitude), ); + mat4.scale( modelMatrix, modelMatrix, diff --git a/packages/maps/src/mapbox/map.ts b/packages/maps/src/mapbox/map.ts index 3073ac8c35..7acae87b6f 100644 --- a/packages/maps/src/mapbox/map.ts +++ b/packages/maps/src/mapbox/map.ts @@ -236,6 +236,18 @@ export default class MapboxService public lngLatToContainer(lnglat: [number, number]): IPoint { return this.map.project(lnglat); } + + /** + * 将经纬度转成墨卡托坐标 + * @param lnglat + * @returns + */ + public lngLatToCoord(lnglat: [number, number]) { + // @ts-ignore + let { x, y } = this.lngLatToMercator(lnglat, 0); + return [x, y] as [number, number]; + } + public lngLatToMercator( lnglat: [number, number], altitude: number, diff --git a/packages/three/src/core/IThreeJSLayer.ts b/packages/three/src/core/IThreeJSLayer.ts new file mode 100644 index 0000000000..a0bbca5b48 --- /dev/null +++ b/packages/three/src/core/IThreeJSLayer.ts @@ -0,0 +1,33 @@ +import { ILayer } from '@antv/l7'; +import { + AnimationMixer, + Matrix4, + Object3D + } from 'three'; + +export type ILngLat = [number, number] + +export interface IThreeJSLayer extends ILayer { + // 获取对应地图的经纬度模型矩阵 + getModelMatrix( + lnglat: ILngLat, + altitude: number, + rotation: [number, number, number], + scale: [number, number, number], + ): Matrix4; + + // 获取对应地图的经纬度平移矩阵 + getTranslateMatrix(lnglat: ILngLat, altitude?: number): Matrix4; + + // 设置模型对应地图在经纬度和高度方向的平移 + setObjectLngLat(object: Object3D, lnglat: ILngLat, altitude?: number): void; + + // 根据经纬度设置模型对应地图的平移 + setObjectLngLat(object: Object3D, lnglat: ILngLat, altitude?: number): void; + + // 返回物体在场景中的经纬度 + getObjectLngLat(object: Object3D): ILngLat; + + // 增加加载模型的动画混合器 + addAnimateMixer(mixer: AnimationMixer): void; +} \ No newline at end of file diff --git a/packages/three/src/core/baseLayer.ts b/packages/three/src/core/baseLayer.ts index 6bbc36b7d7..757df65af3 100644 --- a/packages/three/src/core/baseLayer.ts +++ b/packages/three/src/core/baseLayer.ts @@ -7,21 +7,14 @@ import { PerspectiveCamera, Scene, WebGLRenderer, + Object3D } from 'three'; import { IThreeRenderService, ThreeRenderServiceType, } from './threeRenderService'; +import { IThreeJSLayer, ILngLat } from './IThreeJSLayer' const DEG2RAD = Math.PI / 180; -interface IThreeJSLayer extends ILayer { - getModelMatrix( - lnglat: [number, number], - altitude: number, - rotation: [number, number, number], - scale: [number, number, number], - ): Matrix4; - addAnimateMixer(mixer: AnimationMixer): void; -} export default class ThreeJSLayer extends BaseLayer<{ onAddMeshes: (threeScene: Scene, layer: ThreeJSLayer) => void; @@ -36,10 +29,9 @@ export default class ThreeJSLayer // 地图中点墨卡托坐标 private center: IMercator; - // 初始状态相机变换矩阵 /** - * 根据模型 + * 根据数据计算对应地图的模型矩阵 不同地图主要是点位偏移不同 */ public getModelMatrix( lnglat: [number, number], @@ -58,7 +50,53 @@ export default class ThreeJSLayer ); } + /** + * 获取平移矩阵 + * @param lnglat + * @param altitude + * @returns + */ + public getTranslateMatrix( lnglat: ILngLat, altitude: number = 0,) { + return this.getModelMatrix( lnglat, altitude, [0, 0, 0], [1, 1, 1] ) + } + + /** + * 设置当前物体往经纬度和高度方向的移动 + * @param object + * @param lnglat + * @param altitude + */ + public applyObjectLngLat(object: Object3D, lnglat: ILngLat, altitude = 0) { + let positionMatrix = this.getTranslateMatrix(lnglat, altitude) + object.applyMatrix4(positionMatrix) + } + + /** + * 设置物体当前的经纬度和高度 + * @param object + * @param lnglat + * @param altitude + */ + public setObjectLngLat(object: Object3D, lnglat: ILngLat, altitude = 0) { + // @ts-ignore + let [x, y] = this.mapService?.lngLatToCoord(lnglat) + // @ts-ignore + // console.log(this.mapService?.lngLatToCoord(lnglat)) + // if(x && y) { + // console.log('------') + object.position.set(x, y, altitude) + // } + } + + public getObjectLngLat(object: Object3D) { + // let coord = [object.position.x, object.position.y]; + // // @ts-ignore + // return this.mapService.coordToLngLat(coord); + return [0,0] as ILngLat + } + public buildModels() { + // @ts-ignore this.threeRenderService = this.getContainer().get( ThreeRenderServiceType, ); diff --git a/packages/three/src/index.ts b/packages/three/src/index.ts index eeb2447453..8ac01a9c8d 100644 --- a/packages/three/src/index.ts +++ b/packages/three/src/index.ts @@ -1,3 +1,8 @@ import ThreeLayer from './core/baseLayer'; import ThreeRender from './core/threeRender'; -export { ThreeLayer, ThreeRender }; +import { IThreeJSLayer, ILngLat } from './core/IThreeJSLayer'; +import { + + Object3D + } from 'three'; +export { ThreeLayer, ThreeRender, IThreeJSLayer, ILngLat, Object3D }; diff --git a/stories/3D_Model/Components/amap2_three.tsx b/stories/3D_Model/Components/amap2_three.tsx index bb55abd1a2..efe34cdc8f 100644 --- a/stories/3D_Model/Components/amap2_three.tsx +++ b/stories/3D_Model/Components/amap2_three.tsx @@ -1,6 +1,6 @@ import { Scene } from '@antv/l7'; import { GaodeMap, GaodeMapV2, Mapbox } from '@antv/l7-maps'; -import { ThreeLayer, ThreeRender } from '@antv/l7-three'; +import { ThreeLayer, ThreeRender, ILngLat, Object3D } from '@antv/l7-three'; import * as React from 'react'; // import { DirectionalLight, Scene as ThreeScene } from 'three'; import * as THREE from 'three'; @@ -27,7 +27,7 @@ export default class GlTFThreeJSDemo extends React.Component { center: [111.4453125, 32.84267363195431], pitch: 45, rotation: 30, - zoom: 15, + zoom: 13, }), }); this.scene = scene; @@ -37,10 +37,21 @@ export default class GlTFThreeJSDemo extends React.Component { enableMultiPassRenderer: false, onAddMeshes: (threeScene: THREE.Scene, layer: ThreeLayer) => { threeScene.add(new THREE.AmbientLight(0xffffff)); + const sunlight = new THREE.DirectionalLight(0xffffff, 0.25); sunlight.position.set(0, 80000000, 100000000); sunlight.matrixWorldNeedsUpdate = true; threeScene.add(sunlight); + + // threeScene.applyMatrix4( + // layer.getModelMatrix( + // [111.4453125, 32.84267363195431], // 经纬度坐标 + // 0, // 高度,单位米/ + // [Math.PI / 2, -Math.PI, 0], // 沿 XYZ 轴旋转角度 + // [100, 100, 100], // 沿 XYZ 轴缩放比例 + // ), + // ) + // 使用 Three.js glTFLoader 加载模型 const loader = new GLTFLoader(); loader.load( @@ -52,37 +63,22 @@ export default class GlTFThreeJSDemo extends React.Component { // 'https://gw.alipayobjects.com/os/antvdemo/assets/gltf/man/CesiumMan.gltf', 'https://gw.alipayobjects.com/os/bmw-prod/3ca0a546-92d8-4ba0-a89c-017c218d5bea.gltf', (gltf) => { - // console.log(gltf) - const gltfScene = gltf.scene; - // gltfScene.rotation.set(90, 90, 0) + const model: Object3D = gltf.scene; + layer.getSource().data.dataArray.forEach(({ coordinates }) => { - const gltfScene = gltf.scene; - - gltfScene.scale.set(10, 10, 10); - // gltfScene.applyMatrix4( - // // 生成模型矩阵 - // layer.getModelMatrix( - // [coordinates[0], coordinates[1]], // 经纬度坐标 - // 0, // 高度,单位米/ - // [Math.PI / 2, -Math.PI, 0], // 沿 XYZ 轴旋转角度 - // [100, 100, 100], // 沿 XYZ 轴缩放比例 - // ), - // ); - - // gltfScene.applyMatrix4( - // // 生成模型矩阵 - // layer.getModelMatrix( - // // [coordinates[0], coordinates[1]], // 经纬度坐标 - // [0, 0], // 经纬度坐标 - // 0, // 高度,单位米/ - // [Math.PI / 2, -Math.PI, 0], // 沿 XYZ 轴旋转角度 - // [10000, 10000, 10000], // 沿 XYZ 轴缩放比例 - // ), - // ); + model.applyMatrix4( + // 生成模型矩阵 + layer.getModelMatrix( + [coordinates[0], coordinates[1]], // 经纬度坐标 + 0, // 高度,单位米/ + [Math.PI / 2, -Math.PI, 0], // 沿 XYZ 轴旋转角度 + [100, 100, 100], // 沿 XYZ 轴缩放比例 + ), + ); const animations = gltf.animations; if (animations && animations.length) { - const mixer = new THREE.AnimationMixer(gltfScene); + const mixer = new THREE.AnimationMixer(model); // @ts-ignore // for (let i = 0; i < 1; i++) { const animation = animations[2]; @@ -97,11 +93,27 @@ export default class GlTFThreeJSDemo extends React.Component { layer.addAnimateMixer(mixer); } - // 向场景中添加模型 - // threeScene.add(gltfScene); }); + // 向场景中添加模型 + threeScene.add(model); + + let lnglat = [121.107, 30.267069] as [number, number] + let altitude = 0 + let center = scene.getCenter() + // layer.setObjectLngLat(model, lnglat, altitude) + // console.log() + // layer.setObjectLngLat(model, [center.lng + 0.05, center.lat] as ILngLat, 0) + // layer.setObjectLngLat(model, [center.lng + 0.05, center.lat] as ILngLat, 0) + + layer.setObjectLngLat(model, [center.lng + 0.05, center.lat] as ILngLat, 0) + + let t = 0 + setInterval(() => { + t += 0.01 + layer.setObjectLngLat(model, [center.lng, center.lat + Math.sin(t) * 0.1] as ILngLat, 0) + // layer.setObjectLngLat(model, [center.lng + 0.2, center.lat], 0) + }, 16) - threeScene.add(gltfScene); // 重绘图层 layer.render(); }, @@ -117,6 +129,7 @@ export default class GlTFThreeJSDemo extends React.Component { geometry: { type: 'Point', coordinates: [111.4453125, 32.84267363195431], + // coordinates: [121.107, 30.267069], // 该坐标点在钱塘江入海口附近 }, }, ], diff --git a/stories/3D_Model/Components/amap_three.tsx b/stories/3D_Model/Components/amap_three.tsx index c63957acd3..9940b04bca 100644 --- a/stories/3D_Model/Components/amap_three.tsx +++ b/stories/3D_Model/Components/amap_three.tsx @@ -1,6 +1,6 @@ import { Scene } from '@antv/l7'; import { GaodeMap, Mapbox } from '@antv/l7-maps'; -import { ThreeLayer, ThreeRender } from '@antv/l7-three'; +import { ThreeLayer, ThreeRender, ILngLat } from '@antv/l7-three'; import * as React from 'react'; // import { DirectionalLight, Scene as ThreeScene } from 'three'; import * as THREE from 'three'; @@ -41,6 +41,16 @@ export default class GlTFThreeJSDemo extends React.Component { sunlight.position.set(0, 80000000, 100000000); sunlight.matrixWorldNeedsUpdate = true; threeScene.add(sunlight); + + + // threeScene.applyMatrix4( + // layer.getModelMatrix( + // [111.4453125, 32.84267363195431], // 经纬度坐标 + // 0, // 高度,单位米/ + // [Math.PI / 2, -Math.PI, 0], // 沿 XYZ 轴旋转角度 + // [1, 1, 1], // 沿 XYZ 轴缩放比例 + // ), + // ) // 使用 Three.js glTFLoader 加载模型 const loader = new GLTFLoader(); loader.load( @@ -61,7 +71,7 @@ export default class GlTFThreeJSDemo extends React.Component { [coordinates[0], coordinates[1]], // 经纬度坐标 0, // 高度,单位米/ [Math.PI / 2, -Math.PI, 0], // 沿 XYZ 轴旋转角度 - [100, 100, 100], // 沿 XYZ 轴缩放比例 + [1000, 1000, 1000], // 沿 XYZ 轴缩放比例 ), ); const animations = gltf.animations; @@ -80,6 +90,18 @@ export default class GlTFThreeJSDemo extends React.Component { // } layer.addAnimateMixer(mixer); } + // console.log(gltfScene.position) + let center = scene.getCenter() + console.log(center) + console.log(layer.getObjectLngLat(gltfScene)) + // layer.setObjectLngLat(gltfScene, [center.lng + 0.05, center.lat] as ILngLat, 0) + // layer.setObjectLngLat(gltfScene, [center.lng, center.lat] as ILngLat, 0) + let t = 0 + setInterval(() => { + t += 0.01 + layer.setObjectLngLat(gltfScene, [center.lng, center.lat + Math.sin(t) * 0.1] as ILngLat, 0) + // layer.setObjectLngLat(model, [center.lng + 0.2, center.lat], 0) + }, 16) // 向场景中添加模型 threeScene.add(gltfScene); @@ -98,7 +120,7 @@ export default class GlTFThreeJSDemo extends React.Component { properties: {}, geometry: { type: 'Point', - coordinates: [111.4453125, 32.84267363195431], + coordinates: [111.4453125, 32.84267363195431] }, }, ], diff --git a/stories/3D_Model/Components/mapbox_three.tsx b/stories/3D_Model/Components/mapbox_three.tsx index 5d07990def..9f217da74e 100644 --- a/stories/3D_Model/Components/mapbox_three.tsx +++ b/stories/3D_Model/Components/mapbox_three.tsx @@ -1,6 +1,6 @@ import { PolygonLayer, Scene } from '@antv/l7'; import { GaodeMap, Mapbox } from '@antv/l7-maps'; -import { ThreeLayer, ThreeRender } from '@antv/l7-three'; +import { ThreeLayer, ThreeRender, ILngLat } from '@antv/l7-three'; import * as React from 'react'; // import { DirectionalLight, Scene as ThreeScene } from 'three'; import * as THREE from 'three'; @@ -73,8 +73,9 @@ export default class GlTFThreeJSDemo extends React.Component { // 'https://gw.alipayobjects.com/os/bmw-prod/3ca0a546-92d8-4ba0-a89c-017c218d5bea.gltf', (gltf) => { // 根据 GeoJSON 数据放置模型 + const gltfScene = gltf.scene.clone(); layer.getSource().data.dataArray.forEach(({ coordinates }) => { - const gltfScene = gltf.scene.clone(); + gltfScene.applyMatrix4( // 生成模型矩阵 layer.getModelMatrix( @@ -105,6 +106,20 @@ export default class GlTFThreeJSDemo extends React.Component { // 向场景中添加模型 threeScene.add(gltfScene); }); + + let center = scene.getCenter() + console.log(center) + console.log(layer.getObjectLngLat(gltfScene)) + // layer.setObjectLngLat(gltfScene, [center.lng + 0.05, center.lat] as ILngLat, 0) + + // let t = 0 + // setInterval(() => { + // t += 0.01 + // layer.setObjectLngLat(gltfScene, [center.lng, center.lat + Math.sin(t) * 0.1] as ILngLat, 0) + // // layer.setObjectLngLat(model, [center.lng + 0.2, center.lat], 0) + // }, 16) + + // 重绘图层 layer.render(); },