煩雑さを避けるために、第1章ではあえて解説しなかった行列に関する補足的な事柄を本節では取り上げる。
A) 列優先 行優先
行列の表記には2つの方法がある。1つは
列優先(column major)、もう1つは
行優先(row major)である。
これまでにも、行列はさまざまな場面で使われてきたが、それらの行列は詳しくいえば列優先の形式に従って使われていたのである。例えば次の回転行列、平行移動行列に関していえば、
(cosθ0sinθ00100−sinθ0cosθ00001)(100a010b001c0001)左はy軸周りに角度
θだけ回転させる行列、右は
(a,b,c)だけ平行移動させる行列であるが、これらは列優先の形式で書かれているのである。
では、この2つの変換行列を行優先の形式で書いたものを以下に示す。
(cosθ0−sinθ00100sinθ0cosθ00001)(100001000010abc1)これらの行列だけでは違いがわかりにくいので、次の2つの行列を使って説明しよう。
(15913261014371115481216)(12345678910111213141516)左の行列が列優先の形で書かれているものとすれば、それを行優先の形にしたものが右の行列である。
列優先行列の1列目が行優先行列の1行目になっており、列優先行列の2列目が行優先行列の2行目になっている。3列目、4列目についても同様である。つまり、ある行列を列優先、行優先で表した場合、列優先行列の
i 列目が行優先行列の
i 行目に等しい (ただし、
4×4行列の場合は
1≤i≤4)。上の回転行列、平行移動行列についても列優先の形と行優先の形を比べれば、確かに列と行が入れ替わっているのがわかる。
行列の成分について見てみよう。以下の行列
Aを列優先行列とするとき、
A=(a11a12a13a14a21a22a23a24a31a32a33a34a41a42a43a44)Aを行優先の形で表した行列を
ATとすれば、
ATは次のようになる。
AT=(a11a21a31a41a12a22a32a42a13a23a33a43a14a24a34a44)このとき、
ATの
i行
j列目の成分は、
Aの
j行
i列目の成分に等しくなるが、このような行列
ATを
Aの
転置行列(Transpose Matrix)という。すなわち、列優先行列と行優先行列は転置の関係になっているのである(転置行列をさらに転置すると元に戻る。つまり、
(AT)T=A である)。
行列の積の進行方向についても、列優先と行優先では異なる。
列優先行列の積は今まで見てきたものであり、前節で使った例を再度以下に示す。
(100a010b001c0001)(cosθ0sinθ00100−sinθ0cosθ00001)(sx0000sy0000sz00001)(xyz1)=(x′y′z′1)
これは
(x,y,z,1) をまずスケールし、次に回転させて、最後に平行移動を実行するという順序になる。数式における積は、
右から左へ向かって進むが(右から左へ順に掛けていく)、これは実際の変換順序に対応している。
同じ変換を、行優先行列の積で記述すると以下のようになる。
(x y z 1)(sx0000sy0000sz00001)(cosθ0−sinθ00100sinθ0cosθ00001)(100001000010abc1)=(x′ y′ z′ 1)
行優先の形式では、ベクトルは縦並びの列ベクトルではなく横並びの行ベクトルとして表される。この数式は列優先の場合と同じく
(x,y,z,1) をまずスケールし、次に回転させて、最後に平行移動を実行するという順序になるが、異なるのは数式における積の進行方向である。行優先行列の積は、
左から右へ向かって進むのである(左から右へ順に掛けていく)。
一般には列優先の表記が広く使われている。学校教育における数学や物理で行列が使われる場合は、列優先であることが普通である。UnityやOpenGLなども列優先の表記である(DirectXは行優先である)。しかし、3DCGを解説するWebサイトや書籍の中でも行優先で表記するケースは少なくない。したがって、行列を扱った文章を読む場合にはその中で使われている数式が、列優先であるのか行優先であるのかを第1に確認する必要がある。一番簡単な確認方法は、ベクトルと行列の積が書かれていればその記述の仕方ですぐにわかる。
列優先であれば、ベクトルは列ベクトルであり積の一番右に置かれ、積の進行方向は右から左へ進む。
⋯(b11b12b13b14b21b22b23b24b31b32b33b34b41b42b43b44)(a11a12a13a14a21a22a23a24a31a32a33a34a41a42a43a44)(xyz1)
行優先であれば、ベクトルは行ベクトルであり積の一番左に置かれ、積の進行方向は左から右へ進む。
(x y z 1)(a11a21a31a41a12a22a32a42a13a23a33a43a14a24a34a44)(b11b21b31b41b12b22b32b42b13b23b33b43b14b24b34b44)⋯
行優先行列については、ここで見た違いの他に積の定義についても列優先の場合と若干の違いがあるが、行優先についてはこれ以上深くは立ち入らない。ただし、計算結果は列優先であれ行優先であれ、もちろん同じ結果になる。
この講義では、Unityを使用しているため文章中でもプログラムにおいても列優先である。
B) 積が可能になる条件
これまでに扱ってきた行列は、正方行列という行数と列数が等しい行列のみであった。これは以降の章でも同じで、行列といえば正方行列のみを用いる。
正方行列だけを扱ってきたために特に触れてこなかったが、実は行列の積には積が可能になる(定義される)場合とそうでない場合とがある。ここでは、その点について解説しておこう。
以下の解説は
列優先行列の場合について述べたものである。
行列
A、
Bの積
ABが定義されるためには、「
Aの列数と
Bの行数が等しい」という条件を満たしている必要がある。この条件を満たさない2つの行列の積は定義されない、つまり、積が可能ではないのである。
具体的には、
Aが
m×n行列、
Bが
n×l行列のとき、積
ABは定義され、その結果は
m×l行列になる。すなわち、
AB=(⋯⋯⋯⋮m×n⋮⋯⋯⋯)(⋯⋯⋯⋮n×l⋮⋯⋯⋯)=(⋯⋯⋯⋮m×l⋮⋯⋯⋯)
である。
そのとき、
Aの成分を
aij(
i行
j列目の成分)、
Bの成分を
bij、積
ABの成分を
cijとすれば、
cij=n∑k=1aikbkj(1≤i≤m , 1≤j≤l)である。
(例)
(1)
6×4行列
Aと、
4×3行列
Bの積
AB (積は
6×3行列)
AB=(⋯⋯⋯⋮6×4⋮⋯⋯⋯)(⋯⋯⋯⋮4×3⋮⋯⋯⋯)=(⋯⋯⋯⋮6×3⋮⋯⋯⋯)
(2)
4×3行列
Aと、
3×5行列
Bの積
AB (積は
4×5行列)
AB=(⋯⋯⋯⋮4×3⋮⋯⋯⋯)(⋯⋯⋯⋮3×5⋮⋯⋯⋯)=(⋯⋯⋯⋮4×5⋮⋯⋯⋯)
(3)
4×4行列
Aと、
4×1行列
Bの積
AB (積は
4×1行列)
AB=(⋯⋯⋯⋮4×4⋮⋯⋯⋯)(⋯4×1⋯)=(⋯4×1⋯)前節では行列の積の特殊な場合として、
4×4行列と4次元ベクトルの積について述べたが、3番目の例を見ればなぜ行列とベクトルの積が可能になるのかがわかるだろう。