forked from: Stage3Dでエッジ検出(+ Away3D)

by bradsedito forked from Stage3Dでエッジ検出(+ Away3D) (diff: 60)
♥0 | Line 187 | Modified 2012-11-28 23:21:53 | 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/pZrf
 */






package
{
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import away3d.cameras.*;
    import away3d.containers.*;
    import away3d.entities.*;
    import away3d.filters.*;
    import away3d.lights.*;
    import away3d.materials.*;
    import away3d.materials.lightpickers.*;
    import away3d.primitives.*;

    [SWF(width="465", height="465", frameRate="60", backgroundColor="0xFFFFFF")]
   
   
    public class Test extends View3D
    {
        static public const DEPTH_THRESHOLD       :Number    =  0.009;
        static public const dt                    :Number    =  0.009;
        static public const COLOR_SHADE_RATIO     :Number    =  0.3;
        static public const CAMERA_DISTANCE_XZ    :Number    =  1000;
        static public const CAMERA_DISTANCE_Y     :Number    =  1000;
        static public const ROT_VEL               :Number    = 1.0;
        //Util
        static public const POS_ZERO            :Vector3D    = new Vector3D(0,0,0);
        //Away3D
        private var m_View                :View3D;
        private var m_Scene                :Scene3D;
        private var m_Camera            :Camera3D;
        //Rot
        private var m_RotTheta            :Number = 0;
        private var source:BitmapData = new BitmapData(465, 465, true, 0x000000);

        public function Test()
        {
            {
                Wonderfl.disable_capture();
                addChild(new Bitmap(source));
            }
            
            {
                m_View = addChild(new View3D()) as View3D;
                m_View.antiAlias = 4;
                m_View.backgroundColor = 0x888888;
                m_View.backgroundAlpha = 0;
                m_Scene = m_View.scene;
                m_Camera = m_View.camera;
            }
            
            {
                m_Camera.y = CAMERA_DISTANCE_Y;
                m_Camera.z = CAMERA_DISTANCE_XZ;
                m_Camera.lookAt(POS_ZERO);
            }

            //Light
            var lightPicker:StaticLightPicker;
            {
                var light:DirectionalLight = new DirectionalLight(1, -8, 2);
                light.specular = 0.1;
                light.ambient = 0.7;
                m_Scene.addChild(light);

                lightPicker = new StaticLightPicker([light]);
            }

            //Filter
            {
                var edge_filter:EdgeDetectionFilter3D = new EdgeDetectionFilter3D(DEPTH_THRESHOLD, COLOR_SHADE_RATIO);
                m_View.filters3d = [edge_filter];
            }

            //Cube
            {
                const CUBE_W:int = 256;

                var cube_geometry    :CubeGeometry = new CubeGeometry(CUBE_W, CUBE_W, CUBE_W, 4, 4, 4);
                var material        :ColorMaterial = new ColorMaterial(0x88AAAA);
                material.lightPicker = lightPicker;

                var cube_mesh:Mesh;
                for(var i:int = 0; i < 6; ++i){
                    cube_mesh = new Mesh(cube_geometry, material);

                    switch(i){
                    case 0: cube_mesh.x += CUBE_W; break;
                    case 1: cube_mesh.x -= CUBE_W; break;
                    case 2: cube_mesh.y += CUBE_W; break;
                    case 3: cube_mesh.y -= CUBE_W; break;
                    case 4: cube_mesh.z += CUBE_W; break;
                    case 5: cube_mesh.z -= CUBE_W; break;
                    }

                    m_Scene.addChild(cube_mesh);
                }
            }

            //Update
            {
                addEventListener(Event.ENTER_FRAME, Update);
            }
        }

        private function Update(event:Event = null):void
        {
            var delta_time:Number = 1.0 / stage.frameRate;

            //Rotation
            {
                m_RotTheta += ROT_VEL * delta_time;
                if(2*Math.PI <= m_RotTheta){m_RotTheta -= 2*Math.PI;}

                m_Camera.x = CAMERA_DISTANCE_XZ * Math.sin(m_RotTheta);
                m_Camera.z = CAMERA_DISTANCE_XZ * Math.cos(m_RotTheta);

                m_Camera.lookAt(POS_ZERO);
            }

            //Render
            {
                m_View.render();
            }
            {
                m_View.renderer.queueSnapshot(source);
            }

        }
    }
}



import away3d.arcane;
import away3d.cameras.*;
import away3d.core.managers.*;
import away3d.filters.*;
import away3d.filters.tasks.*;
import flash.display3D.*;
import flash.display3D.*;
import flash.display3D.textures.*;

use namespace arcane;

class EdgeDetectionFilter3D extends Filter3DBase
{
    //Task
    private var m_Task_EdgeDetection : Filter3DEdgeDetectionTask;

    //Init
    public function EdgeDetectionFilter3D(depth_threshold:Number = 100, color_shade_ratio:Number = 0.0)
    {
        super();
        m_Task_EdgeDetection = new Filter3DEdgeDetectionTask(depth_threshold, color_shade_ratio);
        addTask(m_Task_EdgeDetection);
    }
}

class Filter3DEdgeDetectionTask extends Filter3DTaskBase
{
    //==Var==

