2011年9月13日火曜日

Android AIDL でservice へアクセスする

Google Developer Day 2011 の参加のためのクイズで、AIDLでサービスへアクセスしてコードを取得してくださいという問題があったので、AIDLについて勉強してみました。




ActivityとServiceの間の通信方法です。






こちらの記事を非常に参考にさせて頂きました。ありがとうございます。




手順は下記です。

1. AIDLファイルにIPCのインターフェースを記述
2. Serviceにインターフェースを実装
3. ActivityからServiceへアクセス
4. Manifest.xmlにServiceを宣言



<手順1>
インターフェースを記述します。

Activityのあるところと同じ階層で、新規ファイルでFileを追加し、拡張子をaidlで保存します。今回のaidlはこのような感じです。



package com.google.android.apps.gddquiz;

interface IQuizService {
  String getCode();
}


ファイルを追加し保存すると、gen以下にR.javaと同じ階層に保存したファイル名と同じ名前で、.javaファイルが自動生成されます。
※packeageのパスがあっているかどうか確認してください。



<手順2>
次に、Serviceにインターフェースを実装します。

既に存在するActivityと同じ名前で、……Service.javaでファイルを追加します。


package com.google.android.apps.gddquiz;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

import com.google.android.apps.gddquiz.IQuizService;;

public class Gdd2011Service extends Service {

@Override
public IBinder onBind(Intent intent) {
System.out.println("Service::onBind");
return quizService;
//return null;
}

private IQuizService.Stub quizService = new IQuizService.Stub(){
public String getCode() throws RemoteException {
System.out.println("test!!!!!");
return getCode();
}
};
}


こんな感じです。Service.onBindをオーバーライドしてインターフェースを実装したクラスインスタンスを返します。


今のところファイル構成はこのような感じです。







<手順3>
ActivityからServiceにアクセスします。
……Activity.javaを開きます。



package com.google.android.apps.gddquiz;

import com.google.android.apps.gddquiz.IQuizService;

import android.app.Activity;
import android.os.Bundle;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.widget.TextView;

public class Gdd2011Activity extends Activity {

private IQuizService quizService;
private TextView tv;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
     
tv = new TextView(this);

     
        Intent intent = new Intent(IQuizService.class.getName());
        bindService(intent, _serviceConnection, BIND_AUTO_CREATE);

       /* ここで実行してましたが、起動できないようだったので、Connection後取得するように☆印の下記に追加しました。
        try {
String code = quizService.getCode();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
*/
    }
 
private ServiceConnection _serviceConnection = new ServiceConnection() {

public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("onServiceConnected!!");
quizService = IQuizService.Stub.asInterface(service);

                        // ☆ ここに移動
try {
String code = quizService.getCode();

            tv.setText(code);
                setContentView(tv);

} catch (RemoteException e) {
System.out.println("Connected false!!");

e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName name) {
quizService = null;
}
};
}


 Intent intent = new Intent(IQuizService.class.getName());
でサービスのインテントを作成し、bindServiceより、アクセスします。


<手順4>
Manifestにサービス追加





       <service android:name=".Gdd2011Service"
                  android:label="@string/app_name"
                  android:process=":remote">
            <intent-filter>
                <action android:name="com.google.android.apps.gddquiz.IQuizService" />
            </intent-filter>
        </service>  

               
           
       



これをActivityタグの後に追加します。


以上です。


間違っていたり、もっといいやりかたがあったら教えて下さい。

よろしくお願いしますー




2011年9月9日金曜日

iPhone Cocos2D 背景をカメラに!





Cocos2D は、iPhoneのゲームアプリでよく使われています。
ゲームアプリを作るならこれを勉強しましょう!


Cocos2D iPhone






まず、これを使うとどんないいことがあるかというと、
・ページの繊維がわかりやすい
・アニメーション豊富でわかりやすく使いやすい
・OpenGLESを普通に使うなら、絶対Cocos2Dを使ったほうが簡単
・フレームアニメーションが気持ちよくできる
・インターフェースビルダーが嫌いな人にはもってこい。インターフェースビルダーは一切使いません。




などなど、他にもたくさんありますが、とりあえず、ゲームっぽい動きのあるアプリを作るならば、使ったほうがいいです。




まずCocos2Dのインストールは、Cocos2dのインストールをどうぞ。










