WebGL による 3D 開発: 第 1 回 WebGL の紹介

3D ハードウェアの能力をブラウザー・アプリケーションで解き放つ

JavaScript 開発者は WebGL API を使用することで、最近の PC やモバイル端末のハードウェアに組み込まれている強力な 3D グラフィックス・アクセラレーション機能を直接利用することができます。WebGL は最近のブラウザーではほとんどサポートされており、これを使用することで、一般 Web ユーザー向けにハイパフォーマンスの 3D ゲーム、アプリケーション、そして 3D で拡張した UI を作成することができます。この記事は、WebGL に初めて取り組む JavaScript 開発者を対象とした全 3 回からなる連載の第 1 回です。今回は、WebGL の基礎および関連する 3D グラフィックスの概念を具体的に示す、基本的なサンプル・アプリケーションに取り組みます。

Sing Li, Consultant, Makawave

Sing LiSing Li は、developerWorks サイトの開設以来、Web や Java に関するさまざまなトピックを取り上げて記事とチュートリアルを書いている developerWorks の著者です。組み込みシステムからスケーラブルなエンタープライズ・システムに至るまで、20 年を超えるシステム・エンジニアリングの経験があり、現在は再び Web 規模のモバイル対応サービスと「モノのインターネット」エコシステムに取り組んでいます。



2014年 2月 27日

3D ハードウェアの進化: 歴史概略

パーソナル・コンピューティングの初期の時代 (1980年代初頭) には、3D アクセラレーション用グラフィックス・ハードウェアを利用できたのは、Silicon Graphics Computer Systems (後に SGI に改名) などの企業で製造された、専門分野に特化した高価なワークステーションだけでした。このようなマシンが対象としていたのは、主に学術界、政府、軍需産業に携わる科学者と研究者、そして娯楽産業の先駆者たちです。初期の頃の PC で使用されていたグラフィックス・ハードウェアには、かなり解像度の低い 2D 機能しか備わっていなかったため、3D の計算処理や描画処理は、アプリケーション・ソフトウェアを使用してオフラインで (そして長い時間をかけて) 実行せざるを得ませんでした。

1990年代の後半になると、PC マニアの人たちはATI Technologies Inc. (現在の AMD) や Nvidia Corp. などの企業で製造された 3D アクセラレーション用グラフィックス・アダプターを手に届く価格で (まだ比較的高価でしたが) 購入できるようになりました。これらのアダプターは、ワークステーション品質のグラフィックスを PC で実現するという技術的なブレークスルーを成し遂げたものの、ディスプレイ解像度やレンダリング/処理能力が低かったため、初期の 3D グラフィックス・アダプターの GPU には限界がありました。

1990年代から 2000年代初頭にかけて、PC 向けの 3D アクセラレーション用アダプターの機能とパフォーマンスは向上し続け、価格も下がっていきました。GPU メーカーのチップは、PC に適用されただけではありません。任天堂やソニーなどのベンダーが提供するゲーム専用のシステムやセットトップ・ボックスにも適用されました。

過去 10 年間を見ると、その半ばまでには、インテル、AMD などといった主流の CPU メーカーが競って 3D レンダリング・ハードウェアをメイン CPU に内蔵したり、同じチップ上で CPU に GPU をバンドルしたりするようになりました。こうした流れによって、3D グラフィックスはあらゆるユーザーにとって大幅に身近なものになりました。PC の歴史上初めて、以前はワークステーション・クラスだった 3D グラフィックスを、サポート・ソフトウェア・ドライバーをダウンロードするだけのコストで PC に導入できるようになりました。

私たちは三次元 (3D) の世界に生きています。それにも関わらず、コンピューターやコンピューター化された機器の操作のほぼすべては、二次元 (2D) ユーザー・インターフェースで行われています。高速で滑らかに動くリアルな 3D アプリケーションは、かつてはコンピューター・アニメーター、科学関連のユーザー、そしてゲーム・マニアが独占していた領域でしたが、比較的最近になってようやく一般の PC ユーザーにも手が届くようになりました (囲み記事「3D ハードウェアの進化: 歴史概略」を参照してください)。

現在、3D グラフィックス・アクセラレーションは主流となっている PC 向け CPU のすべてに組み込まれています。さらにゲーム用 PC には 3D レンダリングを処理する専用のハイパフォーマンス GPU (グラフィックス・プロセッシング・ユニット) が追加されるようになっています。こうした傾向は、携帯電話やタブレットに搭載された RISC (縮小命令セット) ベースの CPU にも反映されており、現在のモバイル CPU には例外なく、強力な 3D 対応グラフィックス・アクセラレーション GPU が内蔵されています。また、サポート・ソフトウェア・ドライバーも成熟を遂げ、今では安定性と効率性を兼ね備えています。

ここ最近のブラウザー・テクノロジーの進化がブラウザーにもたらしたのは、ハードウェア・アクセラレーションを利用する WebGL です。WebGL は 3D JavaScript API であり、機能豊富な HTML5 と共に実行されます。従って、今や、JavaScript 開発者がインタラクティブな 3D ゲーム、アプリケーション、そして 3D で拡張された UI を作成することも可能です。主流のブラウザーに統合された WebGL により、ブラウザーとテキスト・エディターだけを武器とする大勢の開発者たちに、3D アプリケーション開発の門戸がついに開かれました。

この記事では、全 3 回からなる連載の第 1 回として、WebGL を紹介します。始めに 3D ソフトウェア・スタックの進化について簡単に概説した後、WebGL プログラミングの重要な側面をおさえた実践的なサンプル・アプリケーションで WebGL API を体験します (サンプル・コードについては「ダウンロード」を参照してください)。さらに、この完全ながらも理解しやすいサンプル・アプリケーションを開発しながら、3D グラフィックスに関する最も重要ないくつかの概念を説明します (HTML5 の canvas 要素について十分理解していることを前提とします)。今後の連載では、第 2 回で上位レベルの WebGL ライブラリーを紹介し、第 3 回では魅力的な 3D UI および 3D アプリの作成を始められるように、さまざまな要素を 1 つにまとめます。

3D アプリケーションのソフトウェア・スタック

初期の PC では、3D ハードウェア・ドライバーはアプリケーションと一緒にバンドルされるか、アプリケーションにコンパイルされることがほとんどでした。このような構成の場合、ハードウェアに備わるハードウェア・アクセラレーション機能へのアクセスが最適化されるため、最大限のパフォーマンスを得ることができます。基本的に、ハードウェアの機能に対して直接コーディングを行うことになるので、優れた設計のゲームや CAD (コンピューター支援設計) アプリケーションであれば、ハードウェアの能力を最大限に引き出すことができます。図 1 に、このソフトウェア構成を示します。

