ロクナナワークショップ NEWS & REPORT

フォローアップ「Try the ActionScript 3D 野中文雄のFlash CS4で学ぶ3次元表現」

この記事を読むのに必要な時間:およそ 13 分

03:Matrix3Dクラス

Matrix3Dクラスを使うと,DisplayObejctインスタンスを3次元空間で座標変換できる※3]⁠Matrix3DオブジェクトはTransformクラスにプロパティとして備わっており,DisplayObject.transformプロパティからアクセスする。インスタンスの座標変換というのは,具体的には平行移動や拡大・縮小,回転などを指す。

変換のprependとappend

Matrix3Dクラスによる平行移動や拡大・縮小,回転といった座標変換には,次表2のようなメソッドを用いる。各変換について,前に適用する(prepend)メソッドと後に適用する(append)メソッドがそれぞれ用意されている。

表2 Matrix3Dクラスの移動/拡大・縮小/回転のメソッド

変換変換を前に適用するメソッド変換を後に適用するメソッド
平行移動Matrix3D.prependTranslation()Matrix3D.appendTranslation()
拡大・縮小Matrix3D.prependScale()Matrix3D.appendScale()
回転Matrix3D.prependRotation()Matrix3D.appendRotation()

図12 Matrix3Dクラスの平行移動(左)/拡大・縮小(中央)/回転(右)のメソッドの変換結果

図12 Matrix3Dクラスの平行移動(左)/拡大・縮小(中央)/回転(右)のメソッドの変換結果

座標変換を前(prepend)に適用するか,(append)に適用するかの意味と,互いの違いについて,回転を例にとって解説しよう。

Matrix3D.prependRotation()メソッド

Matrix3D.prependRotation()メソッドのシンタックスは,つぎのとおりだ。第1引数に,回転の角度を度数で渡す。そして第2引数には,回転の軸を指定する。xyz軸は,それぞれVector3Dクラスの定数Vector3D.X_AXIS,Vector3D.Y_AXIS,Vector3D.Z_AXISを用いる。

prependRotation(度数角:Number, 回転軸:Vector3D):void

マウスポインタの水平座標に応じた速さで,インスタンスをy軸で回転するフレームアクションが以下のスクリプト3だ。回転するインスタンスmy_mcは,予めタイムラインに配置しておく。

スクリプト3 3次元座標空間におけるインスタンスをy軸で回転させる

// タイムライン: メイン
// 第1フレームアクション
var nX:Number = my_mc.x;
var nDeceleration:Number = 0.3;   // 回転スピードの調整係数
my_mc.z = 0;   // 3次元座標のプロパティを操作
addEventListener(Event.ENTER_FRAME, xRotate);
function xRotate(eventObject:Event):void {
  var nRotationY:Number = (mouseX - nX)*nDeceleration;
  // 3次元座標空間においてy軸でインスタンスを回転
  my_mc.transform.matrix3D.prependRotation(nRotationY, Vector3D.Y_AXIS);
}

ひとつ注意しなければならないのは,デフォルトでは DisplayObject.transformプロパティにTransform.matrix3Dプロパティの値,つまりMatrix3Dオブジェクトが存在しないnullになる)ことだ。DisplayObjectインスタンスに何らかの3次元座標の操作を加えて初めて,Matrix3Dオブジェクトが生成される。そのため,前掲スクリプト003では,DisplayObject.zプロパティに0(デフォルト値)を設定している。

[ムービープレビュー]を見ると,インスタンスはマウスポインタの水平座標がその基準点から離れるほど,y軸を中心として水平方向に速く回転する図13)⁠

図13 インスタンスがマウスポインタの位置に応じた速さで水平に回転

図13 インスタンスがマウスポインタの位置に応じた速さで水平に回転

Matrix3D.appendRotation()メソッド

前掲スクリプト003のリスナー関数xRotate()で,回転するメソッドを Matrix3D.appendRotation()に変えてみよう。メソッドのシンタックスは,基本的にMatrix3D.prependRotation()メソッドと同じだ。

appendRotation(度数角:Number, 回転軸:Vector3D):void

