サイトトップ

Director Flash 書籍 業務内容 プロフィール

Adobe Flash非公式テクニカルノート

変換行列を数学的に捉える

ID: FN0811001 Product: Flash Platform: All Version: CS4 and above/ActionScript 3.0

1. 行列とは
行列」とは、数を行と列の長方形に並べて、その演算規則を定めたものです[*1]。並べた数値全体を()または[]で括って示します。たとえば、2行×2列の行列は、つぎのように書き表します(図001)。なお、行と列の数が等しい行列は、「正方行列」といいます。

図001■2行×2列の正方行列
図001

行列は、一定の決まりにしたがって並んだ複数の数値を、まとめて計算できることが便利な点です。行列の中のひとつひとつの数は、「成分」または「要素」と呼ばれます。

[*1] 行列の機能から見た捉え方については、「行列と線形写像」が参考になります。


2. 行列の乗算
行列は、足し算や引き算のほか、掛け算ができます。加減算が対応する要素同士を足し引きすればよい[*2]のに対し、乗算のやり方は少し変わっています。座標空間を扱う変換行列では、掛け算が重要な役割を果たします。

たとえば、平面のxy座標を2行×1列の行列(列ベクトル)[*3]で表すと、2行×2行の行列と掛け算ができます。その場合、掛けられる左の行列の行と、掛合わせる右の行列の列とを、つぎのように計算します(図002)[*4]。 結果は、2行×1列の行列になります。

図002■2行×2列の正方行列と2行×1列の行列との乗算
図002上図

図002下図

上図002で見たとおり、行列の乗算では、掛合わせるふたつの行列の行数と列数がともに等しい必要はありません。しかし、掛けられる左の行列の列数と、掛合わせる右の行列の行数は等しくなければなりません(図003上図)。したがって、行列では乗算の交換法則は成立たず、掛合わせる順番を入換えると計算ができなかったり(図003下図)、できたとしても結果の行列の数値は変わります。

図003■乗算では左の行列の列数と右の行列の行数は等しくなければならない
図003上図

図003下図

行数×列数の同じ正方行列同士を乗算すると、その結果も同じ行数×列数の正方行列になります(図004)[*5]。したがって、同じ行数×列数の正方行列は、いくつでも掛合わせることができます。

図004■正方行列同士の乗算結果は同じ行数×列数の正方行列になる
図004

以上述べた中で、行列の乗算における重要な特徴は、つぎのふたつになります。

    【行列の乗算の特徴】
  • 順序を変えると結果が変わる
  • 正方行列同士ならいくつでも掛けられる

いくつでも掛けられて、その順序を変えると結果が変わる、というと何かを想い起こさないでしょうか。ビットマップ画像に適用するフィルタと同じ性質です(図005)。実際、フィルタの多くは、内部的に行列を使って処理していると考えられます。

図005■フィルタはいくつでも掛けられて順序により効果が変わる(Flash CS4の[フィルタ])
図005

[*2] したがって、加減算する行列同士の行と列の数は、どちらも互いに等しくなければなりません。

[*3] 1行または1列の行列は、それぞれ「行ベクトル」または「列ベクトル」と呼ばれることもあります。

[*4] 掛けられる左の行列の行と、掛合わせる右の行列の列をベクトルと考えて、それぞれ(a, c)と(x, y)とすれば、乗算結果の要素ax+cyはふたつのベクトルの内積になります。ベクトルの内積については、拙著『ActionScript 3.0プロフェッショナルガイド』M.5.4「ベクトルの内積」(p.625〜)あるいはKIT数学ナビゲーション「内積」などをご参照ください。

[*5] 2行×2列の正方行列AとBを掛け算したときの具体的な計算結果は、以下のとおりです。詳しくは、拙著『ActionScript 3.0プロフェッショナルガイド』M.6「行列」(p.629〜)あるいは「行列」などをご参照ください。

なお、前出注[*4]のように掛けられる行列の行と掛ける行列の列との内積と捉えると、つぎのように表すことができます。


3. 変換行列とMatrixクラス
変換行列は正方行列で、座標と乗じて値を変換します。平面のxy座標を2行×2列の正方行列に掛合わせると、拡大・縮小と回転およびそれらの組合わせとしての傾斜が可能になります(表001)。

表001■正方行列との乗算による座標の結果
変換 変換結果
デフォルト
拡大・縮小
回転
傾斜