図 1. 組み込み 3D ハードウェア・ドライバーを使用したアプリケーション
組み込み 3D ハードウェア・ドライバーを使用したアプリケーション構成の図

一方で、バンドルするには相当コストがかかります。アプリケーションがリリースされてインストールされると、その時点でハードウェア・ドライバーには (バグを含むすべてに) 手を加えることができなくなります。グラフィックス・カードのベンダーがバグを修正したり、パフォーマンスを強化したドライバーを導入したりした場合でも、アプリケーションのユーザーがそれを利用するには、改めてアプリケーションのインストールや更新を行わなければなりません。

その上、グラフィックス・ハードウェアは急速に進化しているため、3D ドライバーがコンパイルされたアプリケーションやゲームは瞬く間に時代に遅れてしまいます。新しいハードウェアが (新規ドライバーや更新されたドライバーと共に) 登場すると同時に、ソフトウェア・ベンダーは新しいリリースを作成して配布しなければなりません。高速ブロードバンド・ネットワークが広く普及するようになる前は、これが、ソフトウェア配布に関する大きな問題でした。

ドライバー更新の問題に対する解決策として、オペレーティング・システムが 3D グラフィックス・ドライバーをホストする役割を担うようになりました。アプリケーションまたはゲームは、OS が提供する API を呼び出し、OS がその呼び出しをネイティブ 3D ハードウェア・ドライバーが受け入れるプリミティブに変換するという仕組みです。図 2 に、この仕組みを示します。

図 2. オペレーティング・システムの 3D API を使用したアプリケーション
オペレーティング・システムの 3D API を使用したアプリケーション構成の図

この仕組みでは、(少なくとも理論上は) アプリケーションを OS の 3D API に対してプログラミングすることができます。そうすれば、アプリケーションは 3D ハードウェア・ドライバーに対する変更に影響されることも、3D ハードウェア自体の進化に影響されることもありません。主流となっているすべてのブラウザーを含め、多くのアプリケーションでは長い間、この構成が功を奏してきました。OS が、あらゆるタイプやスタイルのアプリケーションにも、競合するベンダーたちが提供するグラフィックス・ハードウェアにも果敢に応じる、仲介者の役割を果たしていたのです。けれどもこの OS ですべてを賄うというアプローチは、3D レンダリング・パフォーマンスには大きな打撃をもたらします。最高のハードウェア・アクセラレーション・パフォーマンスを必要とするアプリケーションでは、実際にインストールされているグラフィックス・ハードウェアをディスカバーし、ハードウェアの組み合わせごとにコードを最適化するための調整を実装する必要があることに変わりはありません。さらに、OS の API にベンダー固有の拡張機能をプログラミングしなければならない場合もよくあります。このことから、アプリケーションはやはり、下位にあるドライバーや物理ハードウェアに拘束されてしまいます。

WebGL の時代

時代を現代に移すと、最近ではデスクトップ端末やモバイル端末のすべてに、ハイパフォーマンス 3D ハードウェアが組み込まれています。ブラウザーの機能を利用するために、ますます多くのアプリケーションが JavaScript で開発されるようになり、Web デザイナーと Web アプリケーション開発者は、より高速でより優れた 2D/3D をブラウザーがサポートすることを要求するようになりました。その結果、主流のブラウザー・ベンダーで WebGL が広くサポートされるようになりました。

WebGL がベースとしている OpenGL ES (Embedded System) は、3D ハードウェアにアクセスするための下位レベルの手続き型 API です。1990年代初頭に SGI によって開発された OpenGL は、今では十分に理解された完成度の高い API と見なされています。WebGL は歴史上初めて、JavaScript を使用してネイティブ・スピードに近い速度で機器上の 3D ハードウェアにアクセスすることを可能にしました。WebGL と OpenGL ES はどちらも、非営利団体である Khronos Group の下で進化を続けています。

WebGL API は、下位にある OpenGL ハードウェア・ドライバーにほぼ直接アクセスします。ドライバーにアクセスする上で、ブラウザー・サポート・ライブラリーを使用してコードを変換し、さらにそのコードを OS の 3D API ライブラリーを使用して変換する、といった処理をする必要はありません。図 3 に、この新しいモデルを示します。

図 3. WebGL を使用して 3D ハードウェアにアクセスする JavaScript アプリケーション
WebGL を使用して 3D ハードウェアにアクセスするように構成された JavaScript アプリケーションの図

ハードウェア・アクセラレーションを利用する WebGL は、ブラウザー上の 3D ゲーム、リアルタイムの 3D データ視覚化アプリケーション、斬新なインタラクティブ 3D UI をはじめ、さまざまな可能性を実現できます。OpenGL ES は、既存の WebGL ベースのアプリケーションに影響を与えることなく新しいベンダーのドライバーをインストールできるように標準化されているため、「あらゆるプラットフォームであらゆる 3D ハードウェアを使用できるようにする」という夢のような約束を果たします。


WebGL のハンズオン

ここからは、WebGL を実際に体験します。最新バージョンの Firefox、Chrome、または Safari を起動して、サンプル・コード (「ダウンロード」を参照) に含まれている triangles.html を開いてください。すると、図 4 に示すスクリーン・キャプチャーのようなページが表示されるはずです。このスクリーン・キャプチャーは、OS X 上で実行中の Safari を撮ったものです。

図 4. triangles.html ページ
青色の 2 つの三角形が表示された、triangles.html ページのスクリーン・キャプチャー

WebGL の 3D を構成する軸

WebGL の 3D には、以下の軸があります。

  • 左へ行くとマイナスになり、右へ行くとプラスになる x 軸
  • 下へ行くとマイナスになり、上へ行くとプラスになる y 軸
  • ページの奥へ行くとマイナスになり、手前に来るとプラスになる z 軸

以下の図で WebGL 3D の軸を見るときには、自分が z 軸ポインターの矢印の先に立っていて、z 軸から xy 平面を見下ろしていると想像してください。

WebGL の 3D を構成する軸の図

このページには、一見したところまったく同じ青色の 2 つの三角形が表示されていますが、これらの三角形は等しく作成されているわけではありません。どちらも HTML5 の Canvas を使って描画されていますが、左側の三角形は 2D であり、10 行に満たない JavaScript コードで描画されています。一方、右側の三角形は、4 つの面を持つピラミッド状の 3D オブジェクトであり、これをレンダリングするには 100 行を超える JavaScript WebGL コードを必要としています。

