因为项目需要刚接触的 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;
}