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

第33回 遠近法の投影

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

今回から,Flash Player 10で備わった3次元空間の扱いに入りたい。したがって,Flash CS4 Professional以降が前提となり,サンプルファイルもCS4形式での提供となる。まずは,遠近法の捉え方について説明しよう。

[プロパティ]インスペクタを使った3次元空間の操作

コンピュータグラフィックス(CG)で3次元空間を描くとき,最終的には2次元平面のスクリーンに映さなければならない。つまり,3次元空間で計算した座標を,遠近法にしたがって計算し直し,その結果をスクリーンに投影することになる。この処理は英語で"perspective projection"と呼ばれ,「遠近法投影」とか「透視投影」と訳される。この遠近法を扱うのが,PerspectiveProjectionクラスだ。

だが,インスタンスをいきなりスクリプトで動かす前に,[プロパティ]インスペクタを用いて,3次元空間のプロパティの操作がどのような表現になるのか試してみよう。ステージに置いたインスタンスを選んだら,[プロパティ]インスペクタの[3D位置とビュー]セクションで3次元空間の操作ができる。たとえば,z座標値を大きくすると,インスタンスはサイズが縮まり,ステージの真ん中に向かって動く図1)。

図1 [プロパティ]インスペクタの[3D位置とビュー]セクションで3次元表現を操作

図1 [プロパティ]インスペクタの[3D位置とビュー]セクションで3次元表現を操作

これは,インスタンスに遠近法の表現が加えられたためだ。試しに,同じシンボルのインスタンスをいくつかを同じxy座標に重ねたうえで,z座標値だけを段階的に増やしてみるとよくわかる。z座標値が大きく奥行きの遠いインスタンスほど,サイズは小さくなり,位置はある1点に近づく。この点を「消失点」と呼ぶ図2左図)。消失点は,デフォルトではステージの中央にある。[プロパティ]インスペクタの[3D位置とビュー]セクションでxy座標値を設定すれば動かせる図2右図。※1)。

図2 インスタンスが遠ざかるにつれて消失点に向かって小さくなる

図2 インスタンスが遠ざかるにつれて消失点に向かって小さくなる

[プロパティ]インスペクタの[3D位置とビュー]セクションには,もうひとつ[遠近の角度]というプロパティがある。これは一般には,カメラに関わる用語で「視野角」とか「画角」と呼ばれる角度だ図3右図)。1から179までの数値で定める。値が大きいほど,遠近の差は広がって見える図3左図)。

図3 [プロパティ]インスペクタの[3D位置とビュー]セクションにおける[遠近の角度]

図3 [プロパティ]インスペクタの[3D位置とビュー]セクションにおける[遠近の角度]

※1
[プロパティ]インスペクタの[消失点]は,ドキュメントプロパティだ。つまり,どのタイムラインで設定しても,ステージ上のすべてのMovieClipインスタンスの3次元表現を変える。ただし,その設定をするには,いずれかのMovieClipインスタンスを選んでおかなければならない([ヘルプ]の[Flash CS4 Professionalユーザガイド] > [アートワークの作成および編集] > [3Dグラフィック]参照)。

ステージにランダムなシェイプを配置する

遠近法を操作すると表現がどう変わるかは,インスタンスひとつだけではわかりにくい。そこで,PerspectiveProjectionクラスを試す前に,ステージ一杯に数多くのランダムなシェイプを配置しよう。シェイプは,Shapeクラスで生成する。Shapeインスタンスには,スクリプトで円を描く。その描画をするときに参照するのが,インスタンスのShape.graphicsプロパティだ。

Shape.graphicsプロパティは,ShapeインスタンスがもつGraphicsオブジェクトを参照する。そのオブジェクトに対してGraphicsクラスのメソッドを呼び出せば,Shapeインスタンスにベクターが描ける※2)。ベクターを描くには,まず塗り(もしくは線)を設定する必要がある。塗りはGraphics.beginFill()メソッドでカラーとアルファを決める。

Graphicsオブジェクト.beginFill(カラー値, アルファ値)

カラーは通常16進数の整数,アルファは0から1までの数値(デフォルト値は1)を渡す。そして,塗りを終えるときには,引数のないGraphics.endFill()メソッドを呼出す。円を描くメソッドは,Graphics.drawCircle()メソッドだ。引数は3つで,中心のxy座標値と半径の長さになる。

Graphicsオブジェクト.drawCircle(中心のx座標値, 中心のy座標値, 半径の長さ)

これらの知識をもとにして,中心は基準点(0, 0)で,指定したカラーと半径の円が描かれたShapeインスタンスを返す関数xCreateCircle()は,つぎのように定義される。なお,カラーはデフォルト値を黒(0x000000)とした。

// フレームアクション
function xCreateCircle(nRadius:Number, nColor:uint = 0):Shape {
  var myShape:Shape = new Shape();
  var myGraphics:Graphics = myShape.graphics;
  myGraphics.beginFill(nColor);
  myGraphics.drawCircle(0, 0, nRadius);
  myGraphics.endFill();
  return myShape;
}

