ブレイン・サブライ社主催のセミナー「IT技術者育成研修 実施説明会 ~低コストで即戦力のエンジニアを育成したい企業様向け~ (12月8日)」にラーニング部の大石が登壇します。
詳細・応募要項はこちらです。
http://www.brain-supply.co.jp/
http://www.brain-supply.co.jp/wp-content/uploads/2016/11/20161208seminar.pdf
ブレイン・サブライ社主催のセミナー「IT技術者育成研修 実施説明会 ~低コストで即戦力のエンジニアを育成したい企業様向け~ (12月8日)」にラーニング部の大石が登壇します。
詳細・応募要項はこちらです。
http://www.brain-supply.co.jp/
http://www.brain-supply.co.jp/wp-content/uploads/2016/11/20161208seminar.pdf
株式会社クロノス(大阪本社:大阪市中央区 代表取締役 月村 俊之)は、2017年1月から開催するプログラミングスクール 「IT CARET 」の第6期受講生の募集を開始しました。
http://itcaret.com/
■開催の背景
厚生労働省の懇談会の報告書『「働き方の未来2035」~一人ひとりが輝くために~』(2016年8月)には、少子高齢化社会の到来に伴い、労働力人口の減少する日本において、これからの時代の働き方の予測が記されています。今後、労働力人口を維持、高めていくためにはIoT、AI、VRといった新たなテクノロジーの活用に加えて、ICTを活用した多様な働き方を推進していく必要があります。 このような背景において、コンピュータやプログラミングについて学ぶ必要性は今後も高まっていくと弊社は考えています。
■IT CARET(アイティーキャレット)とは
IT CARETは 価値のあるものづくり を実践するプログラミングスクールです。教材のとおりにプログラミングを書き移すのではなく、創意工夫を凝らし、試行錯誤しながら、利用者にとって価値のあるものづくりを実践することを大切にしています。プログラミングの習得を「楽しい」だけで終わりにせずに、社会に価値として届けるところまでを狙いとしています。
IT CARETの受講者の多くは20代〜40代で非IT系の社会人や文系大学生です。受講者の多くは本業での課題や研究テーマを抱えており、課題解決のツールとしてプログラミングを習得しています。IT CARETでは毎日忙しく過ごされている方でも効率良くプログラミングを習得できるように反転学習システムを採用しています。動画やテキストで構成されるオンライン教材による予習(INPUT)と、専門家による実践形式の講義(OUTPUT)を組み合わせることで効率良くプログラミングを習得できます。
[Webプログラミングコース]
HTMLやCSSを中心にWebプログラミングの基礎を習得します。
初めてプログラミングにチャレンジする方を対象にしたコースです。
[PHPプログラミングコース]
ダイナミックなWebページを開発するプログラミング言語PHPを習得します。
PHPプログラミングの基礎をしっかり習得したい方を対象にしたコースです。
■概要
[Webプログラミングコース]
学習期間:2017年1月16日〜3月27日
◆集合学習開催日
第1回:1月16日(月) 19時15分〜21時45分
第2回:1月30日(月) 19時15分〜21時45分
第3回:2月13日(月) 19時15分〜21時45分
第4回:2月27日(月) 19時15分〜21時45分
第5回:3月13日(月) 19時15分〜21時45分
第6回:3月27日(月) 19時15分〜21時45分
◆自習スペース解放日
1月23日(月) 19時15分〜21時45分
2月 6日(月) 19時15分〜21時45分
2月20日(月) 19時15分〜21時45分
3月 6日(月) 19時15分〜21時45分
会場:株式会社クロノス大阪本社(大阪市中央区久太郎町3-3-9)
参加費:¥69,800(学生割引 ¥49,800)
申込み:Webプログラミングコース
[PHPプログラミングコース]
学習期間:2017年1月17日〜3月28日
◆集合学習開催日
第1回:1月17日(火) 19時15分〜21時45分
第2回:1月31日(火) 19時15分〜21時45分
第3回:2月14日(火) 19時15分〜21時45分
第4回:2月28日(火) 19時15分〜21時45分
第5回:3月14日(火) 19時15分〜21時45分
第6回:3月28日(火) 19時15分〜21時45分
◆自習スペース解放日
1月24日(火) 19時15分〜21時45分
2月 7日(火) 19時15分〜21時45分
2月21日(火) 19時15分〜21時45分
3月 7日(火) 19時15分〜21時45分
会場:株式会社クロノス大阪本社(大阪市中央区久太郎町3-3-9)
参加費:¥69,800(学生割引 ¥49,800)
申込み:PHPプログラミングコース
【お問い合わせ先】
株式会社クロノス 大阪本社
〒 541-0056 大阪府大阪市中央区久太郎町3丁目3-9 ORIX久太郎町ビル 5F
TEL:06-6258-5865
FAX:06-6258-5866
事業推進部 広報G: 谷本
Email: press-contact@kronos-jp.net
株式会社クロノスは経営理念である 「心を豊かにするものづくりとひとづくり」を実践すべくITエンジニア不足問題に対して、ITエンジニア育成という切り口で取り組んで参ります。
【女性限定 初学者向け】Kronos.css
http://kronos.connpass.com/event/44872/
■開催の背景
労働力人口の低下が予想される日本では、IT投資が増加する反面、ソフトウェア開発人材であるITエンジニアが不足が社会問題となっています。
経済産業省は国内IT人材の最新動向と将来推計に関する調査結果を発表し、IT人材は現時点で17万人超が不足しており、今後人口減少に伴い深刻化すると予測しています。
また平成24年12月に発足した第二次安倍内閣以降、「女性活躍」を政府の最重要政策の一つと位置付け、成長戦略の一環として、様々な取組を進められ「女性活躍加速のための重点方針2015」「すべての女性が輝く社会づくり本部」には、「女性が起業を通じてその個性と能力を発揮できるよう、地域における金融機関、創業・産業支援機関、地元企業、起業経験者等の様々な関係者が連携し、女性の起業を支援する体制を整備する」ことが掲げられています。(経済産業省より)
IT業界には有志で開催される勉強会が存在します。
しかしながら、勉強会の参加者の多くは男性であり、女性にとっては参加することに抵抗を感じたり、敷居が高く感じるのが現状のようです。
「ITエンジニア不足問題」を解決する一つのアイデアは、女性エンジニアの活躍にあると考え、このそのような背景において、ITエンジニア育成を事業とする弊社の使命について再考し、上記の問題を解決すべく、女性限定のプログラミング勉強会を開催するに至りました。
近年、弊社は女性エンジニアの採用、育成を積極的に行っています。
「技術を学ぶことが楽しくて仕方がない」と入社1年目のエンジニアは話します。
彼女らは技術の習得に大変意欲的で、開発現場でも一定の評価を得ています。
この度の勉強会も社内で活躍する女性エンジニアが主体となって企画しています。
このような取り組みが、女性エンジニアにとっての勉強会参加への敷居を下げることにより、
参加者が技術を楽しみながら理解を深め、質の高いエンジニアを育成できる場となればと考えています。
■概要
日時:2016年11月22日(火) 19時15分〜
会場:株式会社クロノス大阪本社(大阪市中央区久太郎町3-3-9)
参加費:無料
申込み:下記URLより
http://kronos.connpass.com/event/44872/
株式会社クロノスは経営理念である
株式会社クロノスは、スペイン発祥のラケットスポーツ「Padel」の普及を応援しています。
弊社代表取締役月村俊之は『Padel』を日本に広める広報大使『パデルエバンジェリスト』に就任し、日本パデル協会公認、正式にスペイン大使館様からもご後援をいただき「パデルで日本に笑顔とコミュニケーションの輪を広げる」普及活動をいたしております。
株式会社クロノスはPadelというラケットスポーツ、コミュニケーションスポーツを通じて「心を豊かにする」業務外活動として、東京・大阪本社でパデル部を発足させ、活動をスタートしております。
パデルとはテニスとスカッシュを合わせたようなラケット競技です。40年ほど前にスペインで生まれました。
現在、スペインでの競技人口は300万人と国民的なスポーツとなり、世界21か国に広がっています。ポイントの数え方はテニスと同じですが、パデルは2人対2人のダブルスのみでプレイします。コートのサイズは長方形の20×10メートルで、テニスコートの半分のサイズです。周囲は強化ガラスと金網により仕切られていて、その壁を使ってのプレイもできます。
パデルラケットはテニス用と比べると、柄はテニスより短く、ガットはなくて板状です。重さは大体同じくらいです。ボールはテニスボールと色や形は似てますが、パデルボールの方が空気圧が低く反発力が小さくなります。
引用:日本パデル協会HP
関西の学生やベンチャー企業が集まる場所として注目を浴びるエリア「大阪・西中島」に、2015年、非営利団体「にしなかバレー」が誕生しました。
にしなかバレーWebサイト:http://nishinaka-valley.com/
株式会社クロノスは2002年にこの西中島で創業した経緯もあり、2015年の夏からこの「にしなかバレー」の活動を支援しています。その活動が評価され、日本経済新聞(2016年2月17日号)の夕刊に取材記事が掲載されました。
日本経済新聞電子版:http://www.nikkei.com/article/DGXLASHD10H3U_Q6A210C1AA2P00/
今後も株式会社クロノスとにしなかバレーをどうぞよろしくお願い申し上げます。
最終章です。板ポリゴンへの動きのつけ方を解説します。
・3D座標のz軸
板ポリゴンでは、x軸とy軸を利用して2Dポリゴンを画面に描画しました。
この板ポリゴンのz軸に対して高さをつけると、板ポリゴンが3Dポリゴンに変わります。
今回は、このz軸の算出がポイントです。
z軸には、中心座標から距離と時間に応じて高低差をつけます。高低差はサイン波を利用します。サイン波により波の広がりが表現できます。
では、板ポリゴンに波の広がりを付けてみましょう。
波紋作成
今回は、以下のファイルを修正します。
・Shader.vsh
・Shader.fsh
・GameViewController.m
変更箇所について解説します。
変更箇所は、背景を反転させています。
Shader.vsh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
attribute vec4 attr_pos; attribute vec4 attr_color; uniform mat4 unif_pm; varying lowp vec4 vary_color; uniform float drow_count; #define WAVE_HEIGHT 0.05 #define WAVE_WIDTH 8.0 #define WAVE_SPEED 0.06 #define PI 3.14159265 void main() { vec4 p = attr_pos; float height = WAVE_HEIGHT * (1.0 - abs(p.x * 1.3)) * (1.0 - abs(p.y * 1.3)); float r = sqrt(dot(p.xy, p.xy)); float t = drow_count * WAVE_SPEED; p.z = height * sin((r - t) * PI * WAVE_WIDTH); gl_Position = unif_pm * p; vary_color = attr_color; vary_color.z = p.z; } |
定数は、WAVE_HEIGHT:波の高さ、WAVE_WIDTH:波の幅、WAVE_SPEED:波の速度、PI:円周率を設定します。
mainメソッドには、以下を追加します。
・波の広がりであるz軸の算出
・フラグメントシェーダに連携するためのカラーの設定
波の広がりの算出は、以下のとおりです。
波の広がり(z軸の高さ) = 波の高さ ✕ sin(半径 ー 時間)
波の高さは、座標0から離れるに従ってなくなるようにします。係数を1.0にすると端の波がなくなります。今回は、波紋に見せるため1.3の係数を掛けます。
半径は、p.xy におけるベクトル空間の距離を算出します。
時間は、drow_count と定数を利用して速度を調整します。
サイン波の算出は、定数を利用して波の幅を調整します。
フラグメントシェーダには、z軸の高さを連携します。
Shader.fsh
1 2 3 4 5 6 7 8 9 |
varying lowp vec4 vary_color; #define COLOR_WEIGHT 0.05 void main() { mediump float i = ((COLOR_WEIGHT) + vary_color.z) * 0.5; mediump float wc = i / COLOR_WEIGHT; gl_FragColor = vec4(0.5 * wc, 0.9 * wc, 0.9, 0.0); } |
カラーは、頂点シェーダから連携されたz軸の高さを利用します。
z軸の範囲は、頂点シェーダの定数 WAVE_HEIGHT になります。ここでは、 -0.05〜0.05の間で設定されます。
カラーは0.0〜1.0で設定されるため、-0.05〜0.05が0.0〜1.0になるように変換処理を追加します。
また、水の色としてRGBカラーの赤:0.5、緑:0.9、青:0.9を設定します。この時、波の低い箇所は暗く、高い箇所は明るくなるように gl_FragColor を調整します。
GameViewController.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
#import "GameViewController.h" #import <OpenGLES/ES2/glext.h> typedef struct { // X値 GLfloat x; // Y値 GLfloat y; // Z値 GLfloat z; // U値 GLfloat u; // V値 GLfloat v; } VertexData; // 分割数 static const int kDivCount = 120; // 頂点数 = Y頂点数 * X頂点数 static const int kVertexCount = (kDivCount+1) * (kDivCount+1); // 頂点インデックス数 = Y座標のインデックス数 * X座標のインデックス数 static const int kIndexCount = (kDivCount) * (3+(((kDivCount+1)-2)*2)+3); // カウント float count = 0; @interface GameViewController () { // レンダリング用プログラムシェーダー GLuint _program; // 頂点バッファ GLuint vertices_buffer; // インデックスバッファ GLuint indices_buffer; // 視点 GLKMatrix4 projection_modelview; } @property (strong, nonatomic) EAGLContext *context; @property (strong, nonatomic) GLKBaseEffect *effect; - (void)setupGL; - (void)tearDownGL; - (BOOL)loadShaders; - (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file; - (BOOL)linkProgram:(GLuint)prog; - (BOOL)validateProgram:(GLuint)prog; @end |
頂点シェーダで波の広がりを算出するための変数 count を定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
- (void)setupGL { [EAGLContext setCurrentContext:self.context]; [self loadShaders]; // 板ポリゴン作成 { { // 頂点バッファ { // 頂点バッファ VertexData vertrices[kVertexCount]; // 頂点間の長さ float divisions = 1.0f / kDivCount; // 頂点作成 int i = 0; for (int y = 0; y <= kDivCount; y++){ for (int x = 0; x <= kDivCount; x++){ float tx = (x * divisions) * 2 - 1.0f; float ty = (y * divisions) * 2 - 1.0f; float tz = 0.0f; vertrices[i].x = tx; vertrices[i].y = ty; vertrices[i].z = tz; vertrices[i].u = tx; vertrices[i].v = ty; i++; } } // 頂点バッファ作成 glGenBuffers(1, &vertices_buffer); assert(glGetError() == GL_NO_ERROR); assert(vertices_buffer != 0); // バインド glBindBuffer(GL_ARRAY_BUFFER, vertices_buffer); assert(glGetError() == GL_NO_ERROR); // アップロード glBufferData(GL_ARRAY_BUFFER, sizeof(VertexData) * kVertexCount, &vertrices, GL_STATIC_DRAW); assert(glGetError() == GL_NO_ERROR); // バインド解除 glBindBuffer(GL_ARRAY_BUFFER, 0); } // インデックスバッファ { // インデックスバッファ int indices[kIndexCount]; // y座標最大値 int maxYposition = kDivCount + 1; int i = 0; for (int y = 0; y < kDivCount; y++){ for (int x = 0; x < kDivCount+1; x++){ int idx0 = x + (y * maxYposition); int idx1 = idx0 + maxYposition; if(x == 0) { // 先頭x座標の場合、縮退三角形の対応をする indices[i++] = idx0; indices[i++] = idx0; indices[i++] = idx1; } else if (x == kDivCount) { // 後尾x座標の場合、縮退三角形の対応をする indices[i++] = idx0; indices[i++] = idx1; indices[i++] = idx1; } else { indices[i++] = idx0; indices[i++] = idx1; } } } // インデックスバッファ glGenBuffers(1, &indices_buffer); assert(glGetError() == GL_NO_ERROR); assert(indices_buffer != 0); // バインド glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_buffer); assert(glGetError() == GL_NO_ERROR); // アップロード glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * kIndexCount, &indices, GL_STATIC_DRAW); assert(glGetError() == GL_NO_ERROR); // バインド解除 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } } // カメラ初期化 { // 画角 float degree = 25.0f; //カメラ範囲 float near = 0.0f; float far = 10.0f; // カメラ位置 float eyeX = 0.0f; float eyeY = 2.7f; float eyeZ = 1.7f; // ターゲット位置 float targetX = 0.0f; float targetY = 0.0f; float targetZ = 0.0f; // カメラベクトル float upX = 0.0f; float upY = -1.0f; float upZ = 0.0f; // カメラ初期値設定 float aspect = (GLfloat) self.view.bounds.size.width / (GLfloat) self.view.bounds.size.height; GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(degree), aspect, near, far); GLKMatrix4 modelViewMatrix = GLKMatrix4MakeLookAt(eyeX, eyeY, eyeZ, targetX, targetY, targetZ, upX, upY, upZ); projection_modelview = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix); } } } |
板ポリゴンをズームアップするため、カメラの設定値を修正します。
画角とカメラの位置に注目してください。
1 2 3 4 5 6 7 |
- (void)update { // 描画回数更新 { count = count + 0.1; } } |
updateメソッドは、描画前に処理されるメソッドです。
count は頂点シェーダで利用する時間の代わりに使用します。描画されるタイミングでカウントアップします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { glClearColor(0.6f, 0.8f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // シェーダー利用開始 glUseProgram(_program); assert(glGetError() == GL_NO_ERROR); // バッファバインド glBindBuffer(GL_ARRAY_BUFFER, vertices_buffer); // 描画回数アップロード { // シェーダのuniform変数取得 GLint drow_count = glGetUniformLocation(_program, "drow_count"); // カウント設定 glUniform1f(drow_count, count); } // カメラ設定 { // シェーダのuniform変数取得 GLint unif_pm = glGetUniformLocation(_program, "unif_pm"); // カメラ指定 glUniformMatrix4fv(unif_pm, 1, GL_FALSE, projection_modelview.m); } // 頂点データ読み込み設定 { // シェーダのattribute変数取得 GLint attr_pos = glGetAttribLocation(_program, "attr_pos"); // シェーダ内属性のアクセス許可有効化 glEnableVertexAttribArray(attr_pos); // 利用箇所指定 glVertexAttribPointer(attr_pos, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid *) 0); } // フラグメントデータ読み込み設定 { // シェーダのattribute変数取得 GLint attr_color = glGetAttribLocation(_program, "attr_color"); // シェーダ内属性のアクセス許可有効化 glEnableVertexAttribArray(attr_color); // 利用箇所指定 glVertexAttribPointer(attr_color, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid *) (sizeof(float)*3)); } // インデックスバッファバインド glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_buffer); // シェーダー描画 glDrawElements(GL_TRIANGLE_STRIP, kIndexCount, GL_UNSIGNED_INT, (GLvoid *) 0); assert(glGetError() == GL_NO_ERROR); } |
updateメソッドで算出した count 変数を頂点シェーダへ連携するための処理を追加します。「unif_pm」と同様の設定です。
波の広がりを算出するための処理は以上です。
それでは、シミュレータを起動してみましょう!
シミュレータを起動すると、波紋が画面に描画されます。
※動画を作ってみました!こちらから動画を見れます。
今回は、波紋をテーマにObjective-CとOpenGL でプログラムを書いてみました。
OpenGLの開発は、最初に理解しなければいけないことが多いように感じました。
例えば、Javaで最初に学ぶことは、『Hello World !』をコンソールに出力することです。これは、数行あれば完成します。おまじないが1行、『Hello World !』の出力が1行です。
OpenGLは、まずはOpenGLの言語仕様、初期化から描画までの流れを理解しなければなりません。
さらに動きのあるポリゴンを作成するとなるとカメラ、光、影をベクトル、行列によって計算しなければなりません。
さらに、複雑な動きになると、高レベルな数学の知識が必要になります。
Javaとは違い、OpenGLは最初に乗り越えないといけない壁が高いと思います。
ですが、エンジニアとして、自由に描画できるOpenGLの魅力は尽きません。また、提供されるライブラリなどでは限界があります。
必要な時に、求められることができるようになるためには知識が必要です。
そのためには、OpenGLのような低レベル言語を経験し、エンジニアとしての底力を上げておきましょう!
OpenGL ES2.0で波紋を作る#4 OpenGL ES を組み込むベースを作成
OpenGL ES2.0で波紋を作る#5 格子状の板ポリゴンを作る
OpenGL ES2.0で波紋を作る#7 板ポリゴンに動きをつける
前の章で作成した板ポリゴンへのカメラの使い方を解説します。
・カメラの使い方
板ポリゴンにカメラをつけるには、OpenGL上でのカメラの使い方を理解しなければなりません。
以下、カメラの使い方を解説します。
・プロジェクションの設定
・カメラ視点の設定
・モデルビューの設定
・描画
プロジェクションの設定
□ プロジェクションの概念
プロジェクションは、画角、ニアクリップ、ファークリップを利用します。
以下の図の青色がカメラから見える範囲です。
項目 | 内容 |
---|---|
画角 | Y軸に対する視野領域の角度。 radianを設定します。 |
ニアクリップ | カメラ視点から最初に見える距離。 nearを設定します。 |
ファークリップ | カメラ視点から最後に見える距離。 farを設定します。 |
□ プロジェクションの設定
カメラのプロジェクションの設定は、「GLKMatrix4MakePerspective」を利用します。
GLKMatrix4MakePerspectiveの引数は、下記の通りです。
第1引数:ラジアン。GLKMathDegreesToRadiansを利用することで、度数からラジアンに変換できます。
第2引数:画面のアスペクト比
第3引数:ニアクリップ
第4引数:ファークリップ
1 |
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(degree), aspect, near, far); |
□ カメラ視点の概念
カメラの視点の概念
カメラ視点には、カメラのベクトル、カメラの位置、ターゲットの位置を設定します。
項目 | 内容 |
---|---|
カメラの位置 | カメラの位置座標。 eyeX、eyeY、eyeZを設定します。 |
ターゲットの位置 | カメラから見るターゲットの位置座標。 targetX、targetY、targetZを設定します。 |
カメラのベクトル | カメラの方向。 upX、upY、upZを設定します。 |
カメラ視点の設定
カメラ視点の設定は、「GLKMatrix4MakeLookAt」を利用します。
GLKMatrix4MakeLookAtの引数は、先頭から順にカメラの位置座標、ターゲットの位置座標、カメラのベクトルの座標を設定します。
1 |
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeLookAt(eyeX, eyeY, eyeZ, targetX, targetY, targetZ, upX, upY, upZ); |
□ モデルビュー
頂点シェーダへ連携するためのモデルビューを算出します。
モデルビューは、カメラのプロジェクションとカメラの視点の情報を掛けあわせた情報です。
モデルビューの設定 p>
モデルビューの設定は、「GLKMatrix4Multiply」を利用します。
GLKMatrix4Multiplyは、行列の掛け算を行います。カメラのプロジェクション情報とカメラの視点情報を引数に渡します。
その後、頂点シェーダ側で頂点情報と掛け合わすことでカメラの視点になります。
1 |
GLKMatrix4 projection_modelview = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix); |
□ 描画
頂点シェーダ内のデータアクセス
頂点シェーダ内のデータへアクセスするには、「glUniformMatrix4fv」を利用します。
これで、頂点シェーダが保持する「unif_pm」変数に外部からアクセスできるようになります。
1 2 3 4 5 6 7 |
attribute vec4 attr_pos; uniform mat4 unif_pm; void main() { gl_Position = unif_pm * attr_pos; } |
1 |
GLint unif_pm = glGetUniformLocation(_program, "unif_pm"); |
1 |
glUniformMatrix4fv(unif_pm, 1, GL_FALSE, projection_modelview.m); |
カメラの作成
□ カメラの作成
前の章で作成したrepercussionsプロジェクトに対して、以下のファイルを修正します。
・Shader.vsh
・GameViewController.m
変更箇所について解説します。
変更箇所は、背景を反転させています。
Shader.fsh
1 2 3 4 5 6 7 8 9 10 11 |
attribute vec4 attr_pos; attribute vec4 attr_color; uniform mat4 unif_pm; varying lowp vec4 vary_color; void main() { gl_Position = unif_pm * attr_pos; vary_color = attr_color; } |
カメラ情報は uniform で宣言した変数を利用します。uniform を宣言した unif_pm は、外部からカメラ情報を設定することができます。
※uniform は、attribute とは異なり宣言する数に制限があります。ご注意ください。
gl_Position は、頂点情報とカメラ情報を掛けあわせた情報を受け取ります。
GameViewController.m
1 2 3 4 5 6 7 8 9 10 11 12 |
@interface GameViewController () { // レンダリング用プログラムシェーダー GLuint _program; // 頂点バッファ GLuint vertices_buffer; // 頂点インデックス GLuint indices_buffer; // 視点 GLKMatrix4 projection_modelview; } |
描画時にOpenGLへ連携するモデルビューを宣言します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
- (void)setupGL { [EAGLContext setCurrentContext:self.context]; [self loadShaders]; // 板ポリゴン作成 { { // 頂点バッファ { …省略… } // 頂点インデックスバッファ { …省略… } } // カメラ初期化 { //カメラ範囲 float near = 0.0f; float far = 10.0f; // カメラ角度 float radian = 60.0f; // カメラ位置 float eyeX = 0.0f; float eyeY = 3.0f; float eyeZ = 3.0f; // ターゲット位置 float targetX = 0.0f; float targetY = 0.5f; float targetZ = 0.0f; // カメラベクトル float upX = 0.0f; float upY = -1.0f; float upZ = 0.0f; // カメラ初期値設定 float aspect = (GLfloat) self.view.bounds.size.width / (GLfloat) self.view.bounds.size.height; GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective( GLKMathDegreesToRadians(radian), aspect, near, far); GLKMatrix4 modelViewMatrix = GLKMatrix4MakeLookAt( eyeX, eyeY, eyeZ, targetX, targetY, targetZ, upX, upY, upZ); projection_modelview = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix); } } } |
setupGLメソッドでは、カメラの初期化処理を追加します。
カメラの初期化は、カメラのプロジェクション、カメラ視点を設定し、そこからモデルビューを算出します。
カメラのプロジェクション、カメラ視点、モデルビューは、上記で説明した内容と同じです。
ここでの注意点は、カメラの設定には微調整が必要になることです。
カメラの向き、視点の範囲、距離などが適切に設定されないと対象物を見失うことになります。
例えるならば、カメラのファインダーと同じイメージです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { glClearColor(0.2f, 0.2f, 0.2f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // シェーダー利用開始 glUseProgram(_program); assert(glGetError() == GL_NO_ERROR); // バッファバインド glBindBuffer(GL_ARRAY_BUFFER, vertices_buffer); // カメラ設定 { // シェーダのuniform変数取得 GLint unif_pm = glGetUniformLocation(_program, "unif_pm"); // カメラ指定 glUniformMatrix4fv(unif_pm, 1, GL_FALSE, projection_modelview.m); } // 頂点データ読み込み設定 { …省略… } // フラグメントデータ読み込み設定 { …省略… } // インデックスバッファバインド …省略… // シェーダー描画 …省略… } |
glkViewメソッドでは、頂点シェーダにカメラ情報を連携するための処理を追加します。
シミュレータを起動すると、カメラ視点から眺めた板ポリゴンが画面に描画されます。
次回は、最終章です。
このカメラつき板ポリゴンに対して、時間に応じて高さを設定すると波紋が完成します。
OpenGL ES2.0で波紋を作る#4 OpenGL ES を組み込むベースを作成
OpenGL ES2.0で波紋を作る#5 格子状の板ポリゴンを作る
OpenGL ES2.0で波紋を作る#6 カメラをつける
この章では、OpenGLを利用したプロジェクト作成方法を解説します。
・OpenGLを利用したプロジェクトの作成方法
この記事を作成している時点では、最新のXcodeのバージョンは、6.3.2です。
今後、Xcodeのバージョンアップに伴い、記事通りの手順では進めることができないかもしれません。別途、Apple公式のデベロッパーページにて、ご確認をお願いします。
プロジェクト作成の手順は、以下の流れになります。
1. Xcode起動
2. 新規プロジェクト
3. シミュレータ起動
1. プロジェクト起動
メニューよりプロジェクトを起動します。
以下は、「Spotlight 検索」からXcodeを起動しています。
※Xcodeがない場合、AppleStoreにて「Xcode」を検索し、最新版をインストールしてください。
2. 新規プロジェクト
□ 新規プロジェクト作成
メニュー→ファイル→New→Project…をクリックします。
iOS→Application→Game
プロジェクトの作成では、Gameプロジェクトを選択します。
Gameプロジェクトは、OpenGLが既に設定されており、コントローラーやビューの面倒な設定を省くことができます。
□ プロジェクトの設定
以下の入力項目のポイントは、「Game Technology」に「OpenGL ES」 を利用することです。
入力内容
項目 | 内容 |
---|---|
Product Name | 任意の内容を設定してください。 例)repercussions |
Organization Name | 任意の内容を設定してください。 例)sample |
Organization Identifier | 任意の内容を設定してください。 例)sample |
Langueage | Objective-C |
Game Technology | OpenGL ES |
Device | iPhone |
以上で、Gameプロジェクトが作成できます。
3. シミュレータ起動
Xcodeからシミュレータを起動します。
メニュー→▶ボタン→シミュレータ起動
※初回は、起動に時間がかかることがあります。
シミュレータは、初期サイズが大きいので、画面に合わせて縮小してください。
メニュー→Window→Scale→50%
OpenGLは、GPUを利用することで高速に描画できるライブラリです。
シミュレータはGPUを利用しません。もし、実機が利用できる環境であれば、実機を利用した方がOpenGLの良さを理解しやすいと思います。
OpenGL ES2.0で波紋を作る#3 プロジェクト作成
この章では、波紋の元になる格子状の板ポリゴンの作成について解説します。
・板ポリゴン
・縮退三角形
ポリゴンとは、立体的な物体を表現するための多角形のことを言います。
OpenGLは三角形を利用して多角形を作成します。四角形は三角形を2つ組み合わせ、五角形は3つ組み合わせることで作成できます。
OpenGLのポリゴンも同様に、複数の三角形を組み合わせることで多角形を作成し、立体を表現します。この三角形を組み合わせて、2Dのポリゴンを作成します。ここでは、この2Dポリゴンを「板ポリゴン」と呼びます。
今回、板ポリゴンは以下の設計で作成します。
・1つの四角形を細かく分割する
・分割した四角形から、三角形を作るための頂点を算出する。
・頂点をベースに三角形を作成する
・一つ一つの三角形に色を塗る
板ポリゴン作成
前の章で作成したrepercussionsプロジェクトに対して、以下のファイルを修正します。
・Shader.vsh
・Shader.fsh
・GameViewController.m
変更箇所について解説します。
変更箇所は、背景を反転させています。
Shader.vsh
1 2 3 4 5 6 7 8 9 |
attribute vec4 attr_pos; attribute vec4 attr_color; varying lowp vec4 vary_color; void main() { gl_Position = attr_pos; vary_color = attr_color; } |
Shader.vshファイルは、頂点シェーダです。絵を描くための処理を記載します。
頂点情報は attribute で宣言した変数を利用します。attributeを宣言した attr_pos は、外部から頂点情報を設定することができます。
varying で宣言した vary_color は、頂点シェーダからフラグメントシェーダに情報を連携するための変数です。この後に呼ばれるフラグメントシェーダに色情報を連携します。
gl_Position は、OpenGLの変数です。頂点シェーダから頂点情報を受け取ります。
Shader.fsh
1 2 3 4 5 |
varying lowp vec4 vary_color; void main() { gl_FragColor = vec4(abs(vary_color.x+vary_color.x), abs(vary_color.y+vary_color.y), 1.0, 1.0); } |
Shader.fshファイルは、フラグメントシェーダです。色を塗るための処理を記載します。
フラグメントシェーダでは、頂点情報のように attribute を利用することが出来ません。
そのため、varying にて宣言した vary_color を利用し、頂点シェーダから色情報を受け取ります。
GameViewController.m
「OpenGL ES を組み込むベースを作成」 で説明した修正の必要なメソッドと宣言部について解説します。
以下の修正以外は、そのままです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#import "GameViewController.h" #import typedef struct { // X値 GLfloat x; // Y値 GLfloat y; // Z値 GLfloat z; // U値 GLfloat u; // V値 GLfloat v; } VertexData; // 分割数 static const int kDivCount = 120; // 頂点数 = Y頂点数 * X頂点数 static const int kVertexCount = (kDivCount+1) * (kDivCount+1); // 頂点インデックス数 = Y座標のインデックス数 * X座標のインデックス数 static const int kIndexCount = (kDivCount) * (3+(((kDivCount+1)-2)*2)+3); @interface GameViewController () { // レンダリング用プログラムシェーダー GLuint _program; // 頂点バッファ GLuint vertices_buffer; // インデックスバッファ GLuint indices_buffer; } @property (strong, nonatomic) EAGLContext *context; @property (strong, nonatomic) GLKBaseEffect *effect; - (void)setupGL; - (void)tearDownGL; - (BOOL)loadShaders; - (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file; - (BOOL)linkProgram:(GLuint)prog; - (BOOL)validateProgram:(GLuint)prog; @end |
クラスの宣言部では、波紋の作成に必要な構造体の宣言、定数、インスタンス変数を定義します。
VertexData は、頂点情報を格納するための構造体です。
kDivCount、kVertexCount、kIndexCount は、バッファ作成や描画時に利用するための定数です。
kDivCount は、1枚の四角形を格子状に分割するための数です。
kVertexCount は、格子状に分割した頂点の数です。
kIndexCount は、IBOで利用する頂点のインデックスの数です。
インスタンス変数として、頂点バッファとインデックスバッファの変数を定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
- (void)setupGL { [EAGLContext setCurrentContext:self.context]; [self loadShaders]; // 板ポリゴン作成 { { // 頂点バッファ { // 頂点バッファ VertexData vertrices[kVertexCount]; // 頂点間の長さ float divisions = 1.0f / kDivCount; // 頂点作成 int i = 0; for (int y = 0; y <= kDivCount; y++){ for (int x = 0; x <= kDivCount; x++){ float tx = (x * divisions) * 2 - 1.0f; float ty = (y * divisions) * 2 - 1.0f; float tz = 0.0f; vertrices[i].x = tx; vertrices[i].y = ty; vertrices[i].z = tz; vertrices[i].u = tx; vertrices[i].v = ty; i++; } } // 頂点バッファ作成 glGenBuffers(1, &vertices_buffer); assert(glGetError() == GL_NO_ERROR); assert(vertices_buffer != 0); // バインド glBindBuffer(GL_ARRAY_BUFFER, vertices_buffer); assert(glGetError() == GL_NO_ERROR); // アップロード glBufferData(GL_ARRAY_BUFFER, sizeof(VertexData) * kVertexCount, &vertrices, GL_STATIC_DRAW); assert(glGetError() == GL_NO_ERROR); // バインド解除 glBindBuffer(GL_ARRAY_BUFFER, 0); } |
setupGLメソッドでは、描画に必要なVBO、IBOを作成します。
頂点バッファ/インデックスバッファ作成、バインド、バッファデータのアップロードは、「基礎知識2」(シェーダの効率的な描画) で解説した内容と同じです。
VBOには、頂点情報を設定します。
頂点情報は、VertexDataの配列(vertrices)を利用します。
頂点毎に頂点の座標(x、y、z)と色(u、v)を算出し、VertexDataに設定し、それを配列へ格納します。
頂点の座標は、頂点の分割数と頂点間の長さから算出します。
色は、頂点の座標を利用します。今回は、x座標とy座標をRGBカラーのRとGとして設定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
// インデックスバッファ { //インデックスバッファ int indices[kIndexCount]; // y座標最大値 int maxYposition = kDivCount + 1; int i = 0; for (int y = 0; y < kDivCount; y++){ for (int x = 0; x < kDivCount+1; x++){ int idx0 = x + (y * maxYposition); int idx1 = idx0 + maxYposition; if(x == 0) { // 先頭x座標の場合、縮退三角形の対応をする indices[i++] = idx0; indices[i++] = idx0; indices[i++] = idx1; } else if (x == kDivCount) { // 後尾x座標の場合、縮退三角形の対応をする indices[i++] = idx0; indices[i++] = idx1; indices[i++] = idx1; } else { indices[i++] = idx0; indices[i++] = idx1; } } } // インデックス glGenBuffers(1, &indices_buffer); assert(glGetError() == GL_NO_ERROR); assert(indices_buffer != 0); // バインド glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_buffer); assert(glGetError() == GL_NO_ERROR); // アップロード glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * kIndexCount, &indices, GL_STATIC_DRAW); assert(glGetError() == GL_NO_ERROR); // バインド解除 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } } } } |
IBOは、glDrawElements呼び出し際、GL_TRIANGLE_STRIPモードで描画されます。
GL_TRIANGLE_STRIPモードは、次の1点と前の2点の頂点を利用して三角形を描くモードです。
ここでは、この頂点を算出する処理を記載しています。
IBOは、頂点バッファの頂点情報のインデックスを設定します。この設定には数値の配列(indices)を利用します。
頂点情報のインデックスは、頂点の分割数を元に算出します。
現在のy座標を視点に、x座標から頂点バッファの頂点情報のインデックスを設定します。
その後、次のy座標を算出し、同じように頂点情報のインデックスを設定します。
ここでポイントになるのが、y座標が変わるタイミングです。
x座標の終わりと次のx座標の始まりが繋がるため、無駄な三角形が描画されます。
この繋がりを描画させないための処理として、縮退三角形を利用します。
縮退三角形については、後半部分で解説します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
- (void)tearDownGL { [EAGLContext setCurrentContext:self.context]; glUseProgram(0); glDeleteProgram(_program); { assert(glIsBuffer(vertices_buffer) == GL_TRUE); GLuint buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*) &buffer); assert(buffer == vertices_buffer); } glDeleteBuffers(1, &vertices_buffer); glDeleteBuffers(1, &indices_buffer); { assert(glIsBuffer(vertices_buffer) == GL_FALSE); GLuint buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*) &buffer); assert(buffer == 0); } } |
tearDownGLメソッドは、シェーダをメモリから開放する処理を記載します。
setupGLメソッドで作成したVBO、IBOを削除します。
1 2 3 4 |
- (void)update { // 処理なし } |
updataメソッドは、今回、使用しません。
不要な処理を削除します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // バッファバインド glBindBuffer(GL_ARRAY_BUFFER, vertices_buffer); // 頂点情報設定 { // シェーダのattribute変数取得 GLint attr_pos = glGetAttribLocation(_program, "attr_pos"); // シェーダ内属性のアクセス許可有効化 glEnableVertexAttribArray(attr_pos); // 利用箇所指定 glVertexAttribPointer(attr_pos, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid *) 0); } // フラグメント情報設定 { // シェーダのattribute変数取得 GLint attr_color = glGetAttribLocation(_program, "attr_color"); // シェーダ内属性のアクセス許可有効化 glEnableVertexAttribArray(attr_color); // 利用箇所指定 glVertexAttribPointer(attr_color, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid *) (sizeof(float)*3)); } // インデックスバッファバインド glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_buffer); // シェーダー利用開始 glUseProgram(_program); assert(glGetError() == GL_NO_ERROR); // シェーダー描画 glDrawElements(GL_TRIANGLE_STRIP, kIndexCount, GL_UNSIGNED_INT, (GLvoid *) 0); assert(glGetError() == GL_NO_ERROR); } |
glkViewメソッドでは、初期化時に作成したVBOとIBOをバインドします。そして、画面に板ポリゴンを描画します。
頂点情報設定、フラグメント情報設定、描画は、「基礎知識2」(シェーダの効率的な描画) で説明した内容と同じです。
今回、板ポリゴンを作成するためGL_TRIANGLE_STRIPモードで描画しています。このモードは、縮退三角形を描画しない特徴があります。
縮退三角形とは、面積が0の三角形、または、3点の座標が直線に並ぶ三角形のことを言います。
通常、GL_TRIANGLE_STRIPモードで描画すると上の図のような順番でポリゴンが描かれます。このポリゴンは、2つの三角形で四角形を描いています。
次に、1つの四角形を2分割し、8つの三角形で四角形を描きます。
ポイントは、2→5→3の三角形です。
GL_TRIANGLE_STRIPモードの仕様上、次の1点と前の2点を利用して三角形を描くため、2→5→3の三角形が描かれます。
この三角形が描かれると、波紋が綺麗に表示されなくなります。
この2→5→3の三角形を描画しないためには、どうすれば良いのでしょうか?
それを解決するのが、縮退三角形です。
縮退三角形を利用する箇所は、以下です。
1. y座標が変わるタイミングのx座標の終わり
2. y座標が変わるタイミングのx座標の始まり
修正方法は、以下を追加するだけです。
1. y座標が変わるタイミングのx座標の終わり
x座標の最後の頂点の位置に、同じ頂点を1つ追加します。
→ 以下の図のindices[6]です。
2. y座標が変わるタイミングのx座標の始まり
x座標の最初の頂点の位置に、同じ頂点を1つ追加します。
→ 以下の図のindices[8]です。
これにより縮退三角形が作成され、不要な三角形が描画されなくなります。
シミュレータを起動すると、板ポリゴンが画面に描画されます。
次回は、この板ポリゴンにカメラをつけます。
カメラをつけることで、3D視点から板ポリゴンを眺めることができます。
OpenGL ES2.0で波紋を作る#4 OpenGL ES を組み込むベースを作成
OpenGL ES2.0で波紋を作る#5 格子状の板ポリゴンを作る
この章では、作成したrepercussionsプロジェクトの理解と波紋を作るためのrepercussionsプロジェクトの変更方法について解説します。
・repercussionsプロジェクトの理解
・プロジェクトの変更方法
repercussionsプロジェクトは、既に「OpenGL ES」が取り込まれたプロジェクトです。
各メソッドで「OpenGL ES」がどのように処理しているかを確認しましょう。
repercussionsプロジェクト
プロジェクトを新規作成すると、以下のクラスが自動生成されます。
repercussions
|_AppDelegate.h
|_AppDelegate.m
|_Shader.fsh
|_Shader.vsh
|_GameViewController.h
|_GameViewController.m
|_Main.storyboard
|_Images.xcassets
|_LaunchScreen.xib
|_Supporting Files
| |_Info.plist
| |_main.m
|_repercussionsTests
|_Products
|_repercussions.app
|_repercussionsTests.app
このプロジェクトでは、GameViewControllerクラスが描画処理のメインクラスになっています。このクラスを理解すれば、OpenGLの流れが更に理解できると思います。
では、GameViewControllerクラスの各メソッドにどのような処理を記載しているのか解説します。
・GLKViewController main methods
No. | メソッド | 内容 |
---|---|---|
1 | (void)viewDidLoad | UIViewControllerのライフサイクルにおいて、initの後に呼ばれるメソッドです。 アプリ起動後、Viewが初めて呼び出される際に1回だけ呼ばれます。このタイミングで、シェーダの初期化を行います |
2 | (void)dealloc | メモリ解放時に呼ばれるメソッドです。 ARC(Automatic Reference Counting)にて、コンパイラが適切な場所に、このdeallocメソッドを挿入します。 今回は、OpenGLで利用しているリソースを開放します。 |
3 | (void)didReceiveMemoryWarning | メモリ不足が発生した際に呼ばれるメソッドです。 メモリ不足が発生した場合、OpenGLで利用しているリソースを開放します。 |
4 | (BOOL)prefersStatusBarHidden | ステータスバーを非表示にするメソッドです。 戻り値をtrueにすることで、ステータスバーが非表示になります。 |
5 | (void)setupGL | シェーダを初期化するメソッドです。 |
6 | (void)tearDownGL | シェーダをメモリから開放するメソッドです。 |
・GLKView and GLKViewController delegate methods
No. | メソッド | 内容 |
---|---|---|
7 | (void)update | 処理を更新するメソッドです。 描画しませんが、描画するための計算などを事前に行います。 |
8 | (void)glkView:(GLKView *)view drawInRect:(CGRect)rect | Viewを描画するメソッドです。 シェーダで記載した内容が描画されます。 |
・GLKViewController main methods
No. | メソッド | 内容 |
---|---|---|
9 | (void)viewDidLoad | シェーダをロードするためのメソッドです。 内部では、Shader.vsh、Shader.fshをロードします。 |
10 | (void)dealloc | ロードしたシェーダをコンパイルするためのメソッドです。 |
11 | (void)didReceiveMemoryWarning | プログラマブルシェーダにリンクするためのメソッドです。 |
12 | (BOOL)prefersStatusBarHidden | OpenGLが実行可能かどうかをチェックするためのメソッドです。 |
□ OpenGL ESの初期化
「OpenGL ES」を利用するには、EAGLContextが必要になります。
EAGLContextは、Apple公式サイトのリファレンスに以下のように記載されています。(※1)
An EAGLContext object manages an OpenGL ES rendering context—the state information, commands, and resources needed to draw using OpenGL ES. To execute OpenGL ES commands, you need a current rendering context.
「OpenGL ES Framework Referenceより抜粋」
EAGLContextオブジェクトは、OpenGL ESのレンダリングコンテキスト(OpenGL ESを使用して描画するのに必要なリソースやコマンド、状態情報)を管理します。OpenGL ESコマンドを実行するには、現在のレンダリングコンテキストが必要になります。
つまり、EAGLContextが描画に必要な情報を管理しているクラスであり、描画スレッドに管理されたEAGLContextがなければ、OpenGLコマンドは実行することができないことになります。
このEAGLContextクラスのポイントは、オブジェクトの初期化と描画スレッドの管理です。
EAGLContext初期化
EAGLContextは、No.1のviewDidLoadメソッド内で初期化しています。
1 |
@property (strong, nonatomic) EAGLContext *context; |
1 |
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; |
今回は、「OpenGL ES 2.0」を利用するため、「kEAGLRenderingAPIOpenGLES2」の定数を設定しています。
「OpenGL ES」のバージョンによって、この定数は変わります。
OpenGL ESのバージョン | 定数 |
---|---|
1.x | kEAGLRenderingAPIOpenGLES1 |
2.x | kEAGLRenderingAPIOpenGLES2 |
3.x | kEAGLRenderingAPIOpenGLES3 |
描画スレッドの管理
EAGLContextのリファレンスにも記載されていますが、OpenGLコマンドを実行するには、現在のレンダリングコンテキストが必要になります。
現在のレンダリングコンテキストにEAGLContextを設定するには、EAGLContextの「setCurrentContext」を利用します。
1 |
[EAGLContext setCurrentContext:self.context] |
※OpenGLコマンドを実行する前に現在のレンダリングコンテキストに設定しますが、No.7のupdate、No.8のglkViewメソッドでは、現在のレンダリングコンテキストが設定されている状態で実行されるため、設定する必要はありません。
□ シェーダの初期化、破棄、更新、描画
EAGLContextを初期化した後は、シェーダの初期化と破棄、そして、描画処理の更新と描画を行います。
ここでは、OpenGLがどのように利用されているかがポイントになるため、各メソッド内に記載された処理については詳細な説明を省きます。
ただし、前回説明した#1「基礎知識1」(シェーダの初期化)、#2「基礎知識2」(シェーダの効率的な描画)の内容と同じような内容になっています。そちらと合わせて確認してください。
シェーダの初期化
シェーダの初期化は、No.5のsetupGLメソッド内で実施します。
setupGLメソッドは、以下を処理しています。
・シェーダオブジェクトの作成(ロード)とコンパイル
・プログラマブルシェーダへのリンク
・頂点情報設定
・バッファの作成とアップロード
・バッファのバインド、アンバインド
・頂点情報の利用箇所指定
シェーダの破棄
シェーダの破棄は、No.6のtearDownGLメソッド内で実施します。
tearDownGLメソッドは、以下を処理しています。
・バッファの削除
・プログラマブルのリンク削除
更新
更新は、No.7のupdateメソッド内で実施します。
updateメソッドは、以下を処理しています。
・座標再計算(四角形、カメラ)
描画
描画は、No.8のglkViewメソッド内で実施します。
glkViewメソッドは、以下を処理しています。
・カラー設定
・バッファのバインド
・座標アップロード
・描画
repercussionsプロジェクトの変更方法
repercussionsプロジェクトには、12メソッドが定義されていますが、そのうち4メソッドを変更することで、今回のテーマである波紋のメイン処理を作成することができます。
その4メソッドは、シェーダの初期化、破棄、更新、描画で説明したメソッドになります。
それ以外のメソッドは、ほとんどがそのまま利用できます。
No. | メソッド | 内容 |
---|---|---|
5 | (void)setupGL | シェーダを初期化するメソッドです。 |
6 | (void)tearDownGL | シェーダをメモリから開放するメソッドです。 |
7 | (void)update | 処理を更新するメソッドです。 描画しませんが、描画するための計算などを事前に行います。 |
8 | (void)glkView:(GLKView *)view drawInRect:(CGRect)rect | Viewを描画するメソッドです。 シェーダで記載した内容が描画されます。 |
次回は、いよいよ波紋作成です。
波紋を作成するための基礎である板ポリゴンを作成します。
※1・・・「EAGLContext」については、OpenGL ES Framework Reference の EAGLContext を参照してください。
OpenGL ES2.0で波紋を作る#4 OpenGL ES を組み込むベースを作成