123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- function PanoramaControls(camera, domElement) {
-
- // fyz 相机放大缩小
- this.activationThreshold = 1.1;
- this.scrollZoomSpeed = 0.08;
- this.scrollZoomSta = true;
- this.zoomMin = 0.7;
- this.zoomMax = 1.5;
- this.baseFov = 70;
-
- this.camera = camera;
- this.camera.fov = this.baseFov;
-
- this.domElement = domElement;
- this.camera.controls = this;
- this.enabled = true;
- this.target = new THREE.Vector3(0, 0, 0);
- this.lookVector = new THREE.Vector3;
- this.aimFrom = this.camera.position;
- this.lat = 0;
- this.latMin = -60//-40;
- this.latMax = 60//40;
- this.lon = 0;
- this.phi = 0;
- this.theta = 0;
- this.lookSpeed = 0.05;
- this.rotationAcc = new THREE.Vector2;
- this.rotationSpeed = new THREE.Vector2;
- this.rotationHistory = [];
- this.rotationDifference = new THREE.Vector2;
- this.pointerDragOn = !1;
- this.pointer = new THREE.Vector3(0, 0, -1);
- this.pointerDragStart = new THREE.Vector3(0, 0, -1);
- this._wheel = 0;
- this.zoomLevel = 1;
- this.translationWorldDelta = new THREE.Vector3
- this.bindEvents()
- }
- PanoramaControls.prototype.bindEvents = function() {
- window.addEventListener("mousemove", this.onMouseMove.bind(this));
- this.domElement.addEventListener("mousedown", this.onMouseDown.bind(this));
- window.addEventListener("mouseup", this.onMouseUp.bind(this));
- this.domElement.addEventListener("mouseover", (event) => this.pointerDragOn && 0 === event.which && this.onMouseUp(event));
- this.domElement.addEventListener("touchstart", this.onTouchStart.bind(this));
- this.domElement.addEventListener("touchmove", this.onTouchMove.bind(this));
- this.domElement.addEventListener("touchend", this.onTouchEnd.bind(this));
- this.domElement.addEventListener("wheel", this.onMouseWheel.bind(this)); // fyz wheel事件代替mousewheel事件
- this.domElement.addEventListener("DOMMouseScroll", this.onMouseWheel.bind(this));
- this.domElement.addEventListener("contextmenu", (event) => event.preventDefault());
- //document.addEventListener("keydown", this.onKeyDown.bind(this));
- //document.addEventListener("keyup", this.onKeyUp.bind(this));
- }
- PanoramaControls.prototype.lookAt = function(point) {
-
- var directionNegative = this.camera.position.clone().sub(point),
- theta = Math.atan(directionNegative.z / directionNegative.x);
- theta += directionNegative.x < 0 ? Math.PI : 0;
- theta += directionNegative.x > 0 && directionNegative.z < 0 ? 2 * Math.PI : 0;
- this.lon = THREE.Math.radToDeg(theta) + 180;
- let projectorR = Math.sqrt(directionNegative.x * directionNegative.x + directionNegative.z * directionNegative.z),
- phi = Math.atan(directionNegative.y / projectorR);
- this.lat = -THREE.Math.radToDeg(phi)
- }
- PanoramaControls.prototype.startRotationFrom = function(screenX, screenY) {
- this.updatePointer(screenX, screenY);
- this.pointerDragOn = true;
- this.pointerDragStart.copy(this.pointer);
- //TODO
- //this.pointerDragStartIntersect = this.player.getMouseIntersect(this.pointer.clone(), [this.scene.skybox]).point;
- this.rotationHistory = [];
- this.rotationSpeed.set(0, 0);
- }
- PanoramaControls.prototype.onTouchStart = function(event) {
- if (this.enabled) {
- event.preventDefault();
- event.stopPropagation();
- this.startRotationFrom(event.changedTouches[0].clientX, event.changedTouches[0].clientY);
- }
- }
- PanoramaControls.prototype.onMouseDown = function(event) {
- if (this.enabled) {
- event.preventDefault();
- event.stopPropagation()
- switch (event.button) {
- case 0:
- this.startRotationFrom(event.clientX, event.clientY);
- break;
- case 2:
- }
- }
- }
- PanoramaControls.prototype.updateRotation = function( ) {
- if (this.enabled && this.pointerDragOn) {
- var pointerDragStart3D = new THREE.Vector3(this.pointerDragStart.x, this.pointerDragStart.y, 1).unproject(this.camera);
- var pointer3D = new THREE.Vector3(this.pointer.x, this.pointer.y, 1).unproject(this.camera);
- //两交互点分别到原点的长度
- var pointerDragStart3DLength = Math.sqrt(pointerDragStart3D.x * pointerDragStart3D.x + pointerDragStart3D.z * pointerDragStart3D.z);
- var pointer3DLength = Math.sqrt(pointer3D.x * pointer3D.x + pointer3D.z * pointer3D.z);
- //通过Math.atan2计算在XY面上与X轴的夹角弧度。
- //注:因为 z = -1,所以两者到原点的长度近似为x分量(数值的大小也不需要绝对对应)
- var anglePointerDragStart3DToX = Math.atan2(pointerDragStart3D.y, pointerDragStart3DLength); //近似为 anglePointerDragStart3DToX = Math.atan2( pointerDragStart3D.y, pointerDragStart3D.x )
- var anglePointer3DToX = Math.atan2(pointer3D.y, pointer3DLength); //近似为 anglePointer3DToX = Math.atan2( pointer3D.y, pointer3D.x )
- //算出两者角度差,作为竖直方向角度差值(rotationDifference.y)
- this.rotationDifference.y = THREE.Math.radToDeg(anglePointerDragStart3DToX - anglePointer3DToX);
- //y分量清零,原向量等价于在XZ轴上的投影向量
- pointerDragStart3D.y = 0;
- pointer3D.y = 0;
- //归一化(/length),求两者夹角作为
- //判断方向,最后记为水平方向角度差值(rotationDifference.x)
- var anglePointerDragStart3DToPointer3D = Math.acos(pointerDragStart3D.dot(pointer3D) / pointerDragStart3D.length() / pointer3D.length());
- if (!isNaN(anglePointerDragStart3DToPointer3D)) {
- this.rotationDifference.x = THREE.Math.radToDeg(anglePointerDragStart3DToPointer3D);
- if (this.pointerDragStart.x < this.pointer.x) {
- this.rotationDifference.x *= -1;
- }
- }
- //更新pointerDragStart记录当前帧坐标,用于下一帧求帧差值
- this.pointerDragStart.copy(this.pointer);
- }
- }
- PanoramaControls.prototype.onMouseMove = function(event) {
-
- this.updatePointer(event.clientX, event.clientY);
- }
- PanoramaControls.prototype.onTouchMove = function(event) {
- this.updatePointer(event.changedTouches[0].clientX, event.changedTouches[0].clientY)
- }
- PanoramaControls.prototype.updatePointer = function(screenX, screenY) {
- this.pointer.x = screenX / this.domElement.clientWidth * 2 - 1; // 屏幕坐标换算相对于canvas的父级
- this.pointer.y = 2 * -(screenY / this.domElement.clientHeight) + 1;
- }
- PanoramaControls.prototype.endRotation = function() {
- this.pointerDragOn = false;
- try{
- var rotationHistoryAverage = averageVectors(this.rotationHistory);
- }catch(e){
- console.error(e)
- }
-
- this.rotationSpeed.set(rotationHistoryAverage.x * 30, rotationHistoryAverage.y * 30);
- }
- PanoramaControls.prototype.onTouchEnd = function(event) {
- if (this.enabled) {
- event.preventDefault();
- event.stopPropagation();
- this.endRotation()
- }
- }
- PanoramaControls.prototype.onMouseUp = function(event) {
- if (this.enabled) {
- event.preventDefault();
- event.stopPropagation();
- this.endRotation()
- }
- }
- PanoramaControls.prototype.update = function(deltaTime) {
- if (this.enabled) {
- this.updateRotation();
- for (this.rotationHistory.push(this.rotationDifference.clone()); this.rotationHistory.length > 5;) {
- this.rotationHistory.shift();
- }
- this.lon += this.rotationDifference.x;
- this.lat += this.rotationDifference.y;
- this.rotationDifference.set(0, 0);
- this.rotationSpeed.x = this.rotationSpeed.x * (1 - 0.05) + this.rotationAcc.x * 4.5;
- this.rotationSpeed.y = this.rotationSpeed.y * (1 - 0.05) + this.rotationAcc.y * 4.5;
- this.lon += this.rotationSpeed.x * deltaTime;
- this.lat += this.rotationSpeed.y * deltaTime;
-
- this.lat = Math.max(this.latMin, Math.min(this.latMax, this.lat));
- this.phi = THREE.Math.degToRad(90 - this.lat);
- this.theta = THREE.Math.degToRad(this.lon);
- this.lookVector.x = Math.sin(this.phi) * Math.cos(this.theta);
- this.lookVector.y = Math.cos(this.phi);
- this.lookVector.z = Math.sin(this.phi) * Math.sin(this.theta);
- this.camera.position.add(this.translationWorldDelta)
- this.translationWorldDelta.multiplyScalar(0.9);
-
- this.target.copy(this.lookVector).add(this.aimFrom);
- this.camera.lookAt(this.target)
-
-
-
- }
- }
- PanoramaControls.prototype.onMouseWheel = function(event) {
- /* if (this.enabled) {
- // let z = void 0 !== event['wheelDelta'] ? event['wheelDelta'] : 0 !== event.detail && -event.detail;
- // this.flyDirection(new THREE.Vector3(0, 0, -z).normalize());
- this._wheel = Math.floor(event['wheelDeltaY'] / 120);
- this._wheel = Math.abs(this._wheel) > 0.1 ? Math.sign(this._wheel) : 0;
- if (this._wheel !== 0 && this.scrollZoomSta) {
- this._wheel > 0 ? this._wheel = 1 + this.scrollZoomSpeed : this._wheel = 1 - this.scrollZoomSpeed;
- let curZoomLevel = this._wheel * this.zoomLevel;
- this.zoomTo(curZoomLevel);
- }
- } */
-
- let delta
- if (event.wheelDelta !== undefined) { // WebKit / Opera / Explorer 9
- delta = event.wheelDelta;
- } else if (event.detail !== undefined) { // Firefox
- delta = -event.detail;
- }
-
-
-
- if(delta != void 0){//滚轮缩放
- if(delta == 0)return //mac
- let direction = new THREE.Vector3(0,0,-1).applyQuaternion(this.camera.quaternion)
- let moveSpeed = 0.1
- if(delta < 0) moveSpeed *=-1
- this.translationWorldDelta.add(direction.multiplyScalar(moveSpeed))
- }
-
- }
- PanoramaControls.prototype.zoomTo = function(curZoomLevel) {
- curZoomLevel < this.zoomMin && (curZoomLevel = this.zoomMin);
- curZoomLevel > this.zoomMax && (curZoomLevel = this.zoomMax);
- this.zoomLevel = curZoomLevel;
- this.camera.fov = this.baseFov*(1/this.zoomLevel);
- this.camera.updateProjectionMatrix();
- }
- /*
- reset() {
- this.stop()
- }
- stop() {
- this.rotationAcc.set(0, 0);
- this.rotationSpeed.set(0, 0);
- }
- */
- //-------------copyFromPlayer
- PanoramaControls.prototype.handleControlScroll = function(e) {
- e > 0 ? e = 1 + this.scrollZoomSpeed : e < 0 && (e = 1 - this.scrollZoomSpeed);
- 0 !== e && this.zoomBy(e)
- }
- PanoramaControls.prototype.zoomBy = function(e) {
- this.zoomTo(this.zoomLevel * e);
- }
- function averageVectors(e, t) {
- var i = new THREE.Vector3();
- if (0 === e.length) return i;
- for (var r = 0, o = 0; o < e.length; o++) {
- var a = t ? e[o][t] : e[o];
- i.add(a), r++;
- }
- return i.divideScalar(r);
- }
-
|