投稿

ラベル(OpenGL)が付いた投稿を表示しています

OpenGL FrameBuffer オブジェクト(FBO)

Grafika の RecordFBOActivity を見ながら、FBO(FrameBuffer Object)について勉強中。 DRAW_TWICE (draw x2) レンダリング(描画処理;draw メソッド)自体を(デフォルト framebuffer と動画ファイル用に)丸々 2 回行っている。 FBO (draw x1 + blit x2) オフスクリーン用の FBO にレンダリング(draw)を行い、それをデフォルト framebuffer と動画ファイルそれぞれに blit している。 BLIT_FRAMEBUFFER (draw x1 + blit x1) GLES 3.0 の glBlitFramebuffer を使い、デフォルト framebuffer にレンダリング(draw)したものを、先に動画ファイルに blit してから、画面表示用に swap している。 draw は描画オブジェクトの数、blit は転送するデータ(画面)サイズに依るので、DRAW_TWICE がいいのか、それ以外が良いのか一概には言えない。だが明らかに、BLIT_FRAMEBUFFER(draw x1 + blit x1)は FBO(draw x1 + blit x2)より確実に効率が良さそうである。 他、参考:LearnOpenGL: Framebuffers

Beginning Android Games(Android ゲームプログラミング A to Z)その 2

イメージ
前回の記事 その 1 の続き。 前回は本( libGDX の創始者である Mario Zechner 氏の著書“ Beginning Android Games ”(邦題は『 Android ゲームプログラミング A to Z 』))の 7 章の内容がベースだったが、今回は 8 章の内容がベースになる。 7 章では OpenGL ES 1.x そのものの使い方の解説(インプット)に主眼があったのに対して、8 章では「OpenGL そのもの」というよりは、いよいよ「OpenGL を使って」様々なグラフィックス表現を実現する、アウトプットの段階になる。 前回の記事では、Mario Zechner 氏のサンプルプログラムと同じ結果を実現するために、最近の Android プログラミングの事情に合わせて、Kotlin と最新の Android API をベースとし、さらに OpenGL は 2.0 に準拠するため自前のシェーダーを用意して、自分流のサンプルプログラムとライブラリーを構築した。 Game クラスと Screen クラスの構造、そして OpenGL をグラフィックスエンジンとして使用するための GLSurfaceView.Renderer クラスを用意し、その他のファイル入出力やサウンド、タッチ入力などの部分は、Android の API をそのまま使えばいいだけじゃないかということで、サンプルプログラム化、ライブラリー化の対象外としていた。 しかし、8 章では、タッチ入力をサンプルプログラムで使用するので、これだけはどうにかしなければならない。もちろん、Android プログラミングのタッチ入力に熟達している人ならば問題ないが、タッチイベントは独特のノウハウがあるので、普通はかなり面倒な代物である。本の 8 章のサンプルプログラムの側では、3 〜 6 章の過程で用意したライブラリーのタッチハンドラーがあり、そのタッチハンドラーから得られるイベントによって動作するように記述されているので、タッチ入力に関しては、この 8 章の個々のサンプルプログラムで直接扱うよりは、相当するタッチハンドラー用のクラスを用意して対応するのが無難である。 TouchHandler( 本家 ):本はかなり古い時代の Android API を基準としてい

Beginning Android Games(Android ゲームプログラミング A to Z)その 1

イメージ
Android を始めとするマルチプラットフォームの Java 用ゲーム開発フレームワーク libGDX の創始者である Mario Zechner 氏の著書“ Beginning Android Games ”(邦題は『 Android ゲームプログラミング A to Z 』)だが、原著は 3 版が 2016 年、初版の日本語訳版は 2011 年に出版されたきりであり、いずれにしても、最新の Android API からは隔絶した内容のものとなってしまっている。 初版は 10 年を経過(!)しているので、Android API 以外の内容にも古さは否めないが、とはいえ原著の 3 版にしても、ごく一部の Android API に関する部分を 2016 年の時点に合わせて修正したのみで、本の構成内容自体は全く更新されていない。特に、初版の時点では、OpenGL ES の 2.0 が出始めたばかりで普及しておらず、OpenGL ES 1.x を対象にしたのはわかるが、版を重ねても、OpenGL 2.0 以降に対応させてはいない。1.x と 2.0 以降では大きな違いがあるので、そこを変えるとなると大幅な書き直しになってしまうからだろう。また、本を読む初心者にとっても、2.0 以降のプログラマブルシェーダーについての学習のハードルが加わることになり、Android ゲーム開発全般をテーマとする本書のスケールを上回ることになる。 この本の良さはそういった Android プログラミングで直接使える技術の情報源として以外の部分にあるので、依然として一読の価値ある本だと思う。Amazon ではほとんど送料だけみたいな価格で古本が売られていたりするので、興味が湧いたら是非、一冊入手してみることをお勧めする。 自己流ゲームライブラリーの構築 本書を参考にして、自分流のゲームライブラリーを構築してみようと思う。最新の Android API 対応は当然として、その他の要点は次の通り: 2D OpenGL ES 2.0+ Kotlin プラットフォームは Android 専用とし、インターフェース化してマルチプラットフォーム化を意識した設計にするようなことはしない。例えば、ファイル入出力なども、直接 Android API を駆使し、ゲ

ステップアップ OpenGL ES 2.0

