必要条件

この記事に必要な予備知識

Flash Professionalを使ったアプリケーション構築の基本を理解していることが前提になります。ActionScript 3を使った開発経験も必要です。

ユーザーレベル

初級

この記事では、Flashの3Dレンダリング性能を飛躍的に向上できる、Flash Player 11で新たに追加された ActionScript APIについて説明します。このチュートリアルでは、まずStage3Dの概要とその仕組みをご紹介します。そして、ActionScriptを使って頂点バッファーとインデックスバッファーで簡単なStage3Dジオメトリを作成する方法も説明します。

Stage3Dとは

ここ数年、デベロッパーは、Flashの3D機能を駆使して魅力的なプロジェクトをいくつも開発してきました。Papervision3D、Away3D、Alternativa3Dなどの3Dエンジンや、これらのエンジンを使って構築した素晴らしいアプリケーションの存在によって、Flashでリアルタイム3Dレンダリングを実現する必要性が高まりました。

これまで、Flashの3Dレンダリングは、3Dハードウェアアクセラレーションを使わずに実行されていました。バージョン11以前のFlash Playerで3Dをレンダリングする場合は、CPUに依存するソフトウェアモードを使ってきましたが、ソフトウェアモードは、処理速度が遅く、精密な3Dシーンを描画できません。そのため、これまでは3Dゲームで見慣れている高度なグラフィック効果を統合することができませんでした。

しかし、Flash Player 11の登場で新たなチャンスが到来しました。3Dハードウェアアクセラレーションを利用できるようになったため、CPUに依存しないレンダリングが実現しました。この新しいレンダリング方法によって、Flash 3Dコンテンツは、GPU(Graphics Processing Unit)と呼ばれるセカンダリプロセッサ(コンピューターのビデオハードウェアの一部)で処理されます。GPUは、3Dでオブジェクトを描画するための専用ハードウェアの1つです。

Stage3Dの使用

Stage3Dは、アドビがリリースした新しいFlash APIで、リアルタイム3Dレンダリングに特化した機能です。Stage3Dを使うと、ハードウェアアクセラレーション機能をフルに活かして、Flashから直接ユーザーのコンピューターのGPUを利用できます。

このStage3Dのリリースは、Flashデベロッパーにとっては大きなインパクトのある出来事でした。Flashで3Dアクセラレーション機能が使えるようになったことで、これまで実現できなかったFlashゲームやFlashアプリケーションを開発できるチャンスが拡大しました。

3Dハードウェアアクセラレーションが最初にネイティブプラットフォーム用に導入された時のことを思い出してみてください。この出来事によって、3Dコーディングが大きく変わりました。飛躍的にゲームの質が向上し、複雑さも増しました。ハードウェアアクセラレーションは、複雑なモデル、リアルなエフェクト、反応の速いゲーム操作に必要な高速レンダリングを実現し、3Dゲームの性能を大幅に向上しました。

一方、Flash Playerは普及率が98%を超え、誰もが利用できる製品であるため、Flashで開発したゲームやアプリは、世界中のほぼすべてのコンピューターで使用できます。ユーザーは、WebブラウザーにゲームのURLを入力すれば、その場ですぐにゲームで遊ぶことができるのです。Flash Playerはほとんどのブラウザーにインストールされており、ユーザーはその他に何もインストールする必要はありません。特殊なランタイムライブラリやハードウェアは必要なく、OSのバージョンを気にする必要もありません。

場所を問わず誰もが使えるFlash Playerと3Dハードウェアアクセラレーションの組み合わせは大きな影響力を持ち、かつて3Dグラフィックスを高速処理するハードウェアが登場したことでコンピューターゲームが急速に発展したように、今後オンラインゲームも大きな変革を迎える可能性があります。

現在は、2Dコンテンツで作られたFlashサイトが一般的です。では、近い将来、こうした状況はどのように変わっていくのでしょうか。3D体験が楽しめる環境にユーザーは夢中になっているかもしれません。今後、非常に多くのWebサイトが、シンプルな2D体験ではなく、インタラクティブな3Dオブジェクトを駆使したビデオゲームのようなサイトに変わってしまうことも考えられます。

