実現までのステップ

優れた作品を作れるようになるには、ステップアップで理解を深めていくことが大事です。

(以下は、あくまで本ページ筆者の個人的な区分分けです。業界的にこのような理解で捉えられているわけではありません)

静止画としての追求

1. 3Dモデルの読み込みと表示

 ここでいう3Dモデルとは、次のような要素を備える3Dデータを差しています。

  • 人間キャラクターや敵のモンスターなど、3Dゲーム表現を成り立たせるポリゴンメッシュデータ
  • 肌や服の質感を再現するテクスチャ(模様)画像がポリゴンメッシュに張られている。
  • 動きなどのアニメーションが設定されている。

 これらのデータは、デジタルアーティストが主に3Dソフトを使って制作します。

 制作された3Dデータは、プログラムで読み込み、3D APIで表示する必要があります。ポリゴンメッシュの形状をWebGLで画面に表示するためには、次のような工程をプログラムする必要があります。

  • 3Dモデルデータをブラウザに読み込ませ、JavaScriptで解析し、ポリゴンデータを抽出してメモリ上に展開します。
  • メモリ上に保持したポリゴンデータを、WebGLが直接扱えるデータ形式に変換して、WebGL(GPU)に渡します(WebGLのAPIを適切に呼び出す必要があります)。
  • WebGL(GPU)に対して、描画命令を送る(描画準備と描画、それぞれでWebGLのAPIを適切に呼び出す必要があります)

 この過程で、シェーダープログラムというものも作成し、WebGLに渡さなければならないのですが、一旦ここでは脇に置いておきます。

 これが3Dゲームを作るための、最初の基礎となります。

2. テクスチャの表示

 テクスチャ(Texture)とは、ポリゴン(三角形)に貼りつける画像のことです。

これもWebGLのAPIを適切に呼び出して、画像をGPUに転送し、描画する三角形に対して適用する処理を記述する必要があります。

 現在の3Dゲームでは、肌や服などの見た目を模した「模様としてのテクスチャ」(ディフューズテクスチャやベースカラーテクスチャと呼ばれます)の他に、より高度な表現をするための数学的な情報を記録した特殊なテクスチャ(法線テクスチャなど)を利用することも増えてきました。

3. ライティング(シェーディング)計算

前項、前々項のポリゴンとテクスチャだけでも、相応の見栄えがする表現が可能です。

日本のゲームなどでは、陰影のディティールにさほどこだわらないアートが好まれることもあり、クールなポリゴン造形とディフューズ(模様)テクスチャだけで十分な場合もあるでしょう。

しかし、さらに実体感のある3D表現をするためには、「物体が光に照らされることでおきる陰影」を計算により表現することが必要です。

光源の方向を変えれば、キャラクターの全身の陰影のグラデーションがリアルタイムに様変わりする。イラストなどの2D表現手段では、今まで考えられなかったことです。

さて、このライティング計算をできるようになるには、光学の知識を元にした勉強が必要になってきます。つまり、ここから数学の知識が必要になってきます。

実は、WebGLのベースとなったOpenGLの初期バージョンでは、この光の計算を(種類は限られていたものの)パラメーターさえ伝えれば、自動的に計算してくれる時代がありました1

しかし、現在のOpenGLやWebGLにはこの固定シェーダー機能がありません。そもそも現在のGPUハードウェア自体にもそれらの固定機能はありません。柔軟性に欠けるため、ある時期から取り除かれてしまったのです。

その代わり、現在のGPUには「プログラマブルシェーダー」という機能が搭載されています。

これは、プログラマがGPUに対して専用のカスタムプログラムを送信し、GPUがそのプログラムを実行することで、プログラマが意図した任意の処理を実現するものです。

今日のCGプログラマは、このシェーダーというカスタムプログラムの中に光学の計算を記述することで、複雑な陰影をGPUに計算させます。

ちなみにCGの世界においては、日本語としては同じ発音である「陰(シェード)」と「影(シャドウ)」を明確に区別します。以下のサイトの記事に、わかりやすい図解説明が載っています。

http://news.mynavi.jp/column/graphics/020/ 

4. シャドウイング(影)&物理ベースレンダリング(PBR)&グローバルイルミネーション(GI)

前項のライティング計算(というか、前項では「シェーディング」(つまり影(シャドウ)抜き)の意味で話していました)。実は、光の計算といっても、その内容の高度さによって、いくつか段階や種類があります。

