Appleが推奨するPowerVR用テクスチャ画像フォーマット(以後pvrファイルと呼ぶ)の話。
こいつをPNG画像ファイルの代わりに使う事に、なんのメリットがあるかというとメモリ消費が節約できるんですわ。
pvrファイルはオリジナルの画像を多少の劣化を覚悟して圧縮するのが特徴で、実際サンプルソースPVRTextureLoaderプロジェクトで作られたpvrファイルと、オリジナルPNGファイルの大きさを比べるとかなりの差があります。
で、単にファイルの時だけなら、さほど使う価値もないんですが、こいつはメモリ上にロードしたあとも圧縮された状態らしいです。
これは、Appleから提供されるpvrファイル読み込みクラス、PVRTextureのソースでglTexImage2Dの代わりにglCompressedTexImage2Dが利用されてる事からも確認できるわけっす。
で、まあサンプル、さくっと公開したいところだけど、さすがにPVRTextureクラスのソースは、Xcodeが自動生成するソースじゃなく、アカウント制限されたサンプルソースなんで公開はしない方が無難かな~とひよっちゃったりして。
なわけで、今回のサンプルは、自分でPVRTexture.m/hをPVRTextureLoaderサンプルプロジェクトからコピって追加してね。
んじゃ、さっそくpvrファイルの使い方から。
pvrファイルを読み込んでOpenGLが扱えるテクスチャにするには、Apple提供のPVRTextureクラスを使うのが簡単っす。
例えば
というpvrファイルを使いたいなら、いつものようにリソースとして準備(わからない人は「iPhoneアプリ開発、その(22)」を参照)して
こうやってPVRTextureインスタンスを作成して、あとはglBindTextureに渡すときに
というようにすればいい。
で、用がなくなったら
ちゅ~かんじ。
注意する事といえば、このインスタンスが解放されるとき
が呼ばれるので、外側で
なんてやってると、二重解放になるってことくらいかな。
次にpvrファイルの作成方法。
まずは、お勉強のためにターミナルからじかに作ってみましょう。
ターミナルの起動がわからない人は「iPhoneアプリ開発、その(75)」を参照。
まず、PNGファイルからpvrファイルを作成するツールは以下に有ります。そのまま以下の文字列を打ち込んでリターンキーしてみてちょ。
/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/texturetool
て出たら成功。
texturetool
と書くだけで動かないのは、このコマンドが存在する場所を検索する設定ができてないからです。
もし動くようなら、以前に以下の設定をしたってことになります。
texturetoolと打ち込めば動くようにする方法
PATH="$PATH":/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/
と入力してリターンキー。以上。
これでコマンド検索パスが設定されたので、以後はターミナルを終了するまで
texturetool
と入力してリターンキー打ち込むだけで動くはず。ここらへんを詳しく知りたい人は
bash入門
あたりでお勉強してください。ちなみにbashはBourne-Again Shellといいます。
で、texturetoolで出力される内容ですがUsageと書いてるように使い方の説明です。
通常unixのコマンドラインツールは、ユーザーからの指示を自分自身の名称(この場合texturetool)の後ろに続くスペースで区切られた文字列で判断します。
一般に引数というんだけど、複数の指示が必要な場合 -o とか -f というように、 - にアルファベットをつけた形で引数の種類を区別したりします。
上の、-mや-lのようにそれだけで完結するものもあれば、-eや-fのように追加文字列を必要とするものもあるわけです。
まず、-fに指定する文字列は-lで調べる事ができそうなんで、試しに
texturetool -l
と入力しリターンすると
て感じで出力されるわけです。
エンコード(圧縮)はPVRTCで、そのバリエーションとして--channel-weighting-linear、--channel-weighting-perceptual...そんな感じ。
ま、ここらへんはAppleのドキュメント「Technical Q&A QA1611:Creating textures in the PVRTC compression format」に詳しく説明されてるので、わざわざ調べる必要もないんですが、得体のしれないコマンドラインツールに遭遇した時に、こんな対処法もあったなと思い出しましょう。
ドキュメント読んだりして調べる事で、例えばApple提供PVRTextureLoaderサンプルプロジェクトに設定されてるカスタムスクリプトの
$TEXTURE_TOOL -m -e PVRTC --bits-per-pixel-4 -o "$SRCROOT/Images/Brick_mipmap_4.pvr" -f PVR "$SRCROOT/Images/Brick.png"
は
ということがわかるわけです。
ちなみにここで使われている$TEXTURE_TOOLや$SRCROOTは環境変数というものです。$SRCROOTは別のところで定義して引き継ぐ事も、$TEXTURE_TOOLみたいにその場で定義して使う事もできる。
詳しくはAppleのドキュメントXcode Build System Guide>Build Phasesを読みましょう。
ミップマップテクスチャというのは、物体が画面から遠ざかって小さくなった時は、それ専用に用意されたテクスチャに切り替えるという機能のためのテクスチャってことです。
OpenGL サンプル9
あたりがわかりやすいか?
ま、それはともかく試しに「iPhoneアプリ開発、その(106)」のサンプルプロジェクトes10.zipをダウンロードしておいて
texturetool -e PVRTC -o ~/Downloads/es10/frogstar.prv ~/Downloads/es10/frogstar.png
と打ち込んでみてください。
がes10フォルダの中にできてると思います。大きさは32KB。frogstar.pngが148KBなんでなかなかの圧縮率っすね。
ここらへんの比較検討は
Technical Q&A QA1611:Creating textures in the PVRTC compression format
や、nakamura001さんが書いてるブログ
強火で進め「[iPhoneプログラミング][OpenGL ES]テクスチャ圧縮(PVRTC)のクオリティを徹底比較してみた」
が、参考になります。
こうやって手動で用意しても全然問題はないわけですが、Xcodeにはビルドってやれば今までの手順を自動で実行してくれる機能があるわけっす。それが「iPhoneアプリ開発、その(103)」で書いたApple提供サンプルPVRTextureLoaderプロジェクトのビルドプロセスの一環として定義されているカスタムスクリプト記述というわけです。
じゃ、最後にプロジェクトへのカスタムスクリプト追加方法を。
試しにes10のes.xcodeprojプロジェクトを起動して、プロジェクト>新規ビルドフェーズ>新規スクリプトメニューを選択してみましょう。下のようなウィンドウが出てくると思います。
1、こいつに、
TEXTURE_TOOL=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/texturetool
$TEXTURE_TOOL -m -e PVRTC --bits-per-pixel-4 -o "$SRCROOT/frogstar.pvr" -f PVR "$SRCROOT/frogstar.png"
とかき込んで
2、入力ファイルの「+」ボタンを押して出てきた
を
3、出力ファイルの「+」ボタンを押して出てきた
を
にしてウィンドウを閉じてビルドすればfrogstar.pvrを消しておいても、勝手に作られるようになるはず。
注)$SRCROOTてのは、事前に定義済みの変数でes.xcodeprojの存在するフォルダを意味します。
で、できたfrogstar.pvrはプロジェクトにリソースとして登録。
これで、frogstar.pvrがアプリケーションにコピーされる事になる。じっさい「バンドルリソースをコピー(3)」はfrogstar.pvrが加わったので(3)となっている。
ただし、このままだと、さっき作ったfrogstar.pvr生成用スクリプトはこの「バンドルリソースをコピー(3)」より後に実行されてしまい、frogstar.pvrが無い状態でコピーしようとして失敗ってことになる。
これを防ぐためにfrogstar.pvr生成用スクリプトをドラッグして「バンドルリソースをコピー(3)」より前に移動させておく。
これで、frogstar.pvrが作られてからバンドルリソースとしてコピーされることになる。
今回のサンプルソース側の変更部分は#if USE_POWERVR_IMAGE #endifで囲まれたところ。
PVRTexture.m/hは自分でコピーしてね。es.xcodeprojと同じフォルダにおけばいいです。
やべっ、PNG画像のテクスチャglDeleteTexturesするの忘れてたわ。
------------
サンプルプロジェクト:es11.zip
こいつをPNG画像ファイルの代わりに使う事に、なんのメリットがあるかというとメモリ消費が節約できるんですわ。
pvrファイルはオリジナルの画像を多少の劣化を覚悟して圧縮するのが特徴で、実際サンプルソースPVRTextureLoaderプロジェクトで作られたpvrファイルと、オリジナルPNGファイルの大きさを比べるとかなりの差があります。
Brick.png 584KB オリジナル
Brick_4.pvr 132KB RGBA各4ビットで圧縮
Brick_2.pvr 68KB RGBA各2ビットで圧縮
で、単にファイルの時だけなら、さほど使う価値もないんですが、こいつはメモリ上にロードしたあとも圧縮された状態らしいです。
これは、Appleから提供されるpvrファイル読み込みクラス、PVRTextureのソースでglTexImage2Dの代わりにglCompressedTexImage2Dが利用されてる事からも確認できるわけっす。
で、まあサンプル、さくっと公開したいところだけど、さすがにPVRTextureクラスのソースは、Xcodeが自動生成するソースじゃなく、アカウント制限されたサンプルソースなんで公開はしない方が無難かな~とひよっちゃったりして。
なわけで、今回のサンプルは、自分でPVRTexture.m/hをPVRTextureLoaderサンプルプロジェクトからコピって追加してね。
んじゃ、さっそくpvrファイルの使い方から。
pvrファイルを読み込んでOpenGLが扱えるテクスチャにするには、Apple提供のPVRTextureクラスを使うのが簡単っす。
例えば
frog.pvr
というpvrファイルを使いたいなら、いつものようにリソースとして準備(わからない人は「iPhoneアプリ開発、その(22)」を参照)して
PVRTexture* instance;
・
・
・
instance = [PVRTexture pvrTextureWithContentsOfFile:
[[NSBundle mainBundle] pathForResource:@"frog" ofType:@"pvr"]];
[instance retain];
こうやってPVRTextureインスタンスを作成して、あとはglBindTextureに渡すときに
glBindTexture(GL_TEXTURE_2D, [instance name]);
というようにすればいい。
で、用がなくなったら
[instance release];
ちゅ~かんじ。
注意する事といえば、このインスタンスが解放されるとき
glDeleteTextures
が呼ばれるので、外側で
GLuint texture_name = [instance name];
glDeleteTextures(1, &texture_name);
なんてやってると、二重解放になるってことくらいかな。
次にpvrファイルの作成方法。
まずは、お勉強のためにターミナルからじかに作ってみましょう。
ターミナルの起動がわからない人は「iPhoneアプリ開発、その(75)」を参照。
まず、PNGファイルからpvrファイルを作成するツールは以下に有ります。そのまま以下の文字列を打ち込んでリターンキーしてみてちょ。
/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/texturetool
て出たら成功。
texturetool
と書くだけで動かないのは、このコマンドが存在する場所を検索する設定ができてないからです。
もし動くようなら、以前に以下の設定をしたってことになります。
texturetoolと打ち込めば動くようにする方法
PATH="$PATH":/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/
と入力してリターンキー。以上。
これでコマンド検索パスが設定されたので、以後はターミナルを終了するまで
texturetool
と入力してリターンキー打ち込むだけで動くはず。ここらへんを詳しく知りたい人は
bash入門
あたりでお勉強してください。ちなみにbashはBourne-Again Shellといいます。
で、texturetoolで出力される内容ですがUsageと書いてるように使い方の説明です。
Usage: texturetool [-hlm] [-e <encoder>] [-p <preview_file>] -o
<output> [-f <format>] input_image
-h ヘルプ表示
-l 利用できるエンコード法や画像フォーマットの一覧表示
-m 入力ファイルからミップマップファイル作成
-e <encoder> <encoder>で指定されるレベルで作成。
-p <preview_file> -eで指定される画像結果を<preview_file>というPNGファイルで出力。
-e指定が有る場合のみ有効。
-o <output> <output>というファイルで書き出し。
-f <format> <format>フォーマットで出力する。
通常unixのコマンドラインツールは、ユーザーからの指示を自分自身の名称(この場合texturetool)の後ろに続くスペースで区切られた文字列で判断します。
一般に引数というんだけど、複数の指示が必要な場合 -o とか -f というように、 - にアルファベットをつけた形で引数の種類を区別したりします。
上の、-mや-lのようにそれだけで完結するものもあれば、-eや-fのように追加文字列を必要とするものもあるわけです。
まず、-fに指定する文字列は-lで調べる事ができそうなんで、試しに
texturetool -l
と入力しリターンすると
て感じで出力されるわけです。
エンコード(圧縮)はPVRTCで、そのバリエーションとして--channel-weighting-linear、--channel-weighting-perceptual...そんな感じ。
ま、ここらへんはAppleのドキュメント「Technical Q&A QA1611:Creating textures in the PVRTC compression format」に詳しく説明されてるので、わざわざ調べる必要もないんですが、得体のしれないコマンドラインツールに遭遇した時に、こんな対処法もあったなと思い出しましょう。
ドキュメント読んだりして調べる事で、例えばApple提供PVRTextureLoaderサンプルプロジェクトに設定されてるカスタムスクリプトの
$TEXTURE_TOOL -m -e PVRTC --bits-per-pixel-4 -o "$SRCROOT/Images/Brick_mipmap_4.pvr" -f PVR "$SRCROOT/Images/Brick.png"
は
ミップマップファイル作成
PVRTCのbits-per-pixel-4で圧縮
Brick_mipmap_4.pvrというファイル名で出力
出力画像はPVRフォーマット
Brick.pngという入力画像
ということがわかるわけです。
ちなみにここで使われている$TEXTURE_TOOLや$SRCROOTは環境変数というものです。$SRCROOTは別のところで定義して引き継ぐ事も、$TEXTURE_TOOLみたいにその場で定義して使う事もできる。
詳しくはAppleのドキュメントXcode Build System Guide>Build Phasesを読みましょう。
ミップマップテクスチャというのは、物体が画面から遠ざかって小さくなった時は、それ専用に用意されたテクスチャに切り替えるという機能のためのテクスチャってことです。
OpenGL サンプル9
あたりがわかりやすいか?
ま、それはともかく試しに「iPhoneアプリ開発、その(106)」のサンプルプロジェクトes10.zipをダウンロードしておいて
texturetool -e PVRTC -o ~/Downloads/es10/frogstar.prv ~/Downloads/es10/frogstar.png
と打ち込んでみてください。
frogstar.prv
がes10フォルダの中にできてると思います。大きさは32KB。frogstar.pngが148KBなんでなかなかの圧縮率っすね。
ここらへんの比較検討は
Technical Q&A QA1611:Creating textures in the PVRTC compression format
や、nakamura001さんが書いてるブログ
強火で進め「[iPhoneプログラミング][OpenGL ES]テクスチャ圧縮(PVRTC)のクオリティを徹底比較してみた」
が、参考になります。
こうやって手動で用意しても全然問題はないわけですが、Xcodeにはビルドってやれば今までの手順を自動で実行してくれる機能があるわけっす。それが「iPhoneアプリ開発、その(103)」で書いたApple提供サンプルPVRTextureLoaderプロジェクトのビルドプロセスの一環として定義されているカスタムスクリプト記述というわけです。
じゃ、最後にプロジェクトへのカスタムスクリプト追加方法を。
試しにes10のes.xcodeprojプロジェクトを起動して、プロジェクト>新規ビルドフェーズ>新規スクリプトメニューを選択してみましょう。下のようなウィンドウが出てくると思います。
1、こいつに、
TEXTURE_TOOL=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/texturetool
$TEXTURE_TOOL -m -e PVRTC --bits-per-pixel-4 -o "$SRCROOT/frogstar.pvr" -f PVR "$SRCROOT/frogstar.png"
とかき込んで
2、入力ファイルの「+」ボタンを押して出てきた
$(SRCROOT)/myfile
を
$(SRCROOT)/frogstar.png
3、出力ファイルの「+」ボタンを押して出てきた
$(DERIVED_FILE_DIR)/myfile
を
$(SRCROOT)/frogstar.pvr
にしてウィンドウを閉じてビルドすればfrogstar.pvrを消しておいても、勝手に作られるようになるはず。
注)$SRCROOTてのは、事前に定義済みの変数でes.xcodeprojの存在するフォルダを意味します。
で、できたfrogstar.pvrはプロジェクトにリソースとして登録。
これで、frogstar.pvrがアプリケーションにコピーされる事になる。じっさい「バンドルリソースをコピー(3)」はfrogstar.pvrが加わったので(3)となっている。
ただし、このままだと、さっき作ったfrogstar.pvr生成用スクリプトはこの「バンドルリソースをコピー(3)」より後に実行されてしまい、frogstar.pvrが無い状態でコピーしようとして失敗ってことになる。
これを防ぐためにfrogstar.pvr生成用スクリプトをドラッグして「バンドルリソースをコピー(3)」より前に移動させておく。
これで、frogstar.pvrが作られてからバンドルリソースとしてコピーされることになる。
今回のサンプルソース側の変更部分は#if USE_POWERVR_IMAGE #endifで囲まれたところ。
PVRTexture.m/hは自分でコピーしてね。es.xcodeprojと同じフォルダにおけばいいです。
やべっ、PNG画像のテクスチャglDeleteTexturesするの忘れてたわ。
------------
サンプルプロジェクト:es11.zip