以上がStage3Dの概要です。インターネットにつながっているすべてのコンピューターで使用できる3Dゲームやインタラクティブな3Dサイトを構築する場合は、最新コンピューターに搭載されている3Dハードウェアを活用していくことになるでしょう。

3Dハードウェアアクセラレーションの使用

ここでは、3Dハードウェアアクセラレーションを利用したFlashコンテンツの描画について大まかに説明します。

3Dハードウェアアクセラレーションでは、非常に高度なハードウェアであるGPUを利用します。GPUはすべての最新コンピューターに搭載されています。GPUは、3Dコンテンツの描画というタスクを専門的に処理します。

この3Dハードウェアアクセラレーションを設定すると、ソフトウェア(Flashアプリケーション)では、3Dシーンを定義するだけで済むようになります。つまり、Flashアプリケーションは3DシーンのデータをGPUに引き渡し、GPUがそのデータを処理して、3Dシーンを描画します。このプロセスは、CPUを使ってソフトウェアモードで3Dコンテンツを描画するよりもずっと速くレンダリングできます。

ソフトウェアモードとハードウェアモードでのレンダリングの違いを、ぜひ比較してみてください。

一般的には、3Dシーンは3Dジオメトリ(メッシュ)群で定義されます。各ジオメトリは三角形の集合で指定され、各三角形は頂点の集合で構成されます。つまり、3Dシーンの定義とは、頂点の集合を定義し、テクスチャや頂点の色などレンダリングに関係する情報を追加することです。

これまでソフトウェアモードを使用すると、Away3Dなどの3Dエンジンは、この一連の頂点情報を受け取り、画面での三角形の位置を計算した後、「fill」による描画コマンドを順次処理しながら、三角形を1つ1つネイティブにレンダリングするようにFlash Playerに指示を出していました。

エンジン内でスマートにコーディングされるものの、このプロセスは非常に時間がかかりました。場合によっては、描画結果が正確に得られないこともありました。コンテンツがピクセルではなく三角形単位でレンダリングされるため、深度ソートのエラーが発生していました。このため、誤った深度で三角形の位置がずれることがありました。

統計を見ると、通常Flash Player 10のソフトウェアモードで許容範囲のパフォーマンスを維持するためには、最高4,000個の三角形を使ってシーンを描画します。

では、Stage3Dを使用した場合はどうでしょうか。3Dハードウェアアクセラレーションを使用すると、ソフトウェアはジオメトリを定義し、コンピューターのGPUにそのデータを渡します。ジオメトリは、GPUが使用する専用ビデオハードウェアにあるメモリのGPUメモリにアップロードされます。GPUは、3Dコンテンツのレンダリングタスクをすべて引き継ぎながらデータを受け取り、処理します。

ソフトウェアは、レンダリングに必要なパラメーターをGPUに渡すだけなので、より効率的に機能します。例えば、ソフトウェアには、3Dシーンでのアイポイント(3Dカメラ)の位置、光源の位置、シーン内の3Dオブジェクトや3Dエフェクトに関する詳細を設定できます。

GPUは、こうしたデータをすべて受け取ると、定義済みの頂点を分析し始め、三角形単位でシーンをレンダリングしていきます。そして、画面表示の準備が整った最終的なイメージを生成します。

GPUを利用したレンダリングは、ソフトウェアモードよりも高速で処理されます。GPUは、頂点を計算し三角形をレンダリングするという、非常に特定されたタスクに焦点を置いて設計されています。つまり、GPUのハードウェアはこの明確なタスクに特化したものであるため、ハードウェアアクセラレーション機能を使った3Dレンダリングは非常に効率的に処理されるのです。

対照的に、CPUは汎用的なプロセッサです。三角形のレンダリングのために最適化されていません。そのため、ソフトウェアモードを使ってFlash 3Dコンテンツをレンダリングする時には、レンダリング処理の効率性は下がります。

ハードウェアアクセラレーションを使う場合、100万個以上の三角形を含んだシーンをレンダリングするケースは珍しいことではありません。ソフトウェアモードでの4,000個に比べると、その数は飛躍的に増えます。

3Dレンダリングパイプラインの分析

ハードウェアベースの3Dレンダリングは、3Dレンダリングパイプラインによって処理されます。「パイプライン」は、レンダリングプロセスが基本処理の集合体に分割されていることを示す用語です。GPUはひと続きのブロックで構成されており、各ブロックはこうした基本処理の1つを集中的に実行します。ブロック全体は、各ブロックの出力が次のブロックの入力として渡されるカスケード形式になっています。

最も早い段階からリリースされている3Dグラフィックレンダリングパイプラインは、固定機能パイプラインと呼ばれるものです。「固定」という単語は、まったくプログラミングできないパイプラインであることを意味しています。固定機能パイプラインは、入力データとしてジオメトリデータを受け取り、パイプラインブロックを通じてデータを処理し、最終出力結果として描画するイメージを生成するだけなので、多少柔軟性に欠けています(図1を参照)。

固定機能パイプラインを使用する場合、GPUに対して、ジオメトリの詳細(頂点および三角形)、ジオメトリに適用するテクスチャ、3Dシーンでのジオメトリの位置と方向、アイポイント(3Dカメラ)の位置と方向、光源(量、カラー、位置)、レンダリングの実行方法を指定するために必要なその他のパラメーターといった入力データを渡します。

別の言い方をすれば、古いシステムを使う場合は、頂点、三角形、テクスチャに関するデータとパラメーター群をハードウェアに渡すと、3Dハードウェアはそれらのデータをレンダリング処理します。

固定機能パイプラインには、ローカル(モデル)スペースから頂点を変換し、それらを画面に投影する変換処理およびライティング処理ブロックがあります。また、頂点単位のライティング処理も実行します。このブロックでの処理が完了したら、ビューポートクリッピングブロックに進みます。このブロックでは、実際に見える描画イメージに合わせて、はみ出した部分を切り取ります。これによって、画面上ではビューポートのフォーマットに合わせてコンテンツを描画できます。

切り取られたデータは、パイプラインの次の段階であるラスタライザーステージに渡され、テクスチャマッピング処理されます。最後にフォギング(霧)やアルファブレンド効果を適用し、深度に沿ってソートされた正しい順番で三角形のピクセルをレンダリングできるように、深度バッファリングテストを実行します。

これまで固定機能パイプラインは長い間使われてきましたが、時間が経つにつれて、このレンダリングプロセスはいくぶん柔軟性に乏しいことが明らかになってきました。とりわけライティング処理に関しては、基本的なグーローシェーディングやフォンシェーディングなどの標準的なシェーディングモデルしか使えませんでした。固定機能パイプラインには、デベロッパーが面白い効果を独創的に追加できる柔軟性がありません。そのため3次元化された画像はみな同じような描画になってしまうことが多くなっていました。

やがて、プログラマブルグラフィックスパイプラインが開発されました。プログラマブルグラフィックスパイプラインのブロック構成図では、この新しいレンダリングプロセスを説明しています(図2を参照)。

この新しい仕組みがこれまでと大きく違うのは、頂点シェーダーとフラグメントシェーダーという2つのブロックが導入されたことです。この2つのブロックはプログラムで制御することができます。プログラマブルパイプラインを使ってアプリケーションを開発する場合、シェーダーと呼ばれるコードスニペットを作成し、レンダリングパイプライン内での処理内容を決定します。

シェーダーの導入は、パイプラインにおけるささいな変化にしかすぎませんでしたが、3Dレンダリングの世界を全く変えてしまいました。

頂点の変換/修正方法(頂点シェーダー)および三角形のピクセルカラーのレンダリング方法(フラグメントシェーダー)を決定する小さなプログラムを作成することで、これまではレンダリング処理できなかった見事な効果を引き出すことができるようになりました。シェーダーを使うと、あらゆる種類のライティング技法を適用できます。これによって、パイプラインで提供されているデフォルトのライティングは使わず、特定のアプリケーション用にカスタマイズされたプログラムを作成できます。シェーダーを使用すると、陰影、ハードウェアで高速処理されるボーンシステム、その他の魅力的なエフェクトを加えることができます。

この段階で重要なのは、Stage3Dがプログラミングできる機能パイプラインに基づいて開発されているという点です。固定機能パイプラインを使用するという選択肢はありませんが、これはメリットと言えます。シェーダーをプログラミングできることで、グラフィックスハードウェアの威力をフルに活用できるからです。そして、Flash 3Dプロジェクトでも素晴らしいエフェクトを作成できます。

