Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

IbisPaintのOpenGLES2.0

21,088 views

Published on

iPhone Dev勉強会 東京 2012/4/14で発表した資料です。

  • Be the first to comment

IbisPaintのOpenGLES2.0

  1. 1. ibisPaintのOpenGL ES 2.0 株式会社アイビス 神谷栄治12年4月28日土曜日
  2. 2. 自己紹介 • 株式会社アイビス (社員70名ほど) • iPhone, iPad, Android, タブレット, Webシステムの受託開発など • 代表取締役社長 神谷栄治 • ハンドル:かみやん • Twitter:    @kamiyan • 自称、ハッカー社長 初めて言って みたけど( ´Д`)y━・~~12年4月28日土曜日
  3. 3. 自称ハッカー社長 • 小学生:プログラミング、BASIC、Z80アセンブラ • 中学生:初の原稿料をもらう • 大学生:3D野郎、Direct3D、C++、日本初FTPソフト小次 郎プチヒット、機会学習、遺伝的プログラミング • サラリーマン:3D CAD作り、OpenGL、C++ • アイビス設立(26歳):ibisBrowser、ibisMail、ibisPaint、 Java、C++、Objective-C、ロボット作り • 高校生:恋愛♡ ( ´Д`)y━・~~12年4月28日土曜日
  4. 4. プログラミングの醍醐味 高速化! たまんねぇ∼( ´Д`)y━・~~12年4月28日土曜日
  5. 5. アプリの紹介 • ibisMail for iPhone(アイビスメール) • 世界初のメールアプリ。国内有料総合1位獲 得。 • ibisMail for iPad • こちらも国内有料総合1位獲得。 • ibisPaint(アイビスペイント) • こちらも国内有料総合1位獲得。 3冠!!12年4月28日土曜日
  6. 6. ibisPaintの企画 • iOS4.2リリースによりAVFoundationでmovファイルの作 成ができることが分かる!(2010/12) • 作画行程をmovファイルにエンコーディングして YouTubeにアップロードして共有したら楽しいんじゃ ね?! • ウィンドウやツールの変化も記録したいよね! • 高速だし、OpenGLに決定∼! • 「ソーシャルお絵描きアプリ ibisPaint」 バカ受け間違えなし!( ´Д`)y━・~~12年4月28日土曜日
  7. 7. ibispaint.com 完成! JavaServlet+JSP+MySQL PHPは嫌い ( ´Д`)y━・~~12年4月28日土曜日
  8. 8. アプリ動作デモ デモ中∼( ´Д`)y━・~~ AppStoreで「ibisPaint」で検索して「ibisPaint X」を ダウンロードください。無料。iPad / iPhone両対応の ユニバーサルアプリです。12年4月28日土曜日
  9. 9. OpenGL ESのメリット • 超高速! iPad(3rd Gen)なら4コア! • Core GraphicsやCore Imageよりも低レベルライブラリ • AndroidやWindowsなど他のプラットフォームにも移植 しやすい • 漢は黙ってC++ 普段はJava使いだけどな∼ ( ´Д`)y━・~~12年4月28日土曜日
  10. 10. OpenGL ES1.0と2.0の違い(1) • GLES1.0は固定パイプライン、GLES2.0はプログラマブル • GLES1.0は用意された描画パターンから選ぶ • GLES2.0は1pixelごとの色の計算をどうするかをC言語風 の専用言語(シェーダー言語)で書く。12年4月28日土曜日
  11. 11. OpenGL ES1.0と2.0の違い(2) • 1pixelごとにmain()関数がコールされる感じ。 • マルチコアGPUで並列処理!PCの世界だと1000コアと か。 • GLES2.0は行列計算APIがない(削除しなくてもよかった のでは。。) • とにかく、かなり違う! とにかくって小学生かよ ( ´Д`)y━・~~12年4月28日土曜日
  12. 12. 頂点シェーダーと フラグメントシェーダー • 頂点シェーダー(Vertex Shader, vsh)は、頂点位置、頂点 の色、頂点のテクスチャ座標などを決める • フラグメントシェーダー(Fragment Shader, fsh)は、1pixel ごとの色を決める • ibisPaintは2Dのアプリのため頂点シェーダーは、ほとん ど何もしていない • フラグメントシェーダーでいろいろ出来る。12年4月28日土曜日
  13. 13. CPUメモリとGPUメモリ メインメモリ GPUメモリ CPU GPU •メインメモリからGPUメモリへ書き込みはglTexImage2D() •GPUメモリからメインメモリへ読み込みはglReadPixels() •GPUメモリのポインタ等は得られないのでCPUが直接readし たりwriteしたりは出来ない •glTexImage2D()やglReadPixels()は重い(20msぐらい)ので注意 •バックグラウンドThreadから読み書きしてはいけない12年4月28日土曜日
  14. 14. GPUのメモリ • レンダーバッファ • 最終描画先であり、アルファプレーンがない、裏画面と表画 面用の2枚があり、基本は裏画面に描画してフリップで交換 する([EAGLContext presentRenderBuffer:]) • フレームバッファ • カラーバッファ、Zバッファ、ステンシルバッファなどを持つ • ibisPaintでは2Dのためカラーバッファのみ使用、テクスチャ バッファとして使用12年4月28日土曜日
  15. 15. フレームバッファーオブジェクト • Frame Buffer Object(FBO) • 昔はテクスチャバッファは読み取り専用でGPUがその バッファに描画することができなかったが、FBOによ りテクスチャバッファにレンダリングできるように なった。 • 動的テクスチャが可能になった! • ibisPaintではレイヤーのラスターデータはFBO。12年4月28日土曜日
  16. 16. FBO生成 • glGenTextures(); //テクスチャバッファ生成 • glGenFramebuffers(); //フレームバッファ生成 • glBindTexture(); //カレントテクスチャとする • glBindFramebuffer(); //カレントフレームバッファとする • glFramebufferTexture2D(); //フレームバッファとテクスチャ バッファをひも付ける • glCheckFramebufferStatus(); //整合性が取れているか確認12年4月28日土曜日
  17. 17. レンダーバッファの生成 • glGenRenderbuffers(); //レンダーバッファ生成 • glGenFramebuffers(); //フレームバッファ生成 • glBindRenderbuffer(); //カレントレンダーバッファとする • glBindFramebuffer(); //カレントフレームバッファとする • glFramebufferRenderbuffer(); //フレームバッファとレン ダーバッファをひも付け12年4月28日土曜日
  18. 18. フレームバッファの切替 フレームバッファ レンダーバッファ 描画命令 フレームバッファ テクスチャバッファ •glBindFramebuffer();で描画先を切り替 え、実画面とテクスチャバッファを透過 的に扱うことができる12年4月28日土曜日
  19. 19. ibisPaintでのFBOの例 出力先 入力テクスチャ フレームバッファ STEP1 レイヤーに描画 ブラシパターン レイヤー(FBO) テクスチャ STEP2 レイヤーを描画 レンダーバッファ レイヤー(FBO) (裏画面)に描画12年4月28日土曜日
  20. 20. 描画命令(プリミティブ) • 矩形を描け、矩形を塗りつぶせ、円を描け、多角形を描け、ベ ジェ曲線を描けとかはない! • 点、線分、三角形の描画のみ(漢らしい!) • 描画命令は glDrawArrays() or glDrawElements() #define GL_POINTS 点列 #define GL_LINES 線分列 #define GL_LINE_LOOP 閉じたポリライン #define GL_LINE_STRIP 折れ線 #define GL_TRIANGLES 三角形列 #define GL_TRIANGLE_STRIP つながった三角形列(ストリップ) #define GL_TRIANGLE_FAN つながった三角形列(ファン)12年4月28日土曜日
  21. 21. 描画命令(表と裏) • 右回り(Clockwise)が表、左回り(Counterclockwise)が裏? • 右回りが裏、左回りが表? 1 1 3 2 2 3 座標系によるけど裏表を間違えると見えないので注意 glFrontFace(GL_CW); or glFrontFace(GL_CCW);で設定可能12年4月28日土曜日
  22. 22. つながった三角形列 トライアングルストリップ 1 2, 4 矩形を描くのに 3, 6 5 GL_TRIANGLESだと6頂点をGPUへ送る 1 2 3 4 GL_TRIANGLE_STRIPだと4頂点をGPUへ 送るだけで済む(2/3の転送量) 1.5倍高速化!12年4月28日土曜日
  23. 23. つながった三角形列(2) こういうポリゴンデータはよくある。上の例では16ポリゴン。 GL_TRIANGLESだと16x3頂点の48頂点をGPUへ送る。 2 4 6 8 10 12 14 16 18 1 3 5 7 9 11 13 15 17 GL_TRIANGLE_STRIPの場合は、18頂点。ポリゴン数が多い場合1/3に減る。 3倍高速化!12年4月28日土曜日
  24. 24. つながった三角形列(3) こういうポリゴンデータはよくある。GL_TRIANGLE_STRIPを2回描画? →NO。縮退(面積0の三角形を描画する)を使うことで1回の描画 16 18 1719,20 API呼び出しがn回から1回へ高速化12年4月28日土曜日
  25. 25. 頂点フォーマット(PC) • 頂点のデータの型はアプリケーションが決める • PC:頂点位置P(x,y,z), 頂点カラー C(r,g,b,a) 間の色は線形補完 引用 http://openglut.sourceforge.net/redbook_smooth.png12年4月28日土曜日
  26. 26. 頂点フォーマット(PT) • PT:頂点位置P(x,y,z)とテクスチャ座標T(u,v) •四角い画像も三角形2枚で描く •テクスチャ画像は、RGBA 8-8-8-8bitもOK •ピクセルごとにアルファ値が違うものもOK •PNGをテクスチャーバッファにロードする のがよい •頂点カラーCは、C(1.0, 1.0, 1.0, 1.0)とみなさ れる。 •アルファ値がある場合のブレンドは、glBlendFunc()で設定可 能だが普通アルファブレンディング(Src * α + Dst * (1-α))し か使わない。12年4月28日土曜日
  27. 27. 頂点フォーマット(PCT) • PCT:頂点位置P(x,y,z), 頂点カラーC(r,g,b,a), テクスチャ 座標T(u,v) PCだけで描ける マスクテクスチャ 乗算 出力 乗算のところはフラグメント シェーダでカスタマイズ可能12年4月28日土曜日
  28. 28. 頂点フォーマット(PCTT) • PCTT:頂点位置P(x,y,z), 頂点カラーC(r,g,b,a), テクスチャ 座標T1(u,v), テクスチャ座標T2(u,v) • 応用:えんぴつ、クレヨン、画用紙 カレントカラー カレントブラシ カレント背景 パターン パターン 合成12年4月28日土曜日
  29. 29. 頂点フォーマット(PCTT)(2) • クレヨン •背景テクスチャは、シームレステク スチャにする。作り方は「シームレス テクスチャ」で検索。 •背景テクスチャのテクスチャ座標 は、描画位置Pに比例して変化させ て、背景テクスチャが固定されている ように見えるようにする。12年4月28日土曜日
  30. 30. 頂点フォーマット(PCTT)(3) •ブラシパターンは、テクスチャ座標 を固定(普通は、0.0 or 1.0)にし、ペ ンを走らせたときにペンが動いて見え る。 •背景テクスチャのテクスチャラップ モードは、GL_REPEATにする。 •頂点フォーマットとしては、テクスチャの参照はPCTTの ように2枚だけでなくたくさん参照可能(8枚くらいはいけ ると思う)12年4月28日土曜日
  31. 31. アニメーションの例 • 頂点位置Pを平行移動だとスライドイン、スライドアウトアニメー ション • 頂点位置Pを拡大縮小だと、ズームイン、ズームアウトアニメーション • 頂点位置Pを回転させると、回転アニメーション(ibisPaintではレイ ヤーの回転やフォトライブラリインポート時の回転で利用) • 頂点カラーCのアルファ値を変化させるとフェードインフェードアウ ト • テクスチャ座標のT(u, v)を変化させて絵柄をスクロールさせるアニ メーション12年4月28日土曜日
  32. 32. 選択範囲アニメーション • 選択範囲を表す折れ線は、 GL_LINE_STRIP • そこに□□■■の4pixelのテクスチャを設定 • アニメーションとしてLINE STRIPのテク マジックワンド スチャ座標T(u,v)のuを0.25づつずらすこ とで、破線がアニメーション12年4月28日土曜日
  33. 33. シェーダの準備 • glCreateProgram(); //シェーダプログラムの生成 • glCreateShader(); //シェーダの生成(GL_VERTEX_SHADER or GL_FRAGMENT_SHADER) • glShaderSource();// シェーダソースコードの指定 • glCompleShader();// ソースのコンパイル • glGetShaderiv(GL_COMPILE_STATUS);//コンパイル結果の取得 なんとコンパイラ内蔵! GPUのドライバがコンパイルする!12年4月28日土曜日
  34. 34. シェーダの準備(2) • glAttachShader(vsh); //頂点シェーダをセット • glAttachShader(fsh); //フラグメントシェーダをセット • glLinkProgmram(); //vshとfshをリンク • glGetProgramiv(); //リンク結果を取得 • glUseProgram(); //カレントプログラムとする なんとリンクもする!12年4月28日土曜日
  35. 35. シェーダの準備(3) ビルドフロー glCreateProgram() glCreateShader(vsh) glCreateShader(fsh) glShaderSource(vsh) glShaderSource(fsh) glCompileShader(vsh) glCompileShader(fsh) glGetShaderiv(vsh) glGetShaderiv(fsh) glAttachShader(vsh) glAttachShader(fsh) glLinkProgram() glGetProgramiv()12年4月28日土曜日
  36. 36. 頂点シェーダソース(1) • PCT(位置P, カラーC, テクスチャ座標T)の例 attribute vec2 a_position; attribute vec2 a_texCoord; } アトリビュート変数 attribute vec4 a_color; uniform mat4 u_matrix; ユニフォーム変数 varying vec2 v_texCoord; varying vec4 v_color; } バリイング変数 void main(){ gl_Position = u_matrix * vec4(a_position, 0.0, 1.0); v_texCoord = a_texCoord; v_color = a_color; } 位置とカラーとテクスチャ座標を入力してfshへ渡す12年4月28日土曜日
  37. 37. 頂点シェーダソース(2) • PCT(位置P, カラーC, テクスチャ座標T)の例 attribute vec2 a_position; attribute vec2 a_texCoord; attribute vec4 a_color; } アトリビュート変数 •アトリビュート変数とは、glDrawArrays()から来 る値(CPU側がセットした値)。 •頂点シェーダからみると入力変数の宣言 •お絵描きアプリのため、a_positionが2次元(vec2 型)12年4月28日土曜日
  38. 38. 頂点シェーダソース(3) • PCT(位置P, カラーC, テクスチャ座標T)の例 uniform mat4 u_matrix; ユニフォーム変数 •ユニフォーム変数は、汎用のCPU側から来る 変数(CPU側でセット) •上図では、4x4行列を渡している •整数、浮動小数、ベクトル、行列、テクス チャなどをCPUから渡すことが可能 •全GPUコアから参照されるためRead Only12年4月28日土曜日
  39. 39. 頂点シェーダソース(4) • PCT(位置P, カラーC, テクスチャ座標T)の例 varying vec2 v_texCoord; varying vec4 v_color; } バリイング変数 •バリイング変数は、頂点シェーダからフラグメ ントシェーダへ情報を伝達するための変数 •頂点シェーダから見ると出力変数 •フラグメントシェーダから見ると入力変数12年4月28日土曜日
  40. 40. 頂点シェーダソース(5) • PCT(位置P, カラーC, テクスチャ座標T)の例 void main(){ gl_Position = u_matrix * vec4(a_position, 0.0, 1.0); v_texCoord = a_texCoord; v_color = a_color; } •1頂点ごとにmain()関数が呼ばれる •上図、アトリビュート変数のa_positionを4次元に拡張 し、u_matrixを乗算して、gl_Positionとする •gl_Positionは、頂点シェーダの出力変数(固定) •上図、テクスチャ座標とカラーはそのままフラグメント シェーダへ転送12年4月28日土曜日
  41. 41. フラグメントシェーダソース(1) • PCT(位置P, カラーC, テクスチャ座標T)の例 varying vec2 v_texCoord; varying vec4 v_color; uniform sampler2D u_texture; void main(){ vec4 tex = texture2D(u_texture, v_texCoord); gl_FragColor = v_color * tex; } •v_texCoord, v_colorはバリイング変数で頂点 シェーダからの入力(線形補完済み) •u_textureは、ユニホーム変数でsampler2D型。 CPU側からセット12年4月28日土曜日
  42. 42. フラグメントシェーダソース(2) • PCT(位置P, カラーC, テクスチャ座標T)の例 void main(){ vec4 tex = texture2D(u_texture, v_texCoord); gl_FragColor = v_color * tex; } •main()関数は1pixelごとに呼ばれる •texture2D()組み込み関数は、sampler2D型とテクスチャ座 標を入力し、そのテクセルカラーを得る関数 •texはローカル変数 •gl_FragColorは、フラグメントシェーダの最終出力先変数 (固定) •上図では、テクスチャカラーと頂点カラーを乗算している12年4月28日土曜日
  43. 43. シェーダ言語の注意事項 • 色を参照するのは頂点カラーやテクスチャであり、出力先のフレーム バッファの色は取れない。なぜならフラグメントシェーダのmain()は複 数のGPUコアで並列に実行され、その実行順序が未定義であるため。 • ユニフォーム変数はCPU側からセットするがシェーダ言語側からみる と定数。 • if()は使えるが、for()はループ回数が定数のもののみ。 • 色の計算やテクスチャ座標は浮動小数で計算されているが浮動小数内 の計算誤差はやむを得ない • iOSシミュレータではほぼ動かず12年4月28日土曜日
  44. 44. ぼかしフィルタ(1) STEP1 COPY FBOa FBOb 最終出力先 テンポラリFBO 一時的にbindTexture()で入力側へ bindFramebuffer()で出力先とする STEP2 blur shader FBOb FBOa bindTexture()で入力側へ bindFramebuffer()で出力先とする • Blur Shaderを作成する • STEP1∼2を繰り返すとどんどんぼける12年4月28日土曜日
  45. 45. ぼかしフィルタソース •アルゴリズム:カレント点、一つ上の点、左の 点、右の点、下の点の5点の色を足して5で割るBlurShader.vsh BlurShader.fshattribute vec2 a_position; varying vec2 v_texCoord;attribute vec2 a_texCoord; varying vec2 v_texCoordU;uniform mat4 u_matrix; varying vec2 v_texCoordL;uniform vec2 u_pixel_tex;//1pxがtex coordでいくつか varying vec2 v_texCoordR;varying vec2 v_texCoord; varying vec2 v_texCoordD;varying vec2 v_texCoordU; uniform sampler2D u_texture;varying vec2 v_texCoordL; void main(){varying vec2 v_texCoordR; vec4 tex = texture2D(u_texture, v_texCoord);varying vec2 v_texCoordD; vec4 texU = texture2D(u_texture, v_texCoordU);void main(void){ vec4 texL = texture2D(u_texture, v_texCoordL); gl_Position = u_matrix * vec4(a_position, 0.0, 1.0); vec4 texR = texture2D(u_texture, v_texCoordR); v_texCoord = a_texCoord; vec4 texD = texture2D(u_texture, v_texCoordD); v_texCoordU = a_texCoord + vec2(0.0, -u_pixel_tex.y); vec4 tex2 = tex + texU + texL + texR + texD; v_texCoordL = a_texCoord + vec2(-u_pixel_tex.x, 0.0); gl_FragColor = tex2 / 5.0; v_texCoordR = a_texCoord + vec2( u_pixel_tex.x, 0.0); } v_texCoordD = a_texCoord + vec2(0.0, u_pixel_tex.y);}12年4月28日土曜日
  46. 46. フラグメントシェーダ応用 • ぼかし以外も、グレースケール化とか、明度、彩度、 色調とか、コントラストとか、なんでもOK • InstagramもiPhotoもOpenGL ES2.0を使っている • フィルタ系が全部、超高速!!12年4月28日土曜日
  47. 47. ibisPaintでの性能 • iPad2、1024x768(0.78Mpixels)で、レイヤー6枚で 60fps!! • iPad (3rd Gen)、2048x1536(3.14Mpixels)で、レイヤー6枚 で60fps!! 60fpsを死守せよ!!12年4月28日土曜日
  48. 48. まとめ(1) • OpenGLは、低レベルAPIなので高速! • GPUコアは年々増えていく(PCでは1000コア) • フレームバッファオブジェクトでテクスチャバッファ に書き込めるようになった(多段レンダリング) • フラグメントシェーダを使うと色々なフィルタが超高 速に動く12年4月28日土曜日
  49. 49. まとめ(2) • ibisPaintは60fpsで動いている。60fpsを死守せよ! • プログラミングの醍醐味は高速化!たまんねぇ∼ ( ´Д`)y━・~~ • ibisPaint Xは無料でiPhone / iPadのユニバーサルアプリ ダウンロードしてね∼ ( ´Д`)y━・~~ あとでShideShareに上げておきます。 ご清聴ありがとございました。12年4月28日土曜日

×