はじめに
この記事は、WebGLテクノロジーを使用した最新のブラウザーで3Dを表示するために必要な基本的な手順を示すために作成されました。 目標を達成するために、3次元空間に複数の線を構築するタスクを検討します。
仕事のスキーム:
- キャンバスからWebGLコンテキストを取得します。
- シェーダープログラムをダウンロードします。 すなわち:
- シェーダープログラムを作成します。
- 頂点シェーダーとフラグメントシェーダーのソースコードを個別に取得します。
- シェーダーコードのコンパイル。
- プログラムに添付します。
- プログラムをアクティブにします。
- モデルビューと投影の2つのマトリックスをインストールします。
- 頂点データバッファを配置、入力、アクティブ化します。
- 描きます。
1. WebGLコンテキスト
getContext(“ experimental-webgl”)メソッドを呼び出すことにより、キャンバスDOM要素からWebGLコンテキストを取得できます。 Khronos Groupは(https://www.khronos.org/webgl/wiki/FAQ)に次のメソッドを使用してWebGLコンテキストを取得することを推奨していることに注意してください。
var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"]; gl = null; for (var ii = 0; ii < names.length; ++ii) { try { gl = canvas.getContext(names[ii]); } catch(e) {} if (gl) { break; } }
コンテキストが正常に取得されると、glオブジェクトにはOpenGL ESの機能に非常に類似した名前のメソッドがあります。 たとえば、WebGLのクリア関数(COLOR_BUFFER_BIT)はgl.clear(gl.COLOR_BUFFER_BIT)であり、非常に便利です。 ただし、すべてのWebGL関数がOpenGL ES 2.0関数と同じ構文を持っているわけではないことに注意してください。
2.シェーダー
シェーダープログラムは、WebGLを使用してイメージを構築するために不可欠な部分です。 これにより、ラインの各頂点の位置と色が設定されます。 このタスクでは、頂点とフラグメントの2つのシェーダーが使用されます。 3次元空間でラインを作成する場合、頂点シェーダーは、ビューマトリックスと透視投影マトリックスの値に基づいて、空間内の頂点の位置を担当します。 フラグメントシェーダーは、ラインの色を計算するために使用されます。
頂点シェーダー
attribute vec3 aVertexPosition; attribute vec4 aVertexColor; uniform mat4 mvMatrix; uniform mat4 prMatrix; varying vec4 color; void main(void) { gl_Position = prMatrix * mvMatrix * vec4 ( aVertexPosition, 1.0 ); color = aVertexColor; }
フラグメントシェーダー
#ifdef GL_ES precision highp float; #endif varying vec4 color; void main(void) { gl_FragColor = color; }
「均一」の後に定義されるものは、すべての頂点に共通です。 ここで、それらは変換行列です:種と視点。 各頂点の計算で属性が使用された後に定義されるもの。 これがピークの位置とその色です。 「変化」後、頂点からフラグメントシェーダーに転送される変数を定義します。 位置計算の結果を変数gl_Positionに割り当て、色をgl_FragColorに割り当てます。
3.モデルビュー行列と透視投影行列
両方の行列はサイズが4x4で、2次元平面上の3次元オブジェクトの表示を計算するために使用されます。 それらの違いは、種行列が、たとえば、オブザーバーの位置を変更するときのオブジェクトの観察方法を決定し、投影マトリックスが最初に投影方法を決定することです。
このプログラムでは、初期化段階でgluPerspective関数が呼び出されると、射影行列の値が設定されます。将来、この行列はその値を変更しません。 gluPerspective関数は標準ではないので、自分で定義しました。 彼女の議論は、fovy、aspect、zNear、zFarです。 fovy-度単位の垂直視野角の領域。 aspect-ビューポートの幅と高さの比率; zNear-近くのクリッピングプレーンまでの距離(近いものはすべて描画されません); zFar-ファークリッピングプレーンまでの距離(それ以上は描画されません)。
モデル固有のマトリックスの値を設定するには、いくつかのアプローチを使用できます。 たとえば、gluLookAt関数(camX、camY、camZ、tarX、tarY、tarZ、upX、upY、upZ)を作成して使用します-OpenGLの関数の類似物で、座標としてカメラの位置、カメラのターゲット座標、カメラのアップベクトルを取得します。 別の方法は、関数glTranslate、glRotate、glScaleを作成して使用することです。これらの関数は、オブザーバー(カメラ)に対するシフト、回転、スケーリングを生成します。 gluLookAtを使用してカメラの位置を最初に決定し、その後の変換にglTranslate、glRotate、glScaleを使用できます。 何らかの方法で、これらの関数は同じモデル固有のマトリックスの値のみを変更します。 マトリックスの計算を簡単にするために、sylvester.jsライブラリーを使用できます。
両方のマトリックスの値を変更する方法を見つけたので、シェーダープログラムへの転送を検討してください。 モデルビューマトリックスの頂点シェーダーでは、変数「mvMatrix」を使用します。 この変数に行列値を渡すには、まずプログラムでそのインデックスを取得する必要があります。 これを行うには、関数loc = gl.getUniformLocation(shaderProgram、name)を使用します。これは標準です。 ご想像のとおり、最初の引数は2番目の段階で取得されたシェーダープログラムを指す変数で、name引数は値を渡す変数の名前です。この場合、name = "mvMatrix"です。 インデックスができたので、関数gl.uniformMatrix4fv(loc、false、new Float32Array(mat.flatten()))を使用して、行列matの値を渡します。 同様に、インデックスを取得し、射影行列の値を設定します。 シェーダープログラムの種マトリックスは、値が有効になるように変更するたびに更新する必要があることに注意してください。
4.データバッファ
WebGLでバッファを使用する必要があります。 各ポイントの位置とその色は、2つのバッファーに保存されます。 線を描画するポイントの座標を格納するバッファーのすべての作業を行うコードを考えてみましょう。
/* */ vPosBuffer = gl.createBuffer(); /* */ gl.bindBuffer(gl.ARRAY_BUFFER, vPosBuffer); /* */ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verticies), gl.DYNAMIC_DRAW); /* , 3 floats */ gl.vertexAttribPointer(vPosLoc, 3, gl.FLOAT, false, 0, 0); /* */ gl.enableVertexAttribArray(vPosLoc);
ここで、頂点はラインポイントの座標の配列です。 座標は6個で、最初の3個はそれぞれ行の先頭、末尾の次のx、y、z座標です。 vPosLocは、シェーダープログラムの「aVertexPosition」属性のインデックスです。 なぜなら このプログラムでは、シェーダープログラムのアセンブルの段階でgl.bindAttribLocation(shaderProgram、loc、shadersAttrib)を使用してインデックスが明示的に設定されていたので、再度取得する必要はありません。 そうでない場合は、コマンド「vPosLoc = getAttribLocation(shaderProgram、 "aVertexPosition")」を使用してインデックスを取得する必要があります。 2番目のバッファーでも同様のアクションが実行され、データは異なります(頂点の代わりに色の配列)およびシェーダープログラムのインデックス(vPosLocの代わり)。
5.描く
カラーバッファをクリアするか、より簡単に背景を設定するには、標準コマンドを使用します。
gl.clearColor(0, 0, 0, 1); gl.clear(gl.COLOR_BUFFER_BIT);
描いてみましょう
gl.drawArrays(gl.LINES, drawArrayIndexStart, drawArrayLength);
この関数の最初の引数は線を描画することを示し、2番目は描画を開始するバッファ内のインデックス、drawArrayLengthは描画する要素の数です。 なぜなら 頂点の座標を頂点配列からバッファに転送してから、
drawArrayLength = verticies.length / 3;
行が変更されている場合は、手順4、5に従って再描画します。 カメラの位置を変更した場合は、ステップ3とステップ5を実行します。
おわりに
直線を構築するタスクは、天井から取られていませんでした。 微分方程式系を解き、OpenGLを使用して結果を3Dで構築するプログラムがあります。 プログラムをphpに移植し、WebGLを使用して結果を表示することが決定されました。 3次元空間で直線をマッピングする問題を解決するために、リスト(http://ru.wikipedia.org/wiki/WebGL)の最新のエンジン(WebGLU、GLGE、C3DL、Copperlicht、SpiderGL、SceneJS)が研究されました。 このために、メインプログラムとサードパーティエンジンとの通信をユニバーサル化できるインターフェイスが作成されました。 結果はWebGLU、C3DLで達成されました。 その他では、ラインを構築する簡単な方法がないか、最適ではありません。 そのうちの1つでは、ライン関数が文書化されていますが、プロジェクトフォーラムでは、それを使用できないことが明らかになり、ポリゴンで描画することを提案しました。
残念ながら、C3DLを使用する場合、プロセスを最適化することができなかったため、fps値が低くなりました。 WebGLUで作業しているときに、fps値にも影響するエラーが発生しました。 これにより、現在使用中の独自のエンジンを作成しました。 サードパーティ製のエンジンを非難したいわけではありません。サードパーティ製のエンジンは、単純な線画よりも幅広いタスク向けに設計されています。
ブラウザーについて一言。 Firefox 4ベータ8、Chrome 8で-enable-webglを使用してテスト済み。 このタスクで、Firefoxはfps値をChromeの1.5〜2倍以上に示しました。 Chromeをベータ9にアップグレードしても、インジケーターは変更されていません。 Firefoxベータ8がベータ9にアップグレードされたとき、fps値は変更されませんでした。例外は、コンソールに不明瞭なエラーが多くなり、WebGLUを使用するシーンが正しく表示されなくなったことです。
作業バージョンへのリンク
- rnix.dyndns.org/3dpr-独自のエンジンで行を表示します。
- rnix.dyndns.org/3dpr/c3dl.html-cd3lライブラリーの使用
- rnix.dyndns.org/3dpr/webglu.html-webgluライブラリーの使用
参照資料
- cvs.khronos.org/svn/repos/registry/trunk/public/webgl/doc/spec/WebGL-spec.html-WebGL仕様、コマンド構文、OpenGL ESとの違い、
- steps3d.narod.ru/tutorials/webgl-tutorial.html-テクスチャや照明など、詳細に説明されているいくつかの例。
- www.khronos.org/webgl/wiki/Demo_Repository-Google、Apple、Mozillaのいくつかの例。 3人の著者それぞれが、プログラム全体の個々の部分に対して独自のアプローチを持っていることを確認できます。