[ff]: Smooth Shading Sphere Sample

by bradsedito forked from Smooth Shading Sphere Sample (diff: 1)
♥0 | Line 366 | Modified 2012-05-11 00:32:58 | MIT License
play

ActionScript3 source code

/**
 * Copyright bradsedito ( http://wonderfl.net/user/bradsedito )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/shVT
 */

// forked from yuichiroharai's Smooth Shading Sphere Sample
package 
{
    import com.adobe.utils.AGALMiniAssembler;
    import com.adobe.utils.PerspectiveMatrix3D;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.display.Stage3D;
    import flash.display.StageAlign;
    import flash.display.StageQuality;
    import flash.display.StageScaleMode;
    import flash.display3D.Context3D;
    import flash.display3D.Context3DBlendFactor;
    import flash.display3D.Context3DCompareMode;
    import flash.display3D.Context3DProgramType;
    import flash.display3D.Context3DRenderMode;
    import flash.display3D.Context3DTriangleFace;
    import flash.display3D.Context3DVertexBufferFormat;
    import flash.display3D.IndexBuffer3D;
    import flash.display3D.Program3D;
    import flash.display3D.VertexBuffer3D;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Matrix3D;
    import flash.geom.Rectangle;
    import flash.geom.Vector3D;
    import flash.net.URLRequest;
    import flash.system.ApplicationDomain;
    import flash.system.LoaderContext;
    import flash.system.SecurityDomain;
    import flash.text.AntiAliasType;
    import flash.text.Font;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;
    import flash.utils.getTimer;
    import net.hires.debug.Stats;
    
    [SWF(width="465", height="465", backgroundColor="0x000000")]
    public class SmoothShadingSample extends Sprite 
    {

// ----------------------------------------------------------------------------------------------------
// 変数
//
        // Stage 関連
        private var _stageWidth:uint;
        private var _stageHeight:uint;
        private var _stageWidthHarf:uint;
        private var _stageHeightHarf:uint;
        
        // Stage3D 関連
        static private const _SEGMENT:uint = 64;
        
        private var _stage3D:Stage3D;
        private var _context3D:Context3D;
        private var _stage3DSize:uint;
        private var _vertexList:Vector.<Number>;
        private var _indexList:Vector.<uint>;
        private var _indexBuffer:IndexBuffer3D;
        private var _indexNum:uint;
        private var _perspectiveMatrix3D:PerspectiveMatrix3D;
        
        private var _time:uint;
        private var _rotationX:Number = 0;
        private var _rotationY:Number = 0;
        private var _rotationHue:Number = 0;
        
        // AGAL 関連
        private var _agalVertexCommon:String;
        private var _agalVertexNone:String;
        private var _agalVertexAlpha:String;
        private var _agalVertexBrightness:String;
        private var _agalVertexSaturation:String;
        private var _agalVertexContrast:String;
        private var _agalFragment:String;
        private var _agalType:uint;
        
        // テキスト
        static private const TEXT_LIST:Vector.<String> = Vector.<String>([
            "NONE", "ALPHA (0~1)", "BRIGHTNESS (-1~1)", "SATURATION (-1~1)", "CONTRAST (-1~1)"
        ]);
        private var _textField:TextField;
        private var _textFormat:TextFormat;
        
        // カラーサンプル
        private const COLOR_SIZE:uint = 20;
        private const COLOR_RECT:Rectangle = new Rectangle(0, 0, COLOR_SIZE, COLOR_SIZE);
        private var _bmpColor:Bitmap;
        
        // スクリーンショット
        //private var _screenShot:Bitmap;
        
// ----------------------------------------------------------------------------------------------------
// コンストラクタ
//        
        // コンストラクタ
        public function SmoothShadingSample():void 
        {
            Wonderfl.disable_capture();
            //addChild(_screenShot = new Bitmap());
            
            // ステージ設定
            stage.quality = StageQuality.BEST;
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.frameRate = 60;
            
            // ステージイベント
            stage.addEventListener(Event.FULLSCREEN, _atResize);
            stage.addEventListener(Event.RESIZE, _atResize);
            _atResize();
            
            _initStage3D();
            
            // スタッツ
            addChild(new Stats());
        }        
            
            
// ----------------------------------------------------------------------------------------------------
// ステージイベント
//
        // ステージのリサイズ
        private function _atResize(e:Event=null):void 
        {
            _stageWidth = stage.stageWidth;
            _stageHeight = stage.stageHeight;
            _stageWidthHarf = uint(_stageWidth/2);
            _stageHeightHarf = uint(_stageHeight/2);
            
            if (_context3D != null) _resizeStage3D();
            if (_textField != null) _resizeText();
            if (_bmpColor != null) _resizeColor();
        }
        
        
// ----------------------------------------------------------------------------------------------------
// Stage3D
//    
        // Stage3D の初期化
        private function _initStage3D():void 
        {
            _stage3D = stage.stage3Ds[0];
            _stage3D.addEventListener(Event.CONTEXT3D_CREATE, _onContext3dCreate);
            _stage3D.requestContext3D(Context3DRenderMode.AUTO);
        }
        // Stage3D の初期化完了
        private function _onContext3dCreate(e:Event):void
        {
            // Context3D 初期化
            _context3D = _stage3D.context3D;
            //_context3D.enableErrorChecking = true;
            _context3D.setDepthTest(true, Context3DCompareMode.LESS);
            _context3D.setCulling(Context3DTriangleFace.NONE);
            _context3D.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ZERO);
            
            _resizeStage3D();
            
            _context3D.clear(0, 0, 0);
            _context3D.present();
            
            
            _initAgal();
            _setAGAL(_agalType = 2);
            _initSphere();
            _initText();
            _initColor();
            
            // 透視投影変換用 Matrix3D
            _perspectiveMatrix3D = new PerspectiveMatrix3D();
            _perspectiveMatrix3D.perspectiveFieldOfViewLH(Math.PI/4, 1, 0.1, 1000);
            
            // 定数アップロード
            _uploadVertexConstFromMatrix(0, _perspectiveMatrix3D);
            _uploadVertexConstFromVector(8, Vector.<Number>([0, 0.5, 1, 3]));     // 定数
            _uploadVertexConstFromVector(10, Vector.<Number>([0, 1, 0, 4]));     // 光源(xyz), 球体の画面奥への平行移動(w)
            
            addEventListener(Event.ENTER_FRAME, _drawStage3D);
            stage.addEventListener(MouseEvent.CLICK, _changeShadingType);
        }
        // 毎フレームの描画処理
        private function _drawStage3D(e:Event):void
        {
            var currentTime:uint, rotationMatrix:Matrix3D, translationMatrix:Matrix3D, rgb:Vector.<Number>;
            
            // 時間で回転角度を決定
            _time = (currentTime = getTimer()) - _time;
            if ((_rotationY += 0.12 * _time) > 360) _rotationY -= 360;
            if ((_rotationX += 0.09 * _time) > 360) _rotationX -= 360;
            if ((_rotationHue += 0.02 * _time/360) > 1) _rotationHue -= 1;
            _time = currentTime;
            
            // 色生成 コントラストの時のみ明るさを0.75へ
            rgb = _hsbToRGB(_rotationHue, 1, (_agalType == 4) ? 0.75 : 1);
            _changeColor(_uintRgb(rgb[0], rgb[1], rgb[2]));
            
            // 回転の Matrix3D を生成
            rotationMatrix = new Matrix3D();
            rotationMatrix.appendRotation(_rotationY, Vector3D.X_AXIS);
            rotationMatrix.appendRotation(_rotationX, Vector3D.Y_AXIS);
            
            // 定数アップロード
            _uploadVertexConstFromMatrix(4, rotationMatrix);
            _uploadVertexConstFromVector(9, Vector.<Number>([rgb[0], rgb[1], rgb[2], 1]));    // 着色用
            
            // 描画
            _context3D.clear(0, 0, 0);
            _context3D.drawTriangles(_indexBuffer, 0, _indexNum);
            //_context3D.drawToBitmapData(_screenShot.bitmapData);
            _context3D.present();
        }
        
        // Stage3D のリサイズ
        private function _resizeStage3D():void {
            
            // サイズ
            _stage3DSize = (_stageWidth > _stageHeight) ? _stageHeightHarf : _stageWidthHarf;
            _stage3DSize = _stage3DSize * 2; // 偶数になるように調整
            if (_stage3DSize < 466) _stage3DSize = 466;
            
            // 配置
            _stage3D.x = _stageWidthHarf - _stage3DSize/2;
            _stage3D.y = _stageHeightHarf - _stage3DSize/2;
            
            // バッファサイズの初期化
            _context3D.configureBackBuffer(_stage3DSize, _stage3DSize, 16, true);
            
            /*if (_screenShot.bitmapData != null) _screenShot.bitmapData.dispose(); 
            _screenShot.bitmapData = new BitmapData(_stage3DSize,_stage3DSize, false, 0);   
            _screenShot.x = _stage3D.x;
            _screenShot.y = _stage3D.y;*/
        }
        
        // シェーディングの種類を変更
        private function _changeShadingType(e:MouseEvent):void 
        {
            if (++_agalType > 4) _agalType -= 5;
            _setAGAL(_agalType);
            _changeText();
        }
        
// ----------------------------------------------------------------------------------------------------
// Stage3D - 球面データ
//
        // 球面の初期化
        private function _initSphere():void
        {
            var i:uint, j:uint, rotX:Number, rotY:Number, segmentPlus:uint, v:Vector3D, m:Matrix3D,
                vertexBuffer:VertexBuffer3D, vertexNum:uint;
                
            _vertexList = new Vector.<Number>;
            _indexList = new Vector.<uint>;
            
            segmentPlus = _SEGMENT + 1;
            m = new Matrix3D();
            // 頂点リストにデータを追加
            for (j=0;j<segmentPlus;j++) {
                rotY = 180 * (j / _SEGMENT - 0.5);
                for (i=0;i<segmentPlus;i++) {
                    rotX = 360 * (i / _SEGMENT - 0.5);
                    
                    // 真正面(x=0, y=0, z=-1)を基準点として球面の頂点を生成
                    v = new Vector3D(0, 0, -1, 0);
                    m.identity();
                    m.appendRotation(-rotY, Vector3D.X_AXIS);
                    m.appendRotation(-rotX, Vector3D.Y_AXIS);
                    v = m.deltaTransformVector(v);
                    
                    // 色は後で着色
                    _vertexList.push(v.x, v.y, v.z, 1, 1, 1, 1, 1);
                }
            }
            
            // 頂点バッファを生成 & アップロード
            vertexNum = _vertexList.length/8;
            vertexBuffer = _context3D.createVertexBuffer(vertexNum, 8);
            vertexBuffer.uploadFromVector(_vertexList, 0, vertexNum);
            _context3D.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_4);
            _context3D.setVertexBufferAt(1, vertexBuffer, 4, Context3DVertexBufferFormat.FLOAT_4);
            
            // インデックスリストにデータを追加
            for (j=0;j<_SEGMENT;j++) {
                for (i=0;i<_SEGMENT;i++) {            
                    _indexList.push(j*segmentPlus + i, (j+1)*segmentPlus + i+1, (j+1)*segmentPlus + i);
                    _indexList.push(j*segmentPlus + i, j*segmentPlus + i+1, (j+1)*segmentPlus + i+1);
                }
            }
            
            // インデックスバッファを生成
            _indexNum = _indexList.length/3;
            _indexBuffer = _context3D.createIndexBuffer(_indexList.length);
            _indexBuffer.uploadFromVector(_indexList, 0, _indexList.length);
        }
        
        
