deck.gl 叠加 three.js 物体
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;