3Dの移動や回転、拡大・縮小する「行列」について学ぼう

2025年8月27日(水)
大西 武 (オオニシ タケシ)
第7回の今回は、ベクトル座標を移動したり、カメラの視線に合わせて変形したり、遠近法で変形したりする「行列」について解説します。

移動行列

「移動」と言うと平行移動だけを想像しがちですが、回転移動やスケーリング移動も入ります。平行移動と回転、スケーリング行列を計算して1つにまとめた行列のことを「アフィン変換行列」と言います。

回転にはX軸を中心に回転する計算、Y軸を中心に回転する計算、Z軸を中心に回転する計算の3つがあります。スカラの乗算は順番が違っても変化ありませんが、平行移動、XYZ軸回転、スケーリングの行列を乗算する順番により結果が異なることに注意してください。回転の順番によっても結果が変わります。

平行移動行列

平行移動とは、回転もスケーリングもせず真っすぐ頂点の位置が移動することです。計算方法は、図4のように次のサンプルコードの「translate」メソッドの通りです。translateとは「移す」という意味です。これも行列同士を乗算して計算します。

図4:平行移動行列の乗算の概要

・サンプルコード「lib」→「Matrix3D.js」
  translate(v) {
    var a00,a01,a02,a03,a10,a11,a12,a13,a20,a21,a22,a23;
    a00 = this.e[0]; a01 = this.e[1]; a02 = this.e[ 2]; a03 = this.e[ 3];
    a10 = this.e[4]; a11 = this.e[5]; a12 = this.e[ 6]; a13 = this.e[ 7];
    a20 = this.e[8]; a21 = this.e[9]; a22 = this.e[10]; a23 = this.e[11];
    this.e[0] = a00; this.e[1] = a01; this.e[ 2] = a02; this.e[ 3] = a03;
    this.e[4] = a10; this.e[5] = a11; this.e[ 6] = a12; this.e[ 7] = a13;
    this.e[8] = a20; this.e[9] = a21; this.e[10] = a22; this.e[11] = a23;
    this.e[12] = a00 * v.x + a10 * v.y + a20 * v.z + this.e[12];
    this.e[13] = a01 * v.x + a11 * v.y + a21 * v.z + this.e[13];
    this.e[14] = a02 * v.x + a12 * v.y + a22 * v.z + this.e[14];
    this.e[15] = a03 * v.x + a13 * v.y + a23 * v.z + this.e[15];
  }

【サンプルコードの解説】
単位行列に似ており、他に変化があるのは4行目だけです。
戻り値でMatrix3Dのインスタンスを返すのではなく、自分自身の4×4行列のプロパティ数値を計算しています。

X軸回転行列

X軸を中心に回転する行列の計算方法は、図5のように次のサンプルコードの「rotateX」メソッドの通りです。頂点のポイント自体が回転するわけではなく、X軸を中心に頂点の位置が回転するわけです。これも行列同士を乗算して計算します。

図5:X軸回転行列の乗算の概要

言うまでもなく図6のようにMath.sin(ラジアン)で「サイン」の数値を取得でき、Math.cos(ラジアン)で「コサイン」の数値を取得できます。ただ、大抵のプログラミング言語では「半径=1」としてsin、cosの値が取得できます。

図6:円とsin、cosの概要

・サンプルコード「lib」→「Matrix3D.js」
  rotateX(angle) {
    var s = Math.sin(angle);
    var c = Math.cos(angle);
    var a10 = this.e[4];
    var a11 = this.e[5];
    var a12 = this.e[6];
    var a13 = this.e[7];
    var a20 = this.e[8];
    var a21 = this.e[9];
    var a22 = this.e[10];
    var a23 = this.e[11];
    this.e[4] = a10 * c + a20 * s;
    this.e[5] = a11 * c + a21 * s;
    this.e[6] = a12 * c + a22 * s;
    this.e[7] = a13 * c + a23 * s;
    this.e[8] = a10 * -s + a20 * c;
    this.e[9] = a11 * -s + a21 * c;
    this.e[10] = a12 * -s + a22 * c;
    this.e[11] = a13 * -s + a23 * c;
  }

【サンプルコードの解説】
「angle」引数は「ディグリー」角度ではなく「ラジアン」角度です。
戻り値でMatrix3Dのインスタンスを返すのではなく、自分自身の4×4行列のプロパティ数値を計算しています。

Y軸回転行列

Y軸を中心に回転する行列の計算方法は、図7のように次のサンプルコードの「rotateY」メソッドの通りです。頂点のポイント自体が回転するわけではなく、Y軸を中心に頂点の位置が回転するわけです。これも行列同士を乗算して計算します。

図7:Y軸回転行列の乗算の概要

