[英]Device Orientation Controls using an object and not a camera in Three.js
[英]Three.js: rotate camera with both touch and device orientation
我正在使用threejs制作3D項目,該項目允許使用鼠標控制計算機設備的相機,還允許控制觸摸事件和智能手機的deviceorientation事件。 例如, 該站點的工作方式與我想要的相同。
當我使用OrbitControls在PC版本上移動攝像頭時,我將touchstart / move / end事件綁定到mousedown / move / up上, 並且效果很好 。
問題是當我嘗試添加設備方向事件的值時。 這是我嘗試在OrbitControls.js中添加的內容:
THREE.OrbitControls = function (object, domElement) {
const scope = this;
let lastBeta = 0;
let lastGamma = 0;
this.deviceOrientation = {};
function onDeviceOrientationChangeEvent(event) {
scope.deviceOrientation = event;
// Z
var alpha = scope.deviceOrientation.alpha
? THREE.Math.degToRad(scope.deviceOrientation.alpha)
: 0;
// X'
var beta = scope.deviceOrientation.beta
? THREE.Math.degToRad(scope.deviceOrientation.beta)
: 0;
// Y''
var gamma = scope.deviceOrientation.gamma
? THREE.Math.degToRad(scope.deviceOrientation.gamma)
: 0;
// O
var orient = scope.screenOrientation
? THREE.Math.degToRad(scope.screenOrientation)
: 0;
rotateLeft(lastGamma - gamma);
rotateUp(lastBeta - beta);
lastBeta = beta; //is working
lastGamma = gamma; //doesn't work properly
}
window.addEventListener('deviceorientation', onDeviceOrientationChangeEvent, false);
};
由於beta的值在[-180,180]度范圍內,因此垂直旋轉沒有問題,而gamma的范圍為[-90,90],並且在上下定向設備屏幕時該值也會突然變化(即使我認為,它應該返回水平旋轉)。 即使將伽馬的范圍轉換為從-180到180的值,突然的偏移也會使所有操作出錯。
我猜想我必須在deviceOrientationControls.js中使用四元數,但是我真的不知道它是如何工作的,到目前為止,我所做的每一次嘗試都是失敗的。 有誰可以幫助我嗎?
PS:這是對deviceorientation事件的描述的鏈接,以更好地理解真正的alpha beta和gamma。
編輯
我添加了以下代碼片段以顯示beta和gamma的變化。
let deltaBeta = 0; let deltaGamma = 0; if (window.DeviceOrientationEvent) { window.addEventListener('deviceorientation', function (e) { const beta = (e.beta != null) ? Math.round(e.beta) : 0; const gamma = (e.gamma != null) ? Math.round(e.gamma) : 0; deltaBeta = Math.abs(beta - deltaBeta); deltaGamma = Math.abs(gamma - deltaGamma); $("#beta").html("Beta: " + beta); $("#gamma").html("Gamma: " + gamma); if (Math.abs(deltaBeta) > Math.abs(Number($("#deltaBeta").html()))) { $("#deltaBeta").html(deltaBeta); if (Number($("#deltaBeta").html()) >= 30) { $("#deltaBeta").removeAttr("class", "blue").addClass("red"); } } if (Math.abs(deltaGamma) > Math.abs(Number($("#deltaGamma").html()))) { $("#deltaGamma").html(deltaGamma); if (Number($("#deltaGamma").html()) >= 30) { $("#deltaGamma").removeAttr("class", "blue").addClass("red"); } } }, true); } else { $("#gamma").html("deviceorientation not supported"); }
.red { color: red; font-weight: bold; } .blue { color: blue; font-weight: bold; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <body> <div> <span id="beta"></span> <span> [-180; 180]</span> </div> <div> <span>DeltaMax</span> <span id="deltaBeta" class="blue">0</span> </div> <div> <span id="gamma"></span> <span> [-90; 90]</span> </div> <div> <span>DeltaMax</span> <span id="deltaGamma" class="blue">0</span> </div> </body>
我找到了使用將四元數轉換為弧度的函數的解決方案,因此如果有人想使用OrbitControls進行點擊/觸摸+設備方向控制,我想共享它。
我采用初始方向(x1,y1,z1)並計算新的方向(x2,y2,z3),它們之間的差是相機旋轉的變化。 我將這些行添加到初始更新功能
this.update = function () {
// Z
const alpha = scope.deviceOrientation.alpha
? THREE.Math.degToRad(scope.deviceOrientation.alpha)
: 0;
// X'
const beta = scope.deviceOrientation.beta
? THREE.Math.degToRad(scope.deviceOrientation.beta)
: 0;
// Y''
const gamma = scope.deviceOrientation.gamma
? THREE.Math.degToRad(scope.deviceOrientation.gamma)
: 0;
// O
const orient = scope.screenOrientation
? THREE.Math.degToRad(scope.screenOrientation)
: 0;
const currentQ = new THREE.Quaternion().copy(scope.object.quaternion);
setObjectQuaternion(currentQ, alpha, beta, gamma, orient);
const currentAngle = Quat2Angle(currentQ.x, currentQ.y, currentQ.z, currentQ.w);
// currentAngle.z = left - right
this.rotateLeft((lastGamma - currentAngle.z) / 2);
lastGamma = currentAngle.z;
// currentAngle.y = up - down
this.rotateUp(lastBeta - currentAngle.y);
lastBeta = currentAngle.y;
}
function onDeviceOrientationChangeEvent(event) {
scope.deviceOrientation = event;
}
window.addEventListener('deviceorientation', onDeviceOrientationChangeEvent, false);
function onScreenOrientationChangeEvent(event) {
scope.screenOrientation = window.orientation || 0;
}
window.addEventListener('orientationchange', onScreenOrientationChangeEvent, false);
var setObjectQuaternion = function () {
const zee = new THREE.Vector3(0, 0, 1);
const euler = new THREE.Euler();
const q0 = new THREE.Quaternion();
const q1 = new THREE.Quaternion(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5));
return function (quaternion, alpha, beta, gamma, orient) {
// 'ZXY' for the device, but 'YXZ' for us
euler.set(beta, alpha, -gamma, 'YXZ');
// Orient the device
quaternion.setFromEuler(euler);
// camera looks out the back of the device, not the top
quaternion.multiply(q1);
// adjust for screen orientation
quaternion.multiply(q0.setFromAxisAngle(zee, -orient));
}
} ();
function Quat2Angle(x, y, z, w) {
let pitch, roll, yaw;
const test = x * y + z * w;
// singularity at north pole
if (test > 0.499) {
yaw = Math.atan2(x, w) * 2;
pitch = Math.PI / 2;
roll = 0;
return new THREE.Vector3(pitch, roll, yaw);
}
// singularity at south pole
if (test < -0.499) {
yaw = -2 * Math.atan2(x, w);
pitch = -Math.PI / 2;
roll = 0;
return new THREE.Vector3(pitch, roll, yaw);
}
const sqx = x * x;
const sqy = y * y;
const sqz = z * z;
yaw = Math.atan2((2 * y * w) - (2 * x * z), 1 - (2 * sqy) - (2 * sqz));
pitch = Math.asin(2 * test);
roll = Math.atan2((2 * x * w) - (2 * y * z), 1 - (2 * sqx) - (2 * sqz));
return new THREE.Vector3(pitch, roll, yaw);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.