从 VRPose.orientation 四元数获取欧拉角
Getting Euler angle from VRPose.orientation Quarternion
我需要获得 phone 所面对的方向与 horizon 之间的角度 theta(见图)。
为此,我正在使用 web-vr polyfill 库,它允许我访问 VRPose.orientation,作为四元数的相机方向。
现在,我正在尝试将四元数转换为欧拉角,以便能够获得我需要的 theta 角,但在我的尝试中,该角不是独立于其他旋转角度(即,如果用户从其位置转身,同时保持 phone 处于相同方向,角度 theta 会发生变化)。
这是我的代码。
var orientation = frameData.pose.orientation
var a = orientation[0]
var b = orientation[1]
var c = orientation[2]
var d = orientation[3]
var yaw, pitch, roll
roll = Math.atan(2*(a*b + c*d)/(pow2(a) - pow2(b) - pow2(c) + pow2(d)))
pitch = - Math.asin(2*(b*d - a*c))
theta = Math.atan(2*(a*d + b*c)/(pow2(a) + pow2(b) - pow2(c) - pow2(d)))
知道我做错了什么或有其他解决方案的建议吗?
谢谢
您可以将四元数应用于单位向量,然后计算角度:
const vec = new THREE.Vector3();
function getCameraAngle() {
// Reset the vector to a unit vector pointing into the scene
vec.set(0, 0, -1);
// Apply the camera quaternion
vec.applyQuaternion(camera.quaternion);
// Calculate the angle based on Y
return Math.asin(vec.y) * THREE.Math.RAD2DEG;
}
const angle = document.getElementById('angle');
function animate() {
angle.textContent = getCameraAngle().toFixed(2);
renderer.render(scene, camera);
};
// Boilerplate
new WebVRPolyfill();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const scene = new THREE.Scene();
const renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.vr.enabled = true;
document.body.appendChild(renderer.domElement);
WEBVR.createButton(renderer);
scene.add(new THREE.AmbientLight('white', 1));
let grid = new THREE.GridHelper();
scene.add(grid);
grid = new THREE.GridHelper();
grid.rotation.x = Math.PI / 2;
grid.position.set(0, 5, -5);
scene.add(grid);
grid = new THREE.GridHelper();
grid.rotation.x = Math.PI / 2;
grid.position.set(0, 5, 5);
scene.add(grid);
grid = new THREE.GridHelper();
grid.rotation.x = Math.PI / 2;
grid.rotation.z = Math.PI / 2;
grid.position.set(5, 5, 0);
scene.add(grid);
grid = new THREE.GridHelper();
grid.rotation.x = Math.PI / 2;
grid.rotation.z = Math.PI / 2;
grid.position.set(-5, 5, 0);
scene.add(grid);
grid = new THREE.GridHelper();
grid.position.set(0, 10, 0);
scene.add(grid);
renderer.setAnimationLoop(animate);
window.addEventListener("resize", () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
body {
margin: 0;
font-size: 0;
}
#angle {
position: absolute;
top: 10px;
left: 10px;
background: white;
font-size: 20pt;
font-family: monospace;
padding: 0.2em;
}
<script src="https://unpkg.com/webvr-polyfill@0.10.6/build/webvr-polyfill.min.js"></script>
<script src="https://unpkg.com/three@0.95.0/build/three.min.js"></script>
<script src="https://unpkg.com/three@0.95.0/examples/js/vr/WebVR.js"></script>
<span id="angle"></span>
我需要获得 phone 所面对的方向与 horizon 之间的角度 theta(见图)。
为此,我正在使用 web-vr polyfill 库,它允许我访问 VRPose.orientation,作为四元数的相机方向。
现在,我正在尝试将四元数转换为欧拉角,以便能够获得我需要的 theta 角,但在我的尝试中,该角不是独立于其他旋转角度(即,如果用户从其位置转身,同时保持 phone 处于相同方向,角度 theta 会发生变化)。
这是我的代码。
var orientation = frameData.pose.orientation
var a = orientation[0]
var b = orientation[1]
var c = orientation[2]
var d = orientation[3]
var yaw, pitch, roll
roll = Math.atan(2*(a*b + c*d)/(pow2(a) - pow2(b) - pow2(c) + pow2(d)))
pitch = - Math.asin(2*(b*d - a*c))
theta = Math.atan(2*(a*d + b*c)/(pow2(a) + pow2(b) - pow2(c) - pow2(d)))
知道我做错了什么或有其他解决方案的建议吗?
谢谢
您可以将四元数应用于单位向量,然后计算角度:
const vec = new THREE.Vector3();
function getCameraAngle() {
// Reset the vector to a unit vector pointing into the scene
vec.set(0, 0, -1);
// Apply the camera quaternion
vec.applyQuaternion(camera.quaternion);
// Calculate the angle based on Y
return Math.asin(vec.y) * THREE.Math.RAD2DEG;
}
const angle = document.getElementById('angle');
function animate() {
angle.textContent = getCameraAngle().toFixed(2);
renderer.render(scene, camera);
};
// Boilerplate
new WebVRPolyfill();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const scene = new THREE.Scene();
const renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.vr.enabled = true;
document.body.appendChild(renderer.domElement);
WEBVR.createButton(renderer);
scene.add(new THREE.AmbientLight('white', 1));
let grid = new THREE.GridHelper();
scene.add(grid);
grid = new THREE.GridHelper();
grid.rotation.x = Math.PI / 2;
grid.position.set(0, 5, -5);
scene.add(grid);
grid = new THREE.GridHelper();
grid.rotation.x = Math.PI / 2;
grid.position.set(0, 5, 5);
scene.add(grid);
grid = new THREE.GridHelper();
grid.rotation.x = Math.PI / 2;
grid.rotation.z = Math.PI / 2;
grid.position.set(5, 5, 0);
scene.add(grid);
grid = new THREE.GridHelper();
grid.rotation.x = Math.PI / 2;
grid.rotation.z = Math.PI / 2;
grid.position.set(-5, 5, 0);
scene.add(grid);
grid = new THREE.GridHelper();
grid.position.set(0, 10, 0);
scene.add(grid);
renderer.setAnimationLoop(animate);
window.addEventListener("resize", () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
body {
margin: 0;
font-size: 0;
}
#angle {
position: absolute;
top: 10px;
left: 10px;
background: white;
font-size: 20pt;
font-family: monospace;
padding: 0.2em;
}
<script src="https://unpkg.com/webvr-polyfill@0.10.6/build/webvr-polyfill.min.js"></script>
<script src="https://unpkg.com/three@0.95.0/build/three.min.js"></script>
<script src="https://unpkg.com/three@0.95.0/examples/js/vr/WebVR.js"></script>
<span id="angle"></span>