同じタイムラインのフレームアクションからつぎのように関数xCreateCircle()を呼び出すと,ステージ中央に半径10ピクセルで青い円の描かれたShapeインスタンスが配置される図4)。

var myShape:Shape = xCreateCircle(10, 0x0000FF);
addChild(myShape);
myShape.x = stage.stageWidth / 2;
myShape.y = stage.stageHeight / 2;

図4 円の描かれたShapeインスタンスを関数でつくってステージ中央に配置

図4 円の描かれたShapeインスタンスを関数でつくってステージ中央に配置

このShapeインスタンスをいくつもステージ上につくるとき,3次元座標の位置と大きさ,およびカラーをランダムに決めたい。そこで,指定した範囲でランダムな数値が得られる関数xGetRandom()を定義しておこう。0以上1未満のランダムな数値を返すメソッドはMath.random()だ。このランダムな数値を最大値と最小値の範囲に定めるのがつぎの式になる。

Math.random() * (最大値 - 最小値) + 最小値

カラー値は整数にする必要がある。ランダムな整数値を求める場合,最小値を戻り値の範囲に含め,小数点以下を切捨てるため,式はつぎのように変わる(※3)。

Math.floor(Math.random() * (最大値 - 最小値 + 1) + 最小値)

そこで,指定した範囲のランダムな数値を返す関数xGetRandom()は,以下のように定義した。3つの引数は順に,最大値と最小値,および整数で返すかどうかのブール(論理)値だ。引数を渡さなければ,Math.random()メソッドの戻り値がそのまま返される。また,関数の最初のifステートメントは,第1および第2引数が最小値,最大値の順でも処理できるように,値を入替えている。

function xGetRandom(nMax:Number = 1, nMin:Number = 0, bInt:Boolean = false):Number {
  if (nMax < nMin) {
    var nTemp:Number = nMax;
    nMax = nMin;
    nMin = nTemp;
  }
  var nRandom:Number = Math.random();
  if (bInt) {
    return Math.floor(nRandom * (nMax - nMin + 1) + nMin);
  } else {
    return nRandom * (nMax - nMin) + nMin;
  }
}

以下のスクリプト1には,上記ふたつの関数を使ってステージ一杯に任意の数のランダムなShapeインスタンスをつくる関数xCreateShapes()が加えられている。[ムービープレビュー]を確かめると,ステージ上にランダムな位置とサイズ(半径10ピクセル未満)およびカラーの円のShapeインスタンスが100個つくられる図5)。

スクリプト1 ステージ上にランダムな位置とサイズおよびカラーの円のShapeインスタンスをつくる

// タイムライン: メイン
// フレームアクション
xCreateShapes(100);
function xCreateShapes(nCount:uint):void {
  for (var i:uint = 0; i < nCount; i++) {
    var nColor:uint = xGetRandom(0xFFFFFF, 0, true);
    var nRadius:Number = xGetRandom(10);
    var myShape:Shape = xCreateCircle(nRadius, nColor);
    addChild(myShape);
    myShape.x = xGetRandom(stage.stageWidth);
    myShape.y = xGetRandom(stage.stageHeight);
    myShape.z = xGetRandom(stage.stageWidth);
  }
}
function xCreateCircle(nRadius:Number, nColor:uint = 0):Shape {
  var myShape:Shape = new Shape();
  var myGraphics:Graphics = myShape.graphics;
  myGraphics.beginFill(nColor);
  myGraphics.drawCircle(0, 0, nRadius);
  myGraphics.endFill();
  return myShape;
}
function xGetRandom(nMax:Number = 1, nMin:Number = 0, bInt:Boolean = false):Number {
  if (nMax < nMin) {
    var nTemp:Number = nMax;
    nMax = nMin;
    nMin = nTemp;
  }
  var nRandom:Number = Math.random();
  if (bInt) {
    return Math.floor(nRandom * (nMax - nMin + 1) + nMin);
  } else {
    return nRandom * (nMax - nMin) + nMin;
  }
}

図5 ステージ上にランダムな位置とサイズおよびカラーの円のShapeが配置された

図5 ステージ上にランダムな位置とサイズおよびカラーの円のShapeが配置された

もっとも,このままでは見える大きさの違いが,もともとのサイズによるのか,遠近法のせいなのかがわからない。そこでつぎに,PerspectiveProjectionクラスを使ってみよう。

※2
SpriteクラスもSprite.graphicsプロパティにGraphicsオブジェクトの参照をもつ。したがって,Shapeインスタンスと同じようにベクターが描ける。
※3
ランダムな整数値の求め方について詳しくは,少し古いがMath.random()でランダムな整数を取得する方法を参照してほしい。

著者プロフィール

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

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

URLhttp://www.FumioNonaka.com/

著書

コメント

コメントの記入