書替えてみると,インスタンスは自身の基準点ではなく,配置されたタイムラインの基準点を原点として回るようになる。つまり,メインタイムラインに配置したインスタンスをy軸で回転すれば,ステージ左端を軸に回ってしまう図14)⁠

function xRotate(eventObject:Event):void {
  var nRotationY:Number = (mouseX - nX)*nDeceleration;
  my_mc.transform.matrix3D.appendRotation(nRotationY, Vector3D.Y_AXIS);
}

図14 インスタンスがステージ左端をy軸として回転する

図14 インスタンスがステージ左端をy軸として回転する

実は,座標変換は,つねに配置された親タイムラインの基準点を原点として行われる。それは,Matrix3D.prependRotation()メソッドの場合も同じだ。しかし,ふたつのメソッドで回転する原点が異なる結果となったのは,変換の適用される順序が異なるからである。

座標変換が適用される順序

インスタンスのもつMatrix3Dオブジェクトに,引数なしで呼出したコンストラクタにより生成したMatrix3Dインスタンスを設定すると,座標変換が加えられる前のデフォルトの状態に戻すことができる。それは,位置が親タイムラインの基準点,サイズは原寸(水平100%×垂直100%)⁠回転なし(0度)となる図15)⁠

my_mc.transform.matrix3D = new Matrix3D()

図15 インスタンスのデフォルト状態は位置が親タイムラインの基準点

図15 インスタンスのデフォルト状態は位置が親タイムラインの基準点

インスタンスのDisplayObject.transformプロパティがMatrix3DオブジェクトTransform.matrix3Dプロパティの値)をもつとき,Flash PlayerはDisplayObjectインスタンスにそのMatrix3Dオブジェクトを適用してステージに表示する。

変換を前(prepend)に適用するメソッドというのは,このMatrix3Dオブジェクトより先に,インスタンスのデフォルト状態に対して実行される。デフォルトでは,インスタンスと親タイムラインの基準点が一致している。したがって,親タイムラインの基準点を原点として変換しても,インスタンスの基準点で行ったのと同じ結果になる。

変換を後(append)に適用するメソッドは,Matrix3Dオブジェクトが適用されてインスタンスが現行の状態になってから実行される。すると,座標変換は,インスタンスの基準点とは異なる親タイムラインの基準点を原点として適用される。

前掲スクリプト003のリスナー関数xRotate()で, Matrix3D.appendRotation()メソッドを使って Matrix3D.prependRotation()と同じ処理にすることもできる。その場合,変換の適用順序をはっきりと変えてしまえばよい。

function xRotate(eventObject:Event):void {
  var nRotationY:Number = (mouseX - nX)*nDeceleration;
  var myMatrix3D:Matrix3D = my_mc.transform.matrix3D;   // もとのMatrix3Dオブジェクトを保持
  my_mc.transform.matrix3D = new Matrix3D();   // デフォルト状態に戻す
  my_mc.transform.matrix3D.appendRotation(nRotationY, Vector3D.Y_AXIS);   // 回転を先に適用
  my_mc.transform.matrix3D.append(myMatrix3D);   // もとのMatrix3Dオブジェクトを適用
}

なお,Matrix3D.append()メソッドは,引数のMatrix3Dオブジェクトを後からインスタンスに適用して変換する。

append(後から適用する変換:Matrix3D):void

複数の座標変換を組合わせる

前に適用(prepend)する変換の方が,扱いは簡単だ。しかし,変換を組合わせたとき,細かな調整はしづらい。たとえば,スクリプト003に,マウスポインタの垂直方向の動きに対するx軸の回転を加えてみる。

var nX:Number = my_mc.x;
var nY:Number = my_mc.y;
var nDeceleration:Number = 0.3;
my_mc.z = 0;
addEventListener(Event.ENTER_FRAME, xRotate);
function xRotate(eventObject:Event):void {
  var nRotationY:Number = (mouseX - nX)*nDeceleration;
  var nRotationX:Number = (mouseY - nY)*nDeceleration;
  my_mc.transform.matrix3D.prependRotation(nRotationY, Vector3D.Y_AXIS);
  my_mc.transform.matrix3D.prependRotation(nRotationX, Vector3D.X_AXIS);
}

