Merge pull request #776 from antvis/shihui_dev

Shihui dev
This commit is contained in:
YiQianYao 2021-09-22 17:04:19 +08:00 committed by GitHub
commit a4c974261c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 577 additions and 68 deletions

View File

@ -88,6 +88,7 @@
"lint-staged": "^9.2.4",
"node-sass": "^4.12.0",
"npm-run-all": "^4.1.5",
"popmotion": "^9.4.2",
"postcss": "^7.0.18",
"postcss-plugin": "^1.0.0",
"postcss-url": "^8.0.0",

View File

@ -275,6 +275,12 @@ export default class AMapService
};
}
public lngLatToCoord(lnglat: [number, number]): any {
// @ts-ignore
const { x, y } = this.map.lngLatToGeodeticCoord(lnglat);
return [x, -y];
}
public lngLatToMercator(
lnglat: [number, number],
altitude: number,

View File

@ -370,7 +370,9 @@ 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 +381,7 @@ export default class AMapService
modelMatrix,
vec3.fromValues(flat[0], flat[1], altitude),
);
mat4.scale(
modelMatrix,
modelMatrix,

View File

@ -236,6 +236,21 @@ export default class MapboxService
public lngLatToContainer(lnglat: [number, number]): IPoint {
return this.map.project(lnglat);
}
/**
*
* @param lnglat
* @returns
*/
public lngLatToCoord(
lnglat: [number, number],
origin: IMercator = { x: 0, y: 0, z: 0 },
) {
// @ts-ignore
const { x, y } = this.lngLatToMercator(lnglat, 0);
return [x - origin.x, y - origin.y] as [number, number];
}
public lngLatToMercator(
lnglat: [number, number],
altitude: number,

View File

@ -0,0 +1,29 @@
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;
}

View File

@ -3,25 +3,19 @@ import {
AnimationMixer,
Camera,
Matrix4,
Object3D,
PCFSoftShadowMap,
PerspectiveCamera,
Scene,
Vector3,
WebGLRenderer,
} from 'three';
import { ILngLat, IThreeJSLayer } from './IThreeJSLayer';
import {
IThreeRenderService,
ThreeRenderServiceType,
} from './threeRenderService';
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;
@ -29,16 +23,15 @@ 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[] = [];
// 地图中点墨卡托坐标
private center: IMercator;
// 初始状态相机变换矩阵
/**
*
*
*/
public getModelMatrix(
lnglat: [number, number],
@ -57,7 +50,100 @@ 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) {
const positionMatrix = this.getTranslateMatrix(lnglat, altitude);
object.applyMatrix4(positionMatrix);
}
/**
*
* @param object
* @param lnglat
* @param altitude
*/
public setObjectLngLat(object: Object3D, lnglat: ILngLat, altitude = 0) {
// @ts-ignore
const [x, y] = this.lnglatToCoord(lnglat);
object.position.set(x, y, altitude);
}
/**
* three
* @param lnglat
* @returns
*/
public lnglatToCoord(lnglat: ILngLat) {
// @ts-ignore
const [x, y] = this.mapService?.lngLatToCoord(
lnglat,
// @ts-ignore
this.threeRenderService.center,
);
return [x, y];
}
/**
*
* @param object
* @returns
*/
public getObjectLngLat(object: Object3D) {
const coord = [object.position.x, object.position.y];
return [0, 0] as ILngLat;
}
/**
*
* @param object
*/
public adjustMeshToMap(object: Object3D) {
object.up = new Vector3(0, 0, 1);
const defaultLngLat = this.mapService.getCenter();
const modelMatrix = this.getModelMatrix(
[defaultLngLat.lng, defaultLngLat.lat], // 经纬度坐标
0, // 高度,单位米/
[Math.PI / 2, -Math.PI, 0], // 沿 XYZ 轴旋转角度
[1, 1, 1], // 沿 XYZ 轴缩放比例
);
object.applyMatrix4(modelMatrix);
}
/**
* mapbox scale /
* @param object
* @param x
* @param y
* @param z
*/
public setMeshScale(
object: Object3D,
x: number = 1,
y: number = 1,
z: number = 1,
) {
const scaleMatrix = new Matrix4();
scaleMatrix.scale(new Vector3(x, y, z));
object.applyMatrix4(scaleMatrix);
}
public buildModels() {
// @ts-ignore
this.threeRenderService = this.getContainer().get<IThreeRenderService>(
ThreeRenderServiceType,
);
@ -67,16 +153,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());

View File

@ -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;
}
}

