(Away3dlite) 지오데식 Sphere
Away3d Lite GeodesicSphere Test
*
*
* texture http://visibleearth.nasa.gov/
*
* @author Yongho, Ji
* @see http://blog.jidolstar.com/589
* @see http://blog.jidolstar.com/643
/**
* Copyright jidolstar ( http://wonderfl.net/user/jidolstar )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/dnOL
*/
/**
* Away3d Lite GeodesicSphere Test
*
*
* texture http://visibleearth.nasa.gov/
*
* @author Yongho, Ji
* @see http://blog.jidolstar.com/589
* @see http://blog.jidolstar.com/643
*/
package {
import com.bit101.components.*;
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.text.*;
import flash.ui.*;
import net.hires.debug.Stats;
[SWF(width=450, height=450, backgroundColor="#000000")]
public class away3dlite_geodesic_sphere extends Sprite {
private var _view:SphereView;
private var _radius:Number=100;
private var _fractures:Number=5;
private var _showFrame:Boolean=true;
public function away3dlite_geodesic_sphere() {
super();
stage.align=StageAlign.TOP_LEFT;
stage.scaleMode=StageScaleMode.NO_SCALE;
stage.frameRate=60;
createSphereView();
stage.addChild(new Stats());
}
private function createSphereView():void {
var loader:Loader=new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event):void {
var texture:BitmapData=Bitmap(loader.contentLoaderInfo.content).bitmapData;
_view=new SphereView(_radius, _fractures, _showFrame, texture);
stage.addChild(_view);
createSphereViewController();
});
loader.load(new URLRequest("http://lab.alumican.net/wonderfl/fp10sphere/texture.png"), new LoaderContext(true));
}
private function createSphereViewController():void {
var vertexCountLabel:Label=new Label(stage, 100, 86, "");
var surfaceCountLabel:Label=new Label(stage, 180, 86, "");
function updateCount():void {
vertexCountLabel.text="vertex : " + String(_view.getVertexCount());
}
new Label(stage, 100, 10, "SHAPE");
var fractureSlider:HUISlider=new HUISlider(stage, 100, 26, "fractures", function(e:Event):void {
var fracture:Number=Math.round(e.target.value);
if (fracture == _fractures)
return;
_fractures=fracture;
_view.createSphere(_radius, _fractures, _showFrame);
updateCount();
});
var radiusSlider:HUISlider=new HUISlider(stage, 100, 46, "Radius", function(e:Event):void {
var radius:Number=Math.round(e.target.value);
if (radius == _radius)
return;
_radius=radius;
_view.createSphere(_radius, _fractures, _showFrame);
updateCount();
});
var viewFrameCheckBox:CheckBox=new CheckBox(stage, 100, 66, "Show Wire Frame", function(e:Event):void {
_showFrame=viewFrameCheckBox.selected;
_view.createSphere(_radius, _fractures, _showFrame);
});
viewFrameCheckBox.selected=_showFrame;
radiusSlider.minimum=10;
radiusSlider.maximum=800;
radiusSlider.labelPrecision=0;
radiusSlider.value=_radius;
fractureSlider.minimum=0;
fractureSlider.maximum=10;
fractureSlider.labelPrecision=0;
fractureSlider.value=_fractures;
updateCount();
}
}
}
import away3dlite.arcane;
import away3dlite.cameras.*;
import away3dlite.containers.*;
import away3dlite.containers.*;
import away3dlite.core.base.*;
import away3dlite.materials.*;
import away3dlite.primitives.*;
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.net.URLRequest;
import flash.utils.*;
use namespace arcane;
/**
* Sphere를 보여주는 화면
*/
class SphereView extends Sprite {
//[Embed(source="../assets/earthmap1k.jpg")]
//private var SKY:Class;
private var scene:Scene3D;
private var camera:Camera3D
private var view:View3D;
private var _sphere:GeodesicSphere;
private var _frameSphere:GeodesicSphere;
private var _material:BitmapMaterial;
private var _vx:Number=0;
private var _vy:Number=0;
private var rotX:Matrix3D=new Matrix3D();
private var rotY:Matrix3D=new Matrix3D();
private var rot:Matrix3D=new Matrix3D();
public function SphereView($radius:Number, $fractures:Number, $viewframe:Boolean, $texture:BitmapData) {
_material=new BitmapMaterial($texture);
_material.smooth=true;
scene=new Scene3D();
camera=new Camera3D(1,1000);
view=new View3D(scene, camera);
addChild(view);
createSphere($radius, $fractures, $viewframe);
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage(event:Event):void {
addEventListener(Event.ENTER_FRAME, onRenderTick);
removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
addEventListener(Event.REMOVED_FROM_STAGE, onRemovedToStage);
view.x=stage.stageWidth / 2;
view.y=stage.stageHeight / 2;
}
private function onRemovedToStage($event:Event):void {
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedToStage);
removeEventListener(Event.ENTER_FRAME, onRenderTick);
}
public function createSphere($radius:Number, $fractures:Number, $showFrame:Boolean):void {
if (_sphere) {
scene.removeChild(_sphere);
_sphere = null;
}
if (_frameSphere) {
scene.removeChild(_frameSphere);
_frameSphere = null;
}
_sphere=new GeodesicSphere(_material, $radius, $fractures);
scene.addChild(_sphere);
if ($showFrame) {
_frameSphere=new GeodesicSphere(new WireframeMaterial(0xffffff, 0.2), $radius + 1, $fractures);
scene.addChild(_frameSphere);
}
}
protected function onRenderTick($event:Event=null):void {
_vx+=((mouseY / stage.stageHeight - 0.5) * 5 - _vx) * 0.3;
_vy+=(-(mouseX / stage.stageWidth - 0.5) * 5 - _vy) * 0.3;
//http://blog.federicocalvo.com/2009/03/papervision-3d-sphere-globla-axis.html
var tempMatrix:Matrix3D=_sphere.transform.matrix3D;
rotX.identity();
rotX.appendRotation(_vx, Vector3D.X_AXIS);
rotY.identity();
rotY.appendRotation(_vy, Vector3D.Y_AXIS);
rot.identity();
rot.append(rotX);
rot.append(rotY);
tempMatrix.append(rot);
_sphere.transform.matrix3D=tempMatrix.clone();
if (_frameSphere) {
_frameSphere.transform.matrix3D=tempMatrix.clone();
}
view.render();
}
public function getVertexCount():int {
if (!_sphere)
return 0;
return _sphere.vertices.length;
}
}
/**
* Creates a 3d Geodesc sphere primitive.
*/
class GeodesicSphere extends AbstractPrimitive {
private var _radius:Number;
private var _fractures:Number;
private var _yUp:Boolean=true;
/**
* @inheritDoc
*/
protected override function buildPrimitive():void {
super.buildPrimitive();
var D2R:Number=Math.PI / 180; //Degree->Radian
var R2D:Number=180 / Math.PI; //Radian->Degree
var TPI:Number=Math.PI * 2;
var PI:Number=Math.PI;
var HPI:Number=Math.PI / 2;
var hnLat:int=fractures + 1; //위도 방향 쪼갠수/2
var nLat:int=2 * hnLat; //위도 방향 쪼갠수
var nLon:int; //위도에 대한 경도 방향 쪼갠수
var lon:Number; //경도 (단위:라디안)
var lat:Number; //위도(단위:라디안)
var dLat:Number=180 / nLat * D2R; //위도 간격(단위:라디안)
var dLon:Number; //경도 간격(단위:라디안)
var i:int;
var j:int;
var x:Number;
var y:Number;
var z:Number;
var sinLat:Number;
var cosLat:Number;
var sinLon:Number;
var cosLon:Number;
var u:Number;
var v:Number;
////////////////////////////////
// Vertex, UVT 데이타 만들기
////////////////////////////////
// latitude -90->0 :
x=0;
y=0;
z=-_radius;
_yUp ? _vertices.push(x, -z, y) : _vertices.push(x, y, z);
_uvtData.push(0, 0, 1);
for (i=0; i < hnLat; i++) {
nLon=4 * (i + 1); //경도방향 꼭지점수 4, 8, 12, 16, 20...
dLon=360 / nLon * D2R;
lat=-HPI + (i + 1) * dLat;
v=(HPI + lat) / PI;
sinLat=Math.sin(lat);
cosLat=Math.cos(lat);
z=radius * sinLat;
for (j=0; j <= nLon; j++) {
lon=j * dLon;
sinLon=Math.sin(lon);
cosLon=Math.cos(lon);
x=radius * cosLat * cosLon;
y=radius * cosLat * sinLon;
u=lon / TPI;
_yUp ? _vertices.push(x, -z, y) : _vertices.push(x, y, z);
_uvtData.push(u, v, 1);
}
}
//latitude 0 -> 90
for (i=1; i < hnLat; i++) {
nLon=4 * (hnLat - i);
dLon=360 / nLon * D2R;
lat=dLat * i;
v=(HPI + lat) / PI;
sinLat=Math.sin(lat);
cosLat=Math.cos(lat);
z=radius * sinLat;
for (j=0; j <= nLon; j++) {
lon=j * dLon;
sinLon=Math.sin(lon);
cosLon=Math.cos(lon);
x=radius * cosLat * cosLon;
y=radius * cosLat * sinLon;
u=lon / TPI;
_yUp ? _vertices.push(x, -z, y) : _vertices.push(x, y, z);
_uvtData.push(u, v, 1);
}
}
x=0;
y=0;
z=_radius;
_yUp ? _vertices.push(x, -z, y) : _vertices.push(x, y, z);
_uvtData.push(0, 1, 1);
////////////////////////////////
// Face 만들기
////////////////////////////////
var k:int;
var pt0:int, pt1:int, pt2:int; //하나의 폴리곤을 생성하는 Vertex의 index값
var u_idx_start:int, u_idx_end:int, u_idx:int; //상단 index
var l_idx_start:int, l_idx_end:int, l_idx:int; //하단 index
var isUp:int; //지그재그로 컬링 폴리곤을 생성하기 위해
var tris:int; //한개 분면에서 해당 적위에 대한 면의 수
var triIdx:int; //한개 분면에서 해당 적위에 대한 면의 수만큼 index를 증가하기 위해 사용
//Latitude -90->0
tris=1;
u_idx_start=0;
u_idx_end=0;
for (i=0; i < hnLat; ++i) {
//위도 간격으로 상하 시작index와 끝 index를 지정
l_idx_start=u_idx_start;
l_idx_end=u_idx_end;
u_idx_start+=4 * i + 1;
u_idx_end+=4 * (i + 1) + 1;
l_idx=l_idx_start;
u_idx=u_idx_start;
//4분면을 따라 Face를 만들도록 한다.
for (k=0; k < 4; ++k) {
isUp=1;
//한개 분면에 대한 Face의 index를 만들어준다.
for (triIdx=0; triIdx < tris; ++triIdx) {
if (isUp === 1) {
pt0=l_idx;
pt2=u_idx;
u_idx++;
pt1=u_idx;
isUp=0;
} else {
pt0=u_idx;
pt1=l_idx;
l_idx++;
pt2=l_idx;
isUp=1;
}
_indices.push(pt0, pt1, pt2);
//_faceLengths.push(3);
}
}
tris+=2; //한개의 분면에서 해당 적위에 대한 면의 수는 2씩 증가한다.
}
//Latitude 0 -> 90
for (i=hnLat - 1; i >= 0; i--) {
l_idx_start=u_idx_start;
l_idx_end=u_idx_end;
u_idx_start=u_idx_start + 4 * (i + 1) + 1;
u_idx_end=u_idx_end + 4 * i + 1;
tris-=2;
u_idx=u_idx_start;
l_idx=l_idx_start;
for (k=0; k < 4; ++k) {
isUp=0;
for (triIdx=0; triIdx < tris; triIdx++) {
if (isUp === 1) {
pt0=l_idx;
pt2=u_idx;
u_idx++;
pt1=u_idx;
isUp=0;
} else {
pt0=u_idx;
pt1=l_idx;
l_idx++;
pt2=l_idx;
isUp=1;
}
_indices.push(pt0, pt1, pt2);
//_faceLengths.push(3);
}
}
}
}
/**
* Defines the radius of the sphere. Defaults to 100.
*/
public function get radius():Number {
return _radius;
}
public function set radius(val:Number):void {
if (_radius == val)
return;
_radius=val;
_primitiveDirty=true;
}
/**
* Defines the fractures of the sphere. Defaults to 2.
*/
public function get fractures():Number {
return _fractures;
}
public function set fractures(val:Number):void {
if (_fractures == val)
return;
_fractures=val;
_primitiveDirty=true;
}
/**
* Defines whether the coordinates of the plane points use a yUp orientation (true) or a zUp orientation (false). Defaults to true.
*/
public function get yUp():Boolean {
return _yUp;
}
public function set yUp(val:Boolean):void {
if (_yUp == val)
return;
_yUp=val;
_primitiveDirty=true;
}
/**
* Creates a new <code>GeodesicSphere</code> object.
*/
public function GeodesicSphere(material:Material=null, radius:Number=100, fractures:int=2, yUp:Boolean=true) {
super(material);
_radius=radius;
_fractures=fractures;
_yUp=yUp;
bothsides=false;
type="GeodesicSphere";
url="primitive";
}
}