1つ目は、俗に「古典シェーディング」と呼ばれる、計算は単純だが、現実世界と比べてそこまでリアルな結果にはなってくれない手法です(それでも、パラメーターを巧みに調整すれば、まぁまぁいい感じにはなります)。

2つ目は、「シャドウイング(影計算)」です。前項でも言及した通り、これは「シェーディング」とはまた別に、専用に処理する必要があります。「古典シェーディング」では、描画命令を受けて描画される各3Dモデル、それぞれ単体で(独立して)光(直接光)の計算をすればよかったのです。しかし、シャドウイングは、描画対象となる各3Dモデルたちが、それぞれ「影を落とす側」と「影を落とされる側」に、立場として明確に分かれます。その判断をするに当たり、互いの位置関係などから判定処理をしなくてはいけません。

ところが、GPUによる計算は、基本的には、3Dモデル同士の相互関係を直接は処理できません(無理すればできるのですが、まぁ、いっぺんには難しい、と考えてください)。そのため、影の計算には、特別な方法で、段階的な処理が必要となるのです。

リアルタイムCGにおける「影計算」は、それだけで大量に書籍や論文ができてしまうほどの、深いテーマです。しかし、オーソドックスな方法というものは割と確立されています。今後、そこらへんも機会があれば解説していきましょう。

3つ目は、「物理ベースレンダリング」と呼ばれるものです。これは、現実世界の光学などの物理法則をできるだけ満たすように考慮された手法です。ここまで行けると、局所的には「え、すごい!これ、写真じゃないの?」感を出せるようになります。

4つ目は、「グローバルイルミネーション」というものです。これまでの説明で、なんとなく感じている方もいらっしゃると思いますが、WebGL(他の3D APIもそう)をはじめとするリアルタイムCGでは、基本的には直接光しか計算できません。現実世界の光は、色々な物体にぶつかっては反射して、反射した光がまた他の何かにぶつかり、また反射を繰り返して、私たちのカメラや目に入ってきます)。「これらの光(間接光の影響)を、直接光の計算とは別扱いにはなるが、きちんと考慮しよう」というのがグローバルイルミネーション(GI)になります。

前項の「ライティング(シェーディング)計算」は、実質的に本項の上記1つ目「古典シェーディング」のことを意図して説明していました。
これに加え、シャドウイング(影)を加えることで、より物体の存在感を引き立てることができます。

最新のゲームCGなどでは、さらに「物理ベースレンダリング」や「グローバルイルミネーション」の導入が進んでいます。しかし、「古典シェーディング」や、シャドウイングの基礎までならともかくとして、 この「物理ベースレンダリング」や「グローバルイルミネーション」は、その理論や実装が、かなりの難関と言えます。このレベルができれば、「その人はもう業界人としてどっぷり腰まではまっている」と言ってしまっても良いくらいです。ここまでくると、もはや「WebGLという3D APIの取り扱い」というレイヤーをはるかに超えた、より上層のソリューションを扱っています。とは言え、そうしたことを扱える下地としてのWebGLでもあるのです。

ポストプロセスや、パーティクル、ボリュームなどの特殊表現

ポストプロセスとは、後処理のことです。つまり、全ての3Dモデルの描画(ライティング処理含む)を終えてできた、2Dイメージに対して、後処理を加えることです。2D処理と言いつつも、リアルタイムCGにおいては、深度値(物体の奥行き値)などの情報が自然とGPUに残ったりするので、かなり柔軟な加工が可能です。

具体的には、モーションブラー(高速に動く物体を「表示ブレ」させる効果)、グレア(眩しいくらいに明るい部分に、光が溢れ出す効果を入れる)、被写界深度(カメラで、ピントが合っていない箇所にボケができるあの表現)などがあります。いずれも、より現実感を出すために、必要となる要素です。

パーティクルは、火花や煙などを表現する一手法です。ボリュームは、半透明のモヤモヤしたもの(煙や水蒸気、もや、霧など)を指しています、これらは光を散乱させる効果があるのですが、それを計算して表示することを、ボリュームレンダリングと呼びます。

このように、CGにおいては(特にリアルタイムCGにおいては)、表現のために、様々な処理アプローチを併用して、リッチかつリアルな表現を作っていきます。奥が深いですね。

動き・インタラクションの追求