ただし、注意しなければならないのは、2行×2列の正方行列にxy座標の列ベクトルを乗じた場合、その座標変換は配置された座標空間の原点つまり親タイムラインの基準点が起点になるということです。いわば[自由変形ツール]で、変形点を親タイムラインの基準点に置いて変形するのと同じです(図006)。親タイムラインでなく、たとえば自分の基準点を中心に変換することはできません。さらにいえば、単純な座標の移動(平行移動)も、2行×2列の正方行列では実現できないのです。

図006■配置されたタイムラインの基準点を起点に変形
図006

この平行移動ができるようにするため、変換行列はひとつ列を増やすことになります。正方行列でなければ複数の乗算ができませんので、行数も列数に等しくします。また、掛合わせる列ベクトルも同じ行数にしなければなりません。2次元座標空間を扱うMatrixクラスは、変換行列をつぎのように定義します(図007上図)[*6]

図007■Matrixクラスの変換行列と列ベクトル
図007上図
図007下図

列ベクトルの3行目の要素を1にしましたので、乗算した結果の列ベクトルのxy座標にはそれぞれ追加したtxとtyの値が加算されます(図007下図)[*7]。つまり、平行移動したいピクセル数を、このtxとtyに指定すればよいということです。また、正方行列にするために加えた変換行列の3行目は、「0 0 1」という値に固定されていますので、乗算結果の列ベクトルの3行目の要素はつねに1になります。ですから、さらに別の変換行列と乗算することができます。

これで、拡大・縮小や回転、傾斜に加えて、座標の平行移動ができるようになりました。すると、親タイムラインの原点でなく、たとえばインスタンスの基準点を中心に変換することも可能です。そのときは、インスタンスの基準点を原点と一致するように移動し、拡大・縮小や回転などの変換を行ったうえで、初めとは反対方向に移動してもとの位置座標に戻せばよいのです。

Matrixクラスの変換行列は、固定の3行目を除く6つの要素をプロパティとして設定できます[*8]。また、平行移動や拡大・縮小、回転の変換を加えるためのメソッドも用意されています[*9]。Matrixクラスのプロパティやメソッドについて詳しくは、オンラインヘルプの[ActionScript 3.0コンポーネントリファレンスガイド]で「Matrix」の項をご覧ください[*10]

[*6] 2次元座標空間の列ベクトルは、ActionScriptのクラスに定義されていません。3次元座標空間では、後述のVector3DクラスがFlash Player 10以降に実装されます。

[*7] たとえば、図007下図で変換行列の要素aとdを1、bとcを0にすれば、変換結果の列ベクトルの1行目と2行目つまりxy座標の値は(x+tx, y+ty)となり(図008)、もとの列ベクトルのyx座標を水平にtx、垂直にty移動することになります。

図008■Matrixクラスの変換行列によるxy座標の移動
図008

[*8] プロパティ名は、前掲図007に示した変換行列の要素の変数名と同じです。つまり、Matrix.aMatrix.bMatrix.cMatrix.dMatrix.txMatrix.tyとなります。

これらのブロパティを使って長方形のインスタンスを自由な平行四辺形に変換するサンプルスクリプトは、Adobe Flashデベロッパーセンターに「Matrixクラス − 変換行列」という記事として寄稿しました。

[*9] 平行移動はMatrix.translate()、拡大・縮小がMatrix.scale()、回転はMatrix.rotate()というメソッドです。

[*10] [ActionScript 3.0コンポーネントリファレンスガイド]の[Matrix]の項は、変換行列の要素のbとcとが入れ違っています(「Flash CS3ヘルプ正誤表」参照)。なお、この誤りは、英語版のLiveDocsで修正されました。


4. Matrix3Dクラスにおける変換行列の扱い
Flash Player 10からは、3次元座標空間を扱う変換行列がMatrix3Dクラスで扱えるようになりました。変換行列は4行×4列の正方行列になります。ただし、前述のMatrixクラスとは異なり、変換行列の要素をプロパティで直接設定するのでなく、平行移動や拡大・縮小、回転などのメソッドで操作することが基本になります。

これらの変換を組合わせて適用するには、内部的にはそれらの変換行列を乗算したうえで、その結果の変換行列に座標ベクトルを掛け合わせます。気をつけなければならないのは、前述(2.「行列の乗算」【行列の乗算の特徴】)のとおり、行列の掛合わせる「順序を変えると結果が変わる」ということです。

