let BaseLayer = mars3d.layer.BaseLayer; let THREE = window.THREE; //与THREE.js集成 class ThreeLayer extends BaseLayer { constructor(options = {}) { super(options); this._pointerEvents = this.options.pointerEvents; } _showHook(show) { if (show) { this._threejsContainer.style.visibility = "visible"; } else { this._threejsContainer.style.visibility = "hidden"; } } /** * 对象添加到地图前创建一些对象的钩子方法, * 只会调用一次 * @return {void} 无 * @private */ _mountedHook() { if (!THREE) { throw new Error("请引入 three.js 库 "); } let scene = this._map.scene; let threeContainer = mars3d.DomUtil.create("div", "mars3d-threejs"); threeContainer.style.position = "absolute"; threeContainer.style.top = "0px"; threeContainer.style.left = "0px"; threeContainer.style.width = scene.canvas.clientWidth + "px"; threeContainer.style.height = scene.canvas.clientHeight + "px"; threeContainer.style.pointerEvents = this._pointerEvents ? "auto" : "none"; //auto时可以交互,但是没法放大地球, none 没法交互 this._container = threeContainer; let fov = 45; let aspect = scene.canvas.clientWidth / scene.canvas.clientHeight; let near = 1; let far = 10 * 1000 * 1000; // needs to be far to support Cesium's world-scale rendering this.scene = new THREE.Scene(); this.camera = new THREE.PerspectiveCamera(fov, aspect, near, far); this.renderer = new THREE.WebGLRenderer({ alpha: true }); threeContainer.appendChild(this.renderer.domElement); } /** * 对象添加到地图上的创建钩子方法, * 每次add时都会调用 * @return {void} 无 * @private */ _addedHook() { if (this._container) { this._map.container.appendChild(this._container); } this._map.useDefaultRenderLoop = false; //关闭自动渲染 let that = this; (function frame() { //animateFrame: requestAnimationFrame事件句柄,用来清除操作 that._animateFrame = window.requestAnimationFrame(frame); that.update(); //按帧率执行 })(); } /** * 对象从地图上移除的创建钩子方法, * 每次remove时都会调用 * @return {void} 无 * @private */ _removedHook() { window.cancelAnimationFrame(this._animateFrame); delete this._animateFrame; this._map.useDefaultRenderLoop = true; if (this._container) { this._map.container.removeChild(this._container); } } update() { this.renderCesium(); this.renderThreeObj(); this.renderCamera(); } renderCesium() { this._map.viewer.render(); } renderThreeObj() { var width = this._container.clientWidth; var height = this._container.clientHeight; this.renderer.setSize(width, height); this.renderer.render(this.scene, this.camera); } renderCamera() { // register Three.js scene with Cesium this.camera.fov = Cesium.Math.toDegrees(this._map.camera.frustum.fovy); // ThreeJS FOV is vertical this.camera.updateProjectionMatrix(); // Clone Cesium Camera projection position so the // Three.js Object will appear to be at the same place as above the Cesium Globe this.camera.matrixAutoUpdate = false; this.camera.lookAt(new THREE.Vector3(0, 0, 0)); var cvm = this._map.camera.viewMatrix; var civm = this._map.camera.inverseViewMatrix; this.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] ); this.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] ); var width = this._map.scene.canvas.clientWidth; var height = this._map.scene.canvas.clientHeight; this.camera.aspect = width / height; this.renderer.setSize(width, height); this.camera.updateProjectionMatrix(); this.renderer.clear(); this.renderer.render(this.scene, this.camera); } }