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