マジで、最高にややこしいです。やっぱ行列苦手とか言ってられないですね。
まず、最初にハマったのが、実行速度が遅い事。
全然数字あってねー、とか思ってたらガンガン処理落ちしてました。
例えば、こんな感じでCoreMotionを呼ぶのですが、
@property (nonatomic, retain) CMMotionManager *manager; - (void)viewDidLoad { [super viewDidLoad]; self.manager = [[CMMotionManager alloc] init]; //加速度 [self startCMGyroData:50]; } - (void)startCMGyroData:(int)frequency { // ジャイロスコープの有無を確認 if (self.manager.gyroAvailable) { // 更新間隔の指定 self.manager.gyroUpdateInterval = 1 / frequency; // 秒 // ハンドラ CMGyroHandler handler = ^(CMGyroData *data, NSError *error) { double gyro_x = data.rotationRate.x; double gyro_y = data.rotationRate.y; double gyro_z = data.rotationRate.z; //testGyroRectangle.position= CGPointMake(160+160*gyro_x,240+240*gyro_y); testGyroRectangle.frame = CGRectMake(160+160*gyro_x, 240+240*gyro_y, 30*gyro_z, 30*gyro_z); }; // センサーの利用開始 [self.manager startGyroUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:handler]; } }
ここで幾つか落とし穴。
- Blockの所の引数(ここではCMGyroData *data)は使わない。後述のNSLockを使う場合の障壁になる。
- 状況に依るけど、空間座標絡みは、CMRotationMatrixを使うべき。ややこしいけど、理解すれば非常にスマートに処理出来る。
- Block内で、データ取得の際は、NSLockを使う。そーすると、他の処理に引きずられる事無く、割とリアルタイムに数字が取れる。GDCでも良いかも。
- Blockの中のNSLockで記述される処理は極力減らす。(CALayerの更新とかは1つ以上だとスゲー重くなる。)優先度の低い処理は別途timerなどで処理する。
なぜそんなに重いのかというと、カメラと重ねてたから。描画はCALayerなので比較的軽いハズなのだけれども、AVCapture自体が結構重いので、CoreMotionを重ねると激重となってた次第。別スレッドに分けるなどすれば非常に改善されるので、使用する場合はスレッド処理必須かと思う。
また、CoreMotionで取得出来るデータは、幾つか種類があるけど、加速度データは非常に扱いが難しい。
これはジャイロセンサーの特性に依るので、仕方ない。でも、極座標データに変換してくれる関数が入ってる。
取れる値は、CMRotationMatrix、CMQuaternion、CMAttitudeとあるが、それぞれ特性があるので用途によって使い分けるべきところ。
でもオススメは、CMRotationMatrix。情報が少なく概念を理解するのは骨が折れるが、概念を理解すれば、やりたい事が一発でバチっと決まる。計算量が少なく済むので、当然処理も早い。CMAttitudeはオイラー角なので、変換の計算がどうしても多くなる可能性がある。
RotationMatrixはこんな感じで呼ぶ。
CMDeviceMotionHandler handler = ^(CMDeviceMotion *motion, NSError *error) { //引数のmotionは使わない。 CMDeviceMotion* deviceMotion = self.manager.deviceMotion; CMRotationMatrix rotmatrix = deviceMotion.attitude.rotationMatrix; /*各種処理*/ }こんな感じで、rotmatrix.m11とかそんな感じの3x3の行列が渡される。 最初これ、中身の意味が解らなくて、結構悩んでたんだけど、恐らく下記の様な感じ。
rotmatrix.m11 //デバイスのx方向を指示するベクトルを表す絶対x軸方向の座標点 多分-1〜1の範囲。 rotmatrix.m12 //デバイスのx方向を指示するベクトルを表す絶対y軸方向の座標点 rotmatrix.m13 //デバイスのx方向を指示するベクトルを表す絶対z軸方向の座標点 /* 以下略 */
中身が解ってしまえば、こっちのもの。後は回転行列に放り込むなりなんなりで、結構自在に操作出来る感じです。
コツは鉛直方向のベクトルは3次元位置補足済みであれば常に(0,0,-1)を示すので、デバイスの表示面がxy平面だと言う事を意識すると色々上手く運びます。
ちなみに、補足までに時間が掛かり、タマに意図せず狂うので、補正が必要です。
こーいうの結構好きなんで楽しかったです。
これを使ったアプリはリリースし次第またご報告します。
0 件のコメント:
コメントを投稿