|
@@ -1,628 +0,0 @@
|
|
|
-import math from '../util/math'
|
|
|
-import MouseButton from '../enum/MouseButton'
|
|
|
-import ControlEvents from '../enum/eventList/ControlEvents'
|
|
|
-import common from '../util/common'
|
|
|
-import Keys from '../enum/Keys'
|
|
|
-import config from '../../config';
|
|
|
-import transitions from '../util/transitions'
|
|
|
-import lerp from '../util/lerp'
|
|
|
-import easing from '../util/easing'
|
|
|
-import logger from '../../utils/logger'
|
|
|
-import settings from '../settings'
|
|
|
-import {objects} from '../base'
|
|
|
-
|
|
|
-export default class PanoramaControls extends EventEmitter {
|
|
|
- //漫游模式相机控制器
|
|
|
- /**
|
|
|
- * 3D图形变换的坐标系 https://blog.csdn.net/CALL_LKC/article/details/81411034
|
|
|
- * 功能:主要是在漫游模式下控制相机的方向(相机的移动只是做了事件触发,逻辑不在此)
|
|
|
- *
|
|
|
- * 原理:
|
|
|
- * @ 以camera本地坐标系作为参考建立球坐标系,有关球坐标系 https://en.wikipedia.org/wiki/Spherical_coordinate_system
|
|
|
- * @ target作为camera的视点通过鼠标交互在球坐标系运动,然后调用THREE的API:camera.LookAt(target)校正相机方向
|
|
|
- *
|
|
|
- * @param {*} camera 被控制的相机
|
|
|
- */
|
|
|
- constructor(camera, dom,player) {
|
|
|
- super();
|
|
|
- this.camera = camera; //被控制的相机
|
|
|
- this.camera.controls = this;
|
|
|
- this.player = player;
|
|
|
-
|
|
|
-
|
|
|
- this.target = new THREE.Vector3(0, 0, 0); //相机视点,鼠标交互主要影响的对象
|
|
|
- this.lookVector = new THREE.Vector3; //相机方向,以单位向量表示
|
|
|
- this.lookSpeed = .05; //没发现下文用到???
|
|
|
- this.rotationAcc = new THREE.Vector2; //旋转加速度
|
|
|
- this.rotationSpeed = new THREE.Vector2; //旋转速度
|
|
|
-
|
|
|
- /**
|
|
|
- * 球坐标系的相关参数lat,lon 与 phi,theta 两种表示形式
|
|
|
- * 注:少了半径参数,因为是用于约束相机的方向,半径长短在此没有意义,单位1即可,体现在方向向量lookVector上
|
|
|
- */
|
|
|
- this.lat = 0; //纬度,角度表示,直观
|
|
|
- this.lon = 0; //经度,角度表示,直观
|
|
|
- this.phi = 0; //phi,标准球坐标系的参数,弧度表示,用于进行直接计算
|
|
|
- this.theta = 0; //theta,标准球坐标系的参数,弧度表示,用于进行直接计算
|
|
|
-
|
|
|
-
|
|
|
- this.enabled = !1; //是否启用
|
|
|
- this.locked = !1; //是否锁定,可能视角锁死但是其余功能仍在工作
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * 交互行为相关,有鼠标点击与触摸,点击或触摸的地方在此约定统称为交互点
|
|
|
- */
|
|
|
- this.pointer = new THREE.Vector2(0, 0); //交互点的屏幕坐标,有别于DOM坐标,在此存放NDC坐标。(NDC,三维常用坐标系,二维坐标,整个屏幕映射范围(-1,1),屏幕中心为原点,+Y朝上,+X朝右)
|
|
|
- this.pointersLimit = 2; //触摸事件的触摸点的限制个数
|
|
|
- this.pointers = []; //存储交互点的坐标
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- this.rotationHistory = [];
|
|
|
- this.rotationDifference = new THREE.Vector2;
|
|
|
- this.pointerDragOn = !1;
|
|
|
- this.pointerDragStart = new THREE.Vector2(0, 0);
|
|
|
- this.pinchDistance = 0;
|
|
|
- this.moveStart = new THREE.Vector2;
|
|
|
- this.moveTolerance = .01; //拖拽与点击两种交互行为通过鼠标移动距离的临界值来区分,即为此
|
|
|
-
|
|
|
- //鼠标所交互的界面元素
|
|
|
- this.dom = dom;
|
|
|
- //固定垂直视角,许钟文
|
|
|
- this.limitDownAngel = null;
|
|
|
- this.insideLookLimitDown = null;
|
|
|
- }
|
|
|
-
|
|
|
- usable() {
|
|
|
- return this.enabled && !this.locked
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 根据新的方向向量计算所指向的球面坐标(lat,lon)
|
|
|
- * 用到了标准的笛卡尔坐标系转球面坐标系的数学方法
|
|
|
- * 注:THREE 的 Vector3 与 Spherical 两个数学类有互转的方法
|
|
|
- * @param {THREE.Vector3} direction
|
|
|
- */
|
|
|
- lookAt(aim, dir) {
|
|
|
- var t = dir || this.camera.position.clone().sub(aim); //aim所指点的笛卡尔坐标系
|
|
|
-
|
|
|
- /**
|
|
|
- * 以下全为笛卡尔坐标->球座标,不多赘述
|
|
|
- */
|
|
|
- var i = Math.atan(t.z / t.x);
|
|
|
- i += t.x < 0 ? Math.PI : 0;
|
|
|
- i += t.x > 0 && t.z < 0 ? 2 * Math.PI : 0;
|
|
|
- this.lon = THREE.Math.radToDeg(i) + 180;
|
|
|
- var n = Math.sqrt(t.x * t.x + t.z * t.z),
|
|
|
- o = Math.atan(t.y / n);
|
|
|
- this.lat = -THREE.Math.radToDeg(o);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 许钟文 加 看向某个位置
|
|
|
- * 逐渐看向某个位置 通过改变lon和lat
|
|
|
- * @param {THREE.Vector3} aim
|
|
|
- * @param {THREE.Vector3} cameraPos
|
|
|
- * @param {JSON} option
|
|
|
- */
|
|
|
- startLookAt(aim, cameraPos, option) {
|
|
|
- var useLonLat = option && (option.lon != void 0 || option.lat != void 0);
|
|
|
- if (!useLonLat) {
|
|
|
- var e = cameraPos ? cameraPos.clone().sub(aim) : this.camera.position.clone().sub(aim),
|
|
|
- o = Math.atan(e.z / e.x);
|
|
|
- o += e.x < 0 ? Math.PI : 0,
|
|
|
- o += e.x > 0 && e.z < 0 ? 2 * Math.PI : 0;
|
|
|
- var lon = THREE.Math.radToDeg(o) + 180;
|
|
|
- var n = Math.sqrt(e.x * e.x + e.z * e.z),
|
|
|
- i = Math.atan(e.y / n);
|
|
|
- var lat = -THREE.Math.radToDeg(i);
|
|
|
-
|
|
|
- var add = (lon - this.lon) % 360;
|
|
|
- Math.abs(add) > 180 && (add > 0 ? add -= 360 : add += 360);
|
|
|
- lon = this.lon + add;
|
|
|
- var add = (lat - this.lat) % 360;
|
|
|
- Math.abs(add) > 180 && (add > 0 ? add -= 360 : add += 360);
|
|
|
- lat = this.lat + add;
|
|
|
- }
|
|
|
- var time = 1200,
|
|
|
- speedFuc = easing["easeInOutQuad"];
|
|
|
- if (option != void 0) {
|
|
|
- if (option.soon) {
|
|
|
- this.lon = lon;
|
|
|
- this.lat = lat;
|
|
|
- return;
|
|
|
- }
|
|
|
- if (option.speed) {
|
|
|
- /* var a = Math.abs(lon - this.lon) * Math.PI /180;
|
|
|
- var b = Math.abs(lat - this.lat) * Math.PI /180;
|
|
|
- var c0 = Math.sqrt(Math.pow(Math.sin(a/2),2) + Math.pow(Math.sin(b/2),2));
|
|
|
- var c = Math.asin(c0) * 2; //得到旋转角度 cos(c/2)的方 = cos(a/2)的方 + cos(b/2)的方
|
|
|
- time = c / option.speed; */
|
|
|
- if (useLonLat) {
|
|
|
- var c1 = option.lon ? Math.abs(option.lon - this.lon) : 0;
|
|
|
- var c2 = option.lat ? Math.abs(option.lat - this.lat) : 0;
|
|
|
- var c = c1 + c2;
|
|
|
- } else
|
|
|
- var c = Math.abs(lon - this.lon) + Math.abs(lat - this.lat)
|
|
|
-
|
|
|
- time = c / option.speed; //总角度除以速度
|
|
|
- if (option.time)
|
|
|
- time = Math.min(option.time, time);
|
|
|
- } else if (option.time)
|
|
|
- time = option.time;
|
|
|
-
|
|
|
- option.fuc && setTimeout(option.fuc, time)
|
|
|
- //匀速:
|
|
|
- option.constantSpeed && (speedFuc = null);
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
- if (useLonLat) {
|
|
|
- if (option.lon)
|
|
|
- transitions.start(lerp.property(this, "lon", option.lon), time, null, 0, speedFuc);
|
|
|
- if (option.lat)
|
|
|
- transitions.start(lerp.property(this, "lat", option.lat), time, null, 0, speedFuc);
|
|
|
- } else {
|
|
|
- transitions.start(lerp.property(this, "lon", lon), time, null, 0, speedFuc);
|
|
|
- transitions.start(lerp.property(this, "lat", lat), time, null, 0, speedFuc);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 记录拖拽旋转开始时的一些状态
|
|
|
- * @param {number} clientX 屏幕坐标
|
|
|
- * @param {number} clientY 屏幕坐标
|
|
|
- */
|
|
|
- startRotationFrom(clientX, clientY) {
|
|
|
- //以屏幕中心为原点,得到pointer在屏幕的百分比
|
|
|
- var mouse = math.handelPadding(clientX, clientY, this.dom);
|
|
|
- math.convertScreenPositionToNDC(mouse.x, mouse.y, this.pointer, this.dom);
|
|
|
- this.pointerDragOn = !0;
|
|
|
- this.pointerDragStart.copy(this.pointer);
|
|
|
- this.moveStart.copy(this.pointer);
|
|
|
- this.rotationHistory = [];
|
|
|
- this.rotationSpeed.set(0, 0);
|
|
|
- }
|
|
|
-
|
|
|
- onMouseOver(mouseEvent) {
|
|
|
- !this.pointerDragOn || 0 !== mouseEvent.which && 0 !== mouseEvent.buttons || this.onMouseUp(mouseEvent)
|
|
|
- }
|
|
|
-
|
|
|
- onTouchStart(pointerEvent) {
|
|
|
- if (this.usable()) {
|
|
|
- pointerEvent.preventDefault();
|
|
|
- pointerEvent.stopPropagation();
|
|
|
- switch (pointerEvent.touches.length) {
|
|
|
- case 1:
|
|
|
- this.startRotationFrom(pointerEvent.touches[0].clientX, pointerEvent.touches[0].clientY);
|
|
|
- break;
|
|
|
- case 2:
|
|
|
- var t = (pointerEvent.touches[0].clientX - pointerEvent.touches[1].clientX) / app.player.domElement.clientWidth,
|
|
|
- i = (pointerEvent.touches[0].clientY - pointerEvent.touches[1].clientY) / app.player.domElement.clientHeight;
|
|
|
- this.pinchDistance = Math.sqrt(t * t + i * i);
|
|
|
- }
|
|
|
- this.emit(ControlEvents.InputStart, "touch");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- onPointerDown(pointerEvent) {
|
|
|
- if (this.usable() && "touch" === pointerEvent.pointerType)
|
|
|
- {
|
|
|
- if (this.pointers.length < this.pointersLimit)
|
|
|
- {
|
|
|
- this.pointers.push({
|
|
|
- id: pointerEvent.pointerId,
|
|
|
- clientX: pointerEvent.clientX,
|
|
|
- clientY: pointerEvent.clientY
|
|
|
- });
|
|
|
- }
|
|
|
- pointerEvent.touches = this.pointers;
|
|
|
- this.onTouchStart(pointerEvent);
|
|
|
- this.emit(ControlEvents.InputStart, "pointer");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- onMouseDown(mouseEvent) {
|
|
|
- if (this.usable()) {
|
|
|
- mouseEvent.preventDefault();
|
|
|
- mouseEvent.stopPropagation();
|
|
|
- switch (mouseEvent.button) {
|
|
|
- case MouseButton.LEFT:
|
|
|
- this.startRotationFrom(mouseEvent.clientX, mouseEvent.clientY)
|
|
|
- }
|
|
|
- this.emit(ControlEvents.InputStart, "mouse")
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 根据两帧交互点坐标之间的差值,计算两帧角度差值(rotationDifference)用于旋转
|
|
|
- * 1.将两次交互点坐标分别映射到3D空间
|
|
|
- * 2.通过两坐标在XY平面上投影,分别计算与X轴夹角,再求差值作为竖直方向角度差值(rotationDifference.y)
|
|
|
- * 3.通过两坐标在XZ平面上投影,分别计算与X轴夹角,再求差值作为水平方向角度差值(rotationDifference.x)
|
|
|
- */
|
|
|
- updateRotation() {//算拖拽过的角度
|
|
|
- if (this.usable() && this.pointerDragOn) {
|
|
|
- this.camera.matrixWorld = new THREE.Matrix4(); //许钟文加 player的cameras里的panorama是不更新matrixworld的,只有player的camera才更新。不明白为什么更新了转动会很慢。为了miniView的相机旋转加这句。
|
|
|
- //两交互点在3D空间的坐标
|
|
|
- var pointerDragStart3D = new THREE.Vector3(this.pointerDragStart.x, this.pointerDragStart.y, -1).unproject(this.camera),
|
|
|
- pointer3D = new THREE.Vector3(this.pointer.x, this.pointer.y, -1).unproject(this.camera)
|
|
|
-
|
|
|
- //两交互点分别到原点的长度
|
|
|
- ,
|
|
|
- pointerDragStart3DLength = Math.sqrt(pointerDragStart3D.x * pointerDragStart3D.x + pointerDragStart3D.z * pointerDragStart3D.z),
|
|
|
- pointer3DLength = Math.sqrt(pointer3D.x * pointer3D.x + pointer3D.z * pointer3D.z)
|
|
|
-
|
|
|
- //通过Math.atan2计算分别与X轴的夹角弧度。
|
|
|
- //注:因为 z = -1,所以两者到原点的长度近似为x分量,此处只是注重方上,数值的大小没有绝对对应关系
|
|
|
- ,
|
|
|
- anglePointerDragStart3DToX = Math.atan2(pointerDragStart3D.y, pointerDragStart3DLength) //近似为 anglePointerDragStart3DToX = Math.atan2( pointerDragStart3D.y, pointerDragStart3D.x )
|
|
|
- ,
|
|
|
- anglePointer3DToX = Math.atan2(pointer3D.y, pointer3DLength); //近似为 anglePointer3DToX = Math.atan2( pointer3D.y, pointer3D.x )
|
|
|
-
|
|
|
- this.camera.updateMatrix();
|
|
|
- this.camera.updateMatrixWorld();
|
|
|
-
|
|
|
- this.rotationDifference.y = THREE.Math.radToDeg(anglePointerDragStart3DToX - anglePointer3DToX);
|
|
|
- pointerDragStart3D.y = 0;
|
|
|
- pointer3D.y = 0;
|
|
|
- var anglePointerDragStart3DToPointer3D = Math.acos(pointerDragStart3D.dot(pointer3D) / pointerDragStart3D.length() / pointer3D.length());
|
|
|
- // isNaN(s) || (this.rotationDifference.x = THREE.Math.radToDeg(s),
|
|
|
- // this.pointerDragStart.x < this.pointer.x && (this.rotationDifference.x *= -1)),
|
|
|
- if (!isNaN(anglePointerDragStart3DToPointer3D))
|
|
|
- {
|
|
|
- this.rotationDifference.x = THREE.Math.radToDeg(anglePointerDragStart3DToPointer3D);
|
|
|
- if (this.pointerDragStart.x < this.pointer.x)
|
|
|
- {
|
|
|
- this.rotationDifference.x *= -1;
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- this.pointerDragStart.copy(this.pointer);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 处理鼠标移动事件
|
|
|
- * 1.计算鼠标的NDC坐标
|
|
|
- * 2.判断是否是拖拽来决定拖拽行为的执行
|
|
|
- * 3.通过预定义的防误触偏差(moveTolerance),来防止一定的误触
|
|
|
- */
|
|
|
- onMouseMove(mouseEvent) {
|
|
|
- if (this.usable())
|
|
|
- {
|
|
|
- //许钟文加handelPadding这一行。
|
|
|
- var mouse = math.handelPadding(mouseEvent.clientX, mouseEvent.clientY, this.dom)
|
|
|
- math.convertScreenPositionToNDC(mouse.x, mouse.y, this.pointer, this.dom);
|
|
|
- if (this.pointerDragOn)
|
|
|
- {
|
|
|
- if (Math.abs(this.pointer.x - this.moveStart.x) > this.moveTolerance || Math.abs(this.pointer.y - this.moveStart.y) > this.moveTolerance)
|
|
|
- {
|
|
|
- this.emit(ControlEvents.Move, "mouse");
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * 处理触摸移动事件
|
|
|
- * 1.单点触控记录NDC坐标
|
|
|
- * 2.双点触控记录两触摸点距离(映射到[0-1]范围)
|
|
|
- */
|
|
|
- onTouchMove(pointerEvent) {
|
|
|
- if (this.usable())
|
|
|
- {
|
|
|
- this.emit(ControlEvents.Move, "touch");
|
|
|
- switch (pointerEvent.touches.length) {
|
|
|
- case 1:
|
|
|
- var mouse = math.handelPadding(pointerEvent.touches[0].clientX, pointerEvent.touches[0].clientY, this.dom);
|
|
|
- math.convertScreenPositionToNDC(mouse.x, mouse.y, this.pointer, this.dom);
|
|
|
- break;
|
|
|
- case 2:
|
|
|
- var t = (pointerEvent.touches[0].clientX - pointerEvent.touches[1].clientX) / app.player.domElement.clientWidth,
|
|
|
- i = (pointerEvent.touches[0].clientY - pointerEvent.touches[1].clientY) / app.player.domElement.clientHeight,
|
|
|
- n = this.pinchDistance - Math.sqrt(t * t + i * i);
|
|
|
- if (Math.abs(n) > .01)
|
|
|
- {
|
|
|
- this.emit(ControlEvents.InteractionDirect);
|
|
|
- this.emit(ControlEvents.Pinch, n);
|
|
|
- this.pinchDistance -= n;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- onPointerMove(pointerEvent) {
|
|
|
- if (this.usable() && "touch" === pointerEvent.pointerType)
|
|
|
- {
|
|
|
- this.pointers.forEach(function(t) {
|
|
|
- if (pointerEvent.pointerId === t.id)
|
|
|
- {
|
|
|
- t.clientX = pointerEvent.clientX;
|
|
|
- t.clientY = pointerEvent.clientY;
|
|
|
- }
|
|
|
- });
|
|
|
- pointerEvent.touches = this.pointers;
|
|
|
- this.onTouchMove(pointerEvent);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 旋转终止后的行为
|
|
|
- * 1.通过已记录的一组帧旋转量(rotationDifference)求平均值作为停止后惯性速度参考值。
|
|
|
- * 2.通过设置的rotationAfterMoveMultiplier(惯性速度决定因子,用于手动指定影响惯性速度大小),来计算最后的的惯性速度
|
|
|
- */
|
|
|
- endRotation() {
|
|
|
- this.pointerDragOn = !1;
|
|
|
- var e = common.averageVectors(this.rotationHistory);
|
|
|
- this.rotationSpeed.set(e.x * settings.rotationAfterMoveMultiplierX, e.y * settings.rotationAfterMoveMultiplierY)
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 触摸结束触发endRotation行为
|
|
|
- */
|
|
|
- onTouchEnd(pointerEvent) {
|
|
|
- if (this.usable())
|
|
|
- {
|
|
|
- pointerEvent.preventDefault();
|
|
|
- pointerEvent.stopPropagation();
|
|
|
- this.endRotation();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 鼠标抬起触发endRotation行为
|
|
|
- */
|
|
|
- onMouseUp(mouseEvent) {
|
|
|
- if (this.usable())
|
|
|
- {
|
|
|
- mouseEvent.preventDefault();
|
|
|
- mouseEvent.stopPropagation();
|
|
|
- this.endRotation();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- onPointerUp(pointerEvent) {
|
|
|
- if (this.usable() && "touch" === pointerEvent.pointerType)
|
|
|
- {
|
|
|
- this.pointers.forEach(function(t, i) {
|
|
|
- pointerEvent.pointerId === t.id && this.pointers.splice(i, 1)
|
|
|
- }.bind(this));
|
|
|
- pointerEvent.touches = this.pointers;
|
|
|
- this.onTouchEnd(pointerEvent);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 主循环更新,主要通过物理上的刚体旋转行为(角位移,角速度,角加速度,摩擦等)计算得到新的相机视点target,主要是每帧瞬时的状态
|
|
|
- *
|
|
|
- * updateRotation()计算每帧对应的旋转量 rotationDifference
|
|
|
- *
|
|
|
- * 角位移:rotationDifference与原本lon,lat (等价于phi,theta)累加,得到新的角位移
|
|
|
- * 角速度:(rotationDifference数组的平均值 * 速度因子rotationAccelerationInside + 角加速度) - 摩擦rotationFriction。
|
|
|
- *
|
|
|
- * target坐标:新的角位移计算出新的球坐标,转换计算后的球坐标到笛卡尔坐标系
|
|
|
- *
|
|
|
- * @param { number } deltaTime 帧间隔时间。 注:关于帧间隔时间,是个有关物理计算的很重要的值,用于保持物理量与绝对时间的对应而不受帧率的的干扰,下文计算角速度用到。更多请见 https://blog.csdn.net/ChinarCSDN/article/details/82914420
|
|
|
- */
|
|
|
- update(deltaTime) {
|
|
|
- //移动端是鱼眼模式,过渡的时候需要采用鱼眼的算法来计算
|
|
|
-
|
|
|
- // if(!objects.play.ifPlay()){
|
|
|
- // //许钟文-add------某些时刻不旋转
|
|
|
- // if(settings.vrEnabled || !this.player.flying &&!this.player.flyRotate && this.player.mode == "panorama"){
|
|
|
- // //原地mousemove旋转时,只需要直接改camera的quarternion
|
|
|
- // return;
|
|
|
- // }
|
|
|
- // }
|
|
|
- //许钟文-add------某些时刻不旋转
|
|
|
- //if(settings.vrEnabled && !window.ifTest || !this.player.flying &&!this.player.flyRotate && this.player.mode == "panorama"&&!objects.play.control.onUpdate){
|
|
|
- if((settings.vrEnabled && !window.ifTest) || !this.player.flying &&!this.player.flyRotate && this.player.mode == "panorama"&&!objects.play.control.onUpdate){
|
|
|
- //原地mousemove旋转时,只需要直接改camera的quarternion
|
|
|
- //logger.info('不执行PanoramaControls的update');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- // 求出新的rotationDifference
|
|
|
- this.updateRotation();
|
|
|
-
|
|
|
- //记录一组rotationDifference 用于求角速度 rotationSpeed。注:见 endRotation()
|
|
|
- for (this.rotationHistory.push(this.rotationDifference.clone()); this.rotationHistory.length > settings.rotationAfterMoveHistoryCount;)
|
|
|
- {
|
|
|
- this.rotationHistory.shift();
|
|
|
- }
|
|
|
-
|
|
|
- //计算角位移(交互影响下的)
|
|
|
- this.lon += this.rotationDifference.x;
|
|
|
- this.lat += this.rotationDifference.y;
|
|
|
- this.rotationDifference.set(0, 0);
|
|
|
- //计算角速度
|
|
|
- var friction = Math.min(1, settings.rotationFriction * deltaTime * 60) //如果deltaTime > 1/ 60 (比较卡),就增加rotationFriction, 以防止转动过久
|
|
|
- this.rotationSpeed.x = this.rotationSpeed.x * (1 - friction) + this.rotationAcc.x * settings.rotationAccelerationInside;
|
|
|
- this.rotationSpeed.y = this.rotationSpeed.y * (1 - friction) + this.rotationAcc.y * settings.rotationAccelerationInside;
|
|
|
- //计算角位移(交互后,物理定律影响下的)
|
|
|
- this.lon += this.rotationSpeed.x * deltaTime;
|
|
|
- this.lat += this.rotationSpeed.y * deltaTime;
|
|
|
-
|
|
|
- //许钟文
|
|
|
- if(this.limitDownAngel == null){//许钟文 在手机编辑墙壁时俯视角度可以增大
|
|
|
- this.lat = Math.max(this.insideLookLimitDown!=null ? this.insideLookLimitDown : settings.insideLookLimitDown, Math.min(settings.insideLookLimitUp, this.lat)); //通过预定义的俯仰角最大最小范围(insideLookLimitUp、insideLookLimitDown)来限制俯仰角。 注:这种数学计算很常见,因此API也很常见(clamp),等价于 this.lat = THREE.Math.clamp( this.lat, settings.insideLookLimitDown, settings.insideLookLimitUp );
|
|
|
- }
|
|
|
- else{
|
|
|
- this.lat = this.limitDownAngel;//固定垂直视角
|
|
|
- }
|
|
|
- //转换为标准球坐标参数形式,并最终转换为笛卡尔坐标系下
|
|
|
- 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);
|
|
|
-
|
|
|
- //求taget坐标: 当前相机位置 + 方向向量(对于此处旋转来说距离并无意义,方向向量的1即可)
|
|
|
- this.target.copy(this.lookVector).add(this.camera.position);
|
|
|
-
|
|
|
- //THREE的API来更新相机旋转。注:lookAt是四阶矩阵比较常见的API,因此此PanoramaControls计算流程,不算与THREE耦合
|
|
|
- this.camera.lookAt(this.target);
|
|
|
- }
|
|
|
-
|
|
|
- //许钟文 加 用于鱼眼过渡
|
|
|
- updateByLookVectorFish(onlyGetVector) {
|
|
|
- var lookVector;
|
|
|
- //前面几个条件的意思就是:只要不是简单不旋转的那种flying,就需要计算这些:
|
|
|
- if (!this.player.flying || this.player.flyingToTag ||
|
|
|
- this.player.flyRotate || this.player.flyingWithRot ||
|
|
|
- this.player.isWarping() || onlyGetVector) { //减少计算
|
|
|
-
|
|
|
- //if(!(this.player.flying && !this.player.flyingToTag && !player.isWarping() ) || onlyGetVector){//减少计算
|
|
|
- this.lat = Math.max(settings.insideLookLimitDown, Math.min(settings.insideLookLimitUp, this.lat)),
|
|
|
- this.phi = THREE.Math.degToRad(90 - this.lat),
|
|
|
- this.theta = THREE.Math.degToRad(this.lon)
|
|
|
- //FishCam_BackDist: 4/11
|
|
|
- lookVector = new THREE.Vector3;
|
|
|
- var backDist = settings.FishCam_BackDist;
|
|
|
- lookVector.x = settings.skyRadius * backDist * Math.sin(this.phi) * Math.cos(this.theta); //改
|
|
|
- lookVector.y = settings.skyRadius * backDist * Math.cos(this.phi);
|
|
|
- lookVector.z = settings.skyRadius * backDist * Math.sin(this.phi) * Math.sin(this.theta); //改
|
|
|
- this.fishState && this.camera.position.copy(lookVector).negate().add(this.target);
|
|
|
- }
|
|
|
- if (!onlyGetVector && !this.fishState) {
|
|
|
- lookVector && this.lookVector.copy(lookVector)
|
|
|
- this.target = this.player.currentTarget.clone();
|
|
|
- this.camera.position.copy(this.lookVector).negate().add(this.target);
|
|
|
- this.camera.lookAt(this.target);
|
|
|
- } else {
|
|
|
- return lookVector;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 滚轮行为: 触发自定义事件
|
|
|
- */
|
|
|
- onMouseWheel(wheelEvent) {
|
|
|
- if (this.usable()) {
|
|
|
- var t = wheelEvent.wheelDelta || -wheelEvent.detail;
|
|
|
- this.emit(ControlEvents.InteractionDirect);
|
|
|
- this.emit(ControlEvents.Scroll, t);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 键盘按下:触发自定义事件
|
|
|
- */
|
|
|
- onKeyDown(keyboardEvent) {
|
|
|
- if (this.usable())
|
|
|
- {
|
|
|
- if (keyboardEvent.metaKey || keyboardEvent.ctrlKey) {}
|
|
|
- else {
|
|
|
-
|
|
|
- if (config.isTyping || config.isDisableControl) {
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- keyboardEvent.preventDefault();
|
|
|
- this.handleKeyDown(keyboardEvent.which);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- handleKeyDown(keyValue) {
|
|
|
- var t = function(e, t) {
|
|
|
- this.rotationAcc[e] = t
|
|
|
- }
|
|
|
- .bind(this);
|
|
|
- this.emit(ControlEvents.InteractionKey);
|
|
|
- var i = !0;
|
|
|
- switch (keyValue) {
|
|
|
- case Keys.LEFTARROW:
|
|
|
- case Keys.J:
|
|
|
- t("x", -1);
|
|
|
- break;
|
|
|
- case Keys.RIGHTARROW:
|
|
|
- case Keys.L:
|
|
|
- t("x", 1);
|
|
|
- break;
|
|
|
- case Keys.I:
|
|
|
- t("y", 1);
|
|
|
- break;
|
|
|
- case Keys.K:
|
|
|
- t("y", -1);
|
|
|
- break;
|
|
|
- default:
|
|
|
- i = !1
|
|
|
- }
|
|
|
- i && this.emit(ControlEvents.Move, "key")
|
|
|
- }
|
|
|
-
|
|
|
- onKeyUp(keyboardEvent) {
|
|
|
- if (this.usable())
|
|
|
- {
|
|
|
- keyboardEvent.preventDefault();
|
|
|
- keyboardEvent.stopPropagation();
|
|
|
- this.handleKeyUp(keyboardEvent.which);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- handleKeyUp(keyValue) {
|
|
|
- switch (keyValue) {
|
|
|
- case Keys.LEFTARROW:
|
|
|
- case Keys.J:
|
|
|
- case Keys.RIGHTARROW:
|
|
|
- case Keys.L:
|
|
|
- this.rotationAcc.x = 0;
|
|
|
- break;
|
|
|
- case Keys.I:
|
|
|
- case Keys.K:
|
|
|
- this.rotationAcc.y = 0
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- startRotating(e, t) {
|
|
|
- e && (this.rotationAcc.x = e);
|
|
|
- t && (this.rotationAcc.y = t);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 通过物理定律来终止旋转
|
|
|
- */
|
|
|
- stopRotating(e) {
|
|
|
- e && (this.rotationSpeed.x = this.rotationSpeed.y = 0);
|
|
|
- this.rotationAcc.set(0, 0);
|
|
|
- }
|
|
|
-
|
|
|
- reset() {
|
|
|
- this.pointerDragOn = !1;
|
|
|
- this.rotationAcc.set(0, 0);
|
|
|
- this.rotationSpeed.set(0, 0);
|
|
|
- this.pointers = [];
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 序列化,用于保存状态。
|
|
|
- */
|
|
|
- toJSON() {
|
|
|
- var cameraSpatialInfo = {
|
|
|
- camera_position: {
|
|
|
- x: math.toPrecision(this.camera.position.x, 4),
|
|
|
- y: math.toPrecision(this.camera.position.y, 4),
|
|
|
- z: math.toPrecision(this.camera.position.z, 4)
|
|
|
- },
|
|
|
- camera_quaternion: {
|
|
|
- x: math.toPrecision(this.camera.quaternion.x, 4),
|
|
|
- y: math.toPrecision(this.camera.quaternion.y, 4),
|
|
|
- z: math.toPrecision(this.camera.quaternion.z, 4),
|
|
|
- w: math.toPrecision(this.camera.quaternion.w, 4)
|
|
|
- }
|
|
|
- };
|
|
|
- return cameraSpatialInfo;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 反序列化,用于读取状态
|
|
|
- */
|
|
|
- setStateFromJSON(cameraSpatialInfo) {
|
|
|
- this.camera.position.copy(cameraSpatialInfo.camera_position);
|
|
|
- this.camera.quaternion.copy(cameraSpatialInfo.camera_quaternion);
|
|
|
- }
|
|
|
-}
|