因爲項目需要剛接觸的 ARCore,新的方向有很多新的坑,空間中的旋轉很是讓人頭疼,SceneForm 框架提供的 API 其實已經很強大了,還是會有一些漏網的小魚,沒有對應的 API,根據網上的資料和自己的總結,提供以下幾個 Java 版本的接口,希望對大家有幫助。
1、四元數轉歐拉角
Quaternion(四元數)是 SceneForm 提供且建議使用的表示旋轉的方式,四元數可以避免歐拉角方式的萬向節死鎖。
/**
* 四元數轉歐拉角
* @param quaternion 四元數
* @return 歐拉角
*/
public Vector3 quaternion2Eular(Quaternion quaternion) {
double epsilon = 0.0009765625f;
double threshold = 0.5f - epsilon;
Vector3 euler = new Vector3();
double tag = quaternion.w * quaternion.y - quaternion.x * quaternion.z;
// 奇異姿態,俯仰角爲 ±90 度
if (tag < -threshold || tag > threshold) {
int sign = sign(tag);
euler.z = -2 * sign * (float) Math.atan2(quaternion.x, quaternion.w); // yaw
euler.y = sign * (float)(Math.PI / 2.0); // pitch
euler.x = 0; // roll
} else {
euler.x = (float) Math.atan2(
2 * (quaternion.y * quaternion.z + quaternion.w * quaternion.x),
quaternion.w * quaternion.w - quaternion.x * quaternion.x - quaternion.y * quaternion.y + quaternion.z * quaternion.z);
euler.y = (float) Math.asin(-2 * (quaternion.x * quaternion.z - quaternion.w * quaternion.y));
euler.z = (float) Math.atan2(2 * (quaternion.x * quaternion.y + quaternion.w * quaternion.z),
quaternion.w * quaternion.w + quaternion.x * quaternion.x - quaternion.y * quaternion.y - quaternion.z * quaternion.z);
}
float scale = (float)( 180 / Math.PI);
//弧度轉換角度
euler.x = euler.x * scale;
euler.y = euler.y * scale;
euler.z = euler.z * scale;
return euler;
}
private int sign(double param) {
if (param > 0) {
return 1;
} else if (param == 0){
return 0;
} else {
return -1;
}
}
2、旋轉向量轉對應的軸-角表示方式
旋轉向量表示物體在三維空間的旋轉,向量(x,y,z)表示三維空間中旋轉的方向,向量的模表示旋轉的角度(弧度)。
public static class AxisAngle {
Vector3 Axis;
float angle;
}
/**
*
* 旋轉向量轉對應的軸-角表示方式
* @param rotationVector 旋轉向量
* @return 軸-角
*/
public AxisAngle rotationVector2AxisAngle(Vector3 rotationVector) {
//旋轉向量的模(弧度)
float mo = (float) Math.sqrt(
rotationVector.x * rotationVector.x + rotationVector.y * rotationVector.y + rotationVector.z * rotationVector.z);
float angle = (float) (mo * ( 180 / Math.PI));
//生成軸方向的單位向量
rotationVector.x = rotationVector.x / mo;
rotationVector.y = rotationVector.y / mo;
rotationVector.z = rotationVector.z / mo;
AxisAngle axisAngle = new AxisAngle();
axisAngle.Axis = rotationVector;
axisAngle.angle = angle;
return axisAngle;
}
3、將旋轉向量轉換爲對應的四元數
/**
*
* 將旋轉向量轉換爲對應的四元數
* @param rotationVector 旋轉向量
* @return 四元數
*/
public Quaternion rotationVector2Quaternion(Vector3 rotationVector) {
//旋轉向量轉對應的軸-角表示方式
AxisAngle axisAngle = rotationVector2AxisAngle(rotationVector);
if (axisAngle != null) {
//軸-角表示方式轉四元數
Quaternion qu = Quaternion.axisAngle(axisAngle.Axis, axisAngle.angle);
return qu;
}
return null;
}