// ----------------------------------------------------------------------------------------------------
// Stage3D - 定数
//
        // Matrix3D から定数のアップロード
        private function _uploadVertexConstFromMatrix(i:uint, data:Matrix3D):void
        {
            _context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, i, data, true);
        }
        // Vector から定数のアップロード
        private function _uploadVertexConstFromVector(i:uint, data:Vector.<Number>):void
        {
            _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, i, data, data.length/4);
        }
        
        
// ----------------------------------------------------------------------------------------------------
// Stage3D - AGAL
//
        /*
         * AGALの生成
         * 
         * vc0-3    : 透視投影変換用の Matrix3D データ
         * vc4-7    : 球体回転用の Matrix3D データ
         * vc8.x    : 定数 0
         * vc8.y    : 定数 0.5
         * vc8.z    : 定数 1
         * vc8.w    : 定数 3
         * vc9        : 着色用の RGBA データ
         * vc10.xyz    : 光源用のベクトルデータ(0, 0, -1)
         * vc10.w    : 球体の画面奥への平行移動用の定数
         * 
         * vt0        : 座標データを回転したもの
         * vt1        : さらに画面奥に平行移動したもの
         * vt2        : 色データの格納用
         * vt3.x    : 頂点と光源の内積(-1 ~ 1)
         * vt3.y    : (1-内積)/3
         * vt3.z    : (1+内積)
         * vt3.w    : (-0.5*内積)
         * vt4-6    : 彩度やコントラスト用の3×3行列
         */
        private function _initAgal():void
        {
            // 頂点シェーダー 共通
            _agalVertexCommon  = "m44 vt0, va0, vc4 \n";         // 球体を回転
            _agalVertexCommon += "mov vt1, vt0 \n";             // 座標をいったんコピー
            _agalVertexCommon += "add vt1.z, vt1.z, vc10.w \n"; // Z座標のみ画面奥へ平行移動
            _agalVertexCommon += "m44 op, vt1, vc0 \n";            // 透視投影変換して出力
            
            _agalVertexCommon += "mov vt2, va1 \n";                // 元の色の取りだし(結局、使ってないけどエラー防止)
            _agalVertexCommon += "mov vt2, vc9 \n";                // 元の色を使わず着色用の定数をコピー
            _agalVertexCommon += "dp3 vt3.x, va0, vc10 \n";        // 元の座標と光源から内積を計算
            
            // 何もなし
            _agalVertexNone = "mov v0, vt2 \n";                            // 色を出力
            
            // アルファ
            _agalVertexAlpha  = "add vt3.x, vt3.x, vc8.z \n";            // (内積+1)
            _agalVertexAlpha += "mul vt3.x, vt3.x, vc8.y \n";            // (内積+1)*0.5
            _agalVertexAlpha += "mov vt2.w, vt3.x \n";                    // アルファに(内積+1)*0.5を適用
            _agalVertexAlpha += "mov v0, vt2";                             // 色を出力
            
            // 明度
            _agalVertexBrightness  = "add vt2.xyz, vt2.xyz, vt3.x \n";    // 各色に内積を足す
            _agalVertexBrightness += "mov v0, vt2";                     // 色を出力
            
            // 彩度
            _agalVertexSaturation  = "sub vt3.y, vc8.z, vt3.x \n";    // (1-内積)
            _agalVertexSaturation += "div vt3.y, vt3.y, vc8.w \n";    // (1-内積)/3
            _agalVertexSaturation += "mov vt4.xyz, vt3.y \n";        // xyzに(1-内積)/3をコピー
            _agalVertexSaturation += "mov vt5.xyz, vt3.y \n";        // xyzに(1-内積)/3をコピー
            _agalVertexSaturation += "mov vt6.xyz, vt3.y \n";        // xyzに(1-内積)/3をコピー
            _agalVertexSaturation += "mov vt4.w, vc8.x \n";            // wに0をコピー(エラー防止)
            _agalVertexSaturation += "mov vt5.w, vc8.x \n";            // wに0をコピー(エラー防止)
            _agalVertexSaturation += "mov vt6.w, vc8.x \n";            // wに0をコピー(エラー防止)
            _agalVertexSaturation += "add vt4.x, vt4.x, vt3.x \n";    // xに内積を足す
            _agalVertexSaturation += "add vt5.y, vt5.y, vt3.x \n";    // yに内積を足す
            _agalVertexSaturation += "add vt6.z, vt6.z, vt3.x \n";    // zに内積を足す
            _agalVertexSaturation += "m33 vt2.xyz, vt2.xyz, vt4 \n";// vt2  vt4-6 行列掛け算
            _agalVertexSaturation += "mov v0, vt2";                 // 色を出力
            
            // コントラスト
            _agalVertexContrast  = "add vt3.z, vc8.z, vt3.x \n";    // (1+内積)
            _agalVertexContrast += "mul vt3.w, vc8.y, vt3.x \n";    // (0.5*内積)
            _agalVertexContrast += "neg vt3.w, vt3.w \n";            // (-0.5*内積)
            _agalVertexContrast += "mov vt4, vc8.x \n";                // 全部に0をコピー
            _agalVertexContrast += "mov vt5, vc8.x \n";                // 全部に0をコピー
            _agalVertexContrast += "mov vt6, vc8.x \n";                // 全部に0をコピー
            _agalVertexContrast += "mov vt4.x, vt3.z \n";            // xに(1+内積)をコピー
            _agalVertexContrast += "mov vt5.y, vt3.z \n";            // yに(1+内積)をコピー
            _agalVertexContrast += "mov vt6.z, vt3.z \n";            // zに(1+内積)をコピー
            _agalVertexContrast += "m33 vt2.xyz, vt2.xyz, vt4 \n";    // vt2 と vt4-6の 行列掛け算
            _agalVertexContrast += "add vt2.xyz, vt2.xyz, vt3.w \n";// 各色に(-0.5*内積)を足す
            _agalVertexContrast += "mov v0, vt2";                    // 色を出力
            
            // 断片シェーダー
            _agalFragment = "mov oc, v0";
        }
        
        // AGALをアップロード
        // 0=NONE, 1=ALPHA, 2=BRIGHTNESS, 3=SATURATION, 4=CONTRAST
        public function _setAGAL(type:uint=0):void
        {
            var agalVertex:String, vertexAssembler:AGALMiniAssembler, fragmentAssembler:AGALMiniAssembler, program3D:Program3D;
            switch (type) 
            {
                case 0:
                    agalVertex = _agalVertexCommon + _agalVertexNone;
                break;
                case 1:
                    agalVertex = _agalVertexCommon + _agalVertexAlpha;
                break;
                case 2:
                    agalVertex = _agalVertexCommon + _agalVertexBrightness;
                break;
                case 3:
                    agalVertex = _agalVertexCommon + _agalVertexSaturation;
                break;
                case 4:
                    agalVertex = _agalVertexCommon + _agalVertexContrast;
                break;
                default:
            }
            
            vertexAssembler = new AGALMiniAssembler();
            vertexAssembler.assemble(Context3DProgramType.VERTEX, agalVertex);
            fragmentAssembler = new AGALMiniAssembler();
            fragmentAssembler.assemble(Context3DProgramType.FRAGMENT, _agalFragment);
            program3D = _context3D.createProgram();
            program3D.upload(vertexAssembler.agalcode, fragmentAssembler.agalcode);
            _context3D.setProgram(program3D);
        }
        
