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)
|
}
|
}
|