const BaseLayer = mars3d.layer.BaseLayer const 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 库 ") } const scene = this._map.scene const 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 const fov = 45 const aspect = scene.canvas.clientWidth / scene.canvas.clientHeight const near = 1 const 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.viewer.useDefaultRenderLoop = false // 关闭自动渲染 // eslint-disable-next-line const 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.viewer.useDefaultRenderLoop = true if (this._container) { this._map.container.removeChild(this._container) } } update() { this.renderCesium() this.renderThreeObj() this.renderCamera() } renderCesium() { this._map.viewer.render() } renderThreeObj() { const width = this._container.clientWidth const 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)) const cvm = this._map.camera.viewMatrix const 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] ) const width = this._map.scene.canvas.clientWidth const 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) } }