Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

【WebGL / GLSL】ド文系だけど、行列とかラスタライズとか頑張って理解する

More than 1 year has passed since last update.

まだモテない

前回記事、【WebGL / GLSL】デザイナーにモテるためのWebGL入門(概念編)は多くの方にご覧いただき、とてもモチベーションになりました!

ただ、私はまだ概要をさらっと掴んだだけなので、デザイナーにはまだモテていません。
悲願の「モテ」のために、WebGLをさらに踏み込んで理解しようと思います!

おさらい

canvas上にグラフィックが描かれるまでの仕組みは、下記の通りでした。

  1. GLSL(シェーダー)にて、頂点の位置(座標)や色の情報を書く。
  2. JavaScriptのWebGL APIが、GLSLをコンパイルし情報を受け取る。
  3. WebGL APIが、canvasにグラフィックを描く。

これがあんまりにもざっくりしすぎでした。
もう少し詳しく見てみます。

3DCGの基本、「モデル」のはなし

モデル??
佐々木希?乃木坂46?大園桃子?
違います。
以下の画像が3Dモデルの一例です。

スクリーンショット 2019-05-26 22.49.56.png

3Dモデルをフリーでダウンロードできるサイト(Free 3D)から抜粋した画像です。
3Dのこいつを2D空間に表示させることが3DCGをWeb上に表す上でのゴールになります。
ところでこいつ、どうやってできてるんでしょう。

例えば、2Dの世界。
Adobe Photoshopを使う方ならわかるように、
すべての画像は、「ピクセル」という小さな四角形を最小構成要素にできています。
(ピクセルは画素とも呼ばれます。)

では3Dの場合の最小構成要素は何でしょうか?

3Dモデルの最小構成要素、ポリゴン!

p137.png
http://hikochans.com より)

ポリゴンってこいつ? 例のショックのやつ?
いいえ違います。違いますがあながち間違いじゃないかも。

ポリゴンとは、多角形のこと。
3DCGの世界では、ポリゴンは三角形が多いらしいので、以下三角形を前提にお話を進めます。
この最小構成要素である三角形がたくさん集まって、一つの3Dモデルができます。
この三角形が多いほどハイポリといい、3Dモデルもキレイになります。
逆の場合はローポリといい、モデルも荒くなります。

このポケモンのポリゴンも、よくみたら三角形が集まってできているように見えなくもない。。ね?

ポリゴンをもっと細くみていくと、「頂点」にたどり着く。

もっと細かくみてみます。
ポリゴンは三角形。では三角形はどうすればできる?
それは、三つ頂点を作って、それを線で結んでやればいい。
(当たり前だけど。。)

だから、三角形は三つの頂点でできているのだ。

この頂点というキーワードが大事になってくる。

私はエンジニアなわけだし、少しはJavaScriptでコードを書いてみよう。
例えば3DCGの最小構成要素であるポリゴンの頂点をコードで表したい。
難しく表現したが、要は三角形1個だ。
イメージとしてはこんな感じだろうか。

こんなかんじ?
const posisions = [x1, y1, z1, x2, y2, z2, x3, y3, z3];

頂点が三つだから。x座標・y座標・z座標のカタマリが3セット。
うむ。見辛い。
いまは三角形一つの内容だからいいけど、これが実際の3Dモデルにでもなったら。。

