Flash3Dエンジンの開発 その3 | Photoshop CC Tutorials
Zソートを実装しました。

$ピック社長のブログ
できあがりはこちら。

Main.as
package 
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.text.TextField;
import flash.utils.Dictionary;
import primitives.Cube;
import primitives.Cube_01;
import primitives.Cube_02;

import flash.utils.getTimer;

/**
* Zソートプログラム
*/
public class Main extends Sprite
{
private var angle:Number = 0.0; // 回転角度
private var rotM:Matrix4x4 = new Matrix4x4(); // 回転変換行列
private var viewM:Matrix4x4 = new Matrix4x4(); // 視点位置変換行列
private var persM:Matrix4x4 = new Matrix4x4(); // 透視投影変換行列
private var modelM:Matrix4x4 = new Matrix4x4(); // モデル変換行列
private var viewPos:Vector3d; // 視点位置
private var sp:Sprite; // 描画スクリーン
private var proFaces:Array = new Array(); // 透視投影面を格納する

private var textField:TextField; // デバッグエリア

public function Main():void
{
//デバッグエリア
textField = new TextField();
textField.background = true;
textField.border = true;
textField.x = 50;
textField.y = 100;
textField.width = 300;
textField.height = 80;
Debug.textField = textField;
Debug.trace("default");
//this.addChild(textField);

this.addChild(sp = new Sprite());

// リスナー登録
//----------------------------------
//this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
// マウスの左ボタンが押されたときに呼び出されるイベント
//stage.addEventListener(MouseEvent.MOUSE_DOWN, MouseLDownFunc);
// マウスの左ボタンが離されたときに呼び出されるイベント
//stage.addEventListener(MouseEvent.MOUSE_UP, MouseLUpFunc);

init();
}

public function init():void
{
// モデル変換行列の作成
// -------------------------------------------------------
// 視点位置変換行列を作成
var Mv:Array = new Array(3); // 変換後の頂点を格納する
for (var i:int = 0; i < Mv.length; i++ ) {
Mv[i] = new Vertex();
}

viewPos = new Vector3d(0.0, 0.0, 600.0); // 視点位置
// 視点、注視点、上方向を指定
viewM.View(viewPos, new Vector3d(0.0, 0.0, 0.0), new Vector3d(0.0, 1.0, 0.0));

modelM.Mult(viewM);

// 透視投影変換行列の作成
// -------------------------------------------------------
var n:Number = 20.0; // ニアクリップ面
var f:Number = 1000; // ファークリップ面
var fov:Number = 45.0; // 視野角(FOV:Field Of View)
var aspect:Number = Number(400) / Number(300); // aspect比を計算

var PMv:Array = new Array(3); // 変換後の頂点を格納する
for (i = 0; i < PMv.length; i++ ) {
PMv[i] = new Vertex();
}
// 透視投影行列を作成
persM.Projection(n, f, fov, aspect);

this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}

private var cube_01:Cube_01 = new Cube_01(0xff00ff);
private var cube_02:Cube_02 = new Cube_02(0x00ffff);
private var cube_03:Cube = new Cube(0xff0000);

private function onEnterFrame(e:Event):void
{
sp.graphics.clear();

var rotMM:Matrix4x4 = new Matrix4x4();
angle += 1;
if (angle > 360.0) {
angle -= 360.0;
}

rotMM.RotateY(angle * Math.PI / 180);

var trans_01:Matrix4x4 = new Matrix4x4();
trans_01.Translate(0, 0, 0);

var trans_02:Matrix4x4 = new Matrix4x4();
trans_02.Translate(0, 0, 0);

var trans_03:Matrix4x4 = new Matrix4x4();
trans_03.Translate(0, 0, 0);

this.proFaces = new Array();
// 立方体を透視投影で描画しArrayにレンダリング後の面を追加
cube_01.persArray(persM, modelM, viewPos, rotMM, trans_02, this.proFaces);
cube_02.persArray(persM, modelM, viewPos, rotMM, trans_02, this.proFaces);
cube_03.persArray(persM, modelM, viewPos, rotMM, trans_02, this.proFaces);

// Zソートする
var dic:Dictionary = new Dictionary()
for each(var pf:ProjectionFace in proFaces) {
dic[pf] = -pf.getZ();
}

proFaces.sort(function(a:ProjectionFace, b:ProjectionFace):Number {
return dic[b] - dic[a];
});

// レンダリング
for each(var projectionFace:ProjectionFace in proFaces){
// 面を描画していく
projectionFace.draw(sp.graphics);
}
}

}

}


Vertex.as
package
{
/**
* 頂点クラス
*/

public class Vertex
{
public var v:Vector3d;//頂点座標
public var n:Vector3d;//法線ベクトル
public var U:Number; // テクスチャ座標
public var V:Number; // テクスチャ座標

public function Vertex(...args)
{
switch(args.length) {
case 0:
initialize(0, 0, 0, 0, 0, 0, 0.0, 0.0);

break;

case 3:
initialize(args[0], args[1], args[2], 0, 0, 0, 0.0, 0.0);

break;

case 6:
initialize(args[0], args[1], args[2], args[3], args[4], args[5], 0.0, 0.0);

case 8:
initialize(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);

break;
}
}

private function initialize(x:Number, y:Number, z:Number, nx:Number, ny:Number, nz:Number, _U:Number, _V:Number):void
{
this.v = new Vector3d(x, y, z);
this.n = new Vector3d(nx, ny, nz);
this.U = _U;
this.V = _V;
}

}

}


Face.as
package
{
import flash.display.BitmapData;
import flash.display.Graphics;
/**
* 面クラス
*/

public class Face {

public var vertices:Array = new Array(3);
public var z:Number; // 奥行き
public var normal:Vector3d = new Vector3d(); // 法線
public var center:Vector3d; // 面の中心
protected var color:uint; // 面の色
public var PMv:Array; // パースのかかった頂点を格納する
private var d:BitmapData;


public function Face(...args)
{
switch(args.length) {
case 4:
var v0:Vertex = args[0];
var v1:Vertex = args[1];
var v2:Vertex = args[2];
var col:uint = args[3];

this.vertices[0] = v0;
this.vertices[1] = v1;
this.vertices[2] = v2;

this.color = col;

calcNormal();
calculateCenter();

break;
}
}

public function initObject(_d:BitmapData):void
{
this.d = _d;
}

/**
* 面の法線を計算する
*/
private function calcNormal(...args):void
{
switch(args.length) {
case 0:
var v:Vector3d = new Vector3d();
v.calcNormal(this.vertices[0].v, this.vertices[1].v, this.vertices[2].v);
this.normal.x = v.x;
this.normal.y = v.y;
this.normal.z = v.z;

break;

case 1:
v = new Vector3d();
var vArray:Array = args[0];
v.calcNormal(vArray[0].v, vArray[1].v, vArray[2].v);
this.normal.x = v.x;
this.normal.y = v.y;
this.normal.z = v.z;

break;
}
}

/**
* 面の中心を計算する
*/
private function calculateCenter(...args):void
{
switch(args.length) {
case 0:
this.center = new Vector3d();
for (var i:int = 0; i < vertices.length; i++) {
center.Add(this.vertices[i].v);
}

center.x /= vertices.length;
center.y /= vertices.length;
center.z /= vertices.length;

break;

case 1:
var MvArray:Array = args[0];
this.center = new Vector3d();
for (i = 0; i < MvArray.length; i++) {
center.Add(MvArray[i].v);
}

center.x /= MvArray.length;
center.y /= MvArray.length;
center.z /= MvArray.length;

break;
}
//Debug.trace("centerX=" + center.x + " " + "centerY=" + center.y + " " + "centerZ=" + center.z);
}

// 受け取ったモデル変換行列、透視投影変換行列を利用して面をレンダリングし、
// Arrayに追加する
public function persArray(persM:Matrix4x4, modelM:Matrix4x4, eyePos:Vector3d, rotM:Matrix4x4, transM:Matrix4x4, proFaces:Array):void
{
// 変換後の頂点を格納する
var Mv:Array = new Array(vertices.length);
for (var i:int = 0; i < Mv.length; i++ ) {
Mv[i] = new Vertex();
}

// 回転行列と元となる頂点を乗算
for (i = 0; i < vertices.length; i++ ) {
rotM.TransformVector(this.vertices[i].v, Mv[i].v);
}

// 平行移動行列と変換された頂点を乗算
for (i = 0; i < vertices.length; i++ ) {
transM.TransformVector(Mv[i].v);
}

// 背面消去
// -------------------------------------------------------
calculateCenter(Mv);
calcNormal(Mv);
//Debug.trace(Mc.x + " " + Mc.y + " " + Mc.z);

//Debug.trace(this.normal.x + " " + normal.y + " " + normal.z);

// e:視線ベクトル(e' = center - e)
var e:Vector3d = new Vector3d();
e.Subtract(this.center, eyePos);
e.Normalize();
if (normal.DotProduct(e) > 0.0) {
return;
}

// モデル変換
// -------------------------------------------------------
var _PMv:Array = new Array(vertices.length);
for (i = 0; i < _PMv.length; i++ ) {
_PMv[i] = new Vertex();
}

for (i = 0; i < Mv.length; i++ ) {
modelM.TransformVector(Mv[i].v);
persM.TransformVector(Mv[i].v, _PMv[i].v);
_PMv[i].v.y /= Mv[i].v.z;
_PMv[i].v.x /= Mv[i].v.z;
}

// 透視投影変換しレンダリングした面をArrayListに追加する
var projectionFace:ProjectionFace = new ProjectionFace(_PMv, this.color, this.center);
proFaces.push(projectionFace);
}

public function fillPolygon(g:Graphics, persM:Matrix4x4, modelM:Matrix4x4, eyePos:Vector3d, rotM:Matrix4x4, transM:Matrix4x4):void
{
// 変換後の頂点を格納する
var Mv:Array = new Array(vertices.length);
for (var i:int = 0; i < Mv.length; i++ ) {
Mv[i] = new Vertex();
}

// 回転行列と元となる頂点を乗算
for (i = 0; i < vertices.length; i++ ) {
rotM.TransformVector(this.vertices[i].v, Mv[i].v);
}

// 平行移動行列と変換された頂点を乗算
for (i = 0; i < vertices.length; i++ ) {
transM.TransformVector(Mv[i].v);
}

// 背面消去
// -------------------------------------------------------
var Mc:Vector3d = new Vector3d();
rotM.TransformVector(this.center, Mc);
transM.TransformVector(Mc);
calcNormal(Mv);
//Debug.trace(Mc.x + " " + Mc.y + " " + Mc.z);

//Debug.trace(this.normal.x + " " + normal.y + " " + normal.z);

// e:視線ベクトル(e' = Mc - e)
var e:Vector3d = new Vector3d();
e.Subtract(Mc, eyePos);
e.Normalize();
if (normal.DotProduct(e) > 0.0) {
return;
}

// モデル変換
// -------------------------------------------------------
var PMv:Array = new Array(vertices.length);
for (i = 0; i < PMv.length; i++ ) {
PMv[i] = new Vertex();
}

for (i = 0; i < Mv.length; i++ ) {
modelM.TransformVector(Mv[i].v);
persM.TransformVector(Mv[i].v, PMv[i].v);
PMv[i].v.y /= Mv[i].v.z;
PMv[i].v.x /= Mv[i].v.z;
}

/*Debug.trace(Mv[0].v.x + " " + Mv[0].v.y + " " + Mv[0].v.z + "\n" +
Mv[1].v.x + " " + Mv[1].v.y + " " + Mv[1].v.z + "\n" +
Mv[2].v.x + " " + Mv[2].v.y + " " + Mv[2].v.z);*/

// ポリゴンの描画
// -------------------------------------------------------
g.beginFill(this.color);
g.lineStyle(3, 0xffffff);

g.moveTo(PMv[0].v.x * 200 + 200, -PMv[0].v.y * 200 + 150);
g.lineTo(PMv[1].v.x * 200 + 200, -PMv[1].v.y * 200 + 150);
g.lineTo(PMv[2].v.x * 200 + 200, -PMv[2].v.y * 200 + 150);

g.endFill();
}

}
}


