5

ジャイロを使ってARアプリを開発しています。アップルのコード例pARkを使用しました。回転行列を使用して座標の位置を計算しますが、これは非常にうまくいきますが、今は「レーダー」を実装しようとしているので、デバイスの見出しに応じてこれを回転させる必要があります。CLLocationManagerの見出しを使用していますが、正しくありません。

問題は、CMAttitudeを使用してデバイスの見出しを取得し、画面に表示されたものを正確に反映するにはどうすればよいですか?

私は回転行列とそのようなものに不慣れです。

これは、AR座標の計算に使用されるコードの一部です。次の態度でcameraTransformを更新します。

CMDeviceMotion *d = motionManager.deviceMotion;
if (d != nil) {
    CMRotationMatrix r = d.attitude.rotationMatrix;
    transformFromCMRotationMatrix(cameraTransform, &r);
[self setNeedsDisplay];
}

次に、drawRectコードで:

mat4f_t projectionCameraTransform;
multiplyMatrixAndMatrix(projectionCameraTransform, projectionTransform, cameraTransform);

int i = 0;
for (PlaceOfInterest *poi in [placesOfInterest objectEnumerator]) {
    vec4f_t v;
    multiplyMatrixAndVector(v, projectionCameraTransform, placesOfInterestCoordinates[i]);

    float x = (v[0] / v[3] + 1.0f) * 0.5f;
    float y = (v[1] / v[3] + 1.0f) * 0.5f;

ビューをピッチ角で回転させます。モーションの更新は、北を使用して開始されます。

[motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXTrueNorthZVertical];

ですから、デバイスの「ロール」/ヘディングを任意の位置(ピッチとヨーを問わず...)で取得できるはずだと思いますが、方法がわかりません。

4

1 に答える 1

18

CMDeviceMotion によって返される回転行列から進行方向を計算するには、いくつかの方法があります。これは、Apple のコンパスと同じ定義を使用していることを前提としています。つまり、真北を指す +y 方向 (iPhone の上部) は方向 0 を返し、iPhone を右に回転させると方向が増加するため、東は 90、南は 180 です。など。

まず、更新を開始するときは、見出しが利用可能であることを確認してください。

if (([CMMotionManager availableAttitudeReferenceFrames] & CMAttitudeReferenceFrameXTrueNorthZVertical) != 0) {
   ...
}

次に、モーション マネージャーを起動するときに、真北 (または何らかの理由で必要な場合は磁北) を指す X からの回転として姿勢を求めます。

[motionManager startDeviceMotionUpdatesUsingReferenceFrame: CMAttitudeReferenceFrameXTrueNorthZVertical
                                                   toQueue: self.motionQueue
                                               withHandler: dmHandler];

モーション マネージャーがモーションの更新を報告するとき、デバイスが XY 平面でどれだけ回転したかを確認する必要があります。iPhone の上部に関心があるので、その方向のポイントを選択し、返された回転行列を使用して回転させ、回転後のポイントを取得します。

   [m11 m12 m13] [0]   [m12]
   [m21 m22 m23] [1] = [m22]
   [m31 m32 m33] [0]   [m32]

ファンキーな括弧は行列です。ASCII を使用してできる最善の方法です。:)

方位は、回転したポイントと真北の間の角度です。回転したポイントの X 座標と Y 座標を使用して、ポイントと X 軸の間の角度を示すアーク タンジェントを抽出できます。これは実際には私たちが望むものから 180 度ずれているので、それに応じて調整する必要があります。結果のコードは次のようになります。

CMDeviceMotionHandler dmHandler = ^(CMDeviceMotion *aMotion, NSError *error) {
    // Check for an error.
    if (error) {
        // Add error handling here.
    } else {
        // Get the rotation matrix.
        CMAttitude *attitude = self.motionManager.deviceMotion.attitude;
        CMRotationMatrix rm = attitude.rotationMatrix;

        // Get the heading.
        double heading = PI + atan2(rm.m22, rm.m12);
        heading = heading*180/PI;
        printf("Heading: %5.0f\n", heading);
    }
};

落とし穴が 1 つあります。iPhone の上部が真上または真下を向いている場合、方向は定義されていません。その結果、m21 と m22 はゼロか、それに非常に近くなります。アプリにとってこれが何を意味するかを判断し、それに応じて条件を処理する必要があります。たとえば、m12*m12 + m22*m22 がゼロに近い場合、-Z 軸 (iPhone の背後) に基づく見出しに切り替えることができます。


これはすべて、Apple が通常コンパスに対して行っているように、XY 平面を中心に回転することを前提としています。これが機能するのは、モーション マネージャーによって返された回転マトリックスを使用して、Y 軸に沿ってポイントされたベクトルを回転させるためです。これが次のマトリックスです。

[0]
[1]
[0]

別のベクトルを回転するには、たとえば、-Z に沿ったベクトルを回転するには、次のように別の行列を使用します。

[0]
[0]
[-1]

もちろん、逆接線も別の平面でとらなければならないので、代わりに

double heading = PI + atan2(rm.m22, rm.m12);

あなたが使うだろう

double heading = PI + atan2(-rm.m33, -rm.m13);

XZ平面での回転を取得します。

于 2012-07-02T18:51:31.753 に答える