・サンプルコード「lib」→「Matrix3D.js」
  rotateY(angle) {
    var s = Math.sin(angle);
    var c = Math.cos(angle);
    var a00 = this.e[0];
    var a01 = this.e[1];
    var a02 = this.e[2];
    var a03 = this.e[3];
    var a20 = this.e[8];
    var a21 = this.e[9];
    var a22 = this.e[10];
    var a23 = this.e[11];
    this.e[0] = a00 * c + a20 * -s;
    this.e[1] = a01 * c + a21 * -s;
    this.e[2] = a02 * c + a22 * -s;
    this.e[3] = a03 * c + a23 * -s;
    this.e[8] = a00 * s + a20 * c;
    this.e[9] = a01 * s + a21 * c;
    this.e[10] = a02 * s + a22 * c;
    this.e[11] = a03 * s + a23 * c;
  }

【サンプルコードの解説】
angle引数はディグリー角度ではなくラジアン角度です。
戻り値でMatrix3Dのインスタンスを返すのではなく、自分自身の4×4行列のプロパティ数値を計算しています。

Z軸回転行列

Z軸を中心に回転する行列の計算方法は、図8のように次のサンプルコードの「rotateZ」メソッドの通りです。頂点のポイント自体が回転するわけではなく、Z軸を中心に頂点の位置が回転するわけです。これも行列同士を乗算して計算します。

図8:Z軸回転行列の乗算の概要

・サンプルコード「lib」→「Matrix3D.js」
  rotateZ(angle) {
    var s = Math.sin(angle);
    var c = Math.cos(angle);
    var a00 = this.e[0];
    var a01 = this.e[1];
    var a02 = this.e[2];
    var a03 = this.e[3];
    var a10 = this.e[4];
    var a11 = this.e[5];
    var a12 = this.e[6];
    var a13 = this.e[7];
    this.e[0] = a00 * c + a10 * s;
    this.e[1] = a01 * c + a11 * s;
    this.e[2] = a02 * c + a12 * s;
    this.e[3] = a03 * c + a13 * s;
    this.e[4] = a00 * -s + a10 * c;
    this.e[5] = a01 * -s + a11 * c;
    this.e[6] = a02 * -s + a12 * c;
    this.e[7] = a03 * -s + a13 * c;
  }

【サンプルコードの解説】
angle引数はディグリー角度ではなくラジアン角度です。
戻り値でMatrix3Dのインスタンスを返すのではなく、自分自身の4×4行列のプロパティ数値を計算しています。

スケーリング行列

拡大縮小するスケーリング行列の計算方法は、図9のように次のサンプルコード「scale」メソッドの通りです。頂点のポイント自体が大きくなるわけではなく、中心から見て頂点の位置が拡大縮小するわけです。これも行列同士を乗算して計算します。

図9:スケーリング行列の乗算の概要

・サンプルコード「lib」→「Matrix3D.js」
  scale(v) {
    this.e[ 0] *= v.x;
    this.e[ 1] *= v.x;
    this.e[ 2] *= v.x;
    this.e[ 3] *= v.x;
    this.e[ 4] *= v.y;
    this.e[ 5] *= v.y;
    this.e[ 6] *= v.y;
    this.e[ 7] *= v.y;
    this.e[ 8] *= v.z;
    this.e[ 9] *= v.z;
    this.e[10] *= v.z;
    this.e[11] *= v.z;
  }

【サンプルコードの解説】
戻り値でMatrix3Dのインスタンスを返すのではなく、自分自身の4×4行列のプロパティ数値を計算しています。

【コラム】「オンラインカジノ」

オンラインカジノの意味が分かりません。同じオンラインなら株式投資やFXなどの投資をしたら良いのに。まあ、同じくWebサイトを作っている身としては、何でもアリだとは思いますが。株式投資を「世界一面白いオンラインゲームだ」と言う人もたくさんいます。ただ、オンラインカジノは金を取るために何をしてくるか心配ですが、オンライントレードはトレーダーの味方になってくれていると信じています。

著者
大西 武 (オオニシ タケシ)
1975年香川県生まれ。大阪大学経済学部経営学科中退。プログラミング入門書など30冊以上を商業出版する作家。Microsoftで大賞やNTTドコモでグランプリなど20回以上全国区のコンテストに入賞するアーティスト。オリジナルの間違い探し「3Dクイズ」が全国放送のTVで約10回出題。
https://profile.vixar.jp

連載バックナンバー

開発言語技術解説
第7回

3Dの移動や回転、拡大・縮小する「行列」について学ぼう

2025/8/27
第7回の今回は、ベクトル座標を移動したり、カメラの視線に合わせて変形したり、遠近法で変形したりする「行列」について解説します。
開発言語技術解説
第6回

2D〜4Dで向きや大きさを持つ数字の集まり「ベクトル」について学ぼう

2025/8/8
第6回の今回は、向きや大きさを持つ数字の集まりである「ベクトル」について解説します。
開発言語技術解説
第5回

「WebGPU」でシェーダーを使って三角形を1つだけ描画してみよう

2025/7/17
第5回の今回は、WebGPUでシンプルなシェーダーを使って三角形を描画する解説をします。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています