在pointOfView获得ARK的Y旋转

问题描述 投票:2回答:1

我试图在ARKit场景(0 - 360度)中获得视角的真实生活角度。我正在使用来自观点的SCNNode的欧拉角。

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

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

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

提前致谢!

rotation arkit euler-angles pointofview
1个回答
2
投票

我刚刚开始研究类似的情况。在我称之为“标题”之后你是什么,这不像你想象的那样容易定义。

快速背景:仅供参考,有两种旋转,“欧拉”,它们相对于现实世界空间而言,在“极端”极端情况下遭受了他们所谓的万向锁。然后是相对于设备轴的旋转角度,保持在ARCamera的变换属性中。

为了说明差异,euler.y总是意味着设备面向的方式(除非它是扁平的,在这种情况下,万向节锁将其弄脏,因此我们的问题),而变换y总是意味着围绕垂直轴旋转通过电话(其中,只是为了让事情更加混乱,基于ARKit中的设备持有景观)。

(旁注:如果你习惯了CoreMotion,你可能已经注意到在ARKit中,当设备保持平坦时会发生万向节锁定,而在CM中它是直立的)。

那么,无论设备是扁平还是直立,我们如何获得“标题”?下面的解决方案(抱歉,它的目标是c!)执行以下操作:

  1. 取两个法线向量,一个沿着手机的Z轴(从屏幕直接出来)和一个伸出手机底部的向量,我称之为-Y轴(尽管它实际上是+ X轴,当保持风景)。
  2. 通过设备的变换(不是Euler)旋转矢量,投影到XZ平面上,并获得Z轴的投影矢量角度。
  3. 当手机处于直立状态时,Z Normal将是完美的标题,但是当手机是平的时,Y标准是正常使用的。在两者之间,我们将根据手机的“倾斜”(即euler.x)“交叉淡化”。
  4. 一个小问题是,当用户将手机稍微向下压过平面时,由Z Normal给出的标题翻转。我们并不是真的想要这个(更多来自用户体验的视角而不是数学视角)所以让我们检测到这种“向下倾斜”并在发生时将zHeading翻转180˚。

无论设备方向如何,最终结果都是一致且平滑的heading。当设备在肖像和风景之间移动时,它甚至可以工作...... huzzah!

// 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);
© www.soinside.com 2019 - 2024. All rights reserved.