このページのソース・コードを調べると、右側の三角形は大量の WebGL コードによって描画されていることがわかります。それにも関わらず、この三角形は 3D であるようには見えません (赤と青の 3D 眼鏡をかけても、無駄なことです)。

WebGL が描画するのは 2D ビューです

triangles.html の右側の図形が三角形に見える理由は、ピラミッドの向きにあります。このページでは、面ごとに色が塗り分けられたピラミッドの青色の面だけを見ています。これは、ビルの一面を真正面から見ると、2D の四角形しか見えないことと似ています (図 5 をチラッと見て、3D のピラミッドを確認してください)。このことを理解すると、ブラウザーで 3D グラフィックスを扱う場合の核心がより一層明らかになります。つまり、最終的な出力は常に 3D シーンの 2D ビューとなることから、WebGL による 3D シーンの静的レンダリングも必ず 2D のイメージになります。

今度は、ブラウザーに pyramid.html を読み込んでください。このページにピラミッドを描画するコードは、triangles.html のコードとほとんど同じですが、1 つ違う点は、pyramid.html では y 軸の周りにピラミッドを継続的に回転させるためのコードが追加されていることです。つまり、同じ 1 つの 3D シーンを構成する複数の 2D ビューが (WebGL を使用して) 時間をずらして連続して描画されるというわけです。ピラミッドが回転すると、triangles.html で右側に表示されていた青色の三角形は、実は面ごとに色が塗り分けられた 3D ピラミッドの一面であることが明らかにわかります。図 5 に、OS X 上の Safari で表示した pyramid.html のスナップショットを示します。

図 5. pyramid.html ページ上で回転して表示された 3D ピラミッド
pyramid.html ページ上で回転して表示された 3D ピラミッドのスクリーン・キャプチャー

WebGL コードを作成する

リスト 1 に、triangles.html に含まれる 2 つの canvas 要素の HTML コードを記載します。

リスト 1. 2 つの canvas 要素が含まれた HTML コード
<html>
<head>
...
</head>
  <body onload="draw2D();draw3D();">
    <canvas id="shapecanvas" class="front" width="500" height="500">
    </canvas>
    <canvas id="shapecanvas2" style="border: none;" width="500" height="500">
    </canvas>
  <br/>
  </body>
</html>

onload ハンドラーは、2 つの関数 draw2D()draw3D() を呼び出します。draw2D() 関数は、左側の Canvas (shapecanvas) で 2D を描画します。draw3D() 関数は、右側の Canvas (shapecanvas2) で 3D を描画します。

リスト 2 に、左側の Canvas で 2D 三角形を描画するコードを記載します。

リスト 2. HTML5 の Canvas で 2D 三角形を描画する
function draw2D()  {

    var canvas = document.getElementById("shapecanvas");
    var c2dCtx = null;
    var exmsg = "Cannot get 2D context from canvas";
    try {
      c2dCtx = canvas.getContext('2d');
    }
    catch (e)
    {
      exmsg = "Exception thrown: " + e.toString();
    }
    if (!c2dCtx) {
      alert(exmsg);
      throw new Error(exmsg);
    }
    c2dCtx.fillStyle = "#0000ff";
    c2dCtx.beginPath();
    c2dCtx.moveTo(250, 40);        // Top Corner
    c2dCtx.lineTo(450, 250);         // Bottom Right
    c2dCtx.lineTo(50, 250);         // Bottom Left
    c2dCtx.closePath();
    c2dCtx.fill();
  
}

リスト 2 の単純な 2D の描画コードでは、描画コンテキスト c2dCtx が Canvas から取得されます。すると、このコンテキストの描画メソッドが呼び出されて、三角形をたどる一連のパスが作成されます。最後に、閉じられたパスで囲まれた領域が RGB 色 #0000ff (青) で塗りつぶされます。

WebGL の 3D 描画コンテキストを取得する

リスト 3 に示す、canvas 要素から 3D 描画コンテキストを取得するコードは、2D の場合とほとんど変わりません。違っているのは、要求するコンテキスト名が 2d ではなく experimental-webgl となっていることです。