こういう大量の数字のセットを扱いやすくする数学の概念が行列の考え方だ。
ただ、ここでは詳細の理解は後回しにしよう。(わからんから
とにかく、その噂の行列とやらの力を借りて行列ライクに書いてみよう。

const posisions = [
  x1, y1, z1,
  x2, y2, z2,
  x3, y3, z3
];

見やすくなった!!

また頂点というのは、座標以外にも情報を持つ。
例えば法線(これも数学用語。要は面がどっちに向いているか、という情報)がある。

頂点の情報をいれる入れ物、頂点バッファ

前述の通り、1つの頂点を表現するのに、
位置法線などのたくさんの情報が必要。
この頂点に関する様々な情報(頂点さんのプロフィールみたいなもんだね)を格納しておく入れ物があります。

これをvertex buffer object、略してVBOという。
反町?それGTOな。

このVBO、詳細は次回にしますが、JavaScriptのWebGL APIで作成することができ、
WebGL APIを介しGPUに送ります。

①JavaScript側で頂点を定義して、
②空箱(VBO)つくって、
③それに頂点を梱包してシェーダーに輸送するわけだ!!

で、受け取ったシェーダーがごにょごにょして3Dを2Dにしてくれるわけだ。
次はその「ごにょごにょ」を詳しく見ていきます。

とりあえずまとめ。

まとめ

  • ディスプレイの最小構成単位がピクセルのように、3Dモデルには最小単位があり、それをポリゴンという。
  • よくあるポリゴンは三角形。当たり前だが、その三角形は三つの頂点で構成されている。
  • 頂点の情報は、位置だけではなく、色や法線の情報もある。
  • こいつらをいれておく入れ物を、VBO(vertex buffer object)という。
  • 数字のかたまりがたくさん登場。こいつらをうまく扱うための数学の技法が「行列」である。

3Dから2D、もう少し詳しく。

どんどん難しくなってきました。
次は3Dから2Dのグラフィックにする間に何が起きるかを勉強します。
前の記事で「座標変換」という言葉がでてきましたが、それと関係するのかな??

ゴールはピクセル(画素)に変換すること!

先ほどの章で、photoshopの最小単位はピクセルという話をしました。
このピクセルは、2Dの最小単位。
つまり、我々が見るディスプレイでは、
3Dのモデルはピクセルで表示されていなければならないのだ!

3Dのポリゴンから2Dピクセルに変換させることをラスタライズと呼びます。
難しいけど、つまりドット絵を描くってことだよね。
画像にしたらこんな感じだ。

DQ2P8qcUMAE3VK7.jpg
(和歌山大学システム工学部デザイン情報学科の床山准教授のTwitterより引用しています)

では、このゴールに至るまで、
WebGL APIやシェーダーはどんな役割を果たしていくだろうか?

JavaScriptからディスプレイまで

JavaScriptでプログラムを書いてから、
ディスプレイに表示するまでは、大まかに下記の流れ。
(これは自分で作った図なのですが、自信が無い部分なので間違いがあればご教示いただきたく。。)

スクリーンショット 2019-05-27 2.20.05.png

上記の一連の流れ(緑+赤)を、グラフィクスパイプラインと呼ぶ!
また、特にOpenGLで行われている赤色の部分をレンダリングパイプラインと呼びます。

(この図の色使い、弊社のデザイナーに怒られそう)

WebGL APIはソフトとハードの架け橋だ。

ブラウザとOpenGL、二つの項目に分けていることに注目してほしい。
その間をWebGL APIが繋いでいる。

前の記事で、Open GLの話題があった。
Open GLとは、グラフィック描画のための統一規格だ。
(OSとか、ハードウェアとかのレイヤーのおはなし)
これをWebのブラウザ上で動かすために,WebGL APIが入り口を提供してくれている。
(ブラウザとか、ソフトウェアとかレイヤーのおはなし)

WebGL APIは、OpenGLとブラウザを繋げてくれる架け橋だ!

(私はバックエンドではなくフロントエンドエンジニアだから、OS的な裏側の話はわからない。だからOpen GLはとっつきにくいハナシだ。ただ、ブラウザのことだったらわかる。JavaScriptは理解できるから、WebGL APIは理解できる。このAPIは、フロントエンドの僕らにOpen GLへの入り口を提供してくれているんだ!ありがとうWebGL API!!)

グラフィクスパイプラインの全体像

話を戻そう。
グラフィクスパイプラインの処理順番を見ていく。

0. JavaScriptで、WebGL APIを利用する準備をする。

JavaScript上で、3Dモデルの頂点情報(VBO【頂点バッファ】)を用意し、
WebGl APIを通してOpenGLに送る。(頂点シェーダーに送る。)
※前の章で出た話題だ!

1. OpenGL上で、頂点シェーダーが頂点情報を受け取り、座標変換をする。

この辺が最難関。
次の章で細かく見ていきます。

2. ラスタライズをする。

ピクセル情報に。

3. フラグメントシェーダーにより、ピクセルの色が決定される。

3Dモデルのときじゃなくて、ピクセルになってから色がつくんですね〜

4. ディスプレイ上に表示される。

これでゴール!!

とりあえず、全体の大まかな流れを見ていきました。
次回の執筆でコードを書こうと思っているのですが、
この流れまんまの書き方っぽいので、
こういう全体像は大事だと思いました。。

最後に、「頂点シェーダーが頂点情報を受け取り、座標変換をする。」あたりの話を噛み砕いてみたいと思います。

最難関。座標変換について少しでも掴みたい...!

この記事も最後です。
先ほど大まかな処理の流れをみていきましたが、
少しクローズアップして、

①頂点シェーダーが頂点情報を受け取り、座標変換をする。
②ラスタライズをする。

の部分を細かくみていきます。

ラスタライズするためには、頂点を「ごにょごにょ」しなければならない...!?

どうやらラスタライズ(ピクセルにする)するためには、
頂点はありのままの姿じゃダメみたいです。

なぜか?
それは、「3D空間は無限である」ことにヒントがあるようです。
無限である3D空間、
これを「本当にディスプレイに写したい範囲」に限定すること。

そうしないとラスタライズができないということなのです。

「ディスプレイに写したい範囲」に限定するって?

これを数学的に説明すると、
頂点座標にMVP行列をかけてやること
です。

ビジャ?イニエスタ?ポドルスキ?
それVIPな。神戸な。

MVP行列とは、以下のようなものです。

MVP=P\times V\times M

MはModel行列、VはView行列、PはProjection行列を表します。
そして、行列の世界では、掛け算の順番を入れ替えてはいけない決まりがあります。
なので、

M\times V\times P

じゃだめです。

じゃあなんでMVP行列っていうんですか??
紛らわしいなあ。

でもそれは、処理の順番がM→V→Pだから。
それぞれ詳しくみてきましょう。
でもその前に、行列ってのを少しでも理解したいからちょっとだけ。。。

行列って一体なんなのよ!?

線形代数の知識ゼロから始めて行列式「だけ」理解する

この記事でだいぶ「お気持ち」を掴むことができました。

私はど文系なので、全然間違った理解をしているのかもしれませんが、(予防線)
一応下記に理解を書いておきます。

座標変換ってなに??

文字通り、座標が変換されること。
意味がわからないのでビジュアルで例えると、
それは座標上のオブジェクトが拡大したり、回転したりすることだ。

(例えば、オブジェクトが2倍になったとき、要は座標全体が2倍になっていることと同じだ。
【座標が2倍になった = 座標が変換された】

座標変換は、ベクトル(行列)で表すことができる!

ベクトルとは、座標上に置かれた、原点から出る矢印
例えば、【終点がx座標・y座標】のベクトルを

\begin{pmatrix} 0 \\ 1 \end{pmatrix}

で表す。(高校で習った形と違うなあ。。まあいいや)

で、ここからが大事。
座標変換は「2つのベクトルがどう動くか」という情報「だけ」で表現できる。(2次元の場合)
らしい。

「どれくらい動いたか?」を判断するためには基準が必要なので、
基準を置きます。これを基底ベクトルと呼びます!
それは、(0,1)と(1,0)の二つ。

この基底ベクトルを動かす形で話を進めます。
例えば、
座標が2倍になったこと。
これは下記のベクトルで表すことができる。

\begin{pmatrix} 2 \\ 0 \end{pmatrix}\begin{pmatrix} 0 \\ 2 \end{pmatrix}

わかりやすいね。
二つのベクトルが2倍になったんだね。

そして、「(2,0)と(0,2)」なんていう書き方は面倒だ。
だから、行列が登場する。

\begin{pmatrix} 2 & 0 \\ 0 & 2 \end{pmatrix}

こう書くだけで、「座標が2倍になったんだな」と表すことができる。

これは三次元でも同じで、
例えば以下の行列は、画像のイメージだ。

20181031041824.gif

線形代数の知識ゼロから始めて行列式「だけ」理解するのページより引用。)

まとめ!
行列(ベクトル)というのは、座標変換そのものを表現している!!

MVP行列とかいって色々行列を掛け算してるけど、
あれは3Dモデルの頂点座標を、回転させたり拡大させたり縮小させたり頑張ってるわけなのですね。

そうして出来上がったものを、初めてラスタライズできるとのこと。
うん、まあわかったようでわからない。

とりあえず、行列の計算には便利なJavaScriptライブラリがあるらしいので、
計算は気にせずなんとなくの理解にとどめておきます。

で、結局MVP行列ってそれぞれ何なのよ??

Model行列(モデル変換)

モデルのローカル座標をワールド座標に変換すること。

  • ローカル座標 〜3Dモデルについて、原点からの相対座標のこと(原点からどれくらいー?の位置)
  • ワールド座標 〜ワールド(世界)に配置した際の座標。3Dモデルを世界のどこにおくか?という話。

要はスケールの小さいお話から大きいお話にしているわけね。

View行列(ビュー変換)

3Dモデルを写す「カメラ」がどこにあるかを決める。

Projection行列(プロジェクション変換)

三次元のどこからどこまで写すかを決める変換。
ここで、3次元を2次元に落とし込む、投影(Projection)という作業が行われる。

下記のようなイメージらしいが、とりあえずイメージだけ!!

38.gif
MVP行列による座標変換についてより引用)

これで無限に広がる空間から、限られた描画範囲が決まったからラスタライズされたわけですね!

まとめ

前回より深掘りした記事になりましたが、
予想以上に難解で心が折れそうになりました。
なぜならまだHello Worldしてないから。。(前回も言ってたなこれ)

次回は実際にコードを書いていきます!!
デザイナーにモテるために!!!!!!!!!!!!!!

初学者ゆえ、間違いがあればご教示いただけますと幸いです。

参考文献

MVP行列による座標変換について
3D 描画の基礎知識
線形代数の知識ゼロから始めて行列式「だけ」理解する
第1回目 WebGLの概念

yukiTTT
Frontend Developer 文系の営業出身ですが、がんばってます
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away