[test]stage3d, AGAL(3)

by okoi
♥0 | Line 234 | Modified 2011-11-11 19:16:49 | MIT License
play

ActionScript3 source code

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

/**
 * [test]stage3d, AGAL(3)
 * Stage3Dテスト
 * テクスチャの作成
 * アルファブレンド
 */
package 
{
    import com.adobe.utils.AGALMiniAssembler;
    import com.adobe.utils.PerspectiveMatrix3D;
    import flash.display.Stage3D;
    import flash.display3D.Program3D;
    import flash.display3D.Context3D;
    import flash.display3D.Context3DRenderMode;
    import flash.display3D.Context3DVertexBufferFormat;
    import flash.display3D.Context3DProgramType;
    import flash.display3D.Context3DTriangleFace;    
    import flash.display3D.Context3DBlendFactor;
    import flash.display3D.Context3DCompareMode;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.utils.ByteArray;
    import flash.geom.Vector3D;
    import flash.geom.Matrix3D;
    
    [SWF(width = "465", height = "465", frameRate="60")]
    
    /**
     * ...
     * @author okoi
     */
    public class Main extends Sprite 
    {
        private static const WIDTH:int = 465;
        private static const HEIGHT:int = 465;
    
        private var _stage3D:Stage3D;
        private var _context3D:Context3D;
        private var _renderProgram:Program3D;    //    レンダリングプログラム
        
        private var _matProjection:PerspectiveMatrix3D;
        private var _camera:Camera;
        
        private var _particleData:ParticleData;
        private var _particleList:Vector.<Particle>;
        
        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point
            _stage3D = stage.stage3Ds[0];
            _stage3D.addEventListener( Event.CONTEXT3D_CREATE, Context3DCreateHandler );
            _stage3D.requestContext3D( Context3DRenderMode.AUTO );
            
        }
    
        private function Context3DCreateHandler( e:Event ) : void 
        {
            _context3D = _stage3D.context3D;
            _context3D.enableErrorChecking = true;
            _context3D.configureBackBuffer( WIDTH, HEIGHT, 0, true );
            _context3D.setCulling(Context3DTriangleFace.BACK);
            _context3D.setBlendFactors( Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA );
            _context3D.setDepthTest(false, Context3DCompareMode.ALWAYS);
            _renderProgram = _context3D.createProgram();
            
            InitCamera();
            InitProjection();
            InitShader();
            
            _particleData = new ParticleData( _context3D );
            _particleList = new Vector.<Particle>();
            
            _context3D.clear();
            
            AddParticle();
                                    
            addEventListener( Event.ENTER_FRAME, EnterFrameHandler );
        }        
        
        private function InitProjection() : void {
            
            _matProjection = new PerspectiveMatrix3D();
            _matProjection.perspectiveFieldOfViewLH( 45 * Math.PI / 180, WIDTH / HEIGHT, 0.1, 3000 );
        }
        
        private function InitCamera() : void {
            _camera = new Camera();        
        }
        
        private function InitShader() : void {
            
            var agalAssembler:AGALMiniAssembler = new AGALMiniAssembler();

            var code:String = "";
            var vShader:ByteArray;
            var fShader:ByteArray;
            
            code =  "m44 op, va0, vc0\n";
            code += "mov v0, va1\n";
            vShader = agalAssembler.assemble( Context3DProgramType.VERTEX, code );
            
            code = "tex ft0, v0, fs0 <2d,clamp,linear>\n";
            code += "mul oc, ft0, fc0\n";
            //code = "mov oc, v0\n";
            fShader = agalAssembler.assemble( Context3DProgramType.FRAGMENT, code );
            
            _renderProgram.upload( vShader, fShader );
            _context3D.setProgram(_renderProgram);
        }
        
        private function EnterFrameHandler( e:Event ) : void {
            
            var i:int;

            for ( i = _particleList.length - 1; i >= 0; i-- ) {
                if ( _particleList[i].life > 0 )    _particleList[i].life--;
                else                                 _particleList.splice( i, 1 );
            }
            
            _camera.InitView( new Vector3D(0, 0, -2), new Vector3D(0, 0, 0), new Vector3D(0, 1, 0) );
            
            _context3D.clear();
            for ( i = _particleList.length - 1; i >= 0; i-- ){
                var mat:Matrix3D = new Matrix3D();
                var particle:Particle = _particleList[i];
                
                _context3D.setVertexBufferAt( 0, _particleData.vBuf, 0, Context3DVertexBufferFormat.FLOAT_3 );    //    va0
                _context3D.setVertexBufferAt( 1, _particleData.uvBuf, 0, Context3DVertexBufferFormat.FLOAT_2 );    //    va1
                _context3D.setTextureAt( 0, _particleData.texture );
            
                mat.append( particle.matrix );    //    ワールド座標変換
                mat.append( _camera.matrix );    //    ビュー変換変換
                mat.append( _matProjection );    //    プロジェクション座標変換
                
                var alpha:Number = ( particle.life / particle.maxlife > 0.5 ) ? (1 - (particle.life / particle.maxlife)) * 2: (particle.life / particle.maxlife) * 2;
                _context3D.setProgramConstantsFromMatrix( Context3DProgramType.VERTEX, 0, mat, true );    //    vc0    
                _context3D.setProgramConstantsFromVector( Context3DProgramType.FRAGMENT, 0, Vector.<Number>([ particle.r, particle.g, particle.b, alpha ]) );
                _context3D.drawTriangles( _particleData.iBuf );
            }
            _context3D.present();
            
            
            if ( int(Math.random() * 10) == 0 ) {
                AddParticle();
            }
        }
        
        private function AddParticle() : void {
            
            var p:Particle = new Particle();
            
            _particleList.push( p );
        }
    }
    
}

