問題
Flash Player 10から実装されたインスタンスの3次元空間における回転をy軸で行った場合、その角度が正しく反映されないという現象です。
以下のフレームアクションは、タイムラインに置いたMovieClipインスタンスmy_mcをy軸で80度回転します(図001)。[出力]パネルには、つぎのように回転角が表示されます。なお、ふたつ目の数値は、80度に相当するラジアン角です。
80.00003182368921 1.3962639570236206
// フレームアクション
// MovieClipインスタンスmy_mcを配置
var nRotationY:Number = 80;
my_mc.rotationY = 0;
var myMatrix3D:Matrix3D = my_mc.transform.matrix3D;
myMatrix3D.prependRotation(nRotationY, Vector3D.Y_AXIS);
trace(my_mc.rotationY, myMatrix3D.decompose()[1].y);
|
図001■y軸で80度回転したMovieClipインスタンス
つぎに、同じフレームアクションで、回転する角度を100度に変えてみます。インスタンスの見た目は100度回っているものの(図002)、[出力]される角度は80度のときとまったく同じです。
80.00003182368921 1.3962639570236206
// フレームアクション
// MovieClipインスタンスmy_mcを配置
var nRotationY:Number = 100; // 80;
my_mc.rotationY = 0;
var myMatrix3D:Matrix3D = my_mc.transform.matrix3D;
myMatrix3D.prependRotation(nRotationY, Vector3D.Y_AXIS);
trace(my_mc.rotationY, myMatrix3D.decompose()[1].y);
|
図002■y軸で100度回転したMovieClipインスタンス
原因
y軸回りの角度だけでなく、xやz軸の角度も確かめてみると、現象がもう少し詳しくわかります。以下のフレームアクション(スクリプト001)は、Spriteインスタンスを動的に生成し、y軸回りにまず80度回転したうえで、さらに20度(結果100度)回します。すると、[出力]パネルにはつぎのような値が表示されます。
0 80.00003182368921 0
Vector3D(0, 1.3962639570236206, 0)
180.00000500895632 80.00003182368921 180.00000500895632
Vector3D(3.1415927410125732, 1.3962639570236206, 3.1415927410125732)
スクリプト001■Spriteインスタンスを回転させてxyz軸回りの角度を調べる
// フレームアクション
var mySprite:Sprite = new Sprite();
var axis:Vector3D = Vector3D.Y_AXIS; // Vector3D.X_AXIS
mySprite.rotationY = 0;
var myMatrix3D:Matrix3D = mySprite.transform.matrix3D;
myMatrix3D.prependRotation(80, axis);
xTrace(mySprite);
myMatrix3D.prependRotation(20, axis);
xTrace(mySprite);
function xTrace(targetSprite:Sprite):void {
trace(targetSprite.rotationX, targetSprite.rotationY, targetSprite.rotationZ);
trace(targetSprite.transform.matrix3D.decompose()[1]);
}
|
[出力]結果が示すのは、インスタンスをy軸で100度回したとき、y軸回りの角度が80度になるだけでなく、xおよびz軸で反転(180度回転)しているということです。そのため、インスタンスの見た目は、y軸で100度回したのと同じ状態になります。
しかし、y軸による回転がxやz軸の角度に影響することは予測しにくいでしょう。また、xやz軸で回した場合には、このような現象は生じません。たとえば、上記スクリプト001でx軸による回転を試すと、[出力]は以下のようになります。y軸による回転だけ結果が異なるのは、数学的にも理解しにくいといえます[*1]。
79.99999767274336 0 0
Vector3D(1.3962633609771729, 0, 0)
100.0000005060238 0 0
Vector3D(1.7453292608261108, 0, 0)
対処法
DisplayObject.rotationYプロパティを使って回転すれば、プロパティ値が勝手に書替わることは一応防げます。しかし、インスタンスのもつMatrix3Dオブジェクトを調べると、やはりxおよびz軸で反転してしまうようです。
0 80 0
Vector3D(0, 1.3962639570236206, 0)
0 100 0
Vector3D(3.1415927410125732, 1.3962639570236206, 3.1415927410125732)
// フレームアクション
var mySprite:Sprite = new Sprite();
mySprite.rotationY = 80;
xTrace(mySprite);
mySprite.rotationY = 100;
xTrace(mySprite);
function xTrace(targetSprite:Sprite):void {
trace(targetSprite.rotationX, targetSprite.rotationY, targetSprite.rotationZ);
trace(targetSprite.transform.matrix3D.decompose()[1]);
}
|
なお、Matrix3D.recompose()メソッドでy軸回りの角度を100度に指定しても、やはりy軸の回転角は80度になり、xおよびz軸で反転してしまいました(スクリプト002)。したがって、このふるまいそのものを変える方法はなさそうです。できるのは、y軸回りの角度を±180度の範囲に計算し直すことでしょう[*2]。
180.00000500895632 80.00003182368921 180.00000500895632
Vector3D(3.1415927410125732, 1.3962639570236206, 3.1415927410125732)
スクリプト002■Matrix3D.recompose()メソッドでy軸回りの角度を指定する
// フレームアクション
var mySprite:Sprite = new Sprite();
mySprite.rotationY = 0;
var myMatrix3D:Matrix3D = mySprite.transform.matrix3D;
var myVector:Vector.<Vector3D> = myMatrix3D.decompose();
myVector[1] = new Vector3D(0, 100 / 180 * Math.PI, 0);
myMatrix3D.recompose(myVector);
xTrace(mySprite);
function xTrace(targetSprite:Sprite):void {
trace(targetSprite.rotationX, targetSprite.rotationY, targetSprite.rotationZ);
trace(targetSprite.transform.matrix3D.decompose()[1]);
}
|
[*2] 前出注[*1]の02「y軸回りの角度を±180度の範囲に計算し直す」に、スクリプトのサンプルを掲げました。
|
作成者: 野中文雄
更新日: 2010年8月25日 注[*1]に「インスタンスのy軸における回転角の値の範囲」を引用し、その解説に合わせて一部修正。
作成日: 2009年12月6日