rotation - 获取 ARKit pointOfView 的 Y 旋转

标签 rotation arkit euler-angles pointofview

我正在尝试获取 ARKit 场景中现实生活中的视角(0 - 360 度)。我使用来自 pointOfView 的 SCNNode 的欧拉角。

print("\(pointOfView.eulerAngles.y.radiansToDegrees)")

问题是,当向北看时,我得到的结果是 0,当向南看时,我也得到 0。当向东北看时,我得到 -45 度,当向东南看时,我也得到 -45度。似乎SCNNode无法确定南北,只能确定西和东。有什么建议吗?

我通常需要在 ARKit 现实世界场景中实现雷达 View 。预期行为为北:0,东:90,南:180,西:270。

提前致谢!

最佳答案

我刚刚正在研究类似的情况。你所追求的我称之为“标题”,它并不像你想象的那么容易清晰地定义。

快速背景:仅供引用,有两种旋转,“欧拉”,它们相对于现实世界空间,但在“俯仰”极端处受到所谓的万向节锁定的影响。然后是相对于设备轴的旋转角度,保存在 ARCamera 的 Transform 属性中。

为了说明差异,euler.y 始终表示设备面向的方式(除非它是平的,在这种情况下万向节锁会弄乱它,因此我们的问题),而变换 y 始终意味着通过手机绕垂直轴旋转(这让事情变得更加困惑,它是基于 ARKit 中横向放置的设备)。

(旁注:如果您习惯了 CoreMotion,您可能会注意到,在 ARKit 中,当设备平放时会发生万向锁定,而在 CM 中则为直立状态。

那么我们如何获得一个无论设备是平放还是直立都有效的“标题”呢?下面的解决方案(抱歉,它是 Objective-C!)执行以下操作:

  1. 取两个法线向量,一个沿着手机的 Z 轴(直接从屏幕伸出),另一个伸出手机底部,我称之为 -Y 轴(尽管它实际上是 +X 轴)横屏时)。

  2. 通过设备变换(不是欧拉变换)旋转矢量,投影到 XZ 平面上并获取投影矢量相对于 Z 轴的角度。

  3. 当手机直立时,Z 法线将是完美的航向,但当手机平放时,可使用 Y 法线。在此期间,我们将根据手机的“倾斜”进行“交叉淡入淡出”,即 euler.x

  4. 一个小问题是,当用户将手机稍微向下平放时,Z 法线给出的航向会翻转。我们真的不希望出现这种情况(更多的是从用户体验角度而不是数学角度),所以让我们检测这种“向下倾斜”,并在发生时将 zHeading 翻转 180°。

无论设备方向如何,最终结果都是一致且平滑的标题。它甚至可以在设备在纵向和横向之间移动时工作......哇!

// Create a Quaternion representing the devices curent rotation (NOT the same as the euler angles!)
GLKMatrix3 deviceRotM = GLKMatrix4GetMatrix3(SCNMatrix4ToGLKMatrix4(SCNMatrix4FromMat4(camera.transform)));
GLKQuaternion Q = GLKQuaternionMakeWithMatrix3(deviceRotM);

// We want to use the phone's Z normal (in the phone's reference frame) projected onto XZ to get the angle when the phone is upright BUT the Y normal when it's horizontal. We'll crossfade between the two based on the phone tilt (euler x)...
GLKVector3 phoneZNormal = GLKQuaternionRotateVector3(Q, GLKVector3Make(0, 0, 1));
GLKVector3 phoneYNormal = GLKQuaternionRotateVector3(Q, GLKVector3Make(1, 0, 0)); // why 1,0,0? Rotation=(0,0,0) is when the phone is landscape and upright. We want the vector that will point to +Z when the phone is portrait and flat

float zHeading = atan2f(phoneZNormal.x, phoneZNormal.z);
float yHeading = atan2f(phoneYNormal.x, phoneYNormal.z);

// Flip the zHeading if phone is tilting down, ie. the normal pointing down the device suddenly has a +y component
BOOL isDownTilt = phoneYNormal.y > 0;
if (isDownTilt) {
    zHeading = zHeading + M_PI;
    if (zHeading > M_PI) {
        zHeading -= 2 * M_PI;
    }
}

float a = fabs(camera.eulerAngles.x / M_PI_2);
float heading = a * yHeading + (1 - a) * zHeading;

NSLog(@"euler: %3.1f˚   %3.1f˚   %3.1f˚    zHeading=%3.1f˚    yHeading=%3.1f˚    heading=%3.1f˚    a=%.2f    status:%li:%li  zNorm=(%3.2f, %3.2f, %3.2f)    yNorm=(%3.2f, %3.2f, %3.2f)", GLKMathRadiansToDegrees(camera.eulerAngles.x), GLKMathRadiansToDegrees(camera.eulerAngles.y), GLKMathRadiansToDegrees(camera.eulerAngles.z), GLKMathRadiansToDegrees(zHeading), GLKMathRadiansToDegrees(yHeading), GLKMathRadiansToDegrees(heading), a, camera.trackingState, camera.trackingStateReason, phoneZNormal.x, phoneZNormal.y, phoneZNormal.z, phoneYNormal.x, phoneYNormal.y, phoneYNormal.z);

关于rotation - 获取 ARKit pointOfView 的 Y 旋转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49864305/

相关文章:

c++ - 使用 Eigen 以欧拉角旋转四元数

iphone - 使用横滚、俯仰和偏航或四元数或旋转矩阵从 CMAttitude 计算高度和方位角

java - 在 Libgdx 中设置相机旋转

android - 如何在 Android 上的方向更改时避免重新启动 Activity

html - CSS 围绕对象中心旋转 SVG 重复 <use> 元素

ios - ARKit - 在相机上居中 SCNode

swift - 如何将纹理贴合到表面? ARKit SceneKit Swift

ios - SceneKit获取旋转后的节点位置

ios - 缩放受约束的 SCNNode

unity-game-engine - 需要以特定方式旋转物体 - 被万向节锁卡住?