ProjectionFace.as
package  
{
import flash.display.Graphics;
import flash.display.Sprite;
/**
* 透視投影変換後の面クラス
*/
public class ProjectionFace extends Face
{
public function ProjectionFace(...args)
{
super.PMv = args[0];
super.color = args[1];
super.center = args[2];
}

public function getZ():Number
{
return super.center.z;
}

// 透視投影された面を描画する
public function draw(g:Graphics):void
{
// ポリゴンの描画
// -------------------------------------------------------
g.beginFill(super.color);
g.lineStyle(3, 0xffffff);

g.moveTo(super.PMv[0].v.x * 200 + 200, -super.PMv[0].v.y * 200 + 150);
g.lineTo(super.PMv[1].v.x * 200 + 200, -super.PMv[1].v.y * 200 + 150);
g.lineTo(super.PMv[2].v.x * 200 + 200, -super.PMv[2].v.y * 200 + 150);

g.endFill();
}

}

}


Vector3d.as
package  
{
/**
* 3次元ベクトルクラス
*/

public class Vector3d
{
/**
* メンバ変数
*/
public var x:Number;
public var y:Number;
public var z:Number;

/**
* コンストラクタ
* @param ...args
*/
public function Vector3d(...args)
{
switch (args.length) {
case 0:
set(0, 0, 0);

break;

case 3:
var vx:Number = args[0];
var vy:Number = args[1];
var vz:Number = args[2];
set(vx, vy, vz);

break;

case 1:
var v:Vector3d = args[0];
set(v);

break;
}
}

/**
* ベクトルの初期化
* @param v コピーするベクトル
*/
public function Initialize(v:Vector3d):void
{
set(v.x,v.y,v.z);
}

public function set(...args):void
{
switch (args.length) {
case 3:
var vx:Number = args[0];
var vy:Number = args[1];
var vz:Number = args[2];
this.x = vx;
this.y = vy;
this.z = vz;

break;

case 1:
var v:Vector3d = args[0];
this.x = vx;
this.y = vy;
this.z = vz;

break;
}
}

/**
* 加算
* @param Vector v
*/
public function Add(...args):void
{

switch (args.length) {
case 1:
var v:Vector3d = args[0];

this.x += v.x;
this.y += v.y;
this.z += v.z;

break;

case 2:
var v1:Vector3d = args[0];
var v2:Vector3d = args[1];

this.x = v1.x + v2.x;
this.y = v1.y + v2.y;
this.z = v1.z + v2.z;

break;
}
}

/**
* 減算
* @param ...args
*/
public function Subtract(...args):void
{
switch (args.length) {
case 1:
var v:Vector3d = args[0];

this.x -= v.x;
this.y -= v.y;
this.z -= v.z;

break;

case 2:
var v1:Vector3d = args[0];
var v2:Vector3d = args[1];

this.x = v1.x - v2.x;
this.y = v1.y - v2.y;
this.z = v1.z - v2.z;

break;
}
}

/**
* 単位ベクトル(長さが1のベクトル)
*/
public function Normalize():void
{
var _l:Number = 1.0 / Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z);
this.x *= _l;
this.y *= _l;
this.z *= _l;
}

/**
* 内積(ベクトルとベクトルのなす角度を求める)
* @param v
* @return
*/
public function DotProduct(v:Vector3d):Number
{
return (x * v.x + y * v.y + z * v.z);
}

/**
* 外積(主に面に垂直な法線ベクトルを求めるために使用する。)
* @param ...args
*/
public function crossProduct(...args):void
{
switch (args.length) {
case 2:
var a:Vector3d = args[0];
var b:Vector3d = args[1];

var ax:Number = a.x;
var ay:Number = a.y;
var az:Number = a.z;
var bx:Number = b.x;
var by:Number = b.y;
var bz:Number = b.z;

this.x = ay * bz - az * by;
this.y = az * bx - ax * bz;
this.z = ax * by - ay * bx;

break;

case 6:
ax = args[0];
ay = args[1];
az = args[2];
bx = args[3];
by = args[4];
bz = args[5];

this.x = ay * bz - az * by;
this.y = az * bx - ax * bz;
this.z = ax * by - ay * bx;

break;
}
}

public function calcNormal(v1:Vector3d, v2:Vector3d, v3:Vector3d):void
{
// 外積を取る
// ax = v1.x - v2.x;
// ay = v1.y - v2.y;
// az = v1.z - v2.z;
// bx = v1.x - v3.x;
// by = v1.y - v3.y;
// bz = v1.z - v3.z;
crossProduct(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z,
v1.x - v3.x, v1.y - v3.y, v1.z - v3.z);

// 正規化
Normalize();
}

/**
* ベクトルを反転する
*/
public function Invert():void
{
set(-this.x, -this.y, -this.z);
}

}

}


Matrix4x4.as
package 
{
/**
* 4x4マトリックスクラス
*/

public class Matrix4x4
{
/**
* メンバ変数
*/
public var m00:Number,m01:Number,m02:Number,m03:Number;
public var m10:Number,m11:Number,m12:Number,m13:Number;
public var m20:Number,m21:Number,m22:Number,m23:Number;
public var m30:Number,m31:Number,m32:Number,m33:Number;

/**
* コンストラクタ
*/
public function Matrix4x4()
{
this.Initialize();
}

public function Initialize(...args):void
{
switch (args.length)
{
case 0:

// 単位行列で初期化
//-----------------------------------------------------------
//| 1 0 0 0|
//| 0 1 0 0|
//| 0 0 1 0|
//| 0 0 0 1|

m00 = 1;m01 = 0;m02 = 0;m03 = 0;
m10 = 0;m11 = 1;m12 = 0;m13 = 0;
m20 = 0;m21 = 0;m22 = 1;m23 = 0;
m30 = 0;m31 = 0;m32 = 0;m33 = 1;
break;
case 1:

// 初期化
//-----------------------------------------------------------
var m:Matrix4x4 = args[0];

m00 = m.m00;m01 = m.m01;m02 = m.m02;m03 = m.m03;
m10 = m.m10;m11 = m.m11;m12 = m.m12;m13 = m.m13;
m20 = m.m20;m21 = m.m21;m22 = m.m22;m23 = m.m23;
m30 = m.m30;m31 = m.m31;m32 = m.m32;m33 = m.m33;
break;
}
}

/**
* 行列の掛け算(合成)
* @param m 合成するマトリクス
*/
public function Mult(m:Matrix4x4):void
{
var _00:Number = m00*m.m00 + m01*m.m10 + m02*m.m20 + m03*m.m30;
var _01:Number = m00*m.m01 + m01*m.m11 + m02*m.m21 + m03*m.m31;
var _02:Number = m00*m.m02 + m01*m.m12 + m02*m.m22 + m03*m.m32;
var _03:Number = m00*m.m03 + m01*m.m13 + m02*m.m23 + m03*m.m33;
var _10:Number = m10*m.m00 + m11*m.m10 + m12*m.m20 + m13*m.m30;
var _11:Number = m10*m.m01 + m11*m.m11 + m12*m.m21 + m13*m.m31;
var _12:Number = m10*m.m02 + m11*m.m12 + m12*m.m22 + m13*m.m32;
var _13:Number = m10*m.m03 + m11*m.m13 + m12*m.m23 + m13*m.m33;
var _20:Number = m20*m.m00 + m21*m.m10 + m22*m.m20 + m23*m.m30;
var _21:Number = m20*m.m01 + m21*m.m11 + m22*m.m21 + m23*m.m31;
var _22:Number = m20*m.m02 + m21*m.m12 + m22*m.m22 + m23*m.m32;
var _23:Number = m20*m.m03 + m21*m.m13 + m22*m.m23 + m23*m.m33;
var _30:Number = m30*m.m00 + m31*m.m10 + m32*m.m20 + m33*m.m30;
var _31:Number = m30*m.m01 + m31*m.m11 + m32*m.m21 + m33*m.m31;
var _32:Number = m30*m.m02 + m31*m.m12 + m32*m.m22 + m33*m.m32;
var _33:Number = m30*m.m03 + m31*m.m13 + m32*m.m23 + m33*m.m33;

m00 = _00; m01 = _01;m02 = _02;m03 = _03;
m10 = _10; m11 = _11;m12 = _12;m13 = _13;
m20 = _20; m21 = _21;m22 = _22;m23 = _23;
m30 = _30; m31 = _31;m32 = _32;m33 = _33;
}

/**
* 拡大縮小
* @param sx X倍率
* @param sy Y倍率
* @param sz Z倍率
*/
public function Scale(sx:Number, sy:Number, sz:Number):void
{
//| sx 0 0 0|
//| 0 sy 0 0|
//| 0 0 sz 0|
//| 0 0 0 1|

var m:Matrix4x4 = new Matrix4x4();
m.m00 = sx;m.m01 = 0;m.m02 = 0;m.m03 = 0;
m.m10 = 0;m.m11 = sy;m.m12 = 0;m.m13 = 0;
m.m20 = 0;m.m21 = 0;m.m22 = sz;m.m23 = 0;
m.m30 = 0;m.m31 = 0;m.m32 = 0;m.m33 = 1;

// 行列の合成
this.Mult(m);
}

/**
* X軸回転
* @param r 回転角(単位ラジアン)
*/
public function RotateX(r:Number):void
{
var sinx:Number = Math.sin(r);
var cosx:Number = Math.cos(r);

// X軸回転
//| 1 0 0 0|
//| 0 cosX -sinX 0|
//| 0 sinX cosX 0|
//| 0 0 0 1|

var m:Matrix4x4 = new Matrix4x4();
m.m00 = 1;m.m01 = 0;m.m02 = 0;m.m03 = 0;
m.m10 = 0;m.m11 = cosx;m.m12 =-sinx;m.m13 = 0;
m.m20 = 0;m.m21 = sinx;m.m22 = cosx;m.m23 = 0;
m.m30 = 0;m.m31 = 0;m.m32 = 0;m.m33 = 1;

// 行列の合成
this.Mult(m);
}

/**
* Y軸回転
* @param r 回転角(単位ラジアン)
*/
public function RotateY(r:Number):void
{
var siny:Number = Math.sin(r);
var cosy:Number = Math.cos(r);

// Y軸回転
//| cosY 0 sinY 0|
//| 0 1 0 0|
//| -sinY 0 cosY 0|
//| 0 0 0 1|

var m:Matrix4x4 = new Matrix4x4();
m.m00 = cosy;m.m01 = 0;m.m02 = siny;m.m03 = 0;
m.m10 = 0;m.m11 = 1;m.m12 = 0;m.m13 = 0;
m.m20 =-siny;m.m21 = 0;m.m22 = cosy;m.m23 = 0;
m.m30 = 0;m.m31 = 0;m.m32 = 0;m.m33 = 1;

// 行列の合成
this.Mult(m);
}

/**
* Z軸回転
* @param r 回転角(単位ラジアン)
*/
public function RotateZ(r:Number):void
{
var sinz:Number = Math.sin(r);
var cosz:Number = Math.cos(r);

// Z軸回転
//| cosZ -sinZ 0 0|
//| sinZ cosZ 0 0|
//| 0 0 1 0|
//| 0 0 0 1|

var m:Matrix4x4 = new Matrix4x4();
m.m00 = cosz;m.m01 = -sinz;m.m02 = 0;m.m03 = 0;
m.m10 = sinz;m.m11 = cosz;m.m12 = 0;m.m13 = 0;
m.m20 = 0;m.m21 = 0;m.m22 = 1;m.m23 = 0;
m.m30 = 0;m.m31 = 0;m.m32 = 0;m.m33 = 1;

// 行列の合成
this.Mult(m);
}

/**
* 平行移動
* @param ...args
* @param dx X移動量
* @param dy Y移動量
* @param dz Z移動量
*/
public function Translate(...args):void
{
switch (args.length)
{
case 1:
var v:Vector3d = args[0];

Translate(v.x, v.y, v.z);

break;

case 3:
var dx:Number = args[0];
var dy:Number = args[1];
var dz:Number = args[2];

//| 1 0 0 dx|
//| 0 1 0 dy|
//| 0 0 1 dz|
//| 0 0 0 1|

var m:Matrix4x4 = new Matrix4x4();
m.m00 = 1;m.m01 = 0;m.m02 = 0;m.m03 = dx;
m.m10 = 0;m.m11 = 1;m.m12 = 0;m.m13 = dy;
m.m20 = 0;m.m21 = 0;m.m22 = 1;m.m23 = dz;
m.m30 = 0;m.m31 = 0;m.m32 = 0;m.m33 = 1;

// 行列の合成
this.Mult(m);

break;
}
}

/**
* ベクトルとマトリックスの乗算
* @param ...args
* @return ベクトル
*/
public function TransformVector(...args):void
{
switch (args.length)
{
case 1:
var v:Vector3d = args[0];

v.x = m00 * v.x + m01 * v.y + m02 * v.z + m03;
v.y = m10 * v.x + m11 * v.y + m12 * v.z + m13;
v.z = m20 * v.x + m21 * v.y + m22 * v.z + m23;

break;

case 2:
var _in:Vector3d = args[0];
var _out:Vector3d = args[1];

var ax:Number = m00 * _in.x + m01 * _in.y + m02 * _in.z + m03;
var ay:Number = m10 * _in.x + m11 * _in.y + m12 * _in.z + m13;
var az:Number = m20 * _in.x + m21 * _in.y + m22 * _in.z + m23;

_out.set(ax, ay, az);

break;
}
}

/**
* 転置行列の作成
* @param v
*/
public function Invert(v:Matrix4x4):void
{
m00=v.m00;m01=v.m10;m02=v.m20;m03=0;
m10=v.m01;m11=v.m11;m12=v.m21;m13=0;
m20=v.m02;m21=v.m12;m22=v.m22;m23=0;
m30= 0;m31= 0;m32= 0;m33=1;
}

/**
* 射影変換行列
* @param near
* @param far
* @param fov
* @param aspect
*/
public function Projection(near:Number, far:Number, fov:Number, aspect:Number):void
{
var h:Number = 1 / Math.tan(fov * Math.PI / 180);
var w:Number = h / aspect;
var q:Number = far / (far - near)

Initialize();

m00 = w;
m11 = h;
m22 = q;
m23 = -q * near;
m32 = 1.0;
}

/**
* ビュー変換行列の作成
* @param from カメラの位置
* @param at ターゲットの位置
* @param wup カメラの上方向
*/
public function View(from:Vector3d, at:Vector3d, up:Vector3d):void
{
var view_Z:Vector3d = new Vector3d();
var up_Y:Vector3d = new Vector3d();
var right_X:Vector3d = new Vector3d();

view_Z.x = at.x - from.x;
view_Z.y = at.y - from.y;
view_Z.z = at.z - from.z;
view_Z.Normalize();
//Debug.trace(view_Z.x + " " + view_Z.y + " " + view_Z.z );
right_X.crossProduct(view_Z, up);
right_X.Normalize();

up_Y.crossProduct(right_X, view_Z);
//Debug.trace("right_X.x=" + right_X.x + " " + "right_X.y=" + right_X.y + " " + "right_X.z=" + right_X.z);
//Debug.trace("up_Y.x=" + up_Y.x + " " + "up_Y.y=" + up_Y.y + " " + "up_Y.z=" + up_Y.z);

m00 = right_X.x; m01 = right_X.y; m02 = right_X.z; m03 = -from.DotProduct(right_X);
m10 = up_Y.x; m11 = up_Y.y; m12 = up_Y.z; m13 = -from.DotProduct(up_Y );
m20 = view_Z.x; m21 = view_Z.y; m22 = view_Z.z; m23 = -from.DotProduct(view_Z );
m30 = 0;
m31 = 0;
m32 = 0;
m33 = 1.0;
}

}

}


Cube.as
package primitives
{
import Matrix4x4;
import Vector3d;
import Face;

import flash.display.Graphics;
/**
* 立方体クラス
*/
public class Cube
{
private var faces:Array = new Array();

public function Cube(color:uint) {
// 頂点を作成
var v0:Vertex = new Vertex( 100, -100, 100);
var v1:Vertex = new Vertex( 100, 100, 100);
var v2:Vertex = new Vertex( -100, -100, 100);
// 面を作成
var face1:Face = new Face(v0, v1, v2, color);
this.faces.push(face1);

var v3:Vertex = new Vertex( 100, 100, 100);
var v4:Vertex = new Vertex(-100, 100, 100);
var v5:Vertex = new Vertex(-100, -100, 100);
var face2:Face = new Face(v3, v4, v5, color);
this.faces.push(face2);

var v6:Vertex = new Vertex(-100, -100, -100);
var v7:Vertex = new Vertex(-100, 100, -100);
var v8:Vertex = new Vertex( 100, -100, -100);
var face3:Face = new Face(v6, v7, v8, color);
this.faces.push(face3);

var v9:Vertex = new Vertex(-100, 100, -100);
var v10:Vertex = new Vertex(100, 100, -100);
var v11:Vertex = new Vertex(100, -100, -100);
var face4:Face = new Face(v9, v10, v11, color);
this.faces.push(face4);

var v12:Vertex = new Vertex(100, -100, -100);
var v13:Vertex = new Vertex(100, 100, -100);
var v14:Vertex = new Vertex(100, -100, 100);
var face5:Face = new Face(v12, v13, v14, color);
this.faces.push(face5);

var v15:Vertex = new Vertex(100, 100, -100);
var v16:Vertex = new Vertex(100, 100, 100);
var v17:Vertex = new Vertex(100, -100, 100);
var face6:Face = new Face(v15, v16, v17, color);
this.faces.push(face6);

var v18:Vertex = new Vertex( -100, -100, 100);
var v19:Vertex = new Vertex( -100, 100, 100);
var v20:Vertex = new Vertex( -100, -100, -100);
var face7:Face = new Face(v18, v19, v20, color);
this.faces.push(face7);

var v21:Vertex = new Vertex( -100, 100, 100);
var v22:Vertex = new Vertex( -100, 100, -100);
var v23:Vertex = new Vertex( -100, -100, -100);
var face8:Face = new Face(v21, v22, v23, color);
this.faces.push(face8);

var v24:Vertex = new Vertex(100, 100, 100);
var v25:Vertex = new Vertex(100, 100, -100);
var v26:Vertex = new Vertex( -100, 100, 100);
var face9:Face = new Face(v24, v25, v26, color);
this.faces.push(face9);

var v27:Vertex = new Vertex(100, 100, -100);
var v28:Vertex = new Vertex( -100, 100, -100);
var v29:Vertex = new Vertex( -100, 100, 100);
var face10:Face = new Face(v27, v28, v29, color);
this.faces.push(face10);
}

public function fillPolygon(g:Graphics, persM:Matrix4x4, modelM:Matrix4x4, eyePos:Vector3d, rotM:Matrix4x4, transM:Matrix4x4):void
{
for (var i:int = 0; i < faces.length; i++) {
faces[i].fillPolygon(g, persM, modelM, eyePos, rotM, transM);
}
}

public function persArray(persM:Matrix4x4, modelM:Matrix4x4, eyePos:Vector3d, rotM:Matrix4x4, transM:Matrix4x4, proFaces:Array):void
{
for (var i:int = 0; i < faces.length; i++) {
faces[i].persArray(persM, modelM, eyePos, rotM, transM, proFaces);
}
}
}

}