のぐそんブログ

暗いおじさんがシコシコ書くブログです。

3Dで使う行列の基礎について

行列とは

wikipediaで調べたところ行列とは以下のことらしいです。

数学の線型代数学周辺分野における行列(ぎょうれつ、英: matrix)は、数や記号や式などを行と列に沿って矩形状に配列したものである。行の数と列の数が同じ行列は行列の和(英語版)が成分ごとの計算によって与えられる。行列の積の計算はもっと複雑で、2 つの行列がかけ合わせられるためには、積の左因子の列の数と右因子の行の数が一致していなければならない。 wikipediaより

まったく意味がわかりません。 絵で表すとこんな感じです。

行列とは何をしているのか

やっている事自体はそんなに難しくなさそうです。

それぞれの値をかけて足していくだけです。 このとき、行列と掛ける側の要素数が同じである必要があります。

行列を何に使うのか

行列にはベクトルを掛けることができます。

それで、一体何につかうんだよ、という話ですが、 誤解を恐れないで言えば、ベクトルを変換する便利関数として使うことができます。

3Dでは主に座標変換に使用します。

行列を使って座標を回転する

2次元の回転をやってみます。式は決まっていて以下になります。

θは角度意味する記号。

例)2次元の座標(3,2)を90度回転させるとします。

回転行列に当てはめます。

ここで1点注意が必要なことがあります。 javascriptのMath関数でsin、cosを求める際に実際の正しい値と比べると誤差があります。 正しい値を求める場合はビット演算を使用して処理します。

◎Math.sinの誤差

角度 sin Math.sin
0 0 0
90 1 1
180 0 1.2246467991473532e-16
270 -1 -1
360 0 -2.4492935982947064e-16

◎Math.cosの誤差

角度 cos Math.cos
0 1 1
90 0 6.123233995736766e-17
180 -1 -1
270 0 -1.8369701987210297e-16
360 1 1

ビット演算使用して誤差を補正。

var sin =  Math.sin(angle * (Math.PI / 180));
sin = sin * 100 | 0? sin: 0;

var  cos = Math.cos(angle * (Math.PI / 180));
cos = cos = cos * 100 | 0? cos: 0;

参考:来世はなまけものになる予定なので今世はがんばる

回転行列で計算

座標にいれてみると回転できたことがわかります。

行列の種類

単位行列

正方行列の対角成分が1で、どんな値をかけ合わせても、返される結果がかわらない行列のこと。

転置行列

行と列を入れ替えた行列。3Dの座標変換などで出ててくるみたいです。

逆行列

なんらかの行列を適応した値に対して、適応した行列を無効にしてしまう行列です。

Kobito.xrjv39.png

MVP マトリックス

3Dの座標変換で頻繁に登場する行列です。

M ・・・モデル座標変換行列 V ・・・ビュー座標変換行列 P ・・・プロジェクション座標変換行列

モデル座標変換行列(ワールド変換行列)

仮想的な3次元空間の中での、描画されるモデルの位置や、回転、縮小拡大に関する情報を持ちます。

ビュー座標変換行列

3次元空間の中でのカメラの位置、カメラの向き、カメラの上方向を定義します。

プロジェクション座標変換行列

三次元空間上にあったデータをスクリーンに投影する為の情報。 スクリーンの縦横比やカメラの視野角、撮影範囲の手前の距離などがあたります。

Three.jsでのcameraのカメラ設定

Three.jsのカメラのプロパティはビュー座標変換行列と、プロジェクション座標変換行列に別れます。

 var p = {
            fovy: 60,  // プロジェクション
            aspect: width / height, // プロジェクション
            near: 0.1, // プロジェクション
            far: 10.0, // プロジェクション
            x: 0.0, // ビュー
            y: 0.0, // ビュー
            z: 5.0,  // ビュー
  };

//初期化プロパティはプロジェクション
var camera = new THREE.PerspectiveCamera(
        p.fovy,//視野角
        p.aspect,//アスペクト比,
        p.near,//カメラから視体積の手前までの距離
        p.far,//カメラから視体積の奥までの距離
);

//カメラの位置はビュー
camera.position.set(p.x, p.y, p.z);

//カメラの注視点はビュー
camera.lookAt(new THREE.Vector3(0.0, 0.0, 0.0));

まとめ

行列は便利な関数やツールだと思うようにすると、怖くなくなる。