/* 透明な球体の頂点に、あたかも丸いシールが貼り付いているかのように見える 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; } } sphere