まだあります。これまでは、あくまで静止画の世界での話です。実際は、CG映像は動きます。動きも考えなければならないわけです。主な要素をあげていきます。

1. 3Dモデルの表示位置の取り扱い

3Dモデルの表示位置を決定するものはなんでしょうか?いくつか要素があります。

・三角形ポリゴンの頂点データの位置座標

・3Dモデルが階層管理(シーングラフと呼ばれます)されていた場合、各階層に設定されている(頂点データの位置座標に対する)変換行列

・シェーダー内での位置座標の動的な変更

主に、この3つでしょう。2つ目については、「平行移動」「回転」「拡大縮小」の3種類の位置変更操作を表現する、4行4列の行列(変換行列)を用います。「三角形ポリゴンの頂点データの位置座標」 は4要素のベクトルで表現され、このベクトルに変換行列 を掛け算することで、頂点位置座標が、そのシーングラフ上の別の階層構造に移動(写像)される(別の階層構造から見た時の、座標値になる)ことになります。ここまでの説明でよくわからなかったとしても、なんとなく「そういうものなのか」と軽く心に留めておいてください。

2. 階層アニメーション

前項の「シーングラフ上の各階層に設定されている変換行列」をそれぞれ変更することで、階層アニメーションを行うことが可能です。

例えば、親階層には物体Aが、子階層には物体BとCが合ったとします。親階層が右に1メートル移動しました。子階層のBは下に1メートル移動しました。子階層のCは特に動きませんでした。この場合、世界全体の視点で見ると、自身としては動いていなかったはずの物体Cも、右に1メートル動いているのです。なぜなら、右に1メートル移動した親階層に自分が属しているからです。物体Bも同じ理由で右に1メートル動いており、その上でさらに、自分自身が下に1メートル動いています。つまり、物体Bは世界全体からすると、斜めに動いていることになりますね。

この仕組みを使えば、かなり凝った動きができることがわかるでしょう。大型の乗り物や、恒星・惑星・衛星の動きなど、様々なことに応用が可能です。

3. スケルタルアニメーション

階層アニメーションを持ってしても、表現できないアニメーション表現があります。それは、人間や動物の柔軟な動きです。一応、人間も骨で動いていますから、単純化すれば階層アニメーションで処理できなくもありません。それをやっていたのが、初代プレイステーション時代の3DCGです。曲がった腕とか、つなぎ目がぶっちり切れていましたね。現実なら、曲げた部分の皮膚が伸びたり縮んだりするはずです。

それを処理するのが、スケルタルアニメーション、別名「スキニング」です。

これは、キャラクターの体にスケルトン(骨階層)を設定し、キャラクターの各ポリゴン頂点に「何番と何番の骨が動いたら、自分はそれぞれこの割合で位置の影響を受ける」というウェイト値という値を設定しておきます(CGアーティストの方、特にモデラーの方はピンとくるかもしれません。3Dソフトで「ウェイト調整」をやると思います。影響度合いをひたすら塗り塗りして調整しますよね。あれです)。

キャラクターモデルの各頂点は、アニメーション時に、自身に設定されたそのウェイト値を考慮して、それら複数の骨の変換行列からの影響の受け方の割合をコントロールしてもらうわけです(大抵、最近だとこの処理はGPUの頂点シェーダーで行われるケースが多いです)。

こうして、腕を曲げても、いい感じに皮膚が伸び縮みする、現実と同じような自然なキャラクターアニメーションが可能となります。これがスケルタルアニメーションです。

WebGLでも、もちろんこのスケルタルアニメーションを実現できます。ただし、スケルタルアニメーションに必要な情報を3Dソフトで作り込み、それを適切なファイルフォーマットで書き出し、ブラウザ側でその情報を正しく解釈し、頂点シェーダーで(別にJavaScriptでやってもいいですが)、適切に計算させなければなりません。慣れないうちは、試行錯誤が続くでしょう。全てのピースがきっちりハマって動作しないと、おかしなぐんにゃりした形に大変形したりして、正常動作にこぎつけるまでに、非常にストレスフルな経験をすることになります。でも、ご心配なく、このサイトでは、いずれglTFファイルフォーマットを利用した、WebGLによるスキニングアニメーションの実装について、解説記事を書く予定です。

4. 物理シミュレーション

高校で物理の授業を受けたことはありますか? 力学という学習分野があったと思います。あんな気が遠くなるような話が、実はCG表現で活用されています(人生、無駄な勉強などないものですね)。