そこで、Matrix3Dクラスの平行移動や拡大・縮小、回転の各メソッドは、そのための変換行列を前に(prepend)乗じるか後に(append)乗じるかの2種類がそれぞれ提供されています(表002)。たとえば、単純な2次元のxy平面で考えても、親タイムラインの基準点で(z軸の)回転をしてから移動する(図009左図)のと、移動してから親タイムラインの基準点を中心に回転する(図009右図)のでは、明らかに結果は異なります。

表002■Matrix3Dクラスの移動/拡大・縮小/回転のメソッドと変換行列を乗算する順序
変換 変換行列を前に乗じるメソッド 変換行列を後に乗じるメソッド
平行移動 Matrix3D.prependTranslation() Matrix3D.appendTranslation()
拡大・縮小 Matrix3D.prependScale() Matrix3D.appendScale()
回転 Matrix3D.prependRotation() Matrix3D.appendRotation()

図009■平行移動と回転の変換の順序により結果は異なる
図009左図 図009右図

インスタンスに変換が何も加えられていないデフォルトの状態は、その座標が親タイムラインの基準点(0, 0, 0)にあり、xyz軸方向の拡大・縮小の比率はいずれも実寸の1、各軸についての回転はすべて0度が設定された状態です。したがって、インスタンスがその状態でなければ、逆にいうとデフォルトでない変換行列が適用されていることを意味します。

前掲表009の中で変換行列を後に乗じるメソッドというのは、現在のインスタンスに適用されている変換行列の後からメソッドの変換行列を掛合わせます。たとえば、インスタンスの位置が親タイムラインの基準点でなかったなら、Matrix3D.appendRotation()メソッドによりインスタンスは親タイムラインの基準点を中心として回転されます(前掲図009右図)。

変換行列を前に乗じるメソッドは、現在のインスタンスに設定されている変換行列の前にメソッドの変換行列を掛合わせます。つまり、デフォルトの状態に、まずメソッドの変換行列を先に適用します。たとえば、Matrix3D.prependRotation()メソッドはデフォルト状態に戻したインスタンスを初めに回転し、その後にインスタンスのもとの変換行列を乗じます。結果として、インスタンスは配置されていた場所で、自身の基準点を中心に回されたのと同じ状態になります(図009左図)。

以上からは、インスタンスの基準点を原点とする変換は、変換行列を前に乗じるメソッドの方が簡単に思えるかもしまれせん。単純な変換であれば、そういえる場合が多いでしょう。しかし、すでに複数の変換が組合わせて加えられている場合には、デフォルトに戻してしまうことが意図に沿わないこともありえます。

たとえば、親タイムラインの基準点から離れた場所のインスタンスが、インスタンスの基準点を原点にy軸で90度回転して、真横を向いていたとします。インスタンスをその真横の向きのまま、さらにx軸で回転させるにはどうしたらよいでしょうか。

この場合、Matrix3D.prependRotation()メソッドでは、意図した変換になりません。なぜなら、このメソッドを適用する前に、インスタンスはデフォルトの正面向きに戻ります。したがって、正面向きのインスタンスをx軸で回転した後に、y軸による90度の回転と平行移動を掛合わせることになるからです(図010)。

図010■デフォルトに戻して回転した後もとの変換を乗じる
図010左図 図010右図

インスタンスがy軸で横向きのままx軸による回転を行うには、完全にデフォルトに戻す訳にはいきません。戻すのは位置座標のみに止める必要があります。この場合には、変換行列を後から乗じます。つまり、Matrix3D.appendTranslation()メソッドでまず位置座標を親タイムラインの基準点に平行移動し、インスタンスは横向きのままx軸による回転をMatrix3D.appendRotation()で加えます。その後、さらにMatrix3D.appendTranslation()メソッドで、位置座標をもとに戻せばよいのです(図011)。

図011■基準点に移動して回転の変換を乗じてからもとの位置に戻す
図011左図 図011右図

以上より、変換をデフォルト状態から考える場合には、変換行列は前に乗じるメソッドで扱った方が簡単だといえます。しかし、変換された現在の状態をベースにするときは、その内容を個別に考えて、補正や追加を後に乗じるメソッドで処理した方がよいでしょう。いずれにしても、変換行列にかぎらず、行列は一般に乗算の順序に注意する必要があります。


作成者: 野中文雄
作成日: 2008年11月17日


Copyright © 2001-2008 Fumio Nonaka.  All rights reserved.