import flash.display.BitmapData;
import flash.display.Shape;
import flash.display3D.Context3D;
import flash.display3D.textures.Texture;
import flash.display3D.IndexBuffer3D;
import flash.display3D.VertexBuffer3D;
import flash.display3D.Context3DTextureFormat;
import flash.geom.Matrix;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;

class Camera {
    private var _view:Matrix3D;

    public function Camera() {
        
        _view = new Matrix3D();
    }
    
    /**
     * ビュー行列の設定を行う
     * PerspectiveMatrix3DのlookAtLH,RHはバグがあるっぽいので自力計算
     * @param    from
     * @param    at
     * @param    up
     */
    public function InitView( from:Vector3D, at:Vector3D, up:Vector3D ) : void {

        var vz:Vector3D = at.subtract( from );
        vz.normalize();
        var vx:Vector3D = up.crossProduct( vz );
        vx.normalize();
        var vy:Vector3D = vz.crossProduct( vx );
        vy.normalize();
        var vtx:Number = vx.dotProduct( from ) * -1;
        var vty:Number = vy.dotProduct( from ) * -1;
        var vtz:Number = vz.dotProduct( from ) * -1;
        
        _view.identity();
        _view.rawData = Vector.<Number>([
            vx.x, vy.x, vz.x, 0,
            vx.y, vy.y, vz.y, 0,
            vx.z, vy.z, vz.z, 0,
            vtx,  vty,  vtz,  1,
        ]);        
    }
    
    public function get matrix():Matrix3D {
        return    _view;
    }
    
}


class ParticleData {

    private var _vBuf:VertexBuffer3D;
    private var _uvBuf:VertexBuffer3D;
    private var _iBuf:IndexBuffer3D;
    
    private var _texture:Texture = null;
    
    public function ParticleData( context3d:Context3D ) {
        
        _vBuf = context3d.createVertexBuffer( 4, 3 );
        _vBuf.uploadFromVector( 
            Vector.<Number>([
                -0.1,  0.1, 0,
                 0.1,  0.1, 0,
                 0.1, -0.1, 0,
                -0.1, -0.1, 0,
            ]),
            0,
            4
        );
        
        _uvBuf = context3d.createVertexBuffer( 4, 2 );
        _uvBuf.uploadFromVector( 
            Vector.<Number>([
                0,  0,
                1,  0,
                1,  1,
                0,  1,
            ]),
            0,
            4
        );
        
        _iBuf = context3d.createIndexBuffer( 3 * 2 );
        _iBuf.uploadFromVector(
            Vector.<uint>([
                0, 1, 2,
                2, 3, 0,
            ]),
            0,
            3 * 2
        );
        
        
        InitTexture( context3d );
    }

    private function InitTexture( context3d:Context3D ) : void {
        
        var w:int = 16;
        var h:int = 16;
        
        var shape:Shape = new Shape();
        shape.graphics.beginFill( 0xFFFFFF );
        shape.graphics.drawCircle( 0, 0, 5 );
        shape.graphics.endFill();
        
        var bmd:BitmapData = new BitmapData(w, h, true, 0 );
        bmd.draw( shape, new Matrix(1, 0, 0, 1, w/2, h/2), null, null, null, true  );
        
        _texture = context3d.createTexture( w, h, Context3DTextureFormat.BGRA, false );
        _texture.uploadFromBitmapData( bmd );
        
        bmd.dispose();
        bmd = null;
        
    }
    
    public function get vBuf():VertexBuffer3D { return    _vBuf;    }
    public function get uvBuf():VertexBuffer3D { return _uvBuf;    }
    public function get iBuf():IndexBuffer3D { return    _iBuf;    }
    public function get texture():Texture { return    _texture;    }
}

class Particle {
    public var x:Number = 0;
    public var y:Number = 0;
    public var z:Number = 0;
    
    public var r:Number = 1;
    public var g:Number = 1;
    public var b:Number = 1;
    
    public var life:Number;
    public var maxlife:Number;
    
    public function Particle() {
        life = Math.random() * 200 + 100;
        maxlife = life;
        r = Math.random();
        g = Math.random();
        b = Math.random();
        
        x = Math.random() - 0.5;
        y = Math.random() - 0.5;
        z = Math.random();
    }
    
    
    public function get matrix() : Matrix3D {
        var mat:Matrix3D = new Matrix3D();
        
        mat.appendTranslation( x, y, z );
        return    mat;
    }
}