// ----------------------------------------------------------------------------------------------------
// テキスト
//
        private function _initText():void
        {
            var _textFormat:TextFormat;
            _textField = new TextField()
            _textFormat = _textField.defaultTextFormat;
            _textFormat.color = 0xffffff;
            _textFormat.font = "_sans";
            _textField.defaultTextFormat = _textFormat;
            _textField.text = TEXT_LIST[_agalType];
            _textField.selectable = false;
            _textField.autoSize = TextFieldAutoSize.CENTER;
            addChild(_textField);
            
            _resizeText();
        }
        private function _changeText():void
        {
            _textField.text = TEXT_LIST[_agalType];
        }
        private function _resizeText():void
        {
            _textField.x = _stageWidthHarf - (_textField.width/2);
            _textField.y = _stage3DSize*0.85;
        }
        
// ----------------------------------------------------------------------------------------------------
// カラーサンプル
//
        private function _initColor():void
        {
            _bmpColor = new Bitmap()
            _bmpColor.bitmapData = new BitmapData(COLOR_SIZE, COLOR_SIZE, false, 0);
            addChild(_bmpColor);
            _resizeColor();
        }
        private function _changeColor(color:uint):void
        {
            _bmpColor.bitmapData.fillRect(COLOR_RECT, color);
        }
        private function _resizeColor():void
        {
            _bmpColor.x = _stageWidthHarf - COLOR_SIZE/2;
            _bmpColor.y = _stage3DSize*0.9;
        }
        
