deck.gl 叠加 three.js 物体

时间:2024-03-30 21:56:22
import { Matrix4 } from "@math.gl/core"; import { Layer, LayerContext } from "@deck.gl/core"; import DeckGL from "@deck.gl/react"; import { OrbitView } from "@deck.gl/core"; import * as THREE from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; type ThreeLayerProps = { scene: THREE.Scene; center: [number, number, number]; }; class ThreeLayer extends Layer<ThreeLayerProps> { state!: { renderer: THREE.WebGLRenderer; camera: THREE.PerspectiveCamera; controls: OrbitControls; scene: THREE.Scene; }; initializeState(context: LayerContext): void { const renderer = new THREE.WebGLRenderer({ antialias: true, context: context.gl, }); renderer.autoClear = false; const camera = new THREE.PerspectiveCamera( 40, context.deck.width / context.deck.height, 0.00000001, 10000000 ); const controls = new OrbitControls(camera, renderer.domElement); const scene = new THREE.Scene(); camera.position.set(0, 0, 500); camera.lookAt(0, 0, 0); camera.updateProjectionMatrix(); renderer.render(scene, camera); controls.addEventListener("change", () => { renderer.render(scene, camera); }); renderer.resetState(); this.state = { renderer, camera, controls, scene, }; } draw(): void { const viewport = this.context.viewport; // 更新投影矩阵,然后渲染 const { camera, renderer, scene, controls } = this.state; // 计算将 scene 转换到 common space 的矩阵 const position = viewport.projectPosition(viewport.center); const scales = viewport.getDistanceScales(viewport.center); const modelMatrix = new Matrix4() .translate(position) .scale(scales.unitsPerMeter); // 使用 viewport 中的 viewMatrix projectionMatrix 计算 mvpMatrix const viewProjectMatrix = new Matrix4( viewport.viewProjectionMatrix ); const mvpMatrix = viewProjectMatrix.multiplyRight(modelMatrix); camera.projectionMatrix = new THREE.Matrix4().fromArray(mvpMatrix); controls.update(); renderer.resetState(); // 添加物体 const geometry = new THREE.BoxGeometry(10, 10, 10); const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); const cube = new THREE.Mesh(geometry, material); scene.add(cube); const gridHelper = new THREE.GridHelper(200, 3); scene.add(gridHelper); // 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴. const axesHelper = new THREE.AxesHelper(150) scene.add(axesHelper); renderer.render(scene, camera); } } const MapBOX = (props) => { const [viewState, updateViewState] = useState({ latitude: 0, longitude: 0, target: [0, 0, 0], rotationX: -60, rotationOrbit: 0, minZoom: 0, maxZoom: 50, zoom: 10, bearing: 45, }); const _renderLayers = () => { const layer = new ThreeLayer(); return [layer]; }; return ( <DeckGL views={new OrbitView({ id: "map", controller: true })} viewState={viewState} controller={true} onViewStateChange={(v) => updateViewState(v.viewState)} layers={_renderLayers()} parameters={{ clearColor: [0, 0, 0, 0.1], }} ></DeckGL> ); }; export default MapBOX;