    //Shader Const
    private var _data : Vector.<Number>;

    //Init
    public function Filter3DEdgeDetectionTask(depth_threshold:Number, color_shade_ratio:Number)
    {
        super(true);
        var dt:uint

        _data = Vector.<Number>(
        [
            0, 0, 0, 0,//offsetA
            0, 0, 0, 0,//offsetB
            depth_threshold, 1 - color_shade_ratio, 0, 0,        //[depth_threshold, 1 - color_shade_ratio, 0, ??]
            1.0, 1 / 255.0, 1 / 65025.0, 1 / 16581375.0            //深度バッファのRGBとの内積をとることで深度を求める
        ]);
    }

    //Shader : Pixel
    override protected function getFragmentCode() : String
    {
        var code:String;

        //「左上と右下」「右上と左下」のDepthの差(絶対値)の合計を求める
        //- ft0 : posA0,    ft1 : posA1,    ft2 : posB0,    ft3 : posB1
        //- ft4 : depthA0,    ft5 : depthA1,    ft6 : depthB0,    ft7 : depthB1,
        //- ft4 : AbsGapA,    ft6 : AbsGapB
        //- ft4 : TotalGap
        code =    "sub ft0, v0, fc0    \n" +//ft0 = v0 - fc0
                "add ft1, v0, fc0    \n" +//ft1 = v0 + fc0
                "sub ft2, v0, fc1    \n" +//ft2 = v0 - fc1
                "add ft3, v0, fc1    \n" +//ft3 = v0 + fc1
                "tex ft4, ft0, fs1 <2d, nearest>    \n" +//ft4 = fs1.get(ft0)
                "tex ft5, ft1, fs1 <2d, nearest>    \n" +//ft5 = fs1.get(ft1)
                "tex ft6, ft2, fs1 <2d, nearest>    \n" +//ft6 = fs1.get(ft2)
                "tex ft7, ft3, fs1 <2d, nearest>    \n" +//ft7 = fs1.get(ft3)
                "dp4 ft4.z, ft4, fc3        \n" +//ft4.z = rgb_to_depth(ft4)
                "dp4 ft5.z, ft5, fc3        \n" +//ft5.z = rgb_to_depth(ft5)
                "dp4 ft6.z, ft6, fc3        \n" +//ft6.z = rgb_to_depth(ft6)
                "dp4 ft7.z, ft7, fc3        \n" +//ft7.z = rgb_to_depth(ft7)
                "sub ft4.z, ft4.z, ft5.z    \n" +//ft4.z -= ft5.z
                "abs ft4.z, ft4.z            \n" +//ft4.z = abs(ft4.z)
                "sub ft6.z, ft6.z, ft7.z    \n" +//ft6.z -= ft7.z
                "abs ft6.z, ft6.z            \n" +//ft6.z = abs(ft6.z)
                "add ft4.z, ft4.z, ft6.z    \n";//ft4.z += ft6.z

        //Depthの差の合計が閾値以下なら普通の描画、閾値以上なら暗くして描画する
        //- ft0 : Color (Ori => Ori-Dec)
        //- ft1 : 
        //- ft2 : DecColor
        code += "tex ft0, v0, fs0 <2d,linear,clamp>    \n" +//ft0 = fs0.get(v0)
                "slt ft1.x, fc2.x, ft4.z    \n" +//ft1.x = (threshold < depth) // 0:通常描画, 1:陰描画
                "mul ft1.x, ft1.x, fc2.y    \n" +//ft1.x *= ft3.y // 0:通常描画, dec_color_shade_ratio:陰描画
                "mul ft2, ft1.x, ft0        \n" +//ft2 = ft1.x * ft0 // ori*0:通常描画, ori*dec_color_shade_ratio:陰描画
                "mov ft2.w, fc2.z            \n" +//ft2.a = 0
                "sub oc, ft0, ft2            \n";//output = ft0 - ft2 // ori:通常描画, ori*color_shade_ratio:陰描画

        return code;
    }

    //Activate : on
    override public function activate(stage3DProxy : Stage3DProxy, camera : Camera3D, depthTexture : Texture) : void
    {
        var context : Context3D = stage3DProxy._context3D;

        //fs1 = depthTexture
        stage3DProxy.setTextureAt(1, depthTexture);

        //fc0 = _data[0~3]
        //fc1 = _data[4~7]
        //fc2 = _data[8~11]
        //fc3 = _data[12~15]
        context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, _data, 4);
    }

    //Activate : off
    override public function deactivate(stage3DProxy : Stage3DProxy) : void
    {
        stage3DProxy.setTextureAt(1, null);
    }

    //Update : textures
    override protected function updateTextures(stage : Stage3DProxy) : void
    {
        super.updateTextures(stage);

        updateData();
    }

    //Update : data
    private function updateData() : void
    {
        var invW : Number = 1 / _textureWidth;

        //OffsetA
        //fc0 = [-invW, -invW, 0, 0]
        _data[0] = -invW;
        _data[1] = -invW;

        //OffsetB
        //fc1 = [ invW, -invW, 0, 0]
        _data[4] =  invW;
        _data[5] = -invW;
    }
}