鳳 技術部

個人製作とか趣味とか備忘録なあれこれ

webGLで行列計算をしようとした

webGLでの行列

これまでの経験と今回したこと

  1. 過去にライブラリを用いてwindows(DirectX環境)向けにコードを書いたことがあり、そのときに行優先、列優先の話を聞いたことがあった。
  2. ただ、計算内容の詳しいことはやってなかったので、今回調べた。

今回知ったこと

1. そもそも行優先、列優先が2種類あった

・ データの格納方法としての行優先、列優先
前提 1. すべてのデータはメモリ上に格納される
前提 2. メモリは論理的には1列に並んでいる

この二つの前提から1つの結論が導かれる。

行列には行と列とが存在するが、どちらを優先してメモリ上に並べるかを決める必要がある、ということである。

つまり 4x4行列 が次のように存在した場合

m11  m12  m13  m14  
m21  m22  m23  m24  
m31  m32  m33  m34  
m41  m42  m43  m44  

行優先の場合

var mat = new Array(16);

mat[0] // m11
mat[1] // m12
mat[2] // m13
...
mat[15] // m44

列優先の場合

var mat = new Array(16);

mat[0] // m11
mat[1] // m21
mat[2] // m31
...
mat[15] // m44

という風になっている。

GLでは列優先でデータが入る。
・ 計算方法としての行優先、列優先

注意する点はいくつかある。

まず、行優先であれば後ろにかけていくことで計算できるが、列優先では前にかけていくことが必要になる。 また、それぞれの場合で、標準で存在するベクトル型は行優先なら横ベクトル、列優先なら縦ベクトルとして計算しているものと思われる。

例として ローカル座標、ワールド行列、ビュー行列があるものとして、最終的な位置pを求める式は

行優先の場合

 p = Local * World * View 

列優先の場合

p =  World * Local;
p =  View * p 

それぞれ、pから座標を取る。

もっともwebGLjavascriptから触るので適切な関数を作成する必要があるが

GLでは列優先でデータが入る。

2. 行列計算においてOpenGLとDirextXの互換性とWebGL

さて、1.に書いたとが、GLでは常に列優先である。 もっとも、データを転送する際に格納方式が異なるのは困ると思うが、開発するシステム内で適切に管理できるならば、別に計算を行優先ですべて自前で書いてしまっても問題はなさそうである。

すべて自前で書くというのは問題ではないかという突っ込みはおいておく

そのため、ネイティブアプリ開発においてシェーダーに転送する時点で適切に変換できるなら(オーバーヘッドに目を瞑るとして)GLとDirectXに対して共通の処理から得られたデータを転送するのは不可能ではなさそうである。

また、webGLはGLではあるものの、計算等は内部に存在しないため、外部のライブラリを活用するか、自前で作成することが必要になるため、これまでwindowsDirectXしか触っていなかった人がweb開発をする、となった際に、それまでとおなじ感覚で作業したければ、行優先で計算して、列優先のデータ配置で転送するというのは大いにあるかもしれない。

ただし、データを転送する先であるシェーダー(GLSL)は列優先でデータを持ち、また列優先で計算するので、シェーダーとの記述方法をそろえる意味でも列優先で処理するべきかも知れない。

まとめ

OpenGL DirectX WebGL HLSL(DirextXのシェーダ) GLSL(GLのシェーダ)
データ 列優先 行優先 列優先 列優先 列優先
計算 列優先 行優先 数学部分は別途用意 行優先 列優先