リスト 3. canvas 要素から WebGL の 3D コンテキストを取得する
function draw3D()  {
      var canvas = document.getElementById("shapecanvas2");

      var glCtx = null;
      var exmsg = "WebGL not supported";
      try
      {
          glCtx = canvas.getContext("experimental-webgl");
      }
      catch (e)
      {
          exmsg = "Exception thrown: " + e.toString();
      }
      if (!glCtx)
      {
          alert(exmsg);
          throw new Error(exmsg);
      }
 ...

リスト 3 の draw3D() 関数は、ブラウザーで WebGL がサポートされていない場合には、アラートを表示してエラーを発生させます。本番アプリケーションでこの状況に対処するには、そのアプリケーションに応じた固有のコードを使用することをお勧めします。

ビューポートを設定する

WebGL に出力のレンダリング先を指示するには、Canvas 内で WebGL が描画できる領域をピクセル単位で指定して、ビューポートを設定する必要があります。triangles.html では、Canvas 領域全体を使用して出力をレンダリングします。

// set viewport
 glCtx.viewport(0, 0, canvas.width, canvas.height);

次のステップでは、WebGL レンダリング・パイプラインにフィードするデータの作成に取り掛かります。このデータによって、シーンを構成する 3D オブジェクトを記述する必要があります。この例の場合、異なる色で塗り分けられた 4 つの面を持つ 1 つのピラミッドのみで、シーンが構成されます。


3D オブジェクトを記述する

3D レンダリングでのメッシュ

十分な数の三角形を組み合わせれば、どのような形状のオブジェクトでもそれに近い形で表現することができます。オブジェクトを近似表現する 3 次元の三角形の集合は、メッシュと呼ばれます。最近のゲームや 3D アプリケーションでは、数千個もの三角形で構成されたメッシュが使用されることも珍しくありません。

WebGL でレンダリングする 3D オブジェクトを記述するには、三角形を使用してそのオブジェクトを表現する必要があります。WebGL では、オブジェクトを個別の三角形のセットという形か、頂点を共有するひとつながりの三角形という形で、記述することができます。ピラミッドの例では、4 つの面からなるピラミッドが、4 つの個別の三角形のセットで記述されます。各三角形は、その三角形の 3 つの頂点で指定されます。図 6 に、ピラミッドの面のうちの 1 つに対して指定された頂点を示します。

図 6. ピラミッドの一面を記述する頂点
ピラミッドの一面を記述する頂点を示す図

図 6 では、面の 3 つの頂点が、y軸上の (0,1,0)、z 軸上の (0,0,1)、x 軸上の (1,0,0) に指定されています。ピラミッド上では、この面が黄色で塗りつぶされ、青色の面の右側に配置されます。これと同じパターンをピラミッドの他の 3 つの面にも適用することで、すべての面を記述することができます。リスト 4 のコードでは、verts という名前の配列内に、ピラミッドの 4 つの面を定義しています。

リスト 4. ピラミッドを構成する三角形のセットを記述する頂点の配列
// Vertex Data
vertBuffer = glCtx.createBuffer();
glCtx.bindBuffer(glCtx.ARRAY_BUFFER, vertBuffer);
var verts = [
0.0, 1.0, 0.0,
-1.0, 0.0, 0.0,
0.0, 0.0, 1.0,

0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
1.0, 0.0, 0.0,

0.0, 1.0, 0.0,
1.0, 0.0, 0.0,
0.0, 0.0, -1.0,

0.0, 1.0, 0.0,
0.0, 0.0, -1.0,
-1.0, 0.0, 0.0

];
glCtx.bufferData(glCtx.ARRAY_BUFFER, new Float32Array(verts), 
   glCtx.STATIC_DRAW);

verts 配列には、ピラミッドの底面 (実際は、x-z 面上にある正方形) は含まれていないことに注目してください。ピラミッドは y 軸を中心軸として回転されるため、ページの閲覧者にピラミッドの底面が見えることはないためです。閲覧者が決して目にすることのないオブジェクトの面はレンダリングしないのが、3D 作業の慣例となっています。表示されない面をレンダリングしないことで、複雑なオブジェクトのレンダリングに要する時間を大幅に短縮することができます。

JavaScript — Float32Array 型の配列

Float32Array などの型付き配列は、比較的新しいブラウザーでサポートされるようになっている、JavaScript のデータ型であり、まったく同じフォーマットの一連のバイナリー・データ要素を格納する、メモリーの連続領域 (JavaScript の ArrayBuffer) を表します。型付き配列は、バイナリー・バッファーに入れられた下位レベルのロー・データを JavaScript で極めて効率良く操作するのに役立つだけでなく、JavaScript アプリケーション・コードと下位レベルの OpenGL ドライバーとの間で大量のデータ (例えば、WebGL プログラミングで使用される行列など) を受け渡しする際にも役立ちます。基本的に、型付き配列は JavaScript API で操作する C 言語スタイルの配列です。型付き配列は、メディアやグラフィックスを処理するアプリケーション用にフォーマット設定されたバイナリー・バッファーのデータを JavaScript で直接扱えるようにするために導入されました。

リスト 4 では、3D ハードウェアが効率良くアクセスできるバイナリー・フォーマットのバッファーに、verts 配列内のデータが入れられます。この処理は一貫して、JavaScript の WebGL 呼び出しによって行われます。まず、WebGL の glCtx.createBuffer() を呼び出してサイズがゼロの新しいバッファーを作成し、glCtx.bindBuffer() の呼び出しによって、新しく作成されたバッファーを OpenGL レベルの ARRAY_BUFFER ターゲットにバインドします。次に、JavaScript でロードするデータ値の配列が定義されると、glCtx.bufferData() を呼び出して、現在バインドされているバッファーのサイズを設定します。最後に、JavaScript データを (最初に JavaScript 配列を Float32Array バイナリー・フォーマットに変換してから) デバイス・ドライバー・レベルのバッファーに入れます。

従って、vertBuffer 変数が参照するハードウェア・レベルのバッファーに、必要な頂点情報が格納されることになります。WebGL レンダリング・パイプラインの他のプロセッサーは、このバッファー内のデータに効率良く、直接アクセスすることができます。


ピラミッドの面の色を指定する

次にセットアップする必要があるのは、colorBuffer で参照される下位レベルのバッファーです。このバッファーには、ピラミッドの各面の色情報が入れられます。この例で使用する色は、青、黄、緑、赤です。リスト 5 に、colorBuffer のセットアップ内容を記載します。

リスト 5. ピラミッドの各面の色を指定する colorBuffer のセットアップ
colorBuffer = glCtx.createBuffer();
        glCtx.bindBuffer(glCtx.ARRAY_BUFFER, colorBuffer);
        var faceColors = [
            [0.0, 0.0, 1.0, 1.0], // front  (blue)
            [1.0, 1.0, 0.0, 1.0], // right  (yellow)
            [0.0, 1.0, 0.0, 1.0], // back   (green)
            [1.0, 0.0, 0.0, 1.0], // left   (red)
        ];
        var vertexColors = [];
        faceColors.forEach(function(color) {
            [0,1,2].forEach(function () {
              vertColors = vertColors.concat(color);
            });
        });        glCtx.bufferData(glCtx.ARRAY_BUFFER,
         new Float32Array(vertexColors), glCtx.STATIC_DRAW);

リスト 5 に示されている下位レベルの colorBuffer バッファーは、createBuffer()bindBuffer()、および bufferData() を呼び出すことによってセットアップされています。これらの呼び出しは、vertBuffer に使用されているものとまったく同じです。

ただし、WebGL にはピラミッドの「面」の概念がありません。WebGL は面の代わりに三角形と頂点のみを使用して動作するため、色のデータを頂点に関連付ける必要があります。リスト 5 では、仲介となる faceColors という名前の JavaScript 配列が vertColors 配列を初期化します。vertColors は、下位レベルの colorBuffer をロードする際に使用される JavaScript 配列です。faceColors 配列には、4 つの面のそれぞれに対応する 4 つの色 (青、黄、緑、赤) が格納されます。これらの色は、RGBA (Red, Green, Blue, Alpha) 形式で指定されます。

vertColors 配列には、各三角形の頂点ごとの色が、vertBuffer 内での色の出現順で格納されます。4 つの三角形にはそれぞれに 3 つの頂点があるため、最終的な vertColors 配列には色のエントリーが合計 12 個含まれることになります (各エントリーは、4 つの float 型の数値で構成される配列です)。ピラミッドの面を表現する各三角形の 3 つの頂点のそれぞれに同じ色を割り当てるために、ネストされた forEach ループが使用されています。


OpenGL シェーダーの概要

ここで当然頭に浮かんでくる疑問は、三角形の 3 つの頂点に色を指定すると、どのような仕組みで三角形全体がその色でレンダリングされるのか、というものです。この疑問に対する答えを明らかにするには、WebGL レンダリング・パイプラインに含まれる、「頂点シェーダー」と「フラグメント (ピクセル) シェーダー」という 2 つのプログラマブル・コンポーネントの動作を理解する必要があります。これらのシェーダーは、3D アクセラレーション・ハードウェアの GPU で実行可能なコードにコンパイルすることができます。最近の 3D ハードウェアの中には、ハイパフォーマンス・レンダリングを実現するために、何百ものシェーダー動作を並行して実行可能なものもあります。

頂点シェーダーは、指定された頂点ごとに実行されます。頂点シェーダーは特定の頂点に関連付けられた色、位置、テクスチャー、およびその他の情報を入力として取ります。この入力データを計算して変換することで、その特定の頂点をレンダリングするビューポート上の 2D 位置、ならびに頂点の色やその他の属性を決定します。一方、フラグメント・シェーダーは、各頂点によって形成される三角形を構成する各ピクセルの色とその他の属性を決定します。WebGL では、頂点シェーダーもフラグメント・シェーダーも GLSL (OpenGL Shading Language) を使用してプログラミングします。

GLSL

GLSL は、ANSI C と同様の (そして、C++ のいくつかの概念を追加した) 構文を使用する、ドメインに特化されたプログラミング言語であり、使用可能なオブジェクト情報 (形状、位置、パースペクティブ (遠近法)、色、照明、テクスチャー (質感)、およびその他の関連する情報) を、3D オブジェクトがレンダリングされる 2D Canvas の各ピクセルとして表示される実際の色にマッピングするために使用されます。

GLSL を使用して独自のシェーダー・プログラムを作成する方法についての詳細は、この記事では説明しませんが、このサンプル・プログラムの残りの部分を理解するには、GLSL コードに関する最小限の知識が必要です。そこで、シェーダーを中心としたコード全体を理解できるように、サンプル・プログラムで使用されている 2 つの単純な GLSL シェーダーの動作を説明することにします。

この連載の次回の記事では、より上位レベルの 3D ライブラリーとフレームワークを使用して WebGL を扱う方法を説明しますが、これらのライブラリーとフレームワークは GLSL コードを透過的に統合するため、自分でシェーダーを作成する必要はないはずです。

WebGL でシェーダー・プログラムを処理する

シェーダー・プログラムとは、ハードウェアの GPU でそのまま実行できる、関連するシェーダー (通常は、WebGL の頂点シェーダーとフラグメント・シェーダー) がリンクされたバイナリーのことです。シェーダーは、単純なほぼ 1 行のコードであることも、極めて複雑な複数の機能を実行する、数百行からなる並列コードになることもあります。

WebGL でシェーダーを実行するには、その前に、シェーダー・プログラムの GLSL ソース・コードをバイナリー・コードにコンパイルしてからリンクしておく必要があります。ベンダー提供の 3D ドライバーには、コンパイラーとリンカーが組み込まれています。開発者に必要な作業は、GLSL コードを JavaScript でサブミットし、コンパイル・エラーが発生していないことを確認した後、パラメーターとして作成した行列をリンクすることですが、WebGL にはこれらの全操作を行うための API があります。図 7 に、WebGL を介した GLSL コードのサブミットについて説明した図を示します。

図 7. WebGL を介した GLSL シェーダー・コードのコンパイルとリンク
WebGL を介した GLSL コードのサブミット時に発生するシーケンスの図

リスト 6 に、サンプル・プログラムの GLSL シェーダーを取得、コンパイル、リンクするコードを記載します。

リスト 6. WebGL で GLSL シェーダー・コードをコンパイルおよびリンクする
var vertShaderCode = document.getElementById("vertshader").textContent;
var fragShaderCode = document.getElementById("fragshader").textContent;

var fragShader = glCtx.createShader(glCtx.FRAGMENT_SHADER);

glCtx.shaderSource(fragShader, fragShaderCode);
glCtx.compileShader(fragShader);

if (!glCtx.getShaderParameter(fragShader, glCtx.COMPILE_STATUS)) {
   var errmsg = "fragment shader compile failed: "
    + glCtx.getShaderInfoLog(fragShader);
   alert(errmsg);
   throw new Error()
  }

var vertShader = glCtx.createShader(glCtx.VERTEX_SHADER);


glCtx.shaderSource(vertShader, vertShaderCode);
glCtx.compileShader(vertShader);

if (!glCtx.getShaderParameter(vertShader, glCtx.COMPILE_STATUS)) {
   var errmsg = "vertex shader compile failed : "
       + glCtx.getShaderInfoLog(vertShader);
   alert(errmsg);
   throw new Error(errmsg)
  }


// link the compiled vertex and fragment shaders 
shaderProg = glCtx.createProgram();
glCtx.attachShader(shaderProg, vertShader);
glCtx.attachShader(shaderProg, fragShader);
glCtx.linkProgram(shaderProg);

リスト 6 では、頂点シェーダーのソース・コードがストリングとして vertShaderCode に格納され、フラグメント・シェーダーのソース・コードが fragShaderCode に格納されます。2 つのソース・コードはどちらも document.getElementById().textContent プロパティーを介して DOM の <script> 要素から抽出されます。

glCtx.createShader(glCtx.VERTEX_SHADER) によって頂点シェーダーが作成され、glCtx.createShader(glCtx.FRAGMENT_SHADER) によってフラグメント・シェーダーが作成されます。

glCtx.shaderSource() によってソース・コードがシェーダーにロードされた後、glCtx.compileShader() によってソース・コードがコンパイルされます。

コンパイルが完了すると、コードが正常にコンパイルされたことを確認するために、glCtx.getShaderParameter() が呼び出されます。コンパイル・エラーをコンパイラー・ログから取り出すには、glCtx.getShaderInfoLog() を使用します。

頂点シェーダーとフラグメント・シェーダーが両方とも正常にコンパイルされた後、この 2 つをリンクしてシェーダーの実行プログラムの形にします。それにはまず、glCtx.createProgram() を呼び出して、下位レベルのプログラム・オブジェクトを作成します。続いて glCtx.attachShader() を呼び出し、コンパイル済みバイナリーをプログラムに関連付けます。そして最後に、glCtx.linkProgram() を呼び出すことで、これらのバイナリーをリンクします。

頂点シェーダーおよびフラグメント・シェーダーの GLSL コード

頂点シェーダーは、先ほど JavaScript の vertBuffer 変数と colorBuffer 変数として準備した入力データ・バッファーに対して動作します。リスト 7 に、頂点シェーダーの GLSL ソース・コードを記載します。

リスト 7. 頂点シェーダーの GLSL ソース・コード
attribute vec3 vertPos;
attribute vec4 vertColor;
uniform mat4 mvMatrix;
uniform mat4 pjMatrix;
varying lowp vec4 vColor;
void main(void) {
  gl_Position = pjMatrix * mvMatrix * vec4(vertPos, 1.0);
  vColor = vertColor;
}

リスト 7 について説明すると、attribute というキーワードは、頂点データごとのデータに対して WebGL と頂点シェーダーとの連携を指定するストレージ修飾子です。この例の場合、シェーダーが実行されるたびに、vertBuffer に入れられた頂点の位置情報が vertPos に格納されます。vertColor には、先ほどセットアップした colorBuffer で指定された色が、その頂点の色として格納されます。

uniform というストレージ修飾子は、JavaScript で設定された値を、シェーダー・コード内で読み取り専用パラメーターとして使用するように指定します。これらのバッファー内の値は、(特に、アニメーション時に) JavaScript コードによって変更される可能性がありますが、シェーダー・コードによって変更されることは決してありません。別の言い方をすれば、これらの値を変更できるのは CPU だけであり、レンダリング GPU が変更することはできません。設定後の uniform 値は、頂点シェーダー・コードで処理されるすべての頂点に共通で使用されます。この例の mvMatrix には、JavaScript でセットアップされたモデル・ビュー行列が格納され、pjMatrix にはプロジェクション (投影) 行列が格納されます (モデル・ビュー行列とプロジェクション行列については次のセクションで取り上げます)。

3D 開発でのパターンとしての補間

「補間」とは概念的パターンであり、3D グラフィックスの作品やアニメーションでは、このパターンを何度も目にします。この補間という概念は、時間または空間内の決められたポイントでの属性や振る舞いを定めておき、その中間にあるすべてのポイントでの属性や振る舞いを数学的な計算によって求めることです。このようにすれば、開発者やアニメーターは、通常は大量のデータ・ポイントの指定が必要となる属性や振る舞いの連続的な変化を、ほんの少数のデータ・ポイントで制御できるようになります。

lowp というキーワードは精度の修飾子で、vColor 変数が低い精度の float 型の数値であることを指定していますが、WebGL の色空間で色を記述するにはこれで十分です。gl_position は、シェーダーの変換後の出力値で、これは 3D レンダリング・パイプラインがさらに処理を加えるために内部で使用されます。

vColor 変数には varying ストレージ修飾子が設定されています。varying は、この変数を頂点シェーダーとフラグメント・シェーダーの間のインターフェースとして使用するように指定します。vColor は、頂点ごとに固有の値を 1 つ格納しますが、フラグメント・シェーダーでは、その値が頂点の間で補間されます (フラグメント・シェーダーは、頂点の間にあるピクセルに対して実行されることを思い出してください)。この記事の GLSL の例では、vColor 変数が、頂点シェーダーで各頂点の colorBuffer に指定された色に設定されます。今度は、フラグメント・シェーダーのコードをリスト 8 に記載します。

リスト 8. フラグメント・シェーダーの GLSL ソース・コード
varying lowp vec4 vColor;
 void main(void) {
   gl_FragColor = vColor;
 }

フラグメント・シェーダーは平凡なもので、補間される vColor の値を頂点シェーダーから取得し、その値を出力として使用します。vColor の値は、ピラミッドの各面の 3 つの頂点のそれぞれに対して同じに設定されることから、フラグメント・シェーダーで補間される色はそのまま同じ色に維持されます。

各三角形の少なくとも 1 つの頂点が異なる色になるようにすると、補間の効果を確認することができます。pyramid.html を変更して、リスト 9 の太字で示されたコードを反映させてください。

リスト 9. フラグメント・シェーダーの補間が明らかになるように pyramid.html を変更する
var vertexColors = [];
faceColors.forEach(function(color) {
  [0,1].forEach(function () {
      vertColors = vertColors.concat(color);
   });
   vertColors = vertColors.concat(faceColors[0]);
     });
glCtx.bufferData(glCtx.ARRAY_BUFFER, 
  new Float32Array(vertexColors), glCtx.STATIC_DRAW);

この変更では、各三角形の 1 つの頂点の色は青であることを確実にしています。変更後の pyramid.html をブラウザーにロードすると、青色の面 (この面の頂点はすべて青色のままです) を除くピラミッドのすべての面に、色のグラデーション (補間された色) が適用されているはずです。図 8 に、補間された色のグラデーションが適用されたピラミッドの面を示します (OS X 上の Chrome での表示)。

図 8. 補間された色のグラデーションが適用されるように、ピラミッドの面が変更された pyramid.html
pyramid.html のスクリーン・キャプチャー。補間された色のグラデーションが適用されるように、ピラミッドの面が変更されています。

モデル・ビュー行列とプロジェクション行列

JavaScript による高速な行列処理

3D 変換を処理するには、4x4 行列の乗算が必要になることがよくあります。この計算を JavaScript で効率的に行うには、巧みなコーディングとチューニングが要求されます。幸い、WebGL に合わせて最適に作成された JavaScript 行列ライブラリーを使用できるようになっています。この記事の例では、行列処理に glMatrix ライブラリーが使用されています。

Canvas にレンダリングされる 3D シーンの変換を制御するには、2 つの行列を指定します。それは、モデル・ビュー行列とプロジェクション (投影) 行列です。前に説明したように、頂点シェーダーはこれらの行列を使用して、各 3D 頂点の変換方法を決定します。

モデル・ビュー行列には、モデル (この例ではピラミッド) とビュー (シーンを見るために覗く「カメラ」) の変換が結合されます。モデル・ビュー行列は基本的に、シーンにおけるオブジェクトの位置とそれを見るカメラの位置を制御します。以下のコードは、カメラから 3 ユニット離れた位置にピラミッドを配置して、この例のモデル・ビュー行列をセットアップします。

modelViewMatrix = mat4.create();
mat4.translate(modelViewMatrix, modelViewMatrix, [0, 0, -3]);

vertBuffer のセットアップから、ピラミッドは 2 ユニットの幅であることがわかっています。従って、上記のコードでは、ピラミッドがビューポートの「フレーム全体」を占められるようにします。

プロジェクション行列は、カメラのビューを通じて 3D シーンを 2D ビューポートへと変換するのを制御します。この例でのプロジェクション行列をセットアップするコードは、以下のとおりです。

projectionMatrix = mat4.create();
mat4.perspective(projectionMatrix, Math.PI / 4, canvas.width / canvas.height, 1, 100);

カメラは、Math.PI / 4 (πラジアンの 4分の1、つまり 180 度 / 4 = 45 度) の視野を持つように設定されています。表示対象との距離が 1 ユニットから 100 ユニットまでの範囲である限り、カメラは遠近法による (歪んでいない) 表示を維持することができます。


ビューポートに 3D シーンをレンダリングする

すべてのセットアップが完了した状態でリスト 10 のコードを実行すると、3D シーンが 2D ビューとしてビューポートにレンダリングされます。このコードに含まれる draw() 関数は、update() ラッパーによって呼び出されます。update() ラッパーを使用することで、ピラミッドを回転するための pyramid.html 内のコードをあとで変換するのが容易になります。

リスト 10. シーンをレンダリングする draw() 関数
function draw(ctx) {
  ctx.clearColor(1.0, 1.0, 1.0, 1.0);
  ctx.enable(ctx.DEPTH_TEST);
  ctx.clear(ctx.COLOR_BUFFER_BIT  | ctx.DEPTH_BUFFER_BIT);
  ctx.useProgram(shaderProg);
  ctx.bindBuffer(ctx.ARRAY_BUFFER, vertBuffer);
  ctx.vertexAttribPointer(shaderVertexPositionAttribute, 3 ,
     ctx.FLOAT, false, 0, 0);
  ctx.bindBuffer(ctx.ARRAY_BUFFER, colorBuffer);
  ctx.vertexAttribPointer(shaderVertexColorAttribute, 4 ,
     ctx.FLOAT, false, 0, 0);
  ctx.uniformMatrix4fv(shaderProjectionMatrixUniform, 
      false, projectionMatrix);
  mat4.rotate(modelViewMatrix, modelViewMatrix, 
      Math.PI/4, rotationAxis);
  ctx.uniformMatrix4fv(shaderModelViewMatrixUniform, false, 
      modelViewMatrix);
  ctx.drawArrays(ctx.TRIANGLES, 0, 12 /* num of vertex */);
}

3D 空間でのオブジェクトの配置

3D 開発に熟達するには、x-y-z 座標を指定して 3D 空間にオブジェクトを配置する操作に慣れる必要があります。この記事の単純な例では、配置する必要があるのはカメラとピラミッド (メッシュ) だけですが、複雑な 3D プロジェクトになってくると、複数の 3D オブジェクト (メッシュ) を配置してシーンを作り出さなければならなくなります。さらに、ドラマチックな効果を加えるために、シーンに 1 つ以上の照明を配置しなければならない場合もあります (この記事では、数学演算とコードをともに単純なものにしておくためにデフォルトの設定を使用します)。アニメーションの場合には、3D メッシュの動きを制御するために、シーンに 1 つ以上のパスを配置する必要があります。

リスト 10 ではまず、ctx.clearColor() を呼び出してビューポートを白にクリアした後、ctx.enable(ctx.DEPTH_TEST) を呼び出してデプス・バッファー (z-buffer) を使用可能にします。続いて ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT) を呼び出すことで、カラー・バッファーとデプス・バッファーをクリアします。

