Astro Cube
Astro Cube
*
* I've refered to the following posts
* てっく煮ブログ
*
* AS3.0 で 3D プログラミングを1から勉強する (1)~(4)
* http://d.hatena.ne.jp/nitoyon/20080616/as_3d_lessen1
* http://d.hatena.ne.jp/nitoyon/20080617/as_3d_lessen2
* http://d.hatena.ne.jp/nitoyon/20080618/as_3d_lessen3
* http://d.hatena.ne.jp/nitoyon/20080620/as_3d_lessen3
*
* Adobe デベロッパーセンター
*
* Matrixクラス - 変換行列
* http://www.adobe.com/jp/devnet/flash/articles/matrix_class.html
*
* Matrix3Dクラス - 変換行列2
* http://www.adobe.com/jp/devnet/flash/articles/matrix3d_class.html
*
* fumioNonaka.com
*
* Adobe Flash非公式テクニカルノート - 変換行列を数学的に捉える
* http://www.fumiononaka.com/TechNotes/Flash/FN0811001.html
*
*
/*
* Astro Cube
*
* I've refered to the following posts
* てっく煮ブログ
*
* AS3.0 で 3D プログラミングを1から勉強する (1)~(4)
* http://d.hatena.ne.jp/nitoyon/20080616/as_3d_lessen1
* http://d.hatena.ne.jp/nitoyon/20080617/as_3d_lessen2
* http://d.hatena.ne.jp/nitoyon/20080618/as_3d_lessen3
* http://d.hatena.ne.jp/nitoyon/20080620/as_3d_lessen3
*
* Adobe デベロッパーセンター
*
* Matrixクラス - 変換行列
* http://www.adobe.com/jp/devnet/flash/articles/matrix_class.html
*
* Matrix3Dクラス - 変換行列2
* http://www.adobe.com/jp/devnet/flash/articles/matrix3d_class.html
*
* fumioNonaka.com
*
* Adobe Flash非公式テクニカルノート - 変換行列を数学的に捉える
* http://www.fumiononaka.com/TechNotes/Flash/FN0811001.html
*
*
*/
package {
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.geom.Vector3D;
import flash.geom.Matrix3D;
import flash.display.Graphics;
import __AS3__.vec.Vector;
import flash.geom.PerspectiveProjection;
import flash.utils.Dictionary;
[SWF(backgroundColor="#FFFFFF", frameRate="30")]
public class Astro extends Sprite
{
public static var fov:PerspectiveProjection= new PerspectiveProjection();
private var canvas:Sprite;
private var rad:int;
private var cube:Cube;
public function Astro()
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
cube = new Cube(0, 0, 0, 200)
canvas = new Sprite();
addChild(canvas);
canvas.x = 200;
canvas.y = 200;
canvas.z = 0;
//視野角の設定
fov.fieldOfView = 45;
rad = 0;
addEventListener(Event.ENTER_FRAME, function(evt:Event):void{render();});
}
private function render():void
{
canvas.graphics.clear();
// 回転行列を作成
var matrix:Matrix3D= new Matrix3D();
//X軸方向に傾ける
matrix.appendRotation(Math.PI/180*rad/2, Vector3D.X_AXIS);
//Y軸方向に傾ける
matrix.appendRotation(Math.PI/180*rad*3, Vector3D.Y_AXIS);
//Z軸方向に傾ける
matrix.appendRotation(Math.PI/180*rad, Vector3D.Z_AXIS);
cube.draw(canvas.graphics, matrix);
// 角度更新
rad += 10;
}
}
}
import flash.geom.Vector3D;
import flash.geom.Matrix3D;
import flash.display.Graphics;
import __AS3__.vec.Vector;
import flash.geom.PerspectiveProjection;
import flash.utils.Dictionary;
class Cube
{
private var points:Vector.<Vector3D> = new Vector.<Vector3D>();
public function Cube(x:Number, y:Number, z:Number, len:Number)
{
var diff:Function = function(f:Boolean):Number{return f ? len / 2 : -len / 2;};
// 立方体の頂点8つを作成する
for(var i:int = 0; i < 8; i++)
{
var p:Vector3D= new Vector3D(x + diff(i % 4 % 3 == 0), y + diff(i % 4 < 2), z + diff(i < 4));
points.push(p);
}
}
public function draw(g:Graphics, matrix:Matrix3D):void
{
// 回転後の各頂点の座標を計算
var p:Vector.<Vector3D> = new Vector.<Vector3D>();
for(var i:int = 0; i < points.length; i++)
{
//matrix.appendTranslation(points[i].x, points[i].y, points[i].z);
var pt:Vector3D= matrix.transformVector(points[i]);
var fov:PerspectiveProjection = Astro.fov;
// 点を透視投影する
pt.w = fov.focalLength / (fov.focalLength + pt.z);
pt.project();
//drawPoint(g, pt);
p.push(pt);
}
// 頂点の間を線で結ぶ
for(i = 0; i < 4; i++)
{
//drawLine(g, p[i], p[i + 4]);
//drawLine(g, p[i], p[(i + 1) % 4]);
//drawLine(g, p[i + 4], p[(i + 1) % 4 + 4]);
}
// 面の一覧
var planes:Array = [
[p[0], p[1], p[2], p[3]],
[p[7], p[6], p[5], p[4]],
[p[0], p[4], p[5], p[1]],
[p[1], p[5], p[6], p[2]],
[p[2], p[6], p[7], p[3]],
[p[3], p[7], p[4], p[0]]
];
// 面の中心のZ座標を求める
var z:Dictionary= new Dictionary();
for(i = 0; i < planes.length; i++)
{
z[planes[i]] = (planes[i][0].z + planes[i][1].z + planes[i][2].z + planes[i][3].z) / 4;
}
// Zソート (奥のものから順番に並べる)
planes.sort(function(a:Array, b:Array):Number
{
return z[b] - z[a];
});
// 奥から順番に面を描画
var counter:int = 0;
for each(var plane:Array in planes)
{
drawPlane(g, plane[0], plane[1], plane[2], plane[3]);
}
}
private function drawPlane(g:Graphics, p1:Vector3D, p2:Vector3D, p3:Vector3D, p4:Vector3D):void
{
// 単位法線ベクトル
var v1:Vector3D = p2.subtract(p1);
var v2:Vector3D = p4.subtract(p1);
// ベクトルの外積(2つのベクトルに垂直なベクトル)
var n:Vector3D= cross(v1, v2);
//単位ベクトル(長さ1のベクトル)に変換
n.normalize();
// 光源の方向ベクトルとの内積
var l:Vector3D = new Vector3D(0, 0, -1);
//l と n の内積を面の明るさとする(ランバートの法則)
var brightness:Number = dot(n, l);
// 面を塗る
var b:int = 0x3f * brightness + 0xc0;
g.beginFill(b * 0x10000 + b * 0x100 + b, 0.2);
g.lineStyle(0, 0x666666);
var p:Vector3D;
p = p1.clone(); g.moveTo(p.x, p.y);
p = p2.clone(); g.lineTo(p.x, p.y);
p = p3.clone(); g.lineTo(p.x, p.y);
p = p4.clone(); g.lineTo(p.x, p.y);
g.endFill();
}
private function drawPoint(g:Graphics, p:Vector3D):void
{
g.beginFill(0x000000);
g.drawCircle(p.x, p.y, 3);
g.endFill();
}
private function drawLine(g:Graphics, p1:Vector3D, p2:Vector3D):void
{
g.beginFill(0, 0);
g.lineStyle(1, 0x000000);
g.moveTo(p1.x, p1.y);
g.lineTo(p2.x, p2.y);
g.lineStyle();
g.endFill();
}
// 外積
private function cross(p1:Vector3D, p2:Vector3D):Vector3D
{
return new Vector3D(p1.y * p2.z - p1.z * p2.y,
p1.z * p2.x - p1.x * p2.z,
p1.x * p2.y - p1.y * p2.x);
}
// 内積
private function dot(p1:Vector3D, p2:Vector3D):Number
{
return p1.x * p2.x + p1.y * p2.y + p1.z * p2.z;
}
}