[ムービープレビュー]で確かめると,マウスポインタの水平方向と垂直方向両方の動きに応じて回転の向きと速さが変わる。しかし,回転の方向が不自然だ。 Matrix3D.prependRotation()メソッドは,インスタンスのデフォルト状態に回転の変換を加える。そのため,タイムライン上でインスタンスがどの向きになっているかにかかわらず,インスタンスのx軸とy軸で回転してしまうからだ。

図16 マウスポインタを垂直に動かすとインスタンスのx軸で回転

図16 マウスポインタを垂直に動かすとインスタンスのx軸で回転

後に適用(append)する変換であれば,向きは変えずに位置だけを親タイムラインの基準点に動かすことができる。そこで回転を加えたうえで,位置をもとの座標に戻せばよい。後から適用する平行移動には,Matrix3D.appendTranslation()メソッドを用いる。引数にはxyz座標値を渡すスクリプト4)⁠

appendTranslation(x:Number, y:Number, z:Number):void

スクリプト4 3次元座標空間におけるインスタンスをx軸とy軸で回転させる

// タイムライン: メイン
// 第1フレームアクション
var nX:Number = my_mc.x;
var nY:Number = my_mc.y;
var nDeceleration:Number = 0.3;
my_mc.z = 0;
addEventListener(Event.ENTER_FRAME, xRotate);
function xRotate(eventObject:Event):void {
  var nRotationY:Number = (mouseX - nX)*nDeceleration;
  var nRotationX:Number = (mouseY - nY)*nDeceleration;
  // 3次元座標空間でインスタンスを回転
  my_mc.transform.matrix3D.appendTranslation(-nX, -nY, 0);
  my_mc.transform.matrix3D.appendRotation(nRotationY, Vector3D.Y_AXIS);
  my_mc.transform.matrix3D.appendRotation(nRotationX, Vector3D.X_AXIS);
  my_mc.transform.matrix3D.appendTranslation(nX, nY, 0);
}

Spriteインスタンスに6面で立方体を作成したMatrix3Dクラスの応用サンプル(adv_Matrix3D_cube.fla)でも,基本的に同じ処理内容で3次元空間における回転を行っている図17)⁠ただし,関数はふたつに分け,マウスポインタの座標に応じた回転の向きと速さをrotateCube()で計算し,Spriteインスタンスとそれらの値を引数にしてrotateSprite()で回転させている。

図17 立方体をx軸とy軸で回転

図17 立方体をx軸とy軸で回転

Matrix3D応用サンプル 立方体の回転の処理

var nX:Number = stage.stageWidth / 2;
var nY:Number = stage.stageHeight / 2;
var nSensitivity:Number = 0.2;
var cubeSprite:Sprite = new Sprite();   // 中に別途立方体を作成
function rotateCube(eventObject:Event):void {
  var nRotationX:Number = -(mouseY - nY) * nSensitivity;
  var nRotationY:Number = (mouseX - nX) * nSensitivity;
  rotateSprite(cubeSprite, nRotationX, nRotationY);
}
function rotateSprite(mySprite:Sprite, nRotationX:Number, nRotationY:Number):void {
  var myMatrix3D:Matrix3D = mySprite.transform.matrix3D;
  myMatrix3D.appendTranslation(-nX, -nY, 0);

  myMatrix3D.appendRotation(nRotationX, Vector3D.X_AXIS);
  myMatrix3D.appendRotation(nRotationY, Vector3D.Y_AXIS);
  myMatrix3D.appendTranslation(nX, nY, 0);
}
[※3]
Matrix3Dクラスについては,併せてAdobeデベロッパーセンターに寄稿したMatrix3Dクラス - 変換行列2も参考にしてほしい。

著者プロフィール

ロクナナワークショップ(ロクナナワークショップ)

アドビ認定トレーニングセンター ロクナナワークショップでは,Web業界の第一線で活躍中の講師陣による,実践的な講座を開講しています。全ての講座は最大6名・1日6時間で完結する,PCを操作しながらの集中トレーニングです。

また,各方面で活躍中のクリエイターをお迎えし,最新技術やアイデアをご紹介いただくイベントも開催しています。学生割引もありますので,是非一度参加してみてください。

URL:https://67.org/ws/