その後の ctx.useProgram() の呼び出しでは、前にコンパイルしてリンクした vertShaderfragShader からなる shaderProg を GPU で実行できるようにロードします。次に、ctx.bindBuffer()ctx.vertexAttribPointer() を続けて呼び出すことで、前に JavaScript でセットアップした下位レベルのデータ・バッファー (vertBuffer および colorBuffer) を GLSL シェーダー・プログラムの属性にバインドします (このワークフローは、SQL プログラミングでのストアード・プロシージャーと概念が似ています。SQL プログラミングでは、ストアード・プロシージャーによって実行時にパラメーターをバインドすることにより、プリペアード・ステートメントを再実行できるようにします)。その後にある 2 つの、ctx.uniformMatrix4fv() 呼び出しは、頂点シェーダーが読み取り専用でアクセスするモデル・ビュー行列、プロジェクション行列をそれぞれセットアップします。

最後の同じく重要な ctx.drawArrays() の呼び出しでは、4 つの三角形のセット (合計 12 の頂点) がビューポートにレンダリングされます。

お気付きかもしれませんが、頂点シェーダーがアクセスするモデル・ビュー行列をセットアップする直前に、mat4.rotate(modelViewMatrix, modelViewMatrix, Math.PI/4, rotationAxis) が呼び出されます。この呼び出しは、レンダリングする直前に y 軸を中心軸としてピラミッドを Math.PI/4 (つまり 45 度) 回転させます。図 6 をもう一度見れば、その理由は明らかです。ピラミッドの面のセットアップでは、ピラミッドの端を z 軸上に配置することに注意してください。z 軸上のカメラがスクリーンに向けられている場合、ピラミッドを回転させなければ、カメラに映るのは青色の面の半分と黄色の面の半分です。ピラミッドを 45 度回転させることで、青色の面だけが表示されます。この効果は、mat4.rotate() 呼び出しをコメントアウトして、ページを再びロードすることで、簡単に確認することができます。OS X 上の Firefox でこの結果を表示したのが図 9 です (このバージョンでは、頂点の色補間コードの変更が元に戻されています)。