cocos2dで新規プロジェクトを作成すると、下記のようなファイルがあります。
※バージョンは、1.0.1です。




・GameConfig.h
・AppDelegate.h
・AppDelegate.m
・RootViewController.h
・RootViewController.m
・HellowWorldLayer.h
・HellowWorldLayer.m


※あとライブラリがごっそりあります。




通常のiPhoneアプリでは、Viewという概念で、ViewControllerがViewを表示して、NavigationControllerがViewControllerたちを遷移させてページを切り替えたりなど、Viewという概念の元動いています。


この方の記事がわかりやすいと思います。
UIViewとUIVIewControllerの違いについて




しかし、Cocos2Dではノードやシーン、レイヤーという概念になります。
cocos2dの基本的な概念




では、もともとのWindowや、UIViewControllerからどのような仕組みでcocos2Dの概念になっているのでしょうか。




こんな感じです↓↓↓




下から順番に


WIndow → RootViewController → EAGLView




Ditectorというのが、Cocos2Dでベースになる部分ですが、普通にやるならば、上記のことは一切気にしなくても問題ありません。


Ditectorというのに、シーンやレイヤーが入れ替わって画面遷移したり、レイヤーを重ねたりなどというような形になります。


HellowWorldLayerからNextLayerに切り替わるときは、例えばこんな感じです。




HellowWorldLayerにてボタンを押された際などに、










    id scene = [NextLayer scene];
    id transition = [CCTransitionFade transitionWithDuration:1.0f scene:scene];
    
    CCDirector *director = [CCDirector sharedDirector];
    
    [director replaceScene: transition];












これは、Fadeアニメーションをしつつ画面遷移するという内容です。
Ditectorに載っていたHellowWorldLayerからNextLayerに切り替えます。




このような形で、簡単に遷移できます。










大体、仕組みはこのようになりますが、もし、ARアプリのようなカメラを背景にしたい場合、ちょっと厄介です。




そもそも基本的に、UIView配下でしか使用できないものだからです。
他にもActionSheetや、UITextFiledなどのもともと使用できるものを使いたくても、Cocos2Dだと、ちょっと一工夫しなければ使用することができません。




その方法は、


EAGLView Ditector の下にあるRootViewControllerに貼ることです。


使いたいLayerで、




#import AppDelegate.h





※例えば、UITextField *textField = [UITextField alloc]initWith………];





AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate.viewController addSubView: textField];






という形で、AppDelegateクラスの中で、RootViewControllerを@property 宣言しておけば、上記のようにappDelegateを取得し、RootViewControllerをレイヤーから取得できます。






ですが、これらは上記で概要を説明した通り、DitectorやLayerに関係なく、もとに引いてあるRootViewControllerに貼るわけですから、シーンやレイヤーを移動しても、関係なく表示され続けますので、そのもとのViewControllerから削除剃る必要があります。




[textField remove removeFromSuperView];


で、削除できます。






では、本題のカメラ背景です!






これも上記とやはり概念は同じなので、上記と同じように、RootViewControllerへ貼ることになります。




が、Cocos2Dのlayerの背景をカメラにするわけですから、かなり厄介です。
つまりは、こうなります。




Window → RootViewController ここにカメラを載せる → EAGLView → Layerなど




このような形にするためには、まずは、上記のUITextFieldと同じように、RootViewControllerへカメラを貼ります。
※通常はRootViewに貼るのですが、カメラの場合WIndowに対してはらないと、表示さないようです。なので、Windowの上に乗っかっているRootViewControllerの背景も透明にする必要があります。


詳細はこちら


ですが貼っただけでは、背景はカメラになりません。
なぜかというと、RootViewController(ここではWIndow)の上には、EAGLViewが乗っているからです。


なので、Cocos2Dアニメーションの描画元である、EAGLViewの背景を透明にする必要があります。




<手順>
1. 背景をカメラにしたいシーンやレイヤーで、RootViewController(Windowです)にカメラを貼る
2. EAGLViewの背景を透明にする








カメラを表示するには、UIImagePickerControllerを使うの一般的ですが、重たいという噂だったので、今回は、AVCaptureSessionを使用しました。




1. 背景カメラを挿入したいLayerで


// EAGLView の色を透明宣言しとく。(これだけでは透明にならないです)