ただし、こうしたメリットの活用には責任も伴います。一番シンプルなレンダリングを実行する場合でも、自作のシェーダーを記述しなければなりません。プログラマブルレンダリングパイプラインを使用する際は、これまでの固定機能パイプラインのように、パラメーターをいくつか設定すれば、プロジェクトをレンダリング処理できるというわけにはいきません。

Stage3Dを使用する際のメリットと制限事項

ここでは、標準的なネイティブプラットフォームの3D APIであるOpenGLおよびDirectXと比較しながら、Stage3Dがもたらすメリットを説明します。OpenGLおよびDirect Xは、10年以上使用されてきたAPIで、最新コンピューター向けに優れたゲームを開発する場合に使用される主流のアプローチです。

しかし、OpenGLやDirect Xを使って3Dアプリケーションを開発するのは容易ではありません。単純な三角形のレンダリング処理は非常に簡単ですが、C++で本格的な3Dアプリケーションを開発するには高いスキルが必要です。経験不足のプログラマーでできる仕事ではありません。

ネイティブ3Dアプリケーションの開発で難しい点は、DirectXおよびOpenGLといった標準のAPIを使わなくてはいけないことです。デベロッパーがグラフィックスハードウェアをフル活用するためには、プロジェクトがハードウェアに特化したオプションをすべて備えていなければなりません。ネイティブAPIは非常にハードウェアに近く、アプリケーションの動作中に特定のGPUのハードウェア機能を使って処理するように開発します。多くの場合、最もパワフルなハードウェアをフル活用できるようにコードを調整する必要があります。最新のハードウェアで最も優れたエフェクトを引き出せるため、これはデベロッパー側にはメリットになります。しかし、アプリケーションをさまざまなハードウェアでテストし、コードを調整する必要があります。

Stage3Dを使用すれば、こうした状況を回避できます。Context3DやProgram3DなどのStage3Dの抽出に沿ってコードを記述するだけです。そうすれば、開発したアプリケーションはFlash Player(またはAIRランタイム)をサポートしているすべてプラットフォームで使用できます。

ある意味、Stage3DはネイティブAPIよりも抽象的で、ハードウェアそのものとは少し離れています。その結果、Stage3Dはずっと使いやすくなっていると言えます。

各プラットフォームの個別のパワーを利用するため、特定のハードウェアを対象にしないで開発することになるため、もちろんデメリットもあります。バーチャルのStage3Dプラットフォームに対して包括的なコードを記述するだけであり、Stage3Dは、作成したコードと実際のハードウェアの間に存在する1つのレイヤーとして動作します。

Stage3Dの大きなメリットは、3Dハードウェアアクセラレーションに対応したコードと、通常の2D Flashオーサリングの優れた機能および使いやすさを同じアプリケーション内で同時に利用できることです。

ネイティブの3Dアプリケーションを開発する際、2DのUI開発には、Flashのような柔軟性の高いオーサリングツールを使えず、カスタムソリューションが必要になるケースが多く発生します。

Stage3Dを使用すれば、通常のFlash 2DコンテンツがStage3Dコンテンツと共存することができます。そのため、Flashが持つ実力のすべてを活用できるうえ、3Dの処理を高速化することもできます。デベロッパーは、背景にメインの3Dシーンを配置したり、2D体験の一部として小型の3Dアイテムを埋め込んだりすることができます。

Stage3Dを駆使したアプリケーションは、さまざまなプラットフォームで動作します。AIRアプリケーションとしてStage3Dアプリケーションを実行することも、Flash Playerで再生することもできます。この機能があることで、Stage3Dを使って、デスクトップ向けの標準的な3Dゲームのようなデスクトップ3Dアプリケーションを開発できます。今後は、同じコードを使って、iOSやAndroidなどのモバイルプラットフォームにこのアプリケーションをデプロイできるようになるでしょう。Flash Playerが広く普及しているため、Stage3Dアプリケーションを広範囲に配布できる可能性が見えてきます。

Stage3Dの制限事項

