本方法来自Cesium官网,细节改动来自Github社区
创建该类即可,具体细节备注有写
/* eslint-disable one-var */
import * as THREE from "three";
import { TransformControls } from "three/examples/jsm/controls/TransformControls";
import { WorkSpace } from "./Constructions/workSpace";//一个threejs的工作单元
import { xxgeojson } from "../localJson/datacache/xxgeojson ";
// 区域geojson
import { getThreeCss3dRender, getThreeRender, getThreeScene } from "...someconfig.js";
//初始化threej方法 项目统一方法和用于获取render scene
export default class CesiumThreeController {
isDestory = false
playNode = true
cesium = {
viewer: null
};
three = {
renderer: null,
camera: null,
scene: null,
control: null
};
minWGS84 = [115.56936458615716, 39.284100766866445];
maxWGS84 = [117.10745052365716, 41.107831235616445];
sceneContainer;
// cesium 容器
cesiumContainer = document.getElementById("cesiumContainer");
_3Dobjects = []; // Could be any Three.js object mesh
workSpace
setThreeObjects
constructor(viewer, setThreeObjects, data = xxgeojson ) {
this.setThreeObjects = setThreeObjects
this.initData(data)
.then(data => this.initConfig(data))
.then(() => this.initView(viewer));
}
initData = async datasource => {
// 获取三维场景参考边界 数据来自geojson
// 不要也行 但是形式上需要一个边界计算相机角度朝向,理论上不要出界的好,会影响图像精度
let data = null;
if (typeof datasource == "string") {
data = await fetch(datasource).then(res => {
return res.json();
});
} else {
data = datasource;
}
return data;
};
initConfig = data => {
// 通过获取的在线geojson 计算最小外接矩形边界 计算相机朝向、位置
let coordinates = data.features[0].geometry.coordinates[0];
// 边界
let maxLng = coordinates[0][0],
maxLat = coordinates[0][1];
let minLng = coordinates[0][0],
minLat = coordinates[0][1];
coordinates.forEach(([lng, lat]) => {
if (lng > maxLng) maxLng = lng;
if (lat > maxLat) maxLat = lat;
if (lng < minLng) minLng = lng;
if (lat < minLat) minLat = lat;
});
const minWGS84 = [minLng, minLat];
const maxWGS84 = [maxLng, maxLat];
// 中心
const center = [(maxLng + minLng) / 2, (maxLat + minLat) / 2];
const config = {
minWGS84,
maxWGS84,
center,
geojson: data
};
Object.assign(this, config);
return this;
};
initView = viewer => {
// 初始化cesium,这里使用新建类接收的viewer
// 初始化 threejs
// 初始化相机更新动画anime
this.cesium.viewer = viewer;
this.initThree();
this.init3DObject();
this.anime = window.requestAnimationFrame(this.loop)
};
initThree = () => {
let { three, minWGS84, maxWGS84, _3Dobjects } = this;
let fov = 45;
let width = window.innerWidth;
let height = window.innerHeight;
let aspect = width / height;
let near = 1;
let far = 10 * 1000 * 1000;
// three.scene = new THREE.Scene();
three.scene = getThreeScene()
three.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
// renderer
// three.renderer = new THREE.WebGLRenderer({ alpha: true, logarithmicDepthBuffer: true ,antialias:true});
three.renderer = getThreeRender();
let Amlight = new THREE.AmbientLight(0xffffff, 2);
three.renderer.domElement.style.position = "absolute";
three.renderer.domElement.style.top = "0";
three.renderer.domElement.style.pointerEvents = "none";
three.scene.add(Amlight);
// 注意这里,直接把three容器(canvas 添加到 cesium中,在cesium的canvas之下),
// 这样的话,两个canvas才会重叠起来。
this.cesium.viewer.cesiumWidget.canvas.parentElement.appendChild(
three.renderer.domElement
);
// 2d renderer
// let labelRenderer = new CSS3DRenderer();
let labelRenderer = getThreeCss3dRender()
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0px';
labelRenderer.domElement.style.pointerEvents = "none";
this.cesium.viewer.cesiumWidget.canvas.parentElement.appendChild(
labelRenderer.domElement
);
three.labelRenderer = labelRenderer
let control = new TransformControls(
three.camera,
three.renderer.domElement
);
three.control = control;
const sceneContainer = new THREE.Group();//因为每个3d对象都需要单独计算位置,所以用一个group统一处理
three.scene.add(sceneContainer);
three.scene.add(control);
const _3DOB2 = new _3DObject();//注册3d对象,用于后续刷新相机位置时显示隐藏模型
_3DOB2.threeMesh = sceneContainer;
_3DOB2.minWGS84 = minWGS84;
_3DOB2.maxWGS84 = maxWGS84;
_3Dobjects.push(_3DOB2);//设计上可存储多个threejs的3d对象,但是本类使用sceneContainer总览,所以从始至终只有一个_3DOB2
this.sceneContainer = sceneContainer;
};
init3DObject = () => {
// 创建子类3d对象
this.createThreeObject();
};
loop = () => {
this.anime = window.requestAnimationFrame(this.loop);
if (this.isDestory) {
cancelAnimationFrame(this.anime)
let { renderer, camera, control, scene,labelRenderer } = this.three
scene.remove(camera)
scene.remove(control)
this.cesium.viewer.cesiumWidget.canvas.parentElement.removeChild(
renderer.domElement//threejs render
);
this.cesium.viewer.cesiumWidget.canvas.parentElement.removeChild(
labelRenderer.domElement//threejs 3d/2drender
);
renderer.dispose()
}
if (this.playNode == false) return
this.renderCesium();//cesium刷新
this.renderThreeObj();
};
renderCesium = () => {
// 自动的 有强制刷新要求再刷新
// this.cesium.viewer.render();
};
renderThreeObj = () => {
// threejs更新
let { three, cesium, _3Dobjects, minWGS84, maxWGS84 } = this;
// register Three.js scene with Cesium
three.camera.fov = Cesium.Math.toDegrees(cesium.viewer.camera.frustum.fovy); // ThreeJS FOV is vertical
// three.camera.updateProjectionMatrix();
let cartToVec = function (cart) {
return new THREE.Vector3(cart.x, cart.y, cart.z);
};
// Configure Three.js meshes to stand against globe center position up direction
for (let id in _3Dobjects) {
minWGS84 = _3Dobjects[id].minWGS84;
maxWGS84 = _3Dobjects[id].maxWGS84;
// convert lat/long center position to Cartesian3
let center = Cesium.Cartesian3.fromDegrees(
(minWGS84[0] + maxWGS84[0]) / 2,
(minWGS84[1] + maxWGS84[1]) / 2
);
// get forward direction for orienting model
let centerHigh = Cesium.Cartesian3.fromDegrees(
(minWGS84[0] + maxWGS84[0]) / 2,
(minWGS84[1] + maxWGS84[1]) / 2,
1
);
// use direction from bottom left to top left as up-vector
let bottomLeft = cartToVec(
Cesium.Cartesian3.fromDegrees(minWGS84[0], minWGS84[1])
);
let topLeft = cartToVec(
Cesium.Cartesian3.fromDegrees(minWGS84[0], maxWGS84[1])
);
let latDir = new THREE.Vector3()
.subVectors(bottomLeft, topLeft)
.normalize();
// configure entity position and orientation
_3Dobjects[id].threeMesh.position.copy(center);
_3Dobjects[id].threeMesh.lookAt(centerHigh.x, centerHigh.y, centerHigh.z);
_3Dobjects[id].threeMesh.up.copy(latDir);
}
// Clone Cesium Camera projection position so the
// Three.js Object will appear to be at the same place as above the Cesium Globe
three.camera.matrixAutoUpdate = false;
let cvm = cesium.viewer.camera.viewMatrix;
let civm = cesium.viewer.camera.inverseViewMatrix;
// 注意这里,经大神博客得知,three高版本这行代码需要放在 three.camera.matrixWorld 之前
// 忘记在哪看的了 LOL
three.camera.lookAt(0, 0, 0);
three.camera.matrixWorld.set(
civm[0],
civm[4],
civm[8],
civm[12],
civm[1],
civm[5],
civm[9],
civm[13],
civm[2],
civm[6],
civm[10],
civm[14],
civm[3],
civm[7],
civm[11],
civm[15]
);
three.camera.matrixWorldInverse.set(
cvm[0],
cvm[4],
cvm[8],
cvm[12],
cvm[1],
cvm[5],
cvm[9],
cvm[13],
cvm[2],
cvm[6],
cvm[10],
cvm[14],
cvm[3],
cvm[7],
cvm[11],
cvm[15]
);
// 设置three宽高
let width = cesiumContainer.clientWidth;
let height = cesiumContainer.clientHeight;
let aspect = width / height;
three.camera.aspect = aspect;
three.camera.updateProjectionMatrix();
three.renderer.setSize(width, height);
three.labelRenderer.setSize(width, height)
three.renderer.clear();
three.renderer.render(three.scene, three.camera);
three.labelRenderer.render(three.scene, three.camera);
};
// };
createThreeObject = () => {
// 从这里初始化threejs场景
// 这里的workSpace是一个工作单元,用于搭建threejs场景
let {
three,
cesium,
_3Dobjects,
minWGS84,
maxWGS84,
sceneContainer//3D对象的容器
} = this;
let { scene, control, camera } = three
const workSpace = new WorkSpace(scene, control, camera, sceneContainer, this.setThreeObjects)
this.workSpace = workSpace
};
/***
* 暂停 开始和销毁在anime内控制
*/
// 暂停更新
pause = () => {
this.playNode = false
}
// 开始更新
play = () => {
this.playNode = true
}
// 销毁
destory = () => {
this.isDestory = true
}
}
// 子类 代理threejs的3d对象用
class _3DObject {
constructor() {
// THREEJS 3DObject.mesh
this.threeMesh = null;
// location bounding box
this.minWGS84 = null;
this.maxWGS84 = null;
}
}
/**
* 调整3d对象位置角度 调试用方法 推荐在threejs中调整
*/
function transforme3DGroup() {
let stander = "p";
window.addEventListener("keydown", ({ key }) => {
console.log(key);
if (key == "r") stander = "r";
if (key == "p") stander = "p";
if (key == "h") stander = "h";
if (stander == "p") {
if (key == "ArrowRight") scene.position.x -= 10;
if (key == "ArrowLeft") scene.position.x += 10;
if (key == "ArrowUp") scene.position.y -= 10;
if (key == "ArrowDown") scene.position.y += 10;
} else if (stander == "r") {
if (key == "ArrowUp") scene.rotation.y -= 0.01;
if (key == "ArrowDown") scene.rotation.y += 0.01;
} else if (stander == "h") {
if (key == "ArrowUp") scene.position.z -= 10;
if (key == "ArrowDown") scene.position.z += 10;
}
if (key == "v") console.log(scene);
});
}