図 9. ピラミッドを回転させる前の 2 つの面を表示する pyramid.html
ピラミッドを回転させる前の 2 つの面を表示する pyramid.html のスクリーン・キャプチャー

ピラミッドの回転をアニメーションにする

ブラウザーの間での rAF のサポート

Chrome と Firefox の最新バージョンでは、rAF をデフォルトでサポートしています。Safari では、特別なベンダー・プレフィックスを使用した場合に限り、rAF がサポートされます。rAF をサポートしていないブラウザーのバージョンの場合は、setTimeout に復帰するシムを作成することができます。この記事の例では、サポートしているすべてのブラウザーで一貫した構文を使用して rAF を呼び出せるようにするために、ポリフィル・スクリプトによるソリューションを使用しています。

下位レベルの API である WebGL には、元々アニメーションのサポートが備わっていません。

回転のアニメーションを表示するために、この例では requestAnimationFrame() 関数 (rAF) を使用して、ブラウザーによるアニメーションのサポートを利用しています。requestAnimationFrame() が引数として取るのは、コールバック関数です。ブラウザーは次の画面更新 (通常、1 秒あたり最大 60 回の更新) の前に、この関数をコールバックします。コールバック内では requestAnimationFrame() を再び呼び出して、次の画面更新の前にこの関数が呼び出されるようにする必要があります。

