From 1a161121ffa7c4d4a1c3e7f3deab5ddc3377b728 Mon Sep 17 00:00:00 2001 From: 2912401452 <2912401452@qq.com> Date: Fri, 17 Sep 2021 17:19:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20gaodemap2=20=E5=AF=B9=E9=BD=90=E7=9B=B8?= =?UTF-8?q?=E6=9C=BA=EF=BC=88=E8=A7=86=E5=9B=BE=E3=80=81=E6=8A=95=E5=BD=B1?= =?UTF-8?q?=E7=9F=A9=E9=98=B5=EF=BC=89=20-=20=E5=B0=9A=E6=9C=AA=E5=AF=B9?= =?UTF-8?q?=E9=BD=90=E6=A8=A1=E5=9E=8B=E7=9F=A9=E9=98=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/three/src/core/baseLayer.ts | 8 + packages/three/src/core/threeRenderService.ts | 62 +++++++- stories/3D_Model/Components/amap2_three.tsx | 143 ++++++++++++++++++ stories/3D_Model/Components/threeRender.tsx | 1 - stories/3D_Model/model.stories.tsx | 2 + 5 files changed, 211 insertions(+), 5 deletions(-) create mode 100644 stories/3D_Model/Components/amap2_three.tsx diff --git a/packages/three/src/core/baseLayer.ts b/packages/three/src/core/baseLayer.ts index 53bdbedd30..6bbc36b7d7 100644 --- a/packages/three/src/core/baseLayer.ts +++ b/packages/three/src/core/baseLayer.ts @@ -29,6 +29,7 @@ export default class ThreeJSLayer implements IThreeJSLayer { public type: string = 'custom'; protected threeRenderService: IThreeRenderService; + // 构建 threejs 的 scene private scene: Scene = new Scene(); private renderer: WebGLRenderer; private animateMixer: AnimationMixer[] = []; @@ -67,16 +68,23 @@ export default class ThreeJSLayer } } public renderModels() { + // 获取到 L7 的 gl const gl = this.rendererService.getGLContext(); this.rendererService.setCustomLayerDefaults(); const cullFace = this.mapService.constructor.name === 'AMapService' ? gl.BACK : gl.FRONT; gl.cullFace(cullFace); + + // threejs 的 renderer const renderer = this.threeRenderService.renderer; renderer.state.reset(); renderer.autoClear = false; + + // 获取相机 (不同的地图获取对应的方式不同) const camera = this.threeRenderService.getRenderCamera(); + renderer.render(this.scene, camera); + this.rendererService.setBaseState(); this.animateMixer.forEach((mixer: AnimationMixer) => { mixer.update(this.getTime()); diff --git a/packages/three/src/core/threeRenderService.ts b/packages/three/src/core/threeRenderService.ts index 283dece4a1..19f3da57b1 100644 --- a/packages/three/src/core/threeRenderService.ts +++ b/packages/three/src/core/threeRenderService.ts @@ -25,6 +25,7 @@ export class ThreeRenderService implements IThreeRenderService { public renderer: WebGLRenderer; public camera: Camera; public center: IMercator; + public aspect: number; private scene: ThreeScene; // 初始状态相机变换矩阵 @@ -37,6 +38,7 @@ export class ThreeRenderService implements IThreeRenderService { private readonly mapService: IMapService; public init() { + // 从 L7 的 renderer 中获取可视化层的 canvas/gl const canvas = this.rendererService.getCanvas() as HTMLCanvasElement; const gl = this.rendererService.getGLContext(); if (canvas && gl) { @@ -48,6 +50,8 @@ export class ThreeRenderService implements IThreeRenderService { } const { x, y, z } = this.center; this.cameraTransform = new Matrix4().makeTranslation(x, y, z); + + // 根据 L7 的 canvas/gl 构建 threejs 的 renderer this.renderer = new WebGLRenderer({ canvas, context: gl, @@ -61,12 +65,30 @@ export class ThreeRenderService implements IThreeRenderService { // this.renderer.shadowMap.type = PCFSoftShadowMap; this.scene = new ThreeScene(); - this.camera = new PerspectiveCamera(45, 1, 1, 2000000); + + this.aspect = gl.drawingBufferWidth / gl.drawingBufferHeight; + this.camera = new PerspectiveCamera(45, this.aspect, 1, 20000000); } public getRenderCamera(): Camera { - return this.mapService.constructor.name === 'AMapService' - ? this.AMapCamera() - : this.mapboxCamera(); + /** + * map version + * GAODE1.x + * GAODE2.x + * MAPBOX + */ + switch (this.mapService.version) { + case 'GAODE1.x': + return this.AMapCamera(); + case 'GAODE2.x': + return this.AMap2Camera(); + case 'MAPBOX': + return this.mapboxCamera(); + default: + return this.AMapCamera(); + } + // return this.mapService.constructor.name === 'AMapService' + // ? this.AMapCamera() + // : this.mapboxCamera(); } private mapboxCamera(): Camera { @@ -109,4 +131,36 @@ export class ThreeRenderService implements IThreeRenderService { camera.position.y += -mapCamera.position.y; return camera; } + + private AMap2Camera(): Camera { + // @ts-ignore + const customCoords = this.mapService.map.customCoords; + customCoords.getCenter(); + + const camera = this.camera; + const { + near, + far, + fov, + up, + lookAt, + position, + } = customCoords.getCameraParams(); + // @ts-ignore + camera.near = near; + // @ts-ignore + camera.far = far; + // @ts-ignore + camera.fov = fov; + // @ts-ignore + camera.position.set(...position); + // @ts-ignore + camera.up.set(...up); + // @ts-ignore + camera.lookAt(...lookAt); + // @ts-ignore + camera.updateProjectionMatrix(); + + return camera; + } } diff --git a/stories/3D_Model/Components/amap2_three.tsx b/stories/3D_Model/Components/amap2_three.tsx new file mode 100644 index 0000000000..bb55abd1a2 --- /dev/null +++ b/stories/3D_Model/Components/amap2_three.tsx @@ -0,0 +1,143 @@ +import { Scene } from '@antv/l7'; +import { GaodeMap, GaodeMapV2, Mapbox } from '@antv/l7-maps'; +import { ThreeLayer, ThreeRender } from '@antv/l7-three'; +import * as React from 'react'; +// import { DirectionalLight, Scene as ThreeScene } from 'three'; +import * as THREE from 'three'; +// tslint:disable-next-line:no-submodule-imports +import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; + +export default class GlTFThreeJSDemo extends React.Component { + // @ts-ignore + private scene: Scene; + + public componentWillUnmount() { + this.scene.destroy(); + } + + public async componentDidMount() { + const response = await fetch( + 'https://gw.alipayobjects.com/os/basement_prod/893d1d5f-11d9-45f3-8322-ee9140d288ae.json', + ); + const pointsData = await response.json(); + + const scene = new Scene({ + id: 'map', + map: new GaodeMapV2({ + center: [111.4453125, 32.84267363195431], + pitch: 45, + rotation: 30, + zoom: 15, + }), + }); + this.scene = scene; + scene.registerRenderService(ThreeRender); + scene.on('loaded', () => { + const threeJSLayer = new ThreeLayer({ + 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); + // 使用 Three.js glTFLoader 加载模型 + const loader = new GLTFLoader(); + loader.load( + // 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/DamagedHelmet/glTF/DamagedHelmet.gltf', + // 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/AnimatedCube/glTF/AnimatedCube.gltf', + // 'https://gw.alipayobjects.com/os/antvdemo/assets/gltf/radar/34M_17.gltf', + // 'https://gw.alipayobjects.com/os/antvdemo/assets/gltf/duck/Duck.gltf', // duck + // 'https://gw.alipayobjects.com/os/antvdemo/assets/gltf/truck/CesiumMilkTruck.gltf', // Truck + // '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) + 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 轴缩放比例 + // ), + // ); + + const animations = gltf.animations; + if (animations && animations.length) { + const mixer = new THREE.AnimationMixer(gltfScene); + // @ts-ignore + // for (let i = 0; i < 1; i++) { + const animation = animations[2]; + + // There's .3333 seconds junk at the tail of the Monster animation that + // keeps it from looping cleanly. Clip it at 3 seconds + + const action = mixer.clipAction(animation); + + action.play(); + // } + layer.addAnimateMixer(mixer); + } + + // 向场景中添加模型 + // threeScene.add(gltfScene); + }); + + threeScene.add(gltfScene); + // 重绘图层 + layer.render(); + }, + ); + }, + }) + .source({ + type: 'FeatureCollection', + features: [ + { + type: 'Feature', + properties: {}, + geometry: { + type: 'Point', + coordinates: [111.4453125, 32.84267363195431], + }, + }, + ], + }) + .animate(true); + scene.addLayer(threeJSLayer); + }); + } + + public render() { + return ( +
+ ); + } +} diff --git a/stories/3D_Model/Components/threeRender.tsx b/stories/3D_Model/Components/threeRender.tsx index 43f7cce41f..10eb823bee 100644 --- a/stories/3D_Model/Components/threeRender.tsx +++ b/stories/3D_Model/Components/threeRender.tsx @@ -64,7 +64,6 @@ export default class GlTFThreeJSDemo extends React.Component { .active(true) .size(20); scene.addLayer(imageLayer); - const threeJSLayer = new ThreeLayer({ enableMultiPassRenderer: false, onAddMeshes: (threeScene: THREE.Scene, layer: ThreeLayer) => { diff --git a/stories/3D_Model/model.stories.tsx b/stories/3D_Model/model.stories.tsx index b031ad6727..3a335f8e01 100644 --- a/stories/3D_Model/model.stories.tsx +++ b/stories/3D_Model/model.stories.tsx @@ -1,10 +1,12 @@ import { storiesOf } from '@storybook/react'; import * as React from 'react'; import AMapModel from './Components/amap_three'; +import AMap2Model from './Components/amap2_three'; import MapboxModel from './Components/mapbox_three'; import ThreeRender from './Components/threeRender'; storiesOf('3D 模型', module) .add('ThreeJS Render', () => , {}) .add('高德模型1.x', () => , {}) + .add('高德模型2.x', () => , {}) .add('Mapbox模型', () => , {});