Flash10で球体の作成

Flash10で球体の作成をしてみました。
こんな感じ。
http://moeten.info/flex/20081016_fp10Test/bin-release/test04.html

参考サイト(っというかそのまま)
Enhanced Drawing API
ソースはこちら

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()"
    width="800" height="600" backgroundGradientColors="[0x000000,0xcccccc]"
    >
<mx:Script>
<![CDATA[
//初期化関数
private var globe:Shape;
private function init():void{
    // 地球作成
    globe = new Shape();
    globe.x = 275;
    globe.y = 200;
    myUI.addChild(globe);
    //地球データーの作成
    setGlobeData();
    // 毎フレーム描画
    addEventListener(Event.ENTER_FRAME, render );
    // マウスダウン・アップイベント
    addEventListener(MouseEvent.MOUSE_DOWN, toggleStroke);
    addEventListener(MouseEvent.MOUSE_UP  , toggleStroke);
}
//描画
private function render(event:Event):void {
    //GraphicsTrianglePathのデーターから3Dへ変換
    transformIn3D(triangles, vectors3D, focal, getTimer()/1000);
    //一旦クリア
    globe.graphics.clear();
    //一気に描画
    globe.graphics.drawGraphicsData(globeData);
}
//マウスイベント
private function toggleStroke(event:MouseEvent):void {
    //マウスダウンでラインのサイズを指定
    GraphicsStroke(globeData[0]).thickness = (event.type == MouseEvent.MOUSE_DOWN) ? 1 : NaN;
}
/***********************************************\
 * 球体
\***********************************************/
// グローバル変数
[Embed(source="map.png")]private var Erf:Class;//テクスチャ
private var focal:Number            = 300;//?
private var globeRadius:Number        = 100;//半径
private var globeParallels:int        = 10;//縦ライン
private var globeMeridians:int        = 20;//横ライン
private var frontFace:BitmapData    = Bitmap(new Erf()).bitmapData;//表面用テクスチャ
private var backFace:BitmapData    = getDarkerBitmap(frontFace, .25);//背面用テクスチャ
private var globeData:Vector.<IGraphicsData>;
private var triangles:GraphicsTrianglePath;
private var vectors3D:Vector.<Vector3D>;
private function setGlobeData():void{
    triangles = new GraphicsTrianglePath(
        new Vector.<Number>(), new Vector.<int>(),
        new Vector.<Number>(), TriangleCulling.NEGATIVE);
    vectors3D = new Vector.<Vector3D>();
    createSphere(triangles, vectors3D, globeRadius, globeParallels, globeMeridians);
    var trianglesDark:GraphicsTrianglePath = new GraphicsTrianglePath(
            triangles.vertices, triangles.indices,
            triangles.uvtData, TriangleCulling.POSITIVE);
    globeData = Vector.<IGraphicsData>([
        new GraphicsStroke(NaN, false, "normal", "none", "round", 3, new GraphicsSolidFill(0xFF0000)),
        new GraphicsBitmapFill(backFace, null, false, true),
        trianglesDark,
        new GraphicsBitmapFill(frontFace, null, false, true),
        triangles
    ]);
}
// 球を作成
private function createSphere(trianglePathOut:GraphicsTrianglePath,
                      vertices3DOut:Vector.<Vector3D>,
                      radius:Number = 100,
                      parallels:int = 5,
                      meridians:int = 10):void {
    if (parallels < 3) parallels = 3;
    if (meridians < 3) meridians = 3;
    meridians++; // テクスチャのエッジtexture edge meridian duplicated
    var parallelStops:int = parallels-1; // uの決定用
    var meridianStops:int = meridians-1; // vの決定用
    // ローカル変数
    var r:Number; // 半径
    var x:Number, y:Number, z:Number; // coordinates
    var p:int, pi:int, pa:Number; // parallel vars
    var m:int, mi:int, ma:Number; // meridian vars
    var u:Number, v:Number; // u, v of uvt
    var n:int = -1; // 頂点インデックス
    // 横方向
    for (p=0; p<parallels; p++){
        v  = p/parallelStops;
        pa = v*Math.PI - Math.PI/2;
        y  = radius*Math.sin(pa);
        r  = radius*Math.cos(pa);
        // 縦方向
        for (m=0; m<meridians; m++){
            u  = m/meridianStops;
            ma = u*Math.PI*2;
            x  = r*Math.cos(ma);
            z  = r*Math.sin(ma);
            // 頂点
            vertices3DOut[++n] = new Vector3D(x,y,z);
            // 三角パスアウト
            trianglePathOut.vertices.push(x, y);
            trianglePathOut.uvtData.push(u, v, 1);
            if (m != 0){ // not first meridian (texture edge)
                if (p != parallelStops){ // not last parallel (no next parallel to connect)
                    trianglePathOut.indices.push(n, n+meridians, n+meridians-1);
                    trianglePathOut.indices.push(n, n+meridians-1, n-1);
                }
            }
        }
    }
}
// コンバーター。GraphicsTrianglePathのデーターから3Dへ
private function transformIn3D(trianglePathOut:GraphicsTrianglePath,
                       vertices3DIn:Vector.<Vector3D>,
                       focal:Number,
                       rotationY:Number):void {
    // Yの回転方向についての角度計算
    var ca:Number = Math.cos(rotationY);
    var sa:Number = Math.sin(rotationY);
    var t:Number;
    var i:int, n:int = vertices3DIn.length;
    for (i=0; i<n; i++){
        // Y軸周りのポイント変換
        var x:Number = vertices3DIn[i].x*ca - vertices3DIn[i].z*sa;
        var z:Number = vertices3DIn[i].x*sa + vertices3DIn[i].z*ca;
        // 3D 奥行き
        t = focal/(focal + z);
        // trianglePathOutの設定
        trianglePathOut.uvtData[i*3 + 2]    = t; // テクスチャ用のperspective
        trianglePathOut.vertices[i*2]        = x * t; // perspective x
        trianglePathOut.vertices[i*2 + 1]    = vertices3DIn[i].y * t; // perspective y
    }
}
// 背面用にテクスチャを黒くする
private function getDarkerBitmap(source:BitmapData, darkness:Number):BitmapData {
    var darker:Bitmap = new Bitmap(source);
    darker.transform.colorTransform = new ColorTransform(darkness, darkness, darkness);
    var container:Sprite = new Sprite();
    container.addChild(darker);
    var bmp:BitmapData = new BitmapData(source.width, source.height, source.transparent, 0);
    bmp.draw(container);
    return bmp;
}
]]>
</mx:Script>
<mx:UIComponent id="myUI" width="100%" height="100%"/>
</mx:Application>