requestAnimationFrame() を呼び出す pyramid.html 内のコードは、リスト 11 のとおりです。

リスト 11. 画面を更新するために requestAnimationFrame を呼び出す
function update(gl) {
        requestAnimationFrame(function() { update(gl); });
        draw(gl);
}

リスト 11 では、update() 関数がコールバックとして指定されています。update() も同じく、次のフレームを要求するために requestAnimationFrame() を呼び出す必要があります。update() が呼び出されるたびに、draw() も呼び出されます。

リスト 12 に、y 軸を中心軸としてピラミッドをインクリメンタルに回転させるように変更した triangles.html の draw() 関数を記載します。追加または変更されたコードは太字で示されています。

リスト 12. ピラミッドの回転をアニメーション化する
var onerev = 10000; // ms
var exTime = Date.now();

  function draw(ctx) {
        ctx.clearColor(1.0, 1.0, 1.0, 1.0);
        ctx.enable(ctx.DEPTH_TEST);
        ...
        ctx.uniformMatrix4fv(shaderProjectionMatrixUniform, false, projectionMatrix);
        var now = Date.now();
        var elapsed = now - exTime;
        exTime = now;
        var angle = Math.PI * 2 * elapsed/onerev;
        mat4.rotate(modelViewMatrix, modelViewMatrix, angle, rotationAxis);
        ctx.uniformMatrix4fv(shaderModelViewMatrixUniform, false, modelViewMatrix);
        ctx.drawArrays(ctx.TRIANGLES, 0, 12 /* num of vertex */);
  }