Stage3Dの主な短所は、複数のプラットフォームに対して1つのアプリケーションしか開発できない点です。1つの統合APIで同時にすべてのプラットフォームをターゲットにするため、Stage3Dは最新の3Dグラフィックスでしか再現できない高度な機能がある場合、それを活かしきることができません。

1つのアプリケーションをすべてのプラットフォームに対応させるためには、ターゲットになっているすべてのプラットフォームで、Stage3Dが3Dハードウェアデバイスを抽出する必要があります。

例えば、最新のGPUがサポートしているのはシェーダーモデル(頂点シェーダーやフラグメントシェーダーに使われる標準モデル)のバージョン4.0ですが、Stage3Dのサポート対象はバージョン2.0です。

このため、Stage3Dでコードを記述する場合は、ハイエンドのハードウェアには必要のない制約に縛られることが予想されます。AGALなどのシェーディング言語で利用できるシェーダーのレジスタ数は非常に限られています。使用できる一時レジスタは最大8までに制限されます。シェーダーモデル4.0を使ってGLSLでレジスタをコーディングする場合は4096です。

また、Stage3Dシェーダーで利用できるオペレーションコードは最大200ですが、シェーダーモデル4.0では4096です。Stage3Dシェーダーは条件付き演算やループには対応していませんが、シェーダーモデル3.0と4.0は対応しています。

つまり、Stage3Dのシェーダーは、高度なハードウェアやシェーダーモデルに対応させたコーディングとは対照的に、非常にシンプルなプログラムを作る設計になっています。その結果、現在AAAゲームで見られるようなシェーダーを使った高度なエフェクトの中には、Stage3Dでは実行できないものも出てきます。

Stage3D: Stageの下のステージ

ここでは、Flashの表示モデル内のStage3Dについて説明します。

Flashは、Stageの概念を土台に設計されました。Flashで表示されるオブジェクトはすべて、Stageに追加されたDisplayObjectです。そのため、Stageは、表示されるすべての要素の入れ物です。また、すべての2Dアイテムのルートでもあります。

アドビがFlashに3Dレンダリングを導入した際、3Dに特化した特殊なステージ群を新たに追加しました。この特殊なステージを、Stage3Dと言います(図3を参照)。

複数の描画面を持つStage3Dステージは、メインのFlashステージの下層に配置されます。つまり、Stage3Dを使って開発した3Dコンテンツは、各Stage3Dの矩形のビューポートに合わせてレンダリングされ、通常の2DのFlashコンテンツはその一番上に表示されます。これによって、ハードウェアアクセラレーション機能を使って3Dシーンをレンダリングし、一番上のレイヤーに2Dコンテンツ(ゲームのUIなど)を表示させることができるため、2Dおよび3Dの2つの世界を最高の形で表現できます。UIは、カスタムのUI開発ツールではなく、Flashの各機能と柔軟性を活用して作成することができます。

Stage3Dは複数で使用することができます。各Stage3Dは、固有の矩形ビューポートを持っています。つまり、画面の一部に矩形の3D領域を置き、ほかの部分に別の3D領域を追加して、この上にFlash 2Dオブジェクトを配置することができます。複数のStage3DおよびStageVideoのレイヤーは、部分的(または全体的)に重ねていくことができます。ただし、この最初のリリース版のStage3Dは、レイヤー間のブレンドをサポートしていません。そのため、あるStage3Dレイヤーが別のStage3Dレイヤーを覆っている領域では、重なっている上の方のレイヤーしか表示されません。

ActionScriptでStage3Dを利用するには

ActionScriptでStage3D APIを利用するには、Stage3Dステージを宣言します。このステージは、メインのFlashステージの一部の配列として使用できます。

まず、次のようなコードを記述します。

var stage3D:Stage3D = stage.stage3Ds[0];

Stage3D APIの中心的なクラスは、Stage3Dそのものではありません。事実上のレンダリング表面であるContext3Dです。これには、3Dオブジェクトを描画する表面と、レンダリングを実行するために必要なメソッドとプロパティがすべて格納されます。

Context3Dは、Stage3Dを使う場合の中心となるエンティティです。

Stage3Dオブジェクトを使う際には、まず次のようにContext3Dを呼び出します。