glClearColor(0,0,0,0);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// captureSession 作成
captureSession = [[AVCaptureSession alloc] init];
if ([captureSession canSetSessionPreset:AVCaptureSessionPresetMedium]) {
    captureSession.sessionPreset = AVCaptureSessionPresetMedium;
}
            
NSError *error = nil;
            
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
 if (!input) {
    NSLog(@"input error");
 }
 [captureSession addInput:input];

// 実際に貼るvideoLayer作成
videoPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession:captureSession];
videoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
            
CALayer *viewLayer = [[CCDirector sharedDirector] openGLView].layer;
//NSLog(@"viewLayer = %@", viewLayer);
            
videoPreviewLayer.frame = viewLayer.bounds;

// RootViewControllerへアクセス
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];

// windowに対してカメラの場合、なぜかWindowじゃないと貼れません。
[appDelegate.window.layer insertSublayer:videoPreviewLayer below:appDelegate.viewController.view.layer];

// カメラをWIndowにはらなければならいので、
//その上に乗っかているRootViewControllerの背景も透明にする。
appDelegate.viewController.background = [UIColor clearColor];

[captureSession startRunning];



これで、Windowの上にカメラ映像を貼り、RootViewControllerの背景を透明にすることができました。



次にEAGLViewの背景を透明にします。


2. AppDelega.m

// 下記でEAGLViewのピクセルフォーマットをRGB565からRGBA8へ変更
EAGLView *glView = [EAGLView viewWithFrame:[window bounds]
                                 pixelFormat:kEAGLColorFormatRGB565


                                 pixelFormat:kEAGLColorFormatRGBA8    // kEAGLColorFormatRGBA8に変更
                                 depthFormat:0
];



EAGLViewのレイヤーに対して、同じピクセルフォーマット数でプロパティの設定をする
    
CAEAGLLayer *layer = (CAEAGLLayer*)glView.layer;
layer.opaque = NO;
    
layer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                [NSNumber numberWithBool:YES], 
                                kEAGLDrawablePropertyRetainedBacking,
                                kEAGLColorFormatRGBA8, // kEAGLColorFormatRGBA8
                                kEAGLDrawablePropertyColorFormat, nil];



※ピクセルフォーマットをkEAGLColorFormatRGBA8にしないと、透明になりません。
しかし、kEAGLColorFormatRGBA8にすると、全体的な動作が重たくなりますのでご注意を。

これで実行すれば、背景がカメラになります。




以上です。

皆さんも是非試してみてください。

また内容がおかしかったり、もっといい方法がお分かりの方は、コメントください。













2011年7月27日水曜日

Xcode重すぎ(-。-;

(´・_・`) 今日も一日お疲れさん!



家に帰るのが憂鬱‥



今日も元気にiPhoneアプリを開発したよ‥



でも、Xcodeってさー



なんで、あんなに重たいんだろうね-_-b



固まるし、クラッシュするし、



まじなんなんなんだおー!(´Д` )



って、どーでもいーな。




UIImageViewで、コマ送り系のアニメーションやったお



でも、コレってアニメーション中に、アニメーションのスピードかえられないのよね‥(`_´)ゞ



使えないじゃないかい!!(;゜0゜)




なんかいい方法ないすか??(´・_・`)




これをクリアしないと‥



やっぱ、スピード変える時は、一旦、



[imageView stopAnimation]



してから、




スピード変えて、



[imageView startAnimation]



するしかないすか??




でも、コレってカレント画像(アニメーション中に今表示されている画像)ってわかるの?




とめて、スタートする時は、途中から始めたいじゃん?( ̄◇ ̄;)




明日、頑張ってためしてみるお♪( ´θ`)ノ

2011年7月7日木曜日

iPhone OpenGL + 加速度センサー(accelerometer) OR ジャイロ(Gyro)



(。・ω・)ノ゙ コンチャ♪


久々の書き込みでーっす!iPhoneアプリで久々に手こずりまくったんで、メモっときます‥


今回は、

「iPhone アプリで OpenGL加速度センサーかジャイロを用いて


OpenGLで描かれたオブジェクトを、端末の動きに合わせて回転させる!」


なんかこーゆーの‥



意外と、ブログだったり、ドキュメントないんだよね‥



みたいなものを作りたく、あーでもねー!!こーでもねー!!っとやってきましたが、


やっとそれなりのもんができましたとっ!
(*゚▽゚)/゚・:*【祝】*:・゚\(゚▽゚*)






じゃーその方法ですが、まずはOpenGLのお話からどーすお!






- OpenGL -


iPhoneSDKが新しくなってから??Xcodeのバージョンが新しくなってから??


どっちでもいいですが、OpenGL ES で新規でプロジェクト始めると、


よくある参考書などと内容が異なっていて、使えねぇー!!!!






っと思いきや、じつは対して変わってないのですお!!




前の バージョンで言うところの


- ES1Renderer.mのinitメソッド部分は、


"自分でつけたプロジェクト名ViewController.m"のawakeFromNibで、


- ES1Renderer.mのrenderメソッドは、


"自分でつけたプロジェクト名ViewController.m"のdrawFrameで、


って感じです(ノ゚ρ゚)ノ ォォォ・・ォ・・ォ・・・・




じゃーとりあえず、デフォルトのプロジェクトだと、


オブジェクトが激しい上下運動しててうざいんで、止めましょう!




止め方


- "プロジェクト名"ViewController.mのdrawFrameの中に、



    glTranslatef(0.0f, (GLfloat)(sinf(transY)/2.0f), 0.0f);
    transY += 0.075f;

っていうのがあって、これをコメントアウトする


そーすっと止まる。




とりあえず、コードの流れは、デリゲードが呼ばれて、ぐじゃぐじやって、




awakeFromNibに入って、コンテキスト作ったり(OpenGLで必要な事)して、


同時にStartAnimationが呼ばれると、リンク(CADisplayLinkとかいう‥)でdrawFrame
が呼ばれ続け、呼ばれたらさっき消したコードで、上下運動し続けるっていう仕組みっす。
さっきのコードが上限運動するコードなんで‥大雑把ですが‥


で、とりあえず、静止したオブジェクトが表示されていれば、


ココまではOKですお∑d(≧▽≦*)OK!!



おし!次!






- 加速度センサーやジャイロ -


- 加速度センサー


まず加速度センサーとはなんですか‥ヾ(・・;)ォィォィ




‥‥簡単に言うと、iPhone の傾きがどの軸に対して傾いているか的な!?


そういう事です‥ココ見てください→http://japan.internet.com/developer/20100803/26.html




で、これは、UIAccelerometerって言うもので、これを使うのもよし!


これならば、iPhone3系にも対応しています。






じゃーこれと、OpenGLどー絡めんの??って話ですが、


絡めましたが、うまいこといかず却下!!!


却下なんで、ソースコード載せなくていーっすか‥






じゃー次!




- CoreMotion


iPhone4からこーいーのが使えるんですお!


しかも、少々ややこしいのですが、CoreMotionの中にも3種類あります。


1. Device Motion
2. Accelerometer
3. Gyro


っていう3種類です。2番目は、UIAccelerometerと同じでしょー。
で、1のDeviceMotionの中にも4つ種類があってですね‥




1-1. CMAttribute デバイスの向き
 → なんかGyroっぽいんですが、おそらくこんな感じ
   motion.attribute.pitch X軸の回転角度
   motion.attribute.roll    Y軸の回転角度
   motion.attribute.yaw Z軸の回転角度


1-2. CMRotationRate 
 → 使った事ないんで何とも‥名前的に、回転速度じゃね?


1-3. CMAcceleration gravity
 → 重力速度だって‥ってことは、地球じゃ必ず1じゃねーの?あ、誤差で0.98になるんだって‥はい!必要なし!


1-4. CMAcceleration userAcceleration
 → UIAccelerometerと同じじゃね??




3は回転の速度なので、、、2のAccelerometerと、3-1のattributeを使ってみーよお




- CoreMotion Accelerometer


じゃーまず来れから!


startAnimation メソッドで



    if (!animating) {

        motionManager = [[CMMotionManager alloc] init];




        if(motionManager.accelerometerAvailable) {
            motionManager.accelerometerUpdateInterval = 1.0f / 5.0f;

            

            CMAccelerometerHandler accelerometerHandler;

            accelerometerHandler = ^ (CMAccelerometerData *accelerometerData, NSError* error) {

                

                if(error) {

                    

                }

                else {

                    /*
                    if (accelerometerData.acceleration.x > power){
                        NSLog(@"Accelerometer x:->");
                    }
                    if (accelerometerData.acceleration.x < -1*power){
                        NSLog(@"Accelerometer x:<-");
                    }
                    if (accelerometerData.acceleration.y > power){
                        NSLog(@"Accelerometer y : ↑");
                    }
                    if (accelerometerData.acceleration.y < -1*power){
                        NSLog(@"Accelerometer y : ↓");
                    }
                    if (accelerometerData.acceleration.z > power){
                        NSLog(@"Accelerometer z : 手前");
                    }
                    if (accelerometerData.acceleration.z < -1*power){
                        NSLog(@"Accelerometer z : ");        
                    }*/
                    
// これは.hでCGFloatで定義しておいてくらはい
                    accelX = accelerometerData.acceleration.x;
                    accelY = accelerometerData.acceleration.y;
                    accelZ = accelerometerData.acceleration.z;

                }
            };
            // 向きの更新通知を開始する
            [motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue
                                                withHandler:accelerometerHandler];
        }

        CADisplayLink *aDisplayLink = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(drawFrame)];
        [aDisplayLink setFrameInterval:animationFrameInterval];
        [aDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        self.displayLink = aDisplayLink;
        
        animating = TRUE;
    }

accelX accelY accelZの3つの値は.hで、定義してくださーい‥


で、この数値を使って、OpenGLのオブジェクトをうまく回転させる事ができれば、

デバイスの動きと、オブジェクトが連動して動かせるという理屈ですが‥いかんせん!

うまくいかん_!!!(`(エ)´)ノ_彡☆ブーブー!!


(  ̄っ ̄)ムゥ というか、加速度でやってて気がついてしまった!!!


できなくね‥??



あーできねーさ、、なぜならこの図をみてくれぇ!



ちょっとややこしいんですが、三角関数の計算とか出てきちゃうけど‥

X軸の回転は、iPhoneを図のように向きにして、手前、奥に傾ける(回転)ことにより、

その加速度センサーから、動いた角度を三角関数にならって求める事ができる‥

Z軸の回転は、今度は、図で言うと、左右に傾ける(回転)事によって求める事が可能

しかーし!Y軸って‥

良ーく考えると、このように図の向きで持ったときに、Y軸を中心にまわすと、

iPhoneをY軸の矢印のようにまわしたところで、加速度センサーって反応しないんじゃん。


加速度センサーは、重力の方向に(つまり下)働いてる力を取るんで、加速度センサーは、

Y軸に、-1のまま変わらないんです‥つまり垂直方向の回転は、とれないということになる‥


なんで、、、却下!!!ボツ!ハイ次!!!!





- CoreMotion DiviceMotion  -

よし!これが最終手段であります‥これでできなかったらわからん‥みんなやってるけど‥

とりあえず、ソース

さっきのstartAnimationを変更です‥

Accelerometerの所を下記に


               // 1 Device Motion.

        if (motionManager.deviceMotionAvailable) {
            // 更新の間隔を設定する
            
            motionManager.deviceMotionUpdateInterval = 1.0f / 5.0f;
            
            
            CMDeviceMotionHandler   deviceMotionHandler;
            deviceMotionHandler = ^ (CMDeviceMotion* motion, NSError* error) {
                // デバイスの向きを表示する
                /*
                if (motion.attitude.pitch > power){
                    NSLog(@"x:->");
                }
                if (motion.attitude.pitch < -1*power){
                    NSLog(@"x:<-");
                }
                if (motion.attitude.yaw > power){
                    NSLog(@"y : ↑");
                }
                if (motion.attitude.yaw < -1*power){
                    NSLog(@"y : ↓");
                }
                if (motion.attitude.roll > power){
                    NSLog(@"z : 手前");
                }
                if (motion.attitude.roll < -1*power){
                    NSLog(@"z : ");        
                }*/
                
                gyroX = motion.attitude.roll;
                gyroY = motion.attitude.pitch;
                gyroZ = motion.attitude.yaw;
                NSLog(@"X %f Y %f Z %f", gyroX, gyroY, gyroZ);
            };
            
            // 向きの更新通知を開始する
            [motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue
                                               withHandler:deviceMotionHandler];
        }





よーし、これで、drawFrameをこんなん



- (void)drawFrame
{
    [(EAGLView *)self.view setFramebuffer];
    
    // Replace the implementation of this method to do your own custom drawing.
    static const GLfloat squareVertices[] = {
        -0.5f, -0.5,
        0.5f, -0.5f,
        -0.5f0.5f,
        0.5f0.5f,
    };
    
    static const GLubyte squareColors[] = {
        255, 255,   0, 255,
        0,   255, 255, 255,
        0,     0,   0,   0,
        255,   0, 255, 255,
    };
        
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    
    
    //glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f); // もともとは平行投影。なので最近、と最遠の設定に意味はない。
    glFrustumf(-1.0f, 1.0f, -1.5, 1.5, 3.0f, 100.0f); // 透視投影。最遠はともかく最近は
glTranslatef(0.0f, 0.0f, -3.5f);

    glMatrixMode(GL_MODELVIEW);


    glRotatef(gyroX, 1.0f, 0, 0);
    glRotatef(gyroY, 0, 1.0f, 0);
    glRotatef(gyroZ, 0, 0, 1.0f);


    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);    

    glVertexPointer(2, GL_FLOAT, 0, squareVertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
    glEnableClientState(GL_COLOR_ARRAY);
    
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    
    [(EAGLView *)self.view presentFramebuffer];
}


これでどうじゃ!!



回転させると、ふわふわ動いてなかなかいい感じだったが、、、

ぴたっと収まらない、、止まらない。

僕みたいに、ゆるーく、だらしがない感じになってしまって、いまいち‥


おしーけど、だめっすよ。。



じゃー次は、OpenGLでglLoadMatrixfという、4x4の行列で、回転を表現しよー


glRotatefはやめて。


ヽ(´o`; 行列でばしっと決めちゃえば、ちゃんとぴたっといくのではないかと‥


OpenGLの行列の各軸の回転の定義はこーっすよ


[X軸回転]

[ 1,     0,      0,   0]
[ 0, cos(angle), -sin(angle), 0]
[ 0, sin(angle), cos(angle), 0]
[ 0,     0,      0,   1]


[Y軸回転]

[cos(angle),  0, sin(angle),   0]
[0,      1,     0,    0]
[-sin(angle), 0, cos(angle),   0]
[0,      0,      0,    1]


[Z軸回転]

[cos(angle), -sin(angle), 0, 0]
[sin(angle), cos(angle), 0, 0]
[ 0,     0,    1,   0]
[ 0,     0,    0,   1]


行列を使うには、sinとcosの値が必要なり

( 」´0`)」 ここで!三角関数を思い出さねばならんのですたい!!


忘れた人は、Google先生に聞いてください‥

ここの最初の図のように、
http://www8.plala.or.jp/ap2/suugaku/sankakukansuunoshoho.html

角度がわかってるので、sinとcosはそのまま使えます‥

なので、X軸の回転の場合は、sin(gyroX)、cos(gyroX)とかで、いいんですねぇ〜

これを応用して、3つの軸ごとに4x4の行列を作りますよー


そしてそれを、乗算します!!

行列の乗算って確かかなりめんどくさー!!だからソースこんなんなっちゃました!!!


drawFrameを下記に修正



- (void)drawFrame

{

    [(EAGLView *)self.view setFramebuffer];

    
    // Replace the implementation of this method to do your own custom drawing.
    static const GLfloat squareVertices[] = {
        -0.5f, -0.5,
        0.5f, -0.5f,
        -0.5f0.5f,
        0.5f0.5f,
    };
    
    static const GLubyte squareColors[] = {
        255, 255,   0, 255,
        0,   255, 255, 255,
        0,     0,   0,   0,
        255,   0, 255, 255,
    };
        
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    
    
    //glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f); // もともとは平行投影。なので最近、と最遠の設定に意味はない。
    glFrustumf(-1.0f, 1.0f, -1.5, 1.5, 3.0f, 100.0f); // 透視投影。最遠はともかく最近は
glTranslatef(0.0f, 0.0f, -3.5f);

    glMatrixMode(GL_MODELVIEW);
glPushMatrix();

const float X[16] = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, cos(gyroX), -sin(gyroX), 0.0f,
0.0f, sin(gyroX), cos(gyroX), 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
    const float Y[16] = {
cos(gyroY), 0.0f, sin(gyroY), 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
-sin(gyroY), 0.0f, cos(gyroY), 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
    const float Z[16] = {
cos(gyroZ), -sin(gyroZ), 0.0f, 0.0f,
sin(gyroZ), cos(gyroZ), 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
    // 3つの行列を乗算
    const float XY[16] = {
        X[0]*Y[0]+X[1]*Y[4]+X[2]*Y[8]+X[3]*Y[12], X[0]*Y[1]+X[1]*Y[5]+X[2]*Y[9]+X[3]*Y[13], X[0]*Y[2]+X[1]*Y[6]+X[2]*Y[10]+X[3]*Y[14], X[0]*Y[3]+X[1]*Y[7]+X[2]*Y[11]+X[3]*Y[15],
        X[4]*Y[0]+X[5]*Y[4]+X[6]*Y[8]+X[7]*Y[12], X[4]*Y[1]+X[5]*Y[5]+X[6]*Y[9]+X[7]*Y[13], X[4]*Y[2]+X[5]*Y[6]+X[6]*Y[10]+X[7]*Y[14], X[4]*Y[3]+X[5]*Y[7]+X[6]*Y[11]+X[7]*Y[15],
        X[8]*Y[0]+X[9]*Y[4]+X[10]*Y[8]+X[11]*Y[12], X[8]*Y[1]+X[9]*Y[5]+X[10]*Y[9]+X[11]*Y[13], X[8]*Y[2]+X[9]*Y[6]+X[10]*Y[10]+X[11]*Y[14], X[8]*Y[3]+X[9]*Y[7]+X[10]*Y[11]+X[11]*Y[15],
        X[12]*Y[0]+X[13]*Y[4]+X[14]*Y[8]+X[15]*Y[12], X[12]*Y[1]+X[13]*Y[5]+X[14]*Y[9]+X[15]*Y[13], X[12]*Y[2]+X[13]*Y[6]+X[14]*Y[10]+X[15]*Y[14], X[12]*Y[3]+X[13]*Y[7]+X[14]*Y[11]+X[15]*Y[15],
    };
    const float scaleMatrix[16] = {
        XY[0]*Z[0]+XY[1]*Z[4]+XY[2]*Z[8]+XY[3]*Z[12], XY[0]*Z[1]+XY[1]*Z[5]+XY[2]*Z[9]+XY[3]*Z[13], XY[0]*Z[2]+XY[1]*Z[6]+XY[2]*Z[10]+XY[3]*Z[14], XY[0]*Z[3]+XY[1]*Z[7]+XY[2]*Z[11]+XY[3]*Z[15],
        XY[4]*Z[0]+XY[5]*Z[4]+XY[6]*Z[8]+XY[7]*Z[12], XY[4]*Z[1]+XY[5]*Z[5]+XY[6]*Z[9]+XY[7]*Z[13], XY[4]*Z[2]+XY[5]*Z[6]+XY[6]*Z[10]+XY[7]*Z[14], XY[4]*Z[3]+XY[5]*Z[7]+XY[6]*Z[11]+XY[7]*Z[15],
        XY[8]*Z[0]+XY[9]*Z[4]+XY[10]*Z[8]+XY[11]*Z[12], XY[8]*Z[1]+XY[9]*Z[5]+XY[10]*Z[9]+XY[11]*Z[13], XY[8]*Z[2]+XY[9]*Z[6]+XY[10]*Z[10]+XY[11]*Z[14], XY[8]*Z[3]+XY[9]*Z[7]+XY[10]*Z[11]+XY[11]*Z[15],
        XY[12]*Z[0]+XY[13]*Z[4]+XY[14]*Z[8]+XY[15]*Z[12], XY[12]*Z[1]+XY[13]*Z[5]+XY[14]*Z[9]+XY[15]*Z[13], XY[12]*Z[2]+XY[13]*Z[6]+XY[14]*Z[10]+XY[15]*Z[14], XY[12]*Z[3]+XY[13]*Z[7]+XY[14]*Z[11]+XY[15]*Z[15],
    };

    glLoadMatrixf(scaleMatrix);

    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);    

    glVertexPointer(2, GL_FLOAT, 0, squareVertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
    glEnableClientState(GL_COLOR_ARRAY);
    
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    
    glPopMatrix();
    [(EAGLView *)self.view presentFramebuffer];
}

4x4x4の行列の計算はまじパネェーっす(* ̄o ̄)ゝ


あい!!これでできたー!
ばっちり。でもこの方法であってるのかは、なぞ!


何か質問などあったらおねがいしやす‥



あ、回転軸と、面、角度やジャイロについてまとめたものです。
何かの参考にどうぞ