いわゆる力学と言っても、剛体(変形しない硬い物体)の力学と、弾性体(変形する柔らかい物体)の力学だと、計算で考慮すべき事柄のボリュームが結構違います(後者の方が難しく、計算量が増えます)。最近だと流体力学なども入ってきつつあります。そして、最近はより自然なアニメーションにするために、前項のスケルタルアニメーションと物理シミュレーションを組み合わせたりもします。

色々と頭が痛くなってきますね。WebGLという3D APIから、だいぶ遠いところまで来てしまいました。しかし、こうした物理計算の一部は、GPUで計算させることが可能です。そのためには、WebGLの仕様をよく熟知している必要があります。そう、もはや今の最新CGは、あらゆる数学や物理学、コンピューターサイエンスを結集させた、総合芸術と言えるのです。

5. AI(人工知能)

最近、機械学習などの話題が花盛りです。もちろんそういう要素も最近のゲームでは入って来つつありますが、機械学習・深層学習のブームが到来するずっと前から、ゲームの世界では狭義(というかゲーム業界独特の意味での)のAI開発が盛んでした。まず、ゲームの場合、敵キャラが大抵いますね。彼らは、いい感じに主人公たちを追って来たり、武器を投げてこなくてはいけません。主人公を追って来るためには、つまり3D空間上の主人公の位置へ到達するには、どういう経路で、障害物をどう避けて、移動していけばいいのか、そうしたことを敵キャラが考えなければなりません。また、場の条件が変わったら、戦いを放棄して、逃げたりすると、ゲームとしての演出効果があるでしょう。ステート(状態)をもたせ、複数の状態の間を、遷移させたりもします。こうした狭義のゲームAI、群衆AI、そして最近、隆盛している機械学習など、新たな試みが今後もゲームを始めとしたインタラクティブなCGでは、なされていくはずです。

VRへの対応

 最近では、VR(バーチャルリアリティ)に対応する3Dコンテンツが増えてきました。OculusとかPlayStatoion VRとか、聞いたことありませんか? ヘッドマウントディスプレイという装置を顔にかぶる、あれです。
360度の方向を見渡せる、または歩いて対象の3D物体に近づくことができる、既存のCGにそれらの要素が加わっただけではありますが、その臨場感たるや、普通の液晶ディスプレイで見るのとは雲泥の差です。
まるでその世界にワープしたかのような感覚があり、ゲームはもちろん、様々な分野での応用が期待されています。
WebGLでも、そうしたVRは可能になりつつあります。正確には、WebVRという規格のAPIを組み合わせて実現します。それらについても、いずれ本コンテンツでカバーしていくこととしましょう。

これらをWebGLで実現しよう

 これまで説明してきた各技術は、直接はWebGLとの関連が薄いものもかなりあります。基本的に、WebGLを始めとする3D APIは、三角形に画像を貼って、色を加工して、それを大量に画面に表示しまくることが本分です。そうした低レベル、しかし超高性能(大量処理が可能)なGPUを駆使する力を、うまいこと飼い慣らして、これまで説明して来た総合芸術を実現するためにひたすら使役していくのです。もし、WebGLやGPUがこの世に存在せず、全てを自分でC++でソフトウェア実装せざるをえない世界だったら、世の中は今のようなエンターテインメントで満ち溢れてはいなかったでしょう。

今の世の最先端のCG表現も、やがてはWebGLでできるようになっていきます。その際に必要なのは、これまで説明して来た「絵作り」「動き作り」のアプローチのセンスと、それらを実装できる理論への習熟です。奥が深いですね。

あまり気負わず、最初はできるところから始めて行きましょう。幸い、WebGLは、JavaScriptでコンパイルもせず即座に実行して結果を確かめられ、エラーが起きてもすぐにコンソールにエラーを吐いてくれます。一昔前、C++とDirect3Dを使って、重量級の開発を余儀なくされていた頃とは、はっきり言って環境としては雲泥の差。まるで天国のような開発環境です。

興味ある人なら、チャレンジしない手はないと思います。

このサイト「WebGL Learning Path JP」は始まったばかりですが、そうした皆さんのアイデア・夢を実装できるようになるまでのラーニングパスを、少しずつ繋いでいければ幸いです。

Footnotes

  1. 現在の「プログラマブルシェーダー」と対比して「固定シェーダー」と呼ばれます。