リスト 12 では、フレームごとの回転角度を計算するために、経過時間 elapsed を完全に一回転するために必要な時間で除算しています (この例では、onerev = 10 秒です)。

この連載の今後の記事で、他にも rAF を使用する例を取り上げます。


WebGL の限界を押し広げる

ピラミッドの例では、WebGL プログラミングの重要な基本概念を探り、WebGL で実現できることをほんの少しだけ学びました。

WebGL で可能な驚くべきアプリケーションの例 (現時点での WebGL の限界を押し広げるアプリケーション) を見るには、比較的最近のマシンで実行されている最新の Firefox ブラウザーで、Epic Games による Unreal Engine 3 でのWebGL のデモンストレーション ― Epic Citadel にアクセスしてください。図 10 に、実行中の Epic Citadel を示します (Windows 上の Firefox で実行)。

図 10. Epic Citadel — Epic Games による Unreal Engine 3 でのWebGL のデモンストレーション
Epic Citadel のスクリーン・キャプチャー

Epic Citadel は、(元々 C/C++ で書かれた) 有名なゲーム・エンジン製品を JavaScript および WebGL にコンパイルしたことによる作品です (使用されているコンパイラー・テクノロジーは emscripten であり、出力された JavaScript サブセットは asm.js として知られています)。このゲームでは、WebGL でレンダリングされた中世都市の石畳の道、城、アニメーション化された滝を (インタラクティブな操作によって) 歩き回ることができます。

別の興味深い例としては、Greggman および Human Engines による Google の WebGL Aquarium (水族館) もあります。図 11 に、この水族館が Windows 上の Chrome で実行されている様子を示します。

図 11. Google による斬新なガラスのドーム型水族館の WebGL サンプル
Google の WebGL Aquarium のスクリーン・キャプチャー

この水族館アプリケーションでは、全面がガラスでできた球状の水槽を泳ぎ回る魚の数をユーザーが選択することができます。また、光の反射具合 (Reflection)、水の透明度 (Fog)、光線の射し具合 (Light Rays) などのレンダリング効果を試してみることもできます。


まとめ

WebGL は、JavaScript API で 3D ハードウェアに直接アクセスすることを可能にしますが、この API が下位レベルの API であることに変わりはありません。

  • WebGL は、3D シーン内で何が表示されているかについてはまったく関与せず、そのための概念も備えていません。この記事の例で扱った単純な 3D ピラミッド・オブジェクトは、WebGL API 層では認識されないため、オブジェクトを構成する頂点データを辛抱強く追跡する必要があります。
  • WebGL シーンを描画するための呼び出しごとに、1 つの 2D 画像だけがレンダリングされます。アニメーションそのものは WebGL では扱われないため、アニメーションを実装するにはコードを追加する必要があります。
  • オブジェクトと環境との間での動きや相互作用 (光の反射やオブジェクトの物理特性など) も、コードを追加して実装する必要があります。
  • ユーザー入力、オブジェクトの選択、あるいはオブジェクトの衝突などといったイベントの処理は、上位レベルのコードで実装する必要があります。

ピラミッドを回転させるためだけに 100 行を超えるコードを作成するのは、気が遠くなるような作業に感じられることでしょう。また、かなり複雑な WebGL アプリケーションを作成するには、上位レベルのライブラリーやフレームワークを使用しなければならないのは明らかです。ありがたいことに、WebGL ライブラリー/フレームワークはいくらでもあります。その多くは、オープンソース・コードのコミュニティーから無料で入手できます。第 2 回では、WebGL ライブラリーを利用する方法を探ります。


ダウンロード

内容ファイル名サイズ
Sample codewebgl1dl.zip20KB

参考文献

学ぶために

  • WebGL: Khronos Group のサイトにある WebGL ホーム・ページにアクセスし、WebGL 仕様の最新のワーキング・ドラフトを読んでください。
  • WebGL クイック・リファレンス: WebGL API の構文や概念が一目でわかる便利なチート・シートを活用してください。
  • OpenGL のレンダリング・パイプライン: ハードウェア・アクセラレーションを利用した 3D レンダリングで使用される概念上のハードウェア「パイプライン」の概要を理解してください。
  • HTML5 の Canvas を使って素晴らしいグラフィックスを作成する」(Ken Bluttman 著、developerWorks、2011年2月): HTML5 の Canvas を使用した 2D 描画手法について復習する必要があるならば、この入門記事を調べてください。
  • Chromium のレンダリング用スタック: オープンソースの Chromium ブラウザーが内部でデュアル・レンダリング・スタックにより GPU アクセラレーションをサポートしている方法を調べてください。
  • OpenGL Shading Language」: シェーダー・コードの作成、または実験的な作成についての詳細な GLSL ドキュメントを読んでください。
  • JavaScript 型付き配列: Khronos Group から最新の仕様を入手してください。
  • Can I use WebGL?」: この価値あるサイトでは、最新のブラウザーによる WebGL のバージョンごとのサポートを追跡しています。
  • Epic Citadel: この Epic Games による WebGL ゲーム・エンジンのデモンストレーションで、完全に 3D でレンダリングされた中世都市を歩き回ってください。また、このプロジェクトで使用している emscripten コンパイラーと asm.js (下位レベルの JavaScript サブセット) について調べてください。
  • WebGL Aquarium: この Greggman と Human Engines による WebGL サンプルの Google コードを基に、読者独自の斬新な球状の 3D 水族館の作成を始めてください。

製品や技術を入手するために

議論するために

  • developerWorks コミュニティーに参加してください。ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者によるブログ、フォーラム、グループ、Wiki を調べることができます。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。プロフィールで選択した情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development, Mobile development
ArticleID=963643
ArticleTitle=WebGL による 3D 開発: 第 1 回 WebGL の紹介
publish-date=02272014