ActionScript 3.0で始めるオブジェクト指向スクリプティング

第43回 Vector3Dオブジェクトの座標に遠近法を適用する

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

Vector3D.wプロパティとVector3D.project()メソッドで透視投影を行う

Vector3Dクラスには3次元座標空間における位置ベクトル(x, y, z)の成分となるVector3D.xやVector3D.y,Vector3D.zプロパティに加えて,4つめの成分としてVector3D.wがある※2⁠。このプロパティは,座標値ではなくオプションとして用いる。Vector3D.wプロパティに透視投影の比率を与えると,Vector3D.project()メソッドの呼出しにより,3次元空間座標に透視投影の計算が加えられる。

Vector3Dオブジェクト.project()

このメソッドを使うときには,気をつけるべきことがふたつある。第1は,3次元座標(Vector3D.x/Vector3D.y/Vector3D.zプロパティ)値が,Vector3D.wプロパティの値で割り算されることだ。よって,前掲「3次元空間の座標を2次元平面に透視投影する比率」は,分子分母を入替えて(逆数にして)Vector3D.wプロパティに設定する必要がある。

第2に,Vector3D.project()メソッドは,参照するVector3Dオブジェクトの3次元座標値をそのまま書替える。したがって,もとの3次元空間座標を残しておくには,Vector3Dオブジェクトは複製したうえで操作しなければならない。Vector3Dオブジェクトを複製するには,Vector3D.clone()メソッドを用いる。

このVector3D.project()メソッドとVector3D.wプロパティを使って透視投影を行ったのが,以下のスクリプト1の関数xGetVertices2D()だ図6⁠。

図6 Vector3D.project()メソッドとVector3D.wプロパティで透視投影を行う

図6 Vector3D.project()メソッドとVector3D.wプロパティで透視投影を行う

スクリプト1 3次元空間の頂点座標から2次元平面に透視投影したワイヤーフレームを描く

// フレームアクション
var nUnit:Number = 100 / 2;
var mySprite:Sprite = new Sprite();
var vertices:Vector.<Vector3D> = new Vector.<Vector3D>();
var nDeceleration:Number = 0.3;
var myGraphics:Graphics = mySprite.graphics;
var nFocalLength:Number = transform.perspectiveProjection.focalLength;
mySprite.x = stage.stageWidth / 2;
mySprite.y = stage.stageHeight / 2;
vertices.push(new Vector3D(-nUnit, -nUnit, 0));
vertices.push(new Vector3D(nUnit, -nUnit, 0));
vertices.push(new Vector3D(nUnit, nUnit, 0));
vertices.push(new Vector3D(-nUnit, nUnit, 0));
addChild(mySprite);
addEventListener(Event.ENTER_FRAME, xRotate);
function xRotate(eventObject:Event):void {
  var nRotationY:Number = mySprite.mouseX * nDeceleration;
  xTransform(vertices, nRotationY);
  var vertices2D:Vector.<Point >  = xGetVertices2D(vertices);
  xDrawLines(vertices2D);
}
function xTransform(myVertices:Vector.<Vector3D>, myRotation:Number):void {
  var nLength:uint = myVertices.length;
  var myMatrix3D:Matrix3D = new Matrix3D();
  myMatrix3D.prependRotation(myRotation, Vector3D.Y_AXIS);
  for (var i:int = 0; i<nLength; i++) {
    myVertices[i] = myMatrix3D.transformVector(myVertices[i]);
  }
}
function xGetVertices2D(myVertices:Vector.<Vector3D>):Vector.<Point >  {
  var vertices2D:Vector.<Point> = new Vector.<Point>();
  var nLength:uint = myVertices.length;
  for (var i:uint = 0; i < nLength; i++) {
    var myVector3D:Vector3D = myVertices[i].clone();
    // Vector3D.wプロパティ = (焦点距離 + z位置) / 焦点距離
    myVector3D.w = (nFocalLength + myVector3D.z) / nFocalLength;
    myVector3D.project();
    vertices2D.push(new Point(myVector3D.x, myVector3D.y));
  }
  return vertices2D;
}
function xDrawLines(vertices2D:Vector.<Point>):void {
  var nLength:uint = vertices2D.length;
  var myPoint:Point = vertices2D[nLength - 1];
  myGraphics.clear();
  myGraphics.lineStyle(2, 0x0000FF);
  myGraphics.moveTo(myPoint.x, myPoint.y);
  for (var i:uint = 0; i < nLength; i++) {
    myPoint = vertices2D[i];
    myGraphics.lineTo(myPoint.x, myPoint.y);
  }
}

[ムービープレビュー]を確かめると,回るワイヤーフレームの四角形はパースペクティブがかかって描かれる。次回は面の数を増やしてみよう。

図7 回転するワイヤーフレームの四角形にパースペクティブがかかった

図7 回転するワイヤーフレームの四角形にパースペクティブがかかった(1)

図7 回転するワイヤーフレームの四角形にパースペクティブがかかった(2)

図7 回転するワイヤーフレームの四角形にパースペクティブがかかった(3)

※2
Vector3Dクラス参照。

今回解説した次のサンプルファイルがダウンロードできます。

著者プロフィール

野中文雄(のなかふみお)

ソフトウェアトレーナー,テクニカルライター,オーサリングエンジニア。上智大学法学部卒,慶応義塾大学大学院経営管理研究科修士課程修了(MBA)。独立系パソコン販売会社で,総務・人事,企画,外資系企業担当営業などに携わる。その後,マルチメディアコンテンツ制作会社に転職。ソフトウェアトレーニング,コンテンツ制作などの業務を担当する。2001年11月に独立。Web制作者に向けた情報発信プロジェクトF-siteにも参加する。株式会社ロクナナ取締役(非常勤)。

URLhttp://www.FumioNonaka.com/

著書