// ----------------------------------------------------------------------------------------------------
// カラーユーティリティ
//
        private static function _uintRgb(r:Number, g:Number, b:Number):uint
        {
            return ((r * 0xFF + 0.5) << 16) + ((g * 0xFF + 0.5) << 8) + ((b * 0xFF + 0.5) << 0);
        }
        
        // HSBからRGBへの変換
        private static function _hsbToRGB(hue:Number, saturation:Number, brightness:Number):Vector.<Number>
        {
            var r:Number, g:Number, b:Number, h:Number, f:Number, p:Number, q:Number, t:Number;
            
            r = g = b = 0;
            if (saturation == 0) {
                r = g = b = brightness;
            } else {
                h = (hue - int(hue)) * 6;
                f = h - int(h);
                p = brightness * (1 - saturation);
                q = brightness * (1 - saturation * f);
                t = brightness * (1 - (saturation * (1 - f)));
                switch (int(h)) {
                    case 0:
                        r = brightness;
                        g = t;
                        b = p;
                        break;
                    case 1:
                        r = q;
                        g = brightness;
                        b = p;
                        break;
                    case 2:
                        r = p;
                        g = brightness;
                        b = t;
                        break;
                    case 3:
                        r = p;
                        g = q;
                        b = brightness;
                        break;
                    case 4:
                        r = t;
                        g = p;
                        b = brightness;
                        break;
                    case 5:
                        r = brightness;
                        g = p;
                        b = q;
                        break;
                }
            }
            return Vector.<Number>([r, g, b]);
        }
        
        
        
    }
}