iPhone 3GSの最も優れたイノベーションの1つは、
OpenGL ES 2.0をサポートする、より高速で強力なグラフィックスプラットフォームです。 残念ながら、提供される機会を活用する方法に関する
Appleの情報は非常に少ないです。 ほとんどすべての
APIには 、コードサンプルの優れたドキュメントがありますが、問題は、
OpenGLの場合
、例が常に残されていることです。
さらに、
OpenGL ES 2.0の初心者には、基本的な例も
Xcodeテンプレートも提供され
ていません。 高度なグラフィックス機能を活用するには、それらを自分で習得する必要があります。
OpenGL ES 2.0は、
OpenGL ES 1.1のわずかに変更されたバージョンであり、いくつかの新機能を備えていると誤解しないでください。 それらの違いは基本です! 固定機能を備えたパイプラインはなくなりました。画面に通常の三角形を表示するには、シェーダーを含むコンピューターグラフィックスの基本をより深く理解する必要があります。
ドキュメントが完全に欠けているため、
OpenGL ES 2.0を使用して
iPhoneで最も簡単なアプリケーションを作成することにしました。 ユーザーにとっては、アプリケーションを作成する際の出発点になる可能性があります。 オプションとして、回転ケトルやその他のデザインを検討しましたが、最終的にはモデルのロードについて詳しく説明するのではなく、
Xcodeテンプレートの一部である
OpenGL ES 1.1アプリケーションを更新するだけにしました。 完全な最終コード
はこちらからダウンロードできます 。
興味をそそるものはありません-ただ回転する広場です。 ただし、これは
OpenGLの起動、シェーダーの作成、およびそれらをプログラムに接続して後で使用するための基本を理解するには十分です。 さらに、最終的に
OpenGL ES 1.1では不可能な機能を検討します。 準備はいい?
初期化
OpenGLの初期化
は、実際には
OpenGL ES 1.1と変わりません。 唯一の違いは、
ES 2.0の APIの新しいバージョンを報告する必要があることです。
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
EAGLViewやいわゆる
バックバッファーの作成など、他のすべては以前と同じままです。これらの点については説明しません。
OpenGL ES 2.0を初期化すると、
OpenGL ES 1.1関連の関数を呼び出すことができなくなることに注意してください。 これらを使用しようとすると、これらの機能に適切な設定がないため、プログラムがクラッシュします。 したがって、以前のモデルとの互換性を確保しながら
3GSグラフィックを活用したい場合は、
OpenGL ES 1.1または
2.0をアクティブにしてデバイスタイプを確認する必要があります。各バージョンには独自のコードがあります。
シェーダー作成
OpenGL ES 1.1は、固定機能を備えたパイプラインを使用してポリゴンをレンダリングします。
OpenGL ES 2.0の画面でオブジェクトを視覚化するには、シェーダー(特定のグラフィックスプラットフォーム用に作成されたミニプログラム)を登録する必要があります。 彼らの仕事は、入力データ(頂点と状態)を画面上の画像に変換することです。 シェーダーは
OpenGLシェーダー言語 (
GLSLと略記)で記述されてい
ます 。これは、Cの操作に慣れている人にとってはささいな問題を引き起こすことはありません。もちろん、すべての機能を使用するには、いくつかの詳細を調べる必要があります。 以下に、基本的な概念とそれらの関係のみを示します。
シェーダーには2つのタイプがあります。頂点シェーダーは各頂点に対して実行され、フラグメントシェーダーは各ピクセルに対して実行されます。 技術的には、後者はフラグメントごとに実行されます。フラグメントは、たとえばスムージングの場合、ピクセルに対応しない場合があります。 これまでのところ、レンダリングされたピクセルごとにフラグメントシェーダーが実行されると安全に想定できます。
頂点シェーダーは、切り捨てられたスペース(
Clip Space )内の頂点の位置を計算します。 オプションで、フラグメントシェーダーが後で使用するために他の値を計算できます。
- 頂点シェーダーは、統合と属性の2種類のデータを受け入れます。 統一された入力は、メインプログラムから一度設定され、描画が要求されたときに頂点シェーダーによって処理されるすべての頂点に適用される値です。 したがって、例えば、 世界観の変容は統一された入門書です。
- 単一の描画要求の入力属性は、頂点ごとに異なる場合があります。 位置、通常、色の情報はすべて入門的な属性です。
出力では、頂点シェーダーは2種類のデータを提供します。
- 変数「 gl_Position 」の暗黙の位置、つまり 切り捨てられた空間内の頂点の位置(後でビューポート空間のビューポートに変換されます)。
- さまざまな結果。 可変属性によって定義された変数は頂点間で補間され、結果の値はフラグメントシェーダーへの入力として転送されます。
典型的なプログラムでは、頂点シェーダーは単に頂点の位置を
モデル空間から切り捨てられた空間に変換し、フラグメントシェーダーによる補間のために頂点の色を渡します。
uniform mat4 u_mvpMatrix;
attribute vec4 a_position;
attribute vec4 a_color;
varying vec4 v_color;
void main()
{
gl_Position = u_mvpMatrix * a_position;
v_color = a_color;
}
フラグメントシェーダーは、フラグメントの色(ピクセル)を計算します。 それらの入力パラメーターは、変数「
gl_Position 」に加えて、頂点シェーダーによって生成された可変変数です。 色の計算は、「
gl_Position 」に定数を追加することで制限できます。または、
UV座標によるテクスチャピクセルの検索や、照明条件を考慮した複雑な操作にすることもできます。
フラグメントシェーダーは基本的です。頂点シェーダーから色を取得し、このフラグメントに適用します。
varying vec4 v_color;
void main()
{
gl_FragColor = v_color;
}
これらはすべて曖昧に聞こえるかもしれませんが、これはシェーダーの美しさです。プリセットはなく、レンダリングはユーザーの要望(およびハードウェア機能)のみに依存します。
シェーダー編集
既製のシェーダーがいくつかあります。 それらを機能させる方法は? それにはいくつかのステップが必要で、最初のステップはコンパイルとリンクです。
このプロセスでは、各頂点のソースコードとフラグメントシェーダーをダウンロードし、
OpenGLを数回呼び出してコンパイルする必要があります。
const unsigned int shader = glCreateShader(type);
glShaderSource(shader, 1, (const GLchar**)&source, NULL);
glCompileShader(shader);
シェーダーのコンパイルが完了したらすぐに、シェーダープログラムを作成し、シェーダー自体を追加して、リンクする必要があります。
m_shaderProgram = glCreateProgram();
glAttachShader(m_shaderProgram, vertexShader);
glAttachShader(m_shaderProgram, fragmentShader);
glLinkProgram(m_shaderProgram);
リンクには、フラグメントシェーダーの意図した結果の出力で頂点シェーダーデータをオーバーライドすることが含まれます。
エラーの原因に関するメッセージを表示するリンクをコンパイルおよび確立するときに、エラーを診断することができます。
int success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (success == 0)
glGetShaderInfoLog(shader, sizeof(errorMsg), NULL, errorMsg);
その過程でプログラムをコンパイルしてリンクするというアイデアが気に入らない場合は、多くの人がこの意見を共有していることを急いで指摘します。
Objective-Cでメインプログラムのソースコードをコンパイルするのと同様に、このステップはオフラインで実行することが理想的です。 残念なことに、
Appleにとっての優先事項はオープンであり、将来フォーマットを変更できることです。そのため、「仕事中」のコミュニケーションを確立することを余儀なくされています。 これは煩わしいだけでなく、理論的には、いくつかのシェーダーが存在する場合、かなり低速であることを意味します。 アプリケーションを起動するときに余分な秒を失いたくはありませんが、これまでのところ、
iPhoneでシェーダーを操作する能力と引き換えにそれを当然のことと考えなければなりません。
スナップ
シェーダーを使用する準備はほぼ整いましたが、まず入力データを正しく構成する方法を規定する必要があります。 頂点シェーダーは、構成された
mvpマトリックス(
model-view-projection )、および位置と色を持つ頂点データストリームに依存します。
これを行うために、シェーダープログラムに必要なパラメーターを名前で要求します。 モデルが視覚化される直前に値が設定されるハンドルを返します。
m_a_positionHandle = glGetAttribLocation(m_shaderProgram, "a_position");
m_a_colorHandle = glGetAttribLocation(m_shaderProgram, "a_color");
m_u_mvpHandle = glGetUniformLocation(m_shaderProgram, "u_mvpMatrix");
シェーダーを操作する
そして最後に、シェーダーの助けを借りて、いくつかのポリゴンをレンダリングできます。 必要なのは、シェーダープログラムを実行することだけです...
glUseProgram(m_shaderProgram);
...そして、以前にパラメーターの入力を要求された記述子を使用して、正しい入力を構成します。
glVertexAttribPointer(m_a_positionHandle, 2, GL_FLOAT, GL_FALSE, 0, squareVertices);
glEnableVertexAttribArray(m_a_positionHandle);
glVertexAttribPointer(m_a_colorHandle, 4, GL_FLOAT, GL_FALSE, 0, squareColors);
glEnableVertexAttribArray(m_a_colorHandle);
glUniformMatrix4fv(m_u_mvpHandle, 1, GL_FALSE, (GLfloat*)&mvp.m[0] );
OpenGL ES 1.1で知られているレンダリング関数( "
glDrawArrays "または "
glDrawElements ")のいずれかを呼び出すだけです:
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
すべてがうまくいけば、正しく視覚化されたモデルが画面に表示されます。 私たちの場合、必要な変換、シェーダー、エフェクトを備えた独自のモデルをレンダリングするための基礎となるのは、単なる正方形です。
そして最後に少しボーナス
OpenGL ES 1.1テンプレートと同じ回転正方形を取得するためだけに、これらすべてを行うのはあまり魅力的ではないことを理解しています。 もちろん、これは必要かつ重要な最初のステップですが、それでも...
GLSLでさまざまな効果を作成することがいかに簡単かを示すために、修正されたピクセルシェーダーを紹介します。
float odd = floor(mod(gl_FragCoord.y, 2.0));
gl_FragColor = vec4(v_color.x, v_color.y, v_color.z, odd);
このバージョンのフラグメントシェーダーは、ピクセルが偶数行か奇数行かをチェックし、偶数行を完全に透明としてレンダリングし、画面にストライプの効果を作成します。
OpenGL ES 1.1で同様の結果を達成することは非常に問題がありましたが、バージョン2.0では単純な数行です。
サンプルコードとシェーダーの機能に関するアイデアで武装し、独自のシェーダーを作成して、ゲームに興味深いユニークな視覚効果を追加できるようになりました。
レッスンのソースコードは
こちらからダウンロードでき
ます 。
英語のオリジナル記事のテキストは
こちらです。