feature/threejs
This commit is contained in:
parent
c215fbcefb
commit
a83128db05
|
|
@ -32,7 +32,8 @@ export default class AmapViewer {
|
|||
}
|
||||
|
||||
private initAmapFile() {
|
||||
if ((window as any).AMap && (window as any).Loca) {
|
||||
// && (window as any).Loca
|
||||
if ((window as any).AMap) {
|
||||
this.initMap();
|
||||
} else {
|
||||
const url = `https://webapi.amap.com/maps?v=2.0&key=${AMAP_KEY}`;
|
||||
|
|
@ -53,7 +54,7 @@ export default class AmapViewer {
|
|||
// 获取画布dom
|
||||
this.amapDom = document.getElementById(this.id) as HTMLElement;
|
||||
this.map = new AMap.Map(this.amapDom, {
|
||||
zoom: 18,
|
||||
zoom: 14,
|
||||
center: this.center,
|
||||
resizeEnable: true,
|
||||
viewMode: "3D",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect, useRef } from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import AmapViewer from "@/lib/AmapViewer";
|
||||
import ShadowMaterialAmap from "./modules/shadow";
|
||||
import styles from "./index.less";
|
||||
|
|
@ -10,15 +10,29 @@ type Props = OwnProps;
|
|||
const PAGE_ID = "DEMO_THREEAMAP",
|
||||
CENTER = [118.794694, 32.434165];
|
||||
const ThreeAmap: React.FC<Props> = (props) => {
|
||||
const [isAMapLoaded, setIsAMapLoaded] = useState(false); //判断是否加载完成AMap对象
|
||||
const amapRef = useRef<AmapViewer>();
|
||||
useEffect(() => {
|
||||
init();
|
||||
return () => amapRef.current?.destoryMap();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
const checkAMapLoaded = () => {
|
||||
if (window.AMap && !isAMapLoaded) {
|
||||
setIsAMapLoaded(true);
|
||||
initLayer();
|
||||
}
|
||||
};
|
||||
checkAMapLoaded();
|
||||
if (!isAMapLoaded) window.addEventListener("load", checkAMapLoaded);
|
||||
return () => window.removeEventListener("load", checkAMapLoaded);
|
||||
}, [isAMapLoaded]);
|
||||
const init = () => {
|
||||
amapRef.current = new AmapViewer(PAGE_ID, CENTER);
|
||||
};
|
||||
const initLayer = () => {
|
||||
const amap = amapRef.current;
|
||||
const shadowMaterialAmap = new ShadowMaterialAmap(amap);
|
||||
const shadowMaterialAmap = new ShadowMaterialAmap(amapRef.current as AmapViewer);
|
||||
shadowMaterialAmap.CreateGLlayer();
|
||||
};
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,24 +1,169 @@
|
|||
import type AmapViewer from "src/lib/AmapViewer";
|
||||
import * as THREE from "three";
|
||||
import { Camera, MeshPhongMaterial, PerspectiveCamera, Scene, WebGLRenderer } from "three";
|
||||
|
||||
const guiCtrl = {
|
||||
lightPositionX: 10000,
|
||||
lightPositionY: 5000,
|
||||
lightPositionZ: 5000,
|
||||
cameraNear: 0,
|
||||
caremaFar: 20000,
|
||||
cameraLeft: -5000,
|
||||
cameraRight: 5000,
|
||||
cameraTop: 5000,
|
||||
cameraBottom: -5000,
|
||||
mapSize: 512,
|
||||
planeMaterialOpacity: 0.5
|
||||
};
|
||||
export default class ShadowMaterialAmap {
|
||||
protected Amap!: any;
|
||||
public locationDataSource!: any;
|
||||
public meshes!: any[];
|
||||
public plane!: any;
|
||||
public camera!: PerspectiveCamera;
|
||||
public renderer!: WebGLRenderer;
|
||||
public scene!: Scene;
|
||||
public mat!: MeshPhongMaterial;
|
||||
public isDestroy = false; // 是否销毁
|
||||
|
||||
constructor(map: AmapViewer) {
|
||||
this.Amap = map;
|
||||
this.meshes = [];
|
||||
}
|
||||
|
||||
// 创建 GL 图层
|
||||
public CreateGLlayer() {
|
||||
console.log("gllayer", this.Amap);
|
||||
return;
|
||||
this.locationDataSource = this.Amap.map.customCoords.lngLatsToCoords([
|
||||
[118.794, 32.43] // [118.795, 32.43],
|
||||
// [118.796, 32.43]
|
||||
]);
|
||||
const gllayer = new AMap.GLCustomLayer({
|
||||
zIndex: 10, // 初始化的操作
|
||||
init: (gl: any) => {
|
||||
console.log("gl", gl);
|
||||
this.initRender(gl);
|
||||
this.initScene();
|
||||
this.initCamera();
|
||||
this.initMat();
|
||||
this.addBoxGeometry();
|
||||
// const animate = () => {
|
||||
// if (this.isDestroy) return;
|
||||
// requestAnimationFrame(animate);
|
||||
//
|
||||
// // 全局的公共动画函数,添加函数可同步执行
|
||||
// this.animateEventList.forEach((event) => {
|
||||
// if (event.fun && event.content) event.fun(event.content);
|
||||
// });
|
||||
// };
|
||||
// animate();
|
||||
// const aLight = new THREE.AmbientLight(0xffffff, 0.3);
|
||||
// this.scene.add(aLight);
|
||||
},
|
||||
render: () => {
|
||||
console.log(123);
|
||||
this.renderer.resetState();
|
||||
const { near, far, fov, up, lookAt, position } = this.Amap.map.customCoords.getCameraParams();
|
||||
// 设置相机参数
|
||||
this.camera.near = near;
|
||||
this.camera.far = far;
|
||||
this.camera.fov = fov;
|
||||
// @ts-ignore
|
||||
this.camera.position.set(...position);
|
||||
// @ts-ignore
|
||||
this.camera.up.set(...up);
|
||||
// @ts-ignore
|
||||
this.camera.lookAt(...lookAt);
|
||||
this.camera.updateProjectionMatrix();
|
||||
this.updateDom();
|
||||
this.renderDom();
|
||||
this.renderer.resetState();
|
||||
}
|
||||
});
|
||||
this.Amap.map.add(gllayer);
|
||||
}
|
||||
|
||||
private initRender(gl: any) {
|
||||
// 获取画布dom
|
||||
this.renderer = new THREE.WebGLRenderer({ antialias: true, context: gl });
|
||||
}
|
||||
|
||||
// 创建场景
|
||||
private initScene() {
|
||||
this.scene = new THREE.Scene();
|
||||
// 环境光
|
||||
const aLight = new THREE.AmbientLight(0xffffff, 0.3);
|
||||
this.scene.add(aLight);
|
||||
// 平行光
|
||||
const { lightPositionX, lightPositionY, lightPositionZ, cameraNear, caremaFar, cameraLeft, cameraRight, cameraTop, cameraBottom, mapSize, planeMaterialOpacity } = guiCtrl;
|
||||
const dLight = new THREE.DirectionalLight(0xff0000, 3);
|
||||
dLight.position.set(lightPositionX, lightPositionY, lightPositionZ);
|
||||
dLight.castShadow = true; // 开启阴影投射
|
||||
dLight.shadow.mapSize.width = mapSize; // 增加阴影分辨率
|
||||
dLight.shadow.mapSize.height = mapSize;
|
||||
dLight.shadow.camera.near = cameraNear;
|
||||
dLight.shadow.camera.far = caremaFar;
|
||||
dLight.shadow.camera.left = cameraLeft;
|
||||
dLight.shadow.camera.right = cameraRight;
|
||||
dLight.shadow.camera.top = cameraTop;
|
||||
dLight.shadow.camera.bottom = cameraBottom;
|
||||
this.scene.add(dLight);
|
||||
|
||||
// 创建接收阴影的平面
|
||||
const planeGeo = new THREE.PlaneGeometry(50000, 50000);
|
||||
const shadowMat = new THREE.ShadowMaterial({
|
||||
opacity: planeMaterialOpacity
|
||||
});
|
||||
|
||||
this.plane = new THREE.Mesh(planeGeo, shadowMat);
|
||||
this.plane.receiveShadow = true; // 接收阴影
|
||||
this.scene.add(this.plane);
|
||||
}
|
||||
|
||||
// 初始化相机
|
||||
public initCamera() {
|
||||
this.camera = new THREE.PerspectiveCamera(60, this.Amap.amapDom.clientWidth / this.Amap.amapDom.clientHeight, 100, 1 << 30);
|
||||
}
|
||||
|
||||
// 初始化背景(盒模型背景,视角在盒子里面,看到的是盒子内部)
|
||||
private initMat() {
|
||||
// 加载纹理
|
||||
const texture = new THREE.TextureLoader().load("https://a.amap.com/jsapi_demos/static/demo-center-v2/three.jpeg");
|
||||
texture.minFilter = THREE.LinearFilter;
|
||||
// 创建材质
|
||||
this.mat = new THREE.MeshPhongMaterial({
|
||||
color: 0xfff0f0,
|
||||
depthTest: true,
|
||||
transparent: true,
|
||||
map: texture
|
||||
});
|
||||
}
|
||||
|
||||
private addBoxGeometry() {
|
||||
// 创建几何体
|
||||
const geo = new THREE.BoxGeometry(1000, 1000, 1000);
|
||||
for (let i = 0; i < this.locationDataSource.length; i++) {
|
||||
const d = this.locationDataSource[i];
|
||||
const mesh = new THREE.Mesh(geo, this.mat);
|
||||
mesh.position.set(d[0], d[1], 500);
|
||||
mesh.castShadow = true; // 启用阴影投射
|
||||
mesh.receiveShadow = true; // 接收阴影
|
||||
this.meshes.push({ mesh, count: i });
|
||||
this.scene.add(mesh);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新参数
|
||||
public updateDom() {
|
||||
this.camera.aspect = this.Amap.amapDom.clientWidth / this.Amap.amapDom.clientHeight; // 摄像机视锥体的长宽比,通常是使用画布的宽/画布的高
|
||||
this.camera.updateProjectionMatrix(); // 更新摄像机投影矩阵。在任何参数被改变以后必须被调用,来使得这些改变生效
|
||||
// 禁用自动清理,以保持地图底图可见
|
||||
this.renderer.autoClear = false;
|
||||
this.renderer.shadowMap.enabled = true;
|
||||
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
||||
this.renderer.setSize(this.Amap.amapDom.clientWidth, this.Amap.amapDom.clientHeight);
|
||||
this.renderer.setPixelRatio(window.devicePixelRatio); // 设置设备像素比
|
||||
}
|
||||
|
||||
// 渲染dom
|
||||
public renderDom() {
|
||||
this.renderer?.render(this.scene as Scene, this.camera as Camera);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue