らくさん

2011-10-14

iOSでFTGLESを使ってテキストを描画する

FTGLESについて、日本語での情報があまり無いようなので書いてみました。*1


FTGLESはFTGLOpenGL ES向けに移植したもので、TrueTypeフォントOpenTypeフォントなどをOpenGL ES上でレンダリングすることができます。FTGLもFTGLESも、FreeType2を使ってフォントファイルを読んでいるので、FreeType2が扱えるフォントファイルを使用することができます。*2


ライセンスはFTGLESがMIT License、FreeType2が(BSD Licenseに近い)FreeType License*3なので、AppStoreで配布するのに問題は無いと思います。


FTGLESは今のところOpenGL ES 1.1のみをサポートしていますが、ES 2.0への対応も進行中のようです。元のFTGLがOpenGLの固定機能に依存しているので、ES 2.0へ対応するにはかなりの修正が必要になっているのではないかと思います。


今回作ったもの

f:id:butyricacid:20111014062746p:image:w200


ビルド手順と使用方法

配布元のページに書いてある通りですが、重要なところだけ抜粋しました。


1. libFTGLES.a を作る
git clone https://github.com/cdave1/ftgles.git
git clone https://github.com/cdave1/freetype2-ios.git
cd freetype2-ios/
bash install.sh
cd ../ftgles
ln -s ../freetype2-ios freetype2
cd Xcode
bash install.sh

install.sh内で -sdk iphoneos4.3 とSDKが指定されているので、古いSDKビルドする場合は書き換える必要があります。また、僕の環境では freetype2-iosビルドllvm-gcc-4.2 が無いというエラーが出たので、freetype2.xcodeproj を開いて gcc-4.2 に変更しました。

libFTGLES.a ができたら、自分のXcodeプロジェクトに追加します。


2. ヘッダ検索パスの設定

自分のXcodeプロジェクトのヘッダ検索パスを設定します。

f:id:butyricacid:20111014090247p:image

この例では、自分のプロジェクト直下に ftgles という名前でフォルダを作り、そこで前述の freetype2-ios、ftgles をビルドしています。


3. 使い方
// ftglesのヘッダファイルをインクルードする。
#include "FTGL/ftgles.h"
// フォントファイルからFTFontオブジェクトを作成し、サイズを設定する。
FTFont *font = new FTTextureFont("/path/to/myfont.ttf");
font->FaceSize(72);
// レンダリング
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
font->Render([@"水瀬伊織" UTF8String]);

より詳しい使い方は FTGLのチュートリアル を見てください。


レンダリングモードについて

FTGLESには次の4つのレンダリングモードがあります。*4

  • Texture Font
    • 文字毎にテクスチャを作成する。テクスチャはキャッシュされるので高速。
  • Buffer Font
    • 一行毎にテクスチャを作成する。そのため、同じ文字列を繰り返しレンダリングする場合は Texture Font よりもさらに高速。
  • Polygon Font
  • Outline Font

f:id:butyricacid:20111014072003p:image:leftTexture Font

f:id:butyricacid:20111014072004p:image:leftBuffer Font

f:id:butyricacid:20111014072005p:image:leftPolygon Font

f:id:butyricacid:20111014072006p:image:leftOutline Font


Texture Font と Buffer Font は見た目はほとんど同じです。上の例だと Polygon Font はあまり綺麗ではありませんが、次のように拡大などをすると Polygon Font の利点がわかります。


f:id:butyricacid:20111014062744p:image:w150 f:id:butyricacid:20111014062745p:image:w150 f:id:butyricacid:20111014062746p:image:w150 f:id:butyricacid:20111014062747p:image:w150


また、Polygon Font の場合はマルチサンプリングアンチエイリアス(MSAA)を使用するとジャギーが取れて綺麗になりますが、今回は使用していません。iOSでのMSAAは マルチサンプリングアンチエイリアシング(MSAA)を試してみた が参考になると思います。Outline Font の場合は glEnable(GL_LINE_SMOOTH) をすれば綺麗になるはずと思うのですが、変化はありませんでした。ちょっと調べたところ、実機では GL_LINE_SMOOTH は効かないという記述をいくつか見かけました。後日もう少し詳しく調べてみたいと思います。


システムのフォントファイルにアクセスしたいけど…

FTGLESを使うにはフォントファイルのパスが必要なのでUIFontでフォントを取得してもダメなんですが、次のようにすると一応フォントファイルに直接アクセスできるようです。でもこれって審査通るんですかね?

new FTTextureFont("/System/Library/Fonts/Cache/HiraginoKakuGothicProNW6.otf");

システムのフォントファイルに直接アクセスしてはダメだと、再配布が許可されているフリーフォントバンドルして使うくらいしかできなくなってしまうのでFTGLESはあまり役に立たないものになってしまいますね。


システムのヒラギノ角ゴProN W6を使用

f:id:butyricacid:20111014115121j:image:w150


作ったもの

今回作ったもののソースコード: http://kuramo.ch/iosdev/FTGLES.zip

(FTGLESとIPAフォントを含んでいるので約46MBあります)


ピンチ操作で拡大縮小します。なぞると回転します。ダブルタップで拡大率と回転がリセットされます。

*1「FTGLES」OpenGL ESでTrueTypeフォントをレンダリングするためのライブラリ で軽く触れられているくらいでしょうか

*2:ただし、TrueTypeコレクション(.ttc)についてはFTGL/FTGLESのAPI上でインデックスを指定することができないので、コレクション内の最初のフォントしか使用することができません。(JavieではFTGLを改造してインデックスを指定できるようにしています)

*3:正確にはFreeType LicenseとGPLのデュアルライセンスですが、AppStoreで配布するならGPLは選択できません

*4:FTGLにはさらにいくつかのレンダリングモードがありますがFTGLESには実装されていません

2011-10-05

AVAssetImageGeneratorを使って立方体に動画を貼付けて再生してみる

AVAssetImageGenerator を使うと、動画から任意の時刻のフレームを静止画として切り出すことができます。そこで、切り出した静止画をテクスチャにして、立方体に貼付けて再生してみました。

なお、AVAssetImageGenerator はiOS4以降でしか使えませんが、僕はiOS4で動くデバイスを持っていないのでシミュレータ上でしか動作確認をしていません。実機で動かすとかなり重いんじゃないかという気がしてます。早くiPhone4Sを手に入れないと…


ソースコード: http://kuramo.ch/iosdev/GLMovie.zip

(動画ファイルを含んでいるので約19MBあります。実行すると音も出ますので注意してください)


できること

  • ピンチ操作で拡大縮小
  • パン操作で回転
  • シングルタップで一時停止/再開
  • ダブルタップで停止(最初に巻き戻る)
  • 画面の上端付近をタップすると2倍速、下端付近をタップすると1/2倍速

f:id:butyricacid:20111005045633p:image:h300 f:id:butyricacid:20111005045634p:image:h300


AVAssetImageGenerator について

AV Foundation Programming Guide (日本語PDF) には次のように書かれています。

AVURLAsset の初期化メソッドは、第2引数として options ディクショナリを取ります。このディクショナリで使用される唯一のキーは AVURLAssetPreferPreciseDurationAndTimingKey です。対応する値は、正確な再生時間を指定し、時間単位の正確なランダムアクセスを許可するようにアセットを準備する必要があるかどうかを示すブール値です。

しかし、そのようにして初期化した AVURLAsset から AVAssetImageGenerator を作成しても指定した時刻どおりにフレームを切り出すことはできませんでした。AVURLAssetPreferPreciseDurationAndTimingKey の値によらず、直前のキーフレームが切り出されるようです。これは困りました…

さて、上記の記述の少し先を見てみると、次のようなことも書かれています。

アセットコンポジション(AVMutableComposition)に追加する場合は、通常、正確なランダムアクセスが必要です。次のように、AVURLAssetPreferPreciseDurationAndTimingKey キーとその値として(NSNumberオブジェクトに格納された)YESを含むディクショナリを渡します。

これはつまり、AVURLAssetPreferPreciseDurationAndTimingKey の値が意味をなすのは AVMutableComposition と共に使用した場合なのではないだろうかと考えて試してみたところ、うまくいきました。だいたい以下のような手順になります。

NSURL *assetURL = [[NSBundle mainBundle] URLForResource:@"movie.mp4" withExtension:nil];
NSDictionary *assetOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]
                                            forKey:AVURLAssetPreferPreciseDurationAndTimingKey];
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:assetURL options:assetOptions];

AVAssetTrack *srcTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVMutableComposition *comp = [AVMutableComposition composition];
AVMutableCompositionTrack *track = [comp addMutableTrackWithMediaType:AVMediaTypeVideo
                                          preferredTrackID:kCMPersistentTrackID_Invalid];
NSError *error = nil;
BOOL ok = [track insertTimeRange:srcTrack.timeRange ofTrack:srcTrack atTime:kCMTimeZero error:&error];
AVAssetImageGenerator *imageGen = [[AVAssetImageGenerator alloc] initWithAsset:comp];

2011-10-01

iOSアプリを実機で動かせるようになったので、適当に作ってみた

脱獄開発環境を作ったので早速何か作ってみようと思い、実機でしかできない加速度センサーを使ったものを作ってみました。実用性ゼロだし技術的にも特別なことは何もないですけど。

なお、加速度センサーの使い方とかはググればいっぱい出てくるのでここでは書きません。


ソースコード: http://kuramo.ch/iosdev/Shatter.zip


できること

  • 可愛いいおりんが見られます!
  • タップした場所が壊れます。なぞっても壊れます。
  • 壊れた破片は現実の重力方向に落ちて行きます。
  • 軽くタップすると壊れる範囲は小さく、強くタップすると広く壊れます。
  • もう一度タップすると初期状態に戻ります。

左が軽くタップした場合で、右が強くタップした場合

f:id:butyricacid:20111001212652j:image:h240 f:id:butyricacid:20111001212651j:image:h240


Javieの粉砕エフェクトとかAEのシャッターとかのように壊れますが、重力の方向が現実の重力の方向になっています。


やったこと

  • OpenGL ES Application」でプロジェクトを作成
  • 僕の手元には ES2 で動く実機が無く動作検証できないので、常に ES1 で動くように修正
  • EAGLViewクラスに次のメソッドを実装してタッチイベントを受け取るようにする
    • - (void)touchesBegan:(NSSet*)toucheswithEvent:(UIEvent*)event;
    • - (void)touchesMoved:(NSSet*)toucheswithEvent:(UIEvent*)event;
  • UIAccelerometerを使って加速度を取得できるようにする
    • タップの強さは直前の加速度との差分で
  • OpenGL関連
    • いおりんの画像を読み込んでテクスチャを作成する
    • デプスバッファ用のレンダーバッファを用意し、デプステストを有効にする
    • テクスチャをバインドし、テクスチャマッピングを有効にする
    • 破片の頂点配列とテクスチャ座標の配列を作る
    • glFrustumで視錐台を設定
    • その他いろいろ

ソースコード中には回転軸とか回転角とかあるけど、途中で面倒になって実装してません)



やはり実機で動かせると楽しいですね。画面を上に向けてタップすると画面奥の方へ落ちて行くわけですが、かなり落ちて行ってから画面を下向きにして下から覗き込んで「戻ってきたーw」とかやってしばらく遊んでました。


iOSアプリの脱獄開発環境を作ったメモ

今さらですが実機で動かしてみたいと思いまして。SDKはだいぶ前にインストールしていて、適当にコード書いてシミュレータ上で動かすということはしていました。しかし、AppStoreで公開するようなアプリのネタが無かったので1万円/年のお布施をする気になれませんでした。実際に何か作りたいものができてからでいいかなあ、と。

でも、実機で動かせる環境を整えたら作りたいものの1つや2つ出てくるんじゃないかと思ってお布施脱獄してみることにしました。ということで、このエントリは脱獄したデバイス用の開発環境を整えるためにしたことの備忘録なのです。


環境

  • 初代 iPod touch (iOS 3.1.3)
  • MacOSX 10.5.8
  • Xcode 3.1.4
  • iOS SDK 3.1.3

他の環境での構築方法は http://www39.atwiki.jp/iphonedev/pages/12.html が参考になるようです。


脱獄


AppSyncをインストール

キーチェーンで証明書を作成

Info.plistの編集

ビルドデバイスへの転送

これらは次のページを参考にしました。つまり、必要なことはほとんどここに書かれているということです。

http://unkar.org/r/iPhone/1218719962/345


これで、実機にアプリを転送し実行することが出来ました。


しかし、初代 iPod touch なので色々と残念な感じです。auからiPhone5出たら機種変更するんだ…