sphere
透明な球体の頂点に、あたかも丸いシールが貼り付いているかのように見える 3D 表現
* 2009/01/19 Stats 追加
/* 透明な球体の頂点に、あたかも丸いシールが貼り付いているかのように見える 3D 表現
* 2009/01/19 Stats 追加
*/
package {
/**
* @author YOSHIDA, Akio
* http://aquioux.blog48.fc2.com/blog-entry-538.html
*/
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Vector3D;
import flash.geom.Matrix3D;
import flash.geom.PerspectiveProjection;
import net.hires.debug.Stats;
[SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "#000000")]
public class Main extends Sprite {
Wonderfl.capture_delay(10);
// 3D オブジェクトのコンテナ
private var rootNode:Sprite;
// 頂点
private var vctrVertics:Vector.<Vertex>;
// プロジェクション
private var fov:PerspectiveProjection;
// 回転に関わる変数
private var aX:Number = 0;
private var aY:Number = 0;
// 中心から頂点までの距離
private const DIST:uint = 200;
public function Main() {
createProjection(); // プロジェクション生成
createContainer(); // 3D コンテナ生成
createVertics(); // 頂点生成
this.addChild(new Stats());
// イベントハンドラ
stage.addEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
}
// イベントハンドラ
private function onEnterFrameHandler(e:Event):void {
aX += rootNode.mouseX*0.005;
aY -= rootNode.mouseY*0.005;
// 変換行列生成
var mat:Matrix3D = new Matrix3D();
// 回転を変換行列に合成
mat.appendRotation(aX, Vector3D.Y_AXIS);
mat.appendRotation(aY, Vector3D.X_AXIS);
perspective(mat, fov); // 投影
zsort(); // Zソート
}
// 投影
private function perspective(mat:Matrix3D, fov:PerspectiveProjection):void {
for each (var element:Vertex in vctrVertics) {
element.render(mat, fov, DIST);
}
}
// Zソート
private function zsort():void {
vctrVertics.sort( function(x:Vertex, y:Vertex):Number { return y.z - x.z; } );
var len:uint = vctrVertics.length;
var i:int = len;
while(i--) { rootNode.setChildIndex(vctrVertics[i], len-1); }
}
// プロジェクション生成
private function createProjection():void {
fov = new PerspectiveProjection();
fov.fieldOfView = 60; // 視野角の設定
}
// 3D コンテナ生成
private function createContainer():void{
rootNode = new Sprite();
rootNode.x = stage.stageWidth / 2;
rootNode.y = stage.stageHeight / 2;
rootNode.z = 250;
addChild(rootNode);
}
// 頂点生成
private function createVertics():void {
var baseNum:uint = 4;
var vNum:uint = baseNum * 2;
var hNum:uint = baseNum * 2;
// theta:シータ(θ)は緯度、phi:ファイ(φ)は経度
var theta:Number = Math.PI / (vNum + 1);
var phi:Number = Math.PI * 2 / hNum;
vctrVertics = new Vector.<Vertex>();
var i:uint = 0;
for (var v:int = 0; v < vNum ; v++) {
for (var h:int = 0; h < hNum ; h++) {
var px:Number = DIST * Math.sin(theta*(v+1)) * Math.cos(phi*h);
var pz:Number = DIST * Math.sin(theta*(v+1)) * Math.sin(phi*h);
var py:Number = DIST * Math.cos(theta*(v+1));
var vertex:Vertex = new Vertex(px, py, pz);
rootNode.addChild(vertex);
vctrVertics.push(vertex);
}
}
}
}
}
/*
* 頂点クラス
*/
import flash.display.Shape;
import flash.geom.Vector3D;
import flash.geom.Matrix3D;
import flash.geom.PerspectiveProjection;
import flash.geom.ColorTransform;
class Vertex extends Shape {
private var home:Vector3D = new Vector3D(); // 座標ホームポジション
private var proj:Vector3D = new Vector3D(); // 投影座標
public function Vertex(x:Number, y:Number, z:Number) {
this.x = home.x = x;
this.y = home.y = y;
this.z = home.z = z;
// 描画
graphics.beginFill(0xffffff);
graphics.drawCircle(0, 0, 20);
graphics.endFill();
}
public function render(mat:Matrix3D, fov:PerspectiveProjection, dist:uint):void {
// 投影座標を計算し、自分自身(表示オブジェクト)に適用する
proj = mat.transformVector(home);
proj.w = fov.focalLength / (fov.focalLength + proj.z);
proj.project();
x = proj.x;
y = proj.y;
z = proj.z;
scaleX = scaleY = 1 / proj.w;
// 円が球体に貼り付いているように見せるために円を歪ませる処理
rotation = Math.atan2(y, x) / Math.PI * 180;
scaleX = z / dist;
// 円に裏と表があるように見せるために色を変える処理
var ct:ColorTransform = new ColorTransform();
(z > 0) ? ct.color = 0xffcc00 : ct.color = 0xcc0000;
transform.colorTransform = ct;
}
}