Actionscript 3 AS3中陀螺仪全景角计算的数学方法
我正在尝试添加数学,用陀螺仪控制全景图,并且正在努力。这是AS3内置的移动应用程序 我得到了来自陀螺仪(x和y)的数据,还有当前的角度(平移和倾斜)。我想做的是根据陀螺仪的数据用新角度更新cameraController 我一直在尝试将我在上面找到的Javascript转换为ActionScript3,它可以正常工作,但不是真的 编辑 谢谢,我尝试了这些改变,我添加了相机回滚,因为euler数学需要它,它运行,但数学有问题 全景图似乎只是向上和向左漂移,在以另一种方式移动手机一段时间后,它会向下漂移,然后向右移动 你能看到我在Javascript中遗漏的重要内容吗Actionscript 3 AS3中陀螺仪全景角计算的数学方法,actionscript-3,math,mobile,air,gyroscope,Actionscript 3,Math,Mobile,Air,Gyroscope,我正在尝试添加数学,用陀螺仪控制全景图,并且正在努力。这是AS3内置的移动应用程序 我得到了来自陀螺仪(x和y)的数据,还有当前的角度(平移和倾斜)。我想做的是根据陀螺仪的数据用新角度更新cameraController 我一直在尝试将我在上面找到的Javascript转换为ActionScript3,它可以正常工作,但不是真的 编辑 谢谢,我尝试了这些改变,我添加了相机回滚,因为euler数学需要它,它运行,但数学有问题 全景图似乎只是向上和向左漂移,在以另一种方式移动手机一段时间后,它会向下
import com.adobe.nativeExtensions.GyroscopeEvent;
import flash.events.Event;
import flash.geom.Orientation3D;
public class GyroscopeMaths
{
public function GyroscopeMaths()
{
super();
}
private var isTopAccessible:Boolean = false;
private var isDeviceAvailable:Boolean;
private var isEnabled:Boolean = false;
private var vElasticity:Number = 0;
private var isVRelative:Boolean = false;
private var isCamRoll:Boolean = false;
private var friction:Number = 0.5;
private var isTouching:Boolean = false;
private var validSample:Boolean = false;
private var firstSample:* = null;
private var hOffset:Number = 0;
private var vOffset:Number = 0;
private var hLookAt:Number = 0;
private var vLookAt:Number = 0;
private var camRoll:Number = 0;
private var vLookAtNow:Number = 0;
private var hLookAtNow:Number = 0;
private var hSpeed:Number = 0;
private var vSpeed:Number = 0;
private var vElasticSpeed:Number = 0;
private var camRollNow:Number;
private var pitch:Number;
private var yaw:Number;
private var altYaw:Number;
private var factor:Number;
private var degRad:Number = Math.PI / 180;
public function handleDeviceOrientation(x:Number, y:Number, z:Number):void {
// Process event.alpha, event.beta and event.gamma
var orientation:* = rotateEuler({
"yaw":y * degRad,
"pitch":x * degRad,
"roll": z * degRad
});
yaw = wrapAngle(orientation.yaw / degRad);
pitch = orientation.pitch / degRad;
altYaw = yaw, factor;
hLookAtNow = Pano.instance.pan;
vLookAtNow = Pano.instance.tilt;
hSpeed = hLookAtNow - hLookAt,
vSpeed = vLookAtNow - vLookAt;
// Ignore all sample until we get a sample that is different from the first sample
if (!validSample) {
if (firstSample == null) {
firstSample = orientation;
} else {
if (orientation.yaw != firstSample.yaw || orientation.pitch != firstSample.pitch || orientation.roll != firstSample.roll) {
firstSample = null;
validSample = true;
if (isVRelative) {
vOffset = -pitch;
}
}
}
return;
}
// Fix gimbal lock
if (Math.abs(pitch) > 70) {
altYaw = y;
var altYaw:Number = wrapAngle(altYaw);
if (Math.abs(altYaw - yaw) > 180) {
altYaw += (altYaw < yaw) ? 360 :-360;
}
var factor:Number = Math.min(1, (Math.abs(pitch) - 70) / 10);
yaw = yaw * (1 - factor) + altYaw * factor;
//camRoll *= (1 - factor);
}
// Track view change since last orientation event
// ie:user has manually panned, or krpano has altered lookat
hOffset += hSpeed;
vOffset += vSpeed;
// Clamp vOffset
if (Math.abs(pitch + vOffset) > 90) {
vOffset = (pitch + vOffset > 0) ? (90 - pitch) :(-90 - pitch)
}
hLookAt = wrapAngle(-yaw - 180 + hOffset);
vLookAt = Math.max(Math.min((pitch + vOffset), 90), -90);
// Dampen lookat
if (Math.abs(hLookAt - hLookAtNow) > 180) {
hLookAtNow += (hLookAt > hLookAtNow) ? 360 :-360;
}
hLookAt = (1 - friction) * hLookAt + friction * hLookAtNow;
vLookAt = (1 - friction) * vLookAt + friction * vLookAtNow;
if (Math.abs(camRoll - camRollNow) > 180) {
camRollNow += (camRoll > camRollNow) ? 360 :-360;
}
camRoll = (1 - friction) * camRoll + friction * camRollNow;
var wAh:Number = wrapAngle(hLookAt);
Pano.instance.panoGyroChange(wAh, vLookAt);
//krpano.view.camroll = wrapAngle(camRoll);
if (vOffset != 0 && vElasticity > 0) {
if (vSpeed == 0) {
if (vElasticity == 1) {
vOffset = 0;
vElasticSpeed = 0;
} else {
// vElasticSpeed = 1 - ((1 - vElasticSpeed) * krpano.control.touchfriction);
vOffset *= 1 - (Math.pow(vElasticity, 2) * vElasticSpeed); // use Math.pow to be able to use saner values
if (Math.abs(vOffset) < 0.1) {
vOffset = 0;
vElasticSpeed = 0;
}
}
} else {
vElasticSpeed = 0;
}
}
}
private function rotateEuler(euler:Object):Object {
// This function is based on http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/index.htm
// and http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToEuler/index.htm
trace(euler);
var heading:Number;
var bank:Number;
var attitude:Number;
var ch:Number = Math.cos(euler.yaw);
var sh:Number = Math.sin(euler.yaw);
var ca:Number = Math.cos(euler.pitch);
var sa:Number = Math.sin(euler.pitch);
var cb:Number = Math.cos(euler.roll);
var sb:Number = Math.sin(euler.roll);
var matrix:Array = [
sh * sb - ch * sa * cb, -ch * ca, ch * sa * sb + sh * cb,
ca * cb, -sa, -ca * sb,
sh * sa * cb + ch * sb, sh * ca, -sh * sa * sb + ch * cb
]; // Note:Includes 90 degree rotation around z axis
/* [m00 m01 m02] 0 1 2
* [m10 m11 m12] 3 4 5
* [m20 m21 m22] 6 7 8 */
if (matrix[3] > 0.9999) {
// Deal with singularity at north pole
heading = Math.atan2(matrix[2], matrix[8]);
attitude = Math.PI / 2;
bank = 0;
} else if (matrix[3] < -0.9999) {
// Deal with singularity at south pole
heading = Math.atan2(matrix[2], matrix[8]);
attitude = -Math.PI / 2;
bank = 0;
} else {
heading = Math.atan2(-matrix[6], matrix[0]);
bank = Math.atan2(-matrix[5], matrix[4]);
attitude = Math.asin(matrix[3]);
}
return {
yaw:heading,
pitch:attitude,
roll:bank
};
}
private function wrapAngle(value:Number):Number {
value = value % 360;
return (value <= 180) ? value :value - 360;
} // wrap a value between -180 and 180
//function stringToBoolean(value:Number):String
//{ return (String("yesontrue1").indexOf( String(value:Number) ) >= 0) };
}
import com.adobe.nativeExtensions.com事件;
导入flash.events.Event;
导入flash.geom.Orientation3D;
公共数学课
{
公共函数(数学)
{
超级();
}
私有变量isTopAccessible:Boolean=false;
私有变量isDeviceAvailable:布尔值;
私有变量isEnabled:Boolean=false;
私有变量的波动率:数值=0;
私有变量isvrrelative:Boolean=false;
私有变量isCamRoll:Boolean=false;
私有var摩擦:数值=0.5;
private-var-isTouching:Boolean=false;
私有变量validSample:Boolean=false;
private var firstSample:*=null;
私有var hOffset:Number=0;
私有变量vOffset:Number=0;
私有变量hLookAt:Number=0;
私有变量vLookAt:Number=0;
私有变量camRoll:编号=0;
私有变量vLookAtNow:Number=0;
私有变量hLookAtNow:Number=0;
私有变量hSpeed:Number=0;
私有变量vSpeed:Number=0;
私有变量velasticpeed:Number=0;
私有变量camRollNow:编号;
专用变桨距:数字;
私有变量:编号;
私有变量:编号;
私有var因子:数量;
私有var DEGRADD:Number=Math.PI/180;
公共函数handleDeviceOrientation(x:编号,y:编号,z:编号):无效{
//处理event.alpha、event.beta和event.gamma
变量方向:*=rotateEuler({
“偏航”:y*降级,
“音高”:x*degRad,
“滚动”:z*D
});
偏航=缠绕(方向偏航/下降);
节距=方向。节距/降级;
altYaw=偏航,系数;
hLookAtNow=Pano.instance.pan;
vLookAtNow=Pano.instance.tilt;
hSpeed=hLookAtNow-hLookAt,
vSpeed=vLookAtNow-vLookAt;
//忽略所有样本,直到得到与第一个样本不同的样本
如果(!validSample){
if(firstSample==null){
第一个样本=方向;
}否则{
if(orientation.yaw!=firstSample.yaw | | orientation.pitch!=firstSample.pitch | | orientation.roll!=firstSample.roll){
firstSample=null;
validSample=true;
如果(是相对的){
vOffset=-音高;
}
}
}
返回;
}
//固定万向节锁
如果(数学绝对值(节距)>70){
altYaw=y;
var-altYaw:Number=wrapAngle(altYaw);
如果(数学abs(高度偏航-偏航)>180){
高度偏航+=(高度偏航<偏航)?360:-360;
}
变量系数:数值=数学最小值(1,(数学绝对值(节距)-70)/10);
偏航=偏航*(1-系数)+偏航*系数;
//凸轮轴*=(1-系数);
}
//自上次定向事件以来的轨迹视图更改
//ie:用户已经手动平移,或者krpano已经改变了注视
hOffset+=hSpeed;
vOffset+=vSpeed;
//夹伏偏移
如果(数学绝对值(节距+偏移量)>90){
音量偏移=(音高+音量偏移>0)?(90音高):(-90音高)
}
hLookAt=绞盘(-偏航-180+hOffset);
vLookAt=数学最大值(数学最小值((螺距+偏移量),90),-90);
//抑制注视
if(Math.abs(hLookAt-hLookAtNow)>180){
hLookAtNow+=(hLookAt>hLookAtNow)?360:-360;
}
hLookAt=(1-摩擦力)*hLookAt+摩擦力*hLookAtNow;
vLookAt=(1-摩擦力)*vLookAt+摩擦力*vLookAtNow;
如果(数学abs(camRoll-camRollNow)>180){
camRollNow+=(camRoll>camRollNow)?360:-360;
}
camRoll=(1-摩擦力)*camRoll+摩擦力*camRollNow;
var wAh:Number=wrapAngle(hLookAt);
Pano.instance.PanoGyrogorChange(哇,vLookAt);
//krpano.view.camroll=wrapAngle(camroll);
如果(vOffset!=0&&vElasticity>0){
如果(vSpeed==0){
如果(vElasticity==1){
vOffset=0;
vElasticSpeed=0;
}否则{
//vElasticSpeed=1-((1-vElasticSpeed)*krpano.control.touchfriction);
vOffset*=1-(Math.pow(vElasticity,2)*vElasticSpeed);//使用Math.pow可以使用更合理的值
if(数学绝对值(偏移量)<0.1){
vOffset=0;
vElasticSpeed=0;
}
}
}否则{
vElasticSpeed=0;
}
}
}
专用函数旋转规则(euler:对象):对象{
//此函数基于http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/index.htm
//及http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToEuler/index.htm
轨迹(欧拉);
var标题:编号;
var银行:编号;
var态度:数量;
变量ch:Number=Math.cos(欧拉偏航);
var sh:Number=Math.sin(euler.yaw);
private var isTopAccessible:Boolean = false;
private var isDeviceAvailable:Boolean;
private var isEnabled:Boolean = false;
private var vElasticity:Number = 0;
private var isVRelative:Boolean = false;
private var isCamRoll:Boolean = false;
private var friction:Number = 0.5;
private var isTouching:Boolean = false;
private var validSample:Boolean = false;
private var firstSample:* = null;
private var hOffset:Number = 0;
private var vOffset:Number = 0;
private var hLookAt:Number = 0;
private var vLookAt:Number = 0;
private var camRoll:Number = 0;
private var vLookAtNow:Number = 0;
private var hLookAtNow:Number = 0;
private var hSpeed:Number = 0;
private var vSpeed:Number = 0;
private var vElasticSpeed:Number = 0;
private var camRollNow:Number;
private var pitch:Number;
private var yaw:Number;
private var altYaw:Number;
private var factor:Number;
private var degRad:Number = Math.PI / 180;
public function handleDeviceOrientation(x:Number, y:Number):void {
// Process event.alpha, event.beta and event.gamma
var orientation:* = rotateEuler({
"yaw":y * degRad,
"pitch":x * degRad,
"roll":0
});
yaw = wrapAngle(orientation.yaw / degRad);
pitch = orientation.pitch / degRad;
altYaw = yaw, factor;
hLookAtNow = Pano.instance.pan;
vLookAtNow = Pano.instance.tilt;
hSpeed = hLookAtNow - hLookAt,
vSpeed = vLookAtNow - vLookAt;
// Ignore all sample until we get a sample that is different from the first sample
if (!validSample) {
if (firstSample == null) {
firstSample = orientation;
} else {
if (orientation.yaw != firstSample.yaw || orientation.pitch != firstSample.pitch || orientation.roll != firstSample.roll) {
firstSample = null;
validSample = true;
if (isVRelative) {
vOffset = -pitch;
}
}
}
return;
}
// Fix gimbal lock
if (Math.abs(pitch) > 70) {
altYaw = y;
/*switch(deviceOrientation) {
case 0:
if ( pitch>0 )
altYaw += 180;
break;
case 90:
altYaw += 90;
break;
case -90:
altYaw += -90;
break;
case 180:
if ( pitch<0 )
altYaw += 180;
break;
}*/
var altYaw:Number = wrapAngle(altYaw);
if (Math.abs(altYaw - yaw) > 180) {
altYaw += (altYaw < yaw) ? 360 :-360;
}
var factor:Number = Math.min(1, (Math.abs(pitch) - 70) / 10);
yaw = yaw * (1 - factor) + altYaw * factor;
//camRoll *= (1 - factor);
}
// Track view change since last orientation event
// ie:user has manually panned, or krpano has altered lookat
hOffset += hSpeed;
vOffset += vSpeed;
// Clamp vOffset
if (Math.abs(pitch + vOffset) > 90) {
vOffset = (pitch + vOffset > 0) ? (90 - pitch) :(-90 - pitch)
}
hLookAt = wrapAngle(-yaw - 180 + hOffset);
vLookAt = Math.max(Math.min((pitch + vOffset), 90), -90);
// Dampen lookat
if (Math.abs(hLookAt - hLookAtNow) > 180) {
hLookAtNow += (hLookAt > hLookAtNow) ? 360 :-360;
}
hLookAt = (1 - friction) * hLookAt + friction * hLookAtNow;
vLookAt = (1 - friction) * vLookAt + friction * vLookAtNow;
if (Math.abs(camRoll - camRollNow) > 180) {
camRollNow += (camRoll > camRollNow) ? 360 :-360;
}
camRoll = (1 - friction) * camRoll + friction * camRollNow;
var wAh:Number = wrapAngle(hLookAt);
Pano.instance.panoGyroChange(wAh, vLookAt);
//krpano.view.camroll = wrapAngle(camRoll);
if (vOffset != 0 && vElasticity > 0) {
if (vSpeed == 0) {
if (vElasticity == 1) {
vOffset = 0;
vElasticSpeed = 0;
} else {
// vElasticSpeed = 1 - ((1 - vElasticSpeed) * krpano.control.touchfriction);
vOffset *= 1 - (Math.pow(vElasticity, 2) * vElasticSpeed); // use Math.pow to be able to use saner values
if (Math.abs(vOffset) < 0.1) {
vOffset = 0;
vElasticSpeed = 0;
}
}
} else {
vElasticSpeed = 0;
}
}
}
private function rotateEuler(euler:Object):Object {
// This function is based on http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/index.htm
// and http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToEuler/index.htm
trace(euler);
var heading:Number;
var bank:Number;
var attitude:Number;
var ch:Number = Math.cos(euler.yaw);
var sh:Number = Math.sin(euler.yaw);
var ca:Number = Math.cos(euler.pitch);
var sa:Number = Math.sin(euler.pitch);
var cb:Number = Math.cos(euler.roll);
var sb:Number = Math.sin(euler.roll);
var matrix:Array = [
sh * sb - ch * sa * cb, -ch * ca, ch * sa * sb + sh * cb,
ca * cb, -sa, -ca * sb,
sh * sa * cb + ch * sb, sh * ca, -sh * sa * sb + ch * cb
]; // Note:Includes 90 degree rotation around z axis
/* [m00 m01 m02] 0 1 2
* [m10 m11 m12] 3 4 5
* [m20 m21 m22] 6 7 8 */
if (matrix[3] > 0.9999) {
// Deal with singularity at north pole
heading = Math.atan2(matrix[2], matrix[8]);
attitude = Math.PI / 2;
bank = 0;
} else if (matrix[3] < -0.9999) {
// Deal with singularity at south pole
heading = Math.atan2(matrix[2], matrix[8]);
attitude = -Math.PI / 2;
bank = 0;
} else {
heading = Math.atan2(-matrix[6], matrix[0]);
bank = Math.atan2(-matrix[5], matrix[4]);
attitude = Math.asin(matrix[3]);
}
return {
yaw:heading,
pitch:attitude,
roll:bank
};
}
private function wrapAngle(value:Number):Number {
value = value % 360;
return (value <= 180) ? value :value - 360;
} // wrap a value between -180 and 180
//function stringToBoolean(value:Number):String
//{ return (String("yesontrue1").indexOf( String(value:Number) ) >= 0) };