我正在尝试获取 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!)执行以下操作:
取两个法线向量,一个沿着手机的 Z 轴(直接从屏幕伸出),另一个伸出手机底部,我称之为 -Y 轴(尽管它实际上是 +X 轴)横屏时)。
通过设备变换(不是欧拉变换)旋转矢量,投影到 XZ 平面上并获取投影矢量相对于 Z 轴的角度。
当手机直立时,Z 法线将是完美的航向,但当手机平放时,可使用 Y 法线。在此期间,我们将根据手机的“倾斜”进行“交叉淡入淡出”,即
euler.x
。一个小问题是,当用户将手机稍微向下平放时,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/