stage.stage3Ds[0].addEventListener( Event.CONTEXT3D_CREATE, initStage3D ); stage.stage3Ds[0].requestContext3D(); ... protected function initStage3D(e:Event):void { context3D = stage.stage3Ds[0].context3D; }

頂点バッファーとインデックスバッファーを使ってジオメトリを定義するには

Stage3Dでは、描画する3Dシーンは、ジオメトリの集合(3Dメッシュ)で構成されます。各ジオメトリは三角形の集合で定義され、各三角形は頂点の集合で定義されます。

ジオメトリを描くすべての頂点は、頂点バッファーと呼ばれる構造の中にまとめます。この構造には、頂点に関係するすべてのデータを格納します。データを1つにまとめておくと、一括処理でGPUメモリにアップロードできるので便利です。

頂点バッファーは、次のサンプルのように定義できます。

var vertices:Vector.<Number> = Vector.<Number>([ -0.3,-0.3,0, 1, 0, 0, // x, y, z, r, g, b -0.3, 0.3, 0, 0, 1, 0, 0.3, 0.3, 0, 0, 0, 1, 0.3, -0.3, 0, 1, 0, 0]);

まず、Vectorにすべての頂点情報をまとめます。それぞれの頂点には、頂点位置だけでなく、頂点のプロパティを指定するその他のデータも含まれています。各頂点構造のこうした情報を頂点属性と言います。

頂点属性には、レンダリングパイプラインでジオメトリをどのようにレンダリングするかを指定したジオメトリ関連のデータを格納できます。一般的に、頂点の色やテクスチャの処理に関るUV座標は、頂点属性としてジオメトリに指定します。

上記のサンプルでは、vertices ベクターは4つの頂点を定義しています。各行は1つの頂点を示します。各頂点には頂点位置(各行の最初の3つ)と頂点の色(各行の残りの3つ)の2つの頂点属性が含まれています。

このベクターを作成したら、VertexBuffer3Dインスタンスを作成します。VertexBuffer3Dは、頂点バッファーをGPUメモリにアップロードするために、頂点バッファーのデータをStage3D APIにパッケージするクラスです。

コードサンプルは次の通りです。

// 6つの値を持つ4つの頂点 vertexbuffer = context3D.createVertexBuffer(4, 6); // オフセット0、4つの頂点 vertexbuffer.uploadFromVector(vertices, 0, 4);

Stage3Dでは、頂点バッファーを設定するだけではジオメトリを定義できません。Stage3Dでは3Dメッシュがインデックス化されたメッシュとして定義されるためです。

三角形を定義するためには、三角形の3つの頂点を指定する必要があります。そのため、ジオメトリの三角形を定義する場合は、頂点バッファーから頂点をインデックス化し、それらを三角形にアセンブリするための構造を別に用意する必要があります。この構造をインデックスバッファーと言います。

上記の頂点バッファーは4つの頂点を定義していることを踏まえると、2つの三角形で構成された矩形を定義することが目的であることが見えてきます。頂点バッファーから取得した4つの頂点だけでは、矩形を成す2つの三角形を定義することはできません。

そこで次のコードを使って、追加のインデックスバッファーを作成します。

var indices:Vector.<uint> = Vector.<uint>([0, 1, 2, 2, 3, 0]);

このコードサンプルでは、indices Vectorの最初の3つのエントリーである 0、1、2 は、1つ目の三角形が上記の頂点バッファーから取得した頂点0、1 および 2で構成されることを示しています。さらに、このインデックスバッファーは、頂点バッファーからの頂点2、3および0で構成される2つ目の三角形を生成します。

インデックスバッファーを使用すると、効果的に三角形を定義しジオメトリを作成できます。

頂点バッファーと同じく、インデックスバッファーもIndexBuffer3DというStage3D固有の構造にパッケージする必要があります。GPUにインデックスバッファーをアップロードするには、次のようにIndexBuffer3Dを使います。

// 6つの値を持つインデックスバッファを作成。3つの頂点で2つの三角形を定義する indexBuffer = context3D.createIndexBuffer(6); // オフセット0。6つの値すべて indexBuffer.uploadFromVector (indices, 0, 6);

ジオメトリの定義に必要な作業は以上です。