AR用の姿勢を得る
id:yellow_73:20110815 の続き。
センサの基準となる画面の向きはタブレットとスマートフォンで違う
ヨー、ピッチ、ローについて、前の記事ではうそ書きましたー (差し替え済み)。平面に置いたのが基準です。
繰り返しですが、ポートレイトがセンサの基準になっているとは限りません。
getWindowManager().getDefaultDisplay().getRotation() で Surface.ROTATION_* (*は0, 90, 180, 270)が返ります。方位センサの基準からの回転角度と考えて差し支えないようです。
個人的な趣味と違う
個人的趣味はこんなかんじ。
つまり、右手系なのはそのままで、X軸が北方向を向き(前の図でのY)、各軸矢印方向に同じ向きにねじる、というのがポイント。
なお、左ねじになってるのは、本来は右ねじなのですが、あとでロー、ピッチ、ヨーの回転行列の逆行列を使うため、左ねじでとっちゃいました。
センサ情報を得つつ個人的趣味の系に変換
センサ情報を得るのは http://techbooster.jpn.org/andriod/ui/443/ あたりをもとにして下さい。
private static final float MATRIX000 = { 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1 }; private static final float MATRIX090 = { 0, 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1 }; private static final float MATRIX180 = { -1, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 1 }; private static final float MATRIX270 = { 0, 0, -1, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1 }; float inR = new float[16]; float outR = new float[16]; float magneticValues = new float[3]; float accelerometerValues = new float[3]; private void multiple(int d, float L, float R, float[] A) { int r; int pa = 0; int plb; for (r = 0, plb = 0; r < d; r++, plb += d) { int ple = plb + d; for (int c = 0; c < d; c++) { float a = 0; int pl, pr; for (pl = plb, pr = c; pl < ple; pl++, pr += d) { a += L[pl] * R[pr]; } A[pa++] = a; } } } public void onSensorChanged(SensorEvent event) { .... // magneticValues と accelerometerValues はここでは取ってないので取ってきて下さい。 if (magneticValues != null && accelerometerValues != null) { SensorManager.getRotationMatrix(inR, null, accelerometerValues, magneticValues); int orientation = this.getWindowManager().getDefaultDisplay() .getRotation(); switch (orientation) { case Surface.ROTATION_0: this.multiple(4, inR, MATRIX000, outR); break; case Surface.ROTATION_90: this.multiple(4, inR, MATRIX090, outR); break; case Surface.ROTATION_180: this.multiple(4, inR, MATRIX180, outR); break; case Surface.ROTATION_270: this.multiple(4, inR, MATRIX270, outR); break; default: return; } SensorManager.getOrientation(outR, orientationValues); // 単位はラジアン float yaw = orientationValues[0]; float pitch = -orientationValues[1]; float role = -orientationValues[2]; ...
どんだけ SensorManager#remapCoordinateSystem を信用してないんだ。
なお、センサのロールとピッチは右ねじで進みますが、趣味では左ねじで進むので、マップしたあとに逆転しています。