イメージ
0. OpenGL スケルトン Android では、GLSurfaceView の枠組みの中で OpenGL を処理する形になる。 1. タイルを表示するサンプル 4 個の頂点座標データに基いて、たった一つの矩形のタイルを描くだけだが、この最初の一歩の段階で一挙にハードルが上がる。主には、シェーダーで定義した変数を通じて頂点データを入力するための手続。あとは Kotlin / Java 固有の話として、ダイレクトバッファの形でデータを OpenGL 側に入力するという点。 シェーダー Kotlin / Java 側では、シェーダーは String データに過ぎないが、OpenGL 内部での処理を GLSL で定義するもの。C 言語的なスクリプトであり、公式の クイックリファレンスカード によくまとまっている(詳細な リファレンス も公開されている)。gl_* が予約された変数で、この変数に意図した値を出力することで OpenGL 内の次の処理へと頂点データが渡ることになる。 このサンプルでは、a_Position を通じて Kotlin / Java 側から入力した値をそのまま次へリレーしている。またフラグメントシェーダーにおいては、u_Color を通じて Kotlin / Java 側からセットした値をそのまま各フラグメント(ピクセル)の色として渡している。ちなみに、u_Color は uniform なので、いわゆるグローバル変数的なものとして定義されており、4 つの全ての頂点間で共有されている。一方の a_Position の方は attribute であり、各頂点毎に属する値である(cf. クイックリファレンス p3 Qualifiers)。 シェーダーの使い方 各シェーダーをコンパイルし、バーテックスとフラグメントを組み合わせて一つのシェダープログラムとし、さらに今有効なプログラムとしてそれをセットする(シェーダープログラムは複数用意して使い分けることも可能なため)。 シェーダー変数の確保 シェーダープログラムから、OpenGL への入力に使用するシェーダー変数(のポインターインデックス)を得る。 頂点データの配列 Kotlin / Java 固有の話として、JavaVM 内部のメモリーヒープを使うわけにはいかな

Android / Java と OpenGL ES 2.0 の要点

以下のような人(要するに僕自身のケースと同じ)を対象にしている: Android / Java のアプリ開発についての一般的な理解はある ImageView.onDraw や SurfaceView による動画ならそれほど苦労せずに理解できた しかし、OpenGL (ES 2.0) のことになると色んな解説やサンプルコードを見ても理解に苦しんで中々はかどらない なぜ OpenGL はわざわざああいうことをするようになっているのか? ImageView.onDraw や SurfaceView による動的グラフィックスなら理解しやすかった人にとって、動画とは、パラパラ漫画のようなものというほとんど無意識的な大前提があるわけだ。パラパラ漫画に限らず、映画やアニメなど、世の中の映像記録方式としては、こちらが圧倒的主流。ImageView.onDraw や SurfaceView の場合も、ループを回して、フレームバッファに次々とコマを描き込むだけ。 ところが、OpenGL はそれを許してくれないので、何か物凄く高度な、GPU のハードウェア的な性能を引き出すために、OpenGL の API を通じて描画する必要があるのかと、勘違いする。実際はそう(高度な GPU のハードウェア的な性能を引き出した上でレンダリングするのが目的の API 体系)ではないので、架空の妄想を相手に戦う羽目になり、決して勝利することができない戦いに挑む形になる。 OpenGL はそもそも、パラパラ漫画的なことをプログラマーが自らやることを想定していない(GPU 側の内部処理として行われる)。その一歩手前の部分(モデリング)を主にするのがプログラマーの仕事。モデルを基にしてラスタライズしてフレームバッファに落し込む処理は、GPU 側が(プログラマーが予め定義したフラグメントシェーダーに従って)内部的に行う形になっている。つまり、プログラマーがすべき仕事の領域がそもそも異っている点に気付かなければならない。 言ってみれば、フレームバッファ描き込みによるパラパラ漫画的動画はチカチカと瞬く GIF アニメみたいなもので、OpenGL はヌルヌル動く Flash アニメーションみたいなもの(Flash ももう過去の遺物だが……)。他にも、ペイント系グラフィック(ビットマップ

Android の OpenGL ES と SurfaceView / GLSurfaceView

イメージ
今さらながら Android の OpenGL ES に初めて手を付けてみた。これまでは ImageView の onDraw のカスタムか、ゲーム的なものでも、2D で SurfaceView の画面を丸ごと FrameBuffer として更新するような使い方しかしてこなかった。ところが今回、ちょっと凝った 2D のマップアプリのようなものを作ることになり、先述の通り従来は ImageView の onDraw カスタムで対処してきたのだが、できれば、SurfaceView か、さらには OpenGL ES 化して、Google Map のようなヌルヌルしたものにできないかと思い、3D 用だと思って敬遠してきた OpenGL ES の領域にまで足を踏み入れてみることにした。 SurfaceView 以前、使ったことがあると言っても、ちょっとした 2D ゲームのサンプルで使った程度であり、非ゲームのアプリに利用するというような場合も含めて SurfaceView 自体を研究したことはなかったので、まずは SurfaceView をいじってみることにした。 レンダリング用スレッドを使用する Activity 側で SurfaceHolder.Callback を implement するなりして、レンダリング用スレッドの生成や終了処理を行う。レンダリング用スレッド中では、SurfaceHolder を通じて Surface への(Canvas の描画命令を使った)描画を行う。 Canvas → SurfaceHolder → Surface という 3 重のバインド構造になっているの( 参考 )で初見では戸惑うかもしれないが、やっていることは Surface(framebuffer のようなもの)へのデータの書き込みである。 val canvas: Canvas = holder.lockCanvas() // Canvas#drawBitmap 等を使った描画処理 holder.unlockCanvasAndPost(canvas) レンダリング用スレッドを使わないで、そのままメイン UI スレッドで同様のことを行うこともできるが、圧倒的に処理が重くなる。SurfaceView を使う意味がない。 SurfaceView を使うこと