View File

@ -1,3 +1,5 @@
import { Object3D } from 'three';
import ThreeLayer from './core/baseLayer';
import { ILngLat, IThreeJSLayer } from './core/IThreeJSLayer';
import ThreeRender from './core/threeRender';
export { ThreeLayer, ThreeRender };
export { ThreeLayer, ThreeRender, IThreeJSLayer, ILngLat, Object3D };

View File

@ -0,0 +1,148 @@
import { Scene } from '@antv/l7';
import { GaodeMap, GaodeMapV2, Mapbox } from '@antv/l7-maps';
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';
// 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: 13,
}),
});
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) => {
const model: Object3D = gltf.scene;
layer.getSource().data.dataArray.forEach(({ coordinates }) => {
layer.adjustMeshToMap(model);
// model.scale.set(100, 100, 100)
layer.setMeshScale(model, 100, 100, 100);
const animations = gltf.animations;
if (animations && animations.length) {
const mixer = new THREE.AnimationMixer(model);
// @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(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);
// 重绘图层
layer.render();
},
);
},
})
.source({
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: [111.4453125, 32.84267363195431],
// coordinates: [121.107, 30.267069], // 该坐标点在钱塘江入海口附近
},
},
],
})
.animate(true);
scene.addLayer(threeJSLayer);
});
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
}

View File

