【问题标题】:Getting Y rotation of ARKit pointOfView获取 ARKit pointOfView 的 Y 旋转
【发布时间】:2018-09-26 14:32:43
【问题描述】:

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

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

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

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

提前致谢!

【问题讨论】:

  • 你有解决办法吗??

标签: rotation arkit euler-angles pointofview


【解决方案1】:

我一直在处理类似的情况。在我称之为“标题”之后你是什么,它并不像你想象的那么容易干净地定义。

快速背景:仅供参考,有两种旋转,“欧拉”,它们与现实世界空间相关,但在“俯仰”极端时会遭受他们所谓的万向节锁定。然后是相对于设备轴的旋转角度,保存在ARCamera 的变换属性中。

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

(旁注:如果您习惯 CoreMotion,您可能会注意到在 ARKit 中,当设备平放时会发生 Gimbal Lock,而在 CM 中则是直立时发生)。

那么,无论设备是平的还是直立的,我们如何获得都能正常工作的“航向”?下面的解决方案(对不起,它是objective-c!)执行以下操作:

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

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

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

  4. 一个小问题是,当用户将手机稍微向下放平时,Z Normal 给出的方向会翻转。我们真的不想要这样(从用户体验的角度而不是数学角度)所以让我们检测这种“向下倾斜”并在它发生时将zHeading 180˚ 翻转。

无论设备方向如何,最终结果都是一致且流畅的heading。当设备在纵向和横向之间移动时,它甚至可以工作......呵呵!

// 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);

【讨论】:

  • 知道如何将 simd_float4x4/matrix_float4x4 转换为 GLKMatrix4 吗? O
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-21
  • 2018-01-30
  • 1970-01-01
  • 2018-01-30
  • 2018-01-09
  • 2018-10-26
相关资源
最近更新 更多