@ -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,19 @@ export default class GlTFThreeJSDemo extends React.Component {
sunlight.position.set(0, 80000000, 100000000);
sunlight.matrixWorldNeedsUpdate = true;
threeScene.add(sunlight);
let center = scene.getCenter();
let cubeGeometry = new THREE.BoxBufferGeometry(10000, 10000, 10000);
let cubeMaterial = new THREE.MeshNormalMaterial();
let cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
layer.setObjectLngLat(
cube,
[center.lng + 0.05, center.lat] as ILngLat,
0,
);
threeScene.add(cube);
// 使用 Three.js glTFLoader 加载模型
const loader = new GLTFLoader();
loader.load(
@ -55,15 +68,17 @@ export default class GlTFThreeJSDemo extends React.Component {
// 根据 GeoJSON 数据放置模型
layer.getSource().data.dataArray.forEach(({ coordinates }) => {
const gltfScene = gltf.scene;
gltfScene.applyMatrix4(
// 生成模型矩阵
layer.getModelMatrix(
[coordinates[0], coordinates[1]], // 经纬度坐标
0, // 高度,单位米/
[Math.PI / 2, -Math.PI, 0], // 沿 XYZ 轴旋转角度
[100, 100, 100], // 沿 XYZ 轴缩放比例
),
layer.adjustMeshToMap(gltfScene);
// gltfScene.scale.set(1000, 1000, 1000)
layer.setMeshScale(gltfScene, 1000, 1000, 1000);
layer.setObjectLngLat(
gltfScene,
[coordinates[0] + 0.02, coordinates[1]],
0,
);
const animations = gltf.animations;
if (animations && animations.length) {
const mixer = new THREE.AnimationMixer(gltfScene);
@ -80,6 +95,16 @@ export default class GlTFThreeJSDemo extends React.Component {
// }
layer.addAnimateMixer(mixer);
}
// 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,
);
}, 16);
// 向场景中添加模型
threeScene.add(gltfScene);

View File

@ -1,11 +1,65 @@
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';
// tslint:disable-next-line:no-submodule-imports
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { animate, easeInOut } from 'popmotion';
import { Object3D, Vector3 } from 'three';
let isTravel = false;
function travel(
mesh: Object3D,
path: Vector3[],
duration: number,
callback?: () => any,
) {
if (path.length < 2 || isTravel) return;
isTravel = true;
let startIndex = 0,
len = path.length;
let currentP = path[0],
nextP = path[1];
let t = duration / len;
move(currentP, nextP);
function move(currentP: Vector3, nextP: Vector3) {
animate({
from: {
x: currentP.x,
y: currentP.y,
z: currentP.z,
},
to: {
x: nextP.x,
y: nextP.y,
z: nextP.z,
},
ease: easeInOut,
duration: t,
repeatType: 'loop',
onUpdate: (o) => {
mesh.position.set(o.x, o.y, o.z);
},
onComplete: () => {
startIndex++;
if (startIndex < len - 1) {
let currentP = path[startIndex],
nextP = path[startIndex + 1];
mesh.lookAt(nextP);
move(currentP, nextP);
} else {
isTravel = false;
callback && callback();
}
},
});
}
}
export default class GlTFThreeJSDemo extends React.Component {
// @ts-ignore
@ -61,6 +115,66 @@ export default class GlTFThreeJSDemo extends React.Component {
sunlight.position.set(0, 80000000, 100000000);
sunlight.matrixWorldNeedsUpdate = true;
threeScene.add(sunlight);
let lineData: ILngLat[] = [
[116.71874999999999, 26.745610382199022],
[117.3779296875, 28.8831596093235],
[115.75195312499999, 31.466153715024294],
[113.466796875, 33.32134852669881],
[113.9501953125, 35.85343961959182],
[115.400390625, 38.272688535980976],
[116.5869140625, 40.3130432088809],
[115.6201171875, 42.261049162113856],
[112.236328125, 42.94033923363181],
[109.3798828125, 41.04621681452063],
[103.84277343749999, 39.80853604144591],
[98.9208984375, 39.842286020743394],
[95.2294921875, 40.713955826286046],
[91.7138671875, 39.87601941962116],
[90.8349609375, 37.125286284966805],
[90.3076171875, 35.88905007936091],
[90.703125, 33.284619968887675],
[92.94433593749999, 31.98944183792288],
[96.2841796875, 32.21280106801518],
[98.87695312499999, 32.0639555946604],
[102.919921875, 28.459033019728043],
[107.9736328125, 28.497660832963472],
[108.10546875, 24.206889622398023],
[109.072265625, 23.039297747769726],
[112.763671875, 24.44714958973082],
[116.54296874999999, 25.958044673317843],
];
let lineCoordData = lineData.map((d: ILngLat) => {
return layer.lnglatToCoord(d);
});
// console.log(lineCoordData)
var material = new THREE.LineBasicMaterial({
color: 0x0000ff,
});
var rawPoints: THREE.Vector3[] = [];
lineCoordData.map((d) => {
rawPoints.push(new THREE.Vector3(d[0], d[1], 0));
});
var curve = new THREE.CatmullRomCurve3(rawPoints);
var points = curve.getPoints(200);
var geometry = new THREE.BufferGeometry().setFromPoints(points);
var material = new THREE.LineBasicMaterial({ color: 0xff0000 });
var line = new THREE.LineLoop(geometry, material);
threeScene.add(line);
// console.log(line)
// animate({
// from: 0,
// to: 100,
// duration: 3000,
// onUpdate: latest => console.log(latest)
// })
// 使用 Three.js glTFLoader 加载模型
const loader = new GLTFLoader();
loader.load(
@ -73,17 +187,12 @@ 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(
[coordinates[0], coordinates[1]], // 经纬度坐标
0, // 高度,单位米
[Math.PI / 2, 0, 0], // 沿 XYZ 轴旋转角度
[100000, 100000, 100000], // 沿 XYZ 轴缩放比例
),
);
layer.adjustMeshToMap(gltfScene);
gltfScene.scale.set(500000, 500000, 500000);
// gltfScene.rotation.y = Math.PI
const animations = gltf.animations;
if (animations && animations.length) {
@ -105,6 +214,24 @@ export default class GlTFThreeJSDemo extends React.Component {
// 向场景中添加模型
threeScene.add(gltfScene);
});
let center = scene.getCenter();
// 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) * 10] as ILngLat, 0)
// // layer.setObjectLngLat(model, [center.lng + 0.2, center.lat], 0)
// }, 16)
// travel(gltfScene, points, 5000)
travelLoop();
function travelLoop() {
travel(gltfScene, points, 5000, () => {
travelLoop();
});
}
// 重绘图层
layer.render();
},

View File

@ -37,33 +37,28 @@ export default class GlTFThreeJSDemo extends React.Component {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/893d1d5f-11d9-45f3-8322-ee9140d288ae.json',
);
scene.addImage(
'00',
'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*Rq6tQ5b4_JMAAAAAAAAAAABkARQnAQ',
);
scene.addImage(
'01',
'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*0D0SQ6AgkRMAAAAAAAAAAABkARQnAQ',
);
scene.addImage(
'02',
'https://gw.alipayobjects.com/zos/rmsportal/xZXhTxbglnuTmZEwqQrE.png',
);
const data = await response.json();
const imageLayer = new PointLayer()
.source(data, {
parser: {
type: 'json',
x: 'longitude',
y: 'latitude',
.source(
// [{
// longitude: 120,
// latitude: 30
// }]
data,
{
parser: {
type: 'json',
x: 'longitude',
y: 'latitude',
},
},
})
// .shape('name', ['00', '01', '02'])
)
.shape('triangle')
.color('red')
.active(true)
.size(20);
scene.addLayer(imageLayer);
.size(20)
.animate(true);
// scene.addLayer(imageLayer);
const threeJSLayer = new ThreeLayer({
enableMultiPassRenderer: false,
@ -74,6 +69,9 @@ export default class GlTFThreeJSDemo extends React.Component {
sunlight.matrixWorldNeedsUpdate = true;
threeScene.add(sunlight);
// 使用 Three.js glTFLoader 加载模型
let center = scene.getCenter();
const loader = new GLTFLoader();
loader.load(
// 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/DamagedHelmet/glTF/DamagedHelmet.gltf',
@ -87,15 +85,10 @@ export default class GlTFThreeJSDemo extends React.Component {
// 根据 GeoJSON 数据放置模型
layer.getSource().data.dataArray.forEach(({ coordinates }) => {
const gltfScene = gltf.scene;
gltfScene.applyMatrix4(
// 生成模型矩阵
layer.getModelMatrix(
[coordinates[0], coordinates[1]], // 经纬度坐标
0, // 高度,单位米/
[Math.PI / 2, -Math.PI, 0], // 沿 XYZ 轴旋转角度
[10, 10, 10], // 沿 XYZ 轴缩放比例
),
);
layer.adjustMeshToMap(gltfScene);
layer.setMeshScale(gltfScene, 10, 10, 10);
const animations = gltf.animations;
if (animations && animations.length) {
const mixer = new THREE.AnimationMixer(gltfScene);
@ -115,6 +108,17 @@ export default class GlTFThreeJSDemo extends React.Component {
// 向场景中添加模型
threeScene.add(gltfScene);
// layer.setObjectLngLat(gltfScene, [120, 30], 0)
// @ts-ignore
// console.log(layer.mapService.lngLatToCoord([121.4, 31.258134]))
// let t = 0
// setInterval(() => {
// t += 0.01
// layer.setObjectLngLat(gltfScene, [center.lng, center.lat + Math.sin(t) * 0.005] as ILngLat, 0)
// // layer.setObjectLngLat(model, [center.lng + 0.2, center.lat], 0)
// }, 16)
});
// 重绘图层
layer.render();

View File

@ -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', () => <ThreeRender />, {})
.add('高德模型1.x', () => <AMapModel />, {})
.add('高德模型2.x', () => <AMap2Model />, {})
.add('Mapbox模型', () => <MapboxModel />, {});