forked from: レイトレーシング

by ohisama forked from レイトレーシング (diff: 219)
レイトレーシング習作
参考文献:Javaではじめるレイトレーシング入門(森北出版)
ボタンはhttp://d.hatena.ne.jp/nitoyon/20090423/as3_simple_buttonを使わせて頂きました。

[SWF(width = "465", height = "465", backgroundColor = "0xffffff", fps = "60")]
♥0 | Line 854 | Modified 2013-01-24 12:20:01 | MIT License | (replaced)
play

ActionScript3 source code

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

// forked from termat's レイトレーシング
/**
    レイトレーシング習作
    参考文献:Javaではじめるレイトレーシング入門(森北出版)
    ボタンはhttp://d.hatena.ne.jp/nitoyon/20090423/as3_simple_buttonを使わせて頂きました。
*/
package
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    //[SWF(width = "465", height = "465", backgroundColor = "0xffffff", fps = "60")] 
    public class Practice29 extends Sprite 
    {
        private var image : RayImage;
        private var angle : Number = 0;
        private var radius : Number = 5;
        private var hh : Number = 3.3;
        private var mode : int = 0;
        public function Practice29()
        {
            image = new RayImage();
            addChild(image);
            var bt0 : Button = new Button(50, 30, 5, "Rendering", 11);
            bt0.x = 450;
            bt0.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void { image.startRendering(); } );
            addChild(bt0);
            var bt2 : Button = new Button(50, 20, 5, "△", 12);
            bt2.x = 225;
            bt2.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void { mode = 1; } );
            bt2.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void { mode = 0; } );
            addChild(bt2);
            var bt3 : Button = new Button(50, 20, 5, "▽", 12);
            bt3.x = 225; bt3.y = 480;
            bt3.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void { mode = 2; } );
            bt3.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void { mode = 0; } );
            addChild(bt3);
            var bt4 : Button = new Button(20, 50, 5, "<", 12);
            bt4.y = 225;
            bt4.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void { mode = 3; } );
            bt4.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void { mode = 0; } );
            addChild(bt4);
            var bt5 : Button = new Button(20, 50, 5, ">", 12);
            bt5.x = 480; bt5.y = 225;
            bt5.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void { mode = 4; } );
            bt5.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void { mode = 0; } );
            addChild(bt5);
            var bt6 : Button = new Button(20, 20, 5, "↑", 12);
            bt6.x = 0; bt6.y = 0;
            bt6.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void { mode = 5; } );
            bt6.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void { mode = 0; } );
            addChild(bt6);
            var bt7 : Button = new Button(20, 20, 5, "↓", 12);
            bt7.x = 0; bt7.y = 480;
            bt7.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void { mode = 6; } );
            bt7.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void { mode = 0; } );
            addChild(bt7);
            addEventListener(Event.ENTER_FRAME,update);
        }        
        private function update(e : Event) : void 
        {
            if (!image.isCompeleted) return;
            switch(mode) 
            {
                case 0:
                    return;
                case 1:
                    radius = Math.max(radius - 0.2, 4);
                    break;
                case 2:
                    radius = Math.min(radius + 0.2, 8);
                    break;
                case 3:
                    angle = Math.max(angle-1, -25);
                    break;
                case 4:
                    angle = Math.min(angle + 1, 25);
                    break;
                case 5:
                    hh = Math.min(hh + 0.1, 4.5);
                    break;
                case 6:
                    hh = Math.max(hh - 0.1, 2.5);
                    break;
            }
            var rad : Number = angle / 180 * Math.PI;
            var xx : Number = Math.cos(rad) * radius - Math.sin(rad) * radius;
            var yy : Number = Math.sin(rad) * radius + Math.cos(rad) * radius;
            image.ray.setPosition(xx, yy, 5);
            image.ray.setReference(3, 3, hh);
            image.drawImage();
        }
    }
}
import flash.display.Sprite;
import flash.events.Event;
import flash.text.TextField;
import flash.geom.Matrix;
import flash.filters.ColorMatrixFilter;
import flash.filters.GlowFilter;
import flash.display.Loader;
import flash.display.MovieClip;
import flash.events.Event;
import flash.geom.Vector3D;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.net.URLRequest;
import flash.system.LoaderContext;
class RayImage extends MovieClip 
{
    private var loader : Loader;
    public var bmpImage : BitmapData;
    private var bmpdata : BitmapData;
    private var bmp : Bitmap;
    public var ray : Ray;
    private var tracer : RayTrace;
    private var nodes : Nodes;
    private var shade : Shade;
    private var im : int = 500;
    public var isCompeleted : Boolean = true;
    public function RayImage() : void 
    {
        bmpdata = new BitmapData(500, 500, false, 0xffffff);
        bmp = new Bitmap(bmpdata);
        addChild(bmp);
        loader = new Loader();
        var url : String = "http://assets.wonderfl.net/images/related_images/f/ff/ff48/ff48d14d79a931bfbf6892b8e2558c3c64bc697e";
        var urlReq : URLRequest = new URLRequest(url);
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadCompleted);
        loader.load(urlReq, new LoaderContext(true));
        Wonderfl.capture_delay(20);
    }    
    private function loadCompleted(e : Event) : void
    {
        bmpImage = new BitmapData(loader.width, loader.height);
        bmpImage.draw(loader);
        init();
    }    
    public function init() : void 
    {
        ray = new Ray();
        ray.setPosition(5, 5, 5);
        //視点位置
        ray.setReference(3, 3, 3.3);
        //注視点
        ray.setAbove(0, 0, 1);
        //上方向のベクトル
        ray.createAxis();
        ray.createLight( -1.0, 0, 4.0, 150, 150, 150, 2.0, 0.3);
        ray.bgcolor = 0xccccff;
        ray.setTexture(0);
        ray.setObjectColor(255, 0, 0);
        ray.shadeParameter(0.3, 0.5, 0.1, 1.4, 0.9);
        ray.createSphere(0.0, 0.0, 1.0, 1.0);
        ray.setTexture(1);
        ray.setObjectColor( 0, 150, 0);
        ray.shadeParameter(0.6, 0.7, 0.2, 1.4, 0.5);
        ray.createRectangle( -3, 3, 0, -3, -3, 0, 3, -3, 0, 3, 3, 0);
        nodes = new Nodes();
        var map : Map = new Map(nodes, this);
        tracer = new RayTrace(ray);
        shade = new Shade(ray, nodes, tracer, map);
        tracer.shade = shade;
        //drawImage();
        addEventListener(Event.ENTER_FRAME, update);
    }    
    public function startRendering() : void 
    {
        if (isCompeleted) 
        {
            im = 500;
            isCompeleted = false;
        }
    }    
    public function update(e : Event) : void 
    {
        if (!isCompeleted) 
        {
            redering();
            if (im == 0) isCompeleted = true;
        }
    }    
    public function redering() : void 
    {
        var pj : Number = (im - 250) / 250.0;
        for (var j : int = 0; j < 500; j++) 
        {
            var pi : Number = (j - 250) / 250.0;
            var x : Number = pi * ray.xAxis.x + pj * ray.yAxis.x + ray.reference.x;
            var y : Number = pi * ray.xAxis.y + pj * ray.yAxis.y + ray.reference.y;
            var z : Number = pi * ray.xAxis.z + pj * ray.yAxis.z + ray.reference.z;
            var dirVector : Vector3D = new Vector3D(x - ray.me.x, y - ray.me.y, z - ray.me.z);
            dirVector.normalize();
            if (tracer.seach(dirVector, ray.me.x, ray.me.y, ray.me.z)) 
            {
                nodes.no = 0;
                nodes.setData(tracer.index, 1.0, shade.interPoint.x, shade.interPoint.y, shade.interPoint.z, dirVector, tracer.normalVector, 0);
                bmpdata.setPixel(j, 500-im, shade.colorSet());
            }
            else 
            {
                bmpdata.setPixel(j, 500-im, ray.bgcolor);
            }
        }
        im--;
    }    
    public function drawImage() : void
    {
        for (var i : int = 0; i < 500; i++) 
        {
            var pi : Number = (i - 250) / 250.0;
            for (var j : int = 0; j < 500; j++) 
            {
                var pj : Number = (j - 250) / 250.0;
                var x : Number = pi * ray.xAxis.x + pj * ray.yAxis.x + ray.reference.x;
                var y : Number = pi * ray.xAxis.y + pj * ray.yAxis.y + ray.reference.y;
                var z : Number = pi * ray.xAxis.z + pj * ray.yAxis.z + ray.reference.z;
                var dirVector : Vector3D = new Vector3D(x - ray.me.x, y - ray.me.y, z - ray.me.z);
                dirVector.normalize();
                if (tracer.seach(dirVector, ray.me.x, ray.me.y, ray.me.z)) 
                {
                    if (tracer.index == 0) 
                    {
                        bmpdata.setPixel(i, 500 - j, 0xff9999);
                    }
                    else 
                    {
                        bmpdata.setPixel(i, 500 - j, 0xffffff);
                    }
                }
                else 
                {
                    bmpdata.setPixel(i, 500-j, 0x999999);
                }
            }
        }
    }
}
/* 光源 */
class Light 
{
    public var position : Vector3D;
    public var color : Vector3D;
    public var brightness : Number;
    public var ambient : Number;
}
/* オブジェクト */
class Object3d 
{
    public static const SPHEHE : int = 1;
    public static const RECTANGLE : int = 4;
    public var op : int;
    public var vert1 : Vector3D;
    public var vert2 : Vector3D;
    public var vert3 : Vector3D;
    public var vert4 : Vector3D;
    public var dh : Vector3D;
    public var radius : Number;
    public var color : Vector3D;
    public var textureNum : int;
    public var diffuseReflectance : Number;        //拡散反射率
    public var specularReflectionRate:Number;    //鏡面反射率
    public var luster : Number;                    //面光沢
    public var refractiveIndex : Number;            //屈折率
    public var reflectivity : Number;                //反射率
    public function Object3d(_op:int,x1:Number,y1:Number,z1:Number,
        x2:Number,y2:Number,z2:Number,x3:Number,y3:Number,z3:Number,
        x4:Number,y4:Number,z4:Number,dhx:Number, dhy:Number, dhz:Number,
        _radius:Number,r:int,g:int,b:int,textureNum:int,
        _diffuseReflectance:Number,_specularReflectionRate:Number,_luster:Number,
        _refractiveIndex:Number,_reflectivity:Number)
    {
        this.op = _op;
        vert1 = new Vector3D(x1, y1, z1);    vert2 = new Vector3D(x2, y2, z2);
        vert3 = new Vector3D(x3, y3, z3);    vert4 = new Vector3D(x4, y4, z4);
        dh = new Vector3D(dhx, dhy, dhz);    radius = _radius;
        color = new Vector3D(r, g, b);    
        this.textureNum = textureNum;
        this.diffuseReflectance = _diffuseReflectance;
        this.specularReflectionRate = _specularReflectionRate;
        this.luster = _luster;
        this.refractiveIndex = _refractiveIndex;
        this.reflectivity = _reflectivity;
    }
}
class Nodes 
{
    public var index:Array=new Array();
    public var rate:Array=new Array();
    public var node:Array = new Array();
    public var sight:Vector.<Vector3D>= new Vector.<Vector3D>();
    public var normal:Vector.<Vector3D>= new Vector.<Vector3D>();
    public var n:Array = new Array();
    public var no:int;    
    public function setData(_index:int, _rate:Number, _x:Number, _y:Number, _z:Number, _sight:Vector3D, _nolm:Vector3D, n1:int):void {
        index[no] = _index;
        rate[no] = _rate;
        node[no] = new Vector3D(_x, _y, _z);
        sight[no] = _sight;
        normal[no] = _nolm;
        n[no] = n1;
        no++;
    }    
}
class Ray 
{
    public var list:Vector.<Object3d> = new Vector.<Object3d>();
    public var color:Vector3D;
    public var texture:int;
    public var diffusion:Number;
    public var specular:Number;
    public var luster:Number;
    public var refractive:Number;
    public var reflectivity:Number;
    public var xAxis:Vector3D;
    public var yAxis:Vector3D;
    public var me:Vector3D;
    public var reference:Vector3D;
    public var forAbove:Vector3D;
    public var bgcolor:uint;
    public var light:Light;
    public function size():int 
    {
        return list.length;
    }
    public static function setVector(v:Vector3D,x:Number,y:Number,z:Number):void 
    {
        v.x = x;    v.y = y;    v.z = z;
    }    
    public function shadeParameter(_diffusion:Number,_specular:Number,_luster:Number,_refractive:Number,_reflectivity:Number):void 
    {
        diffusion = _diffusion;
        specular = _specular;
        if (_luster < 1 / 100000000.0) 
        {
            luster = 1 / 100000000.0;
        }
        else 
        {
            luster = _luster;
        }
        refractive = _refractive;
        reflectivity = _reflectivity;
    }
    public function getObject3d(i:int):Object3d 
    {
        return list[i];
    }    
    public function setObjectColor(r:int, g:int, b:int):void 
    {
        color = new Vector3D(r, g, b);
    }
    public function setTexture(m:int):void 
    {
        texture=m;
    }    
    public function setPosition(x:Number,y:Number,z:Number):void 
    {
        me = new Vector3D(x, y, z);
    }
    public function setReference(x:Number,y:Number,z:Number):void 
    {
        reference=new Vector3D(x,y,z);
    }        
    public function setAbove(x:Number,y:Number,z:Number):void 
    {
        forAbove=new Vector3D(x,y,z);
    }
    public function createLight(x:Number,y:Number,z:Number,r:int,g:int,b:int,_brightness:Number,_ambient:Number):void 
    {
        light = new Light();
        light.position = new Vector3D(x, y, z);
        light.color = new Vector3D(r, g, b);
        light.brightness = _brightness;
        light.ambient = _ambient;
    }
    public function createSphere(x:Number,y:Number,z:Number,r:Number):void 
    {
        list.push(new Object3d(1, x, y, z, 0.0, 0.0, 0.0, 0.0,
            0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, r,color.x, color.y, color.z, texture, diffusion,
            specular, luster, refractive, reflectivity));
    }

    public function createRectangle(x1:Number,y1:Number,z1:Number,x2:Number,y2:Number,z2:Number,x3:Number,y3:Number,z3:Number,
        x4:Number,y4:Number,z4:Number):void 
    {
        list.push(new Object3d(4, x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, 0, 0, 0, 0,
            color.x,color.y,color.z,texture,diffusion,specular,luster,refractive,reflectivity));
    }
    public function createAxis():void 
    {
        var screenN:Vector3D = new Vector3D(me.x - reference.x, me.y - reference.y,    me.z - reference.z);
        screenN.normalize();
        var d:Number = screenN.dotProduct(forAbove);
        yAxis = new Vector3D(forAbove.x - d * screenN.x, forAbove.y - d * screenN.y, forAbove.z - d * screenN.z);
        yAxis.normalize();
        xAxis = yAxis.crossProduct(screenN);
        xAxis.normalize();
    }
}
class Map 
{
    private var nodes:Nodes;
    private var image:RayImage;    
    public function Map(n:Nodes,i:RayImage):void 
    {
        nodes = n;
        image = i;
    }    
    public function mapping(j:int,od:Object3d):Vector3D 
    {
        var p:uint = 0;
        if (od.op == Object3d.SPHEHE) { p = mapSphere(j, od); }
        if (od.op == Object3d.RECTANGLE) { p = mapRectangle(j, od); }
        return new Vector3D((0xff & (p >> 16)), (0xff & (p >> 8)), (0xff & p));
    } 
    private function mapSphere(j:int, od:Object3d):uint 
    {
        var a1:Number=nodes.node[j].x-od.vert1.x;
        var a2:Number=nodes.node[j].y-od.vert1.y;
        var a3:Number=nodes.node[j].z-od.vert1.z;
        var u:Number=Math.atan2(a2,a1)/(2.0*Math.PI)+0.5;
        var v:Number=Math.atan2(a3,Math.sqrt(a1*a1+a2*a2))/Math.PI+0.5;
        var x0:int = (u * (image.bmpImage.width - 1));
        var y0:int = (v * (image.bmpImage.height - 1));
        return image.bmpImage.getPixel(x0, y0);
    }
    private function mapRectangle(j:int,od:Object3d):uint 
    {
        var a1:Number = Vector3D.distance(od.vert1, od.vert2);
        var a2:Number = Vector3D.distance(od.vert2, od.vert3);
        var a5:Number=a1*a2;
        a1 = Vector3D.distance(od.vert1, nodes.node[j]);
        a2 = Vector3D.distance(od.vert4, nodes.node[j]);
        var a3:Number = Vector3D.distance(od.vert1, od.vert4);
        var s:Number = (a1 + a2 + a3) / 2.0;
        var a4:Number=Math.sqrt(s*(s-a1)*(s-a2)*(s-a3));
        var u:Number = 2.0 * a4 / a5;
        a1 = Vector3D.distance(od.vert1, nodes.node[j]);
        a2 = Vector3D.distance(od.vert2, nodes.node[j]);
        a3 = Vector3D.distance(od.vert1, od.vert2);
        s = (a1 + a2 + a3) / 2.0;
        a4=Math.sqrt(s*(s-a1)*(s-a2)*(s-a3));
        var v:Number = 2.0 * a4 / a5;
        var x0:int = (u * (image.bmpImage.width - 1));
        var y0:int = (v * (image.bmpImage.height - 1));
        return image.bmpImage.getPixel(x0, y0);
    }
}
class RayTrace 
{
    public var ray:Ray;
    public var shade:Shade;
    public var normalVector:Vector3D = new Vector3D();
    public var min:Number;
    public var max:Number;
    public var index:int = 0;    
    public function RayTrace(r:Ray):void 
    {        
        ray = r;
    }
    public function seach(c:Vector3D, x1:Number, y1:Number, z1:Number):Boolean 
    {
        min = 100;
        for (var i:int = 0; i < ray.size(); i++) 
        {
            var ob:Object3d = ray.getObject3d(i);
            switch(ob.op) 
            {
                case Object3d.SPHEHE:
                    if (intersectSphere(c, i, x1, y1, z1, 0)) return true;
                case Object3d.RECTANGLE:
                    if (intesectRect(c, i, x1, y1, z1, 0)) return true;
            }
        }  
        return false;    
    }
    public function intersectSphere(v:Vector3D, k:int, x1:Number, y1:Number, z1:Number, mode:int):Boolean 
    {
        var flag:Boolean=false;
        var od:Object3d = ray.getObject3d(k);
        var a:Number=(v.x*v.x)+(v.y*v.y)+(v.z*v.z);
        var b:Number=(v.x*(x1-od.vert1.x))+(v.y*(y1-od.vert1.y))+(v.z*(z1-od.vert1.z));
        var c:Number=od.vert1.x*od.vert1.x+od.vert1.y*od.vert1.y+od.vert1.z*od.vert1.z+x1*x1+y1*y1+z1*z1
                -2 * (od.vert1.x * x1 + od.vert1.y * y1 + od.vert1.z * z1) - od.radius * od.radius;
        var d:Number = b * b - a * c;
        var t:Number = 0;
        if (d>0)
        {
            t=(-b-Math.sqrt(d))/a;
            if (t<0)    if (a * c <= 0) t = ( -b + Math.sqrt(d)) / a;
        }
        if (d==0){t=-b/a;}
        if (t>0) 
        {
            var x:Number = x1 + v.x * t;
            var y:Number = y1 + v.y * t;
            var z:Number = z1 + v.z * t;
            d = Math.sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y)    +(z1 - z) * (z1 - z));
            if ((min>d) && (mode==0)) 
            {
                min = d;
                Ray.setVector(shade.interPoint, x, y, z);
                Ray.setVector(normalVector, x - od.vert1.x, y - od.vert1.y, z - od.vert1.z);
                if ( -v.x * normalVector.x - v.y * normalVector.y - v.z * normalVector.z < 0) {
                    Ray.setVector(normalVector, -normalVector.x, -normalVector.y, -normalVector.z);
                }
                index=k;
                flag = true;
            }
            if ((max>d) && (mode>0))flag=true; 
        }
        return flag;
    }
    public function intesectRect(v:Vector3D, k:int, xx:Number, yy:Number, zz:Number, mode:int):Boolean 
    {
        var flag:Boolean=false;
        var od:Object3d = ray.getObject3d(k);
        var a:Number = (od.vert2.y - od.vert1.y) * (od.vert4.z - od.vert1.z) - (od.vert2.z - od.vert1.z) * (od.vert4.y - od.vert1.y);
        var b:Number = (od.vert2.z - od.vert1.z) * (od.vert4.x - od.vert1.x) - (od.vert2.x - od.vert1.x) * (od.vert4.z - od.vert1.z);
        var c:Number = (od.vert2.x - od.vert1.x) * (od.vert4.y - od.vert1.y) - (od.vert2.y - od.vert1.y) * (od.vert4.x - od.vert1.x);
        var d:Number = -(a * od.vert1.x + b * od.vert1.y + c * od.vert1.z);
        var t1:Number = -(a * xx + b * yy + c * zz + d);
        var t2:Number = a * v.x + b * v.y + c * v.z;
        if ((t2 != 0) && ((t1 / t2) > 0)) 
        {
            var x:Number = xx + v.x * t1 / t2;
            var y:Number = yy + v.y * t1 / t2;
            var z:Number = zz + v.z * t1 / t2;
            d = Math.sqrt((xx - x) * (xx - x) + (yy - y) * (yy - y) + (zz - z) * (zz - z));
            var x1:Number = x - od.vert1.x;
            var y1:Number = y - od.vert1.y;
            var z1:Number = z - od.vert1.z;
            var d1:Number=Math.sqrt(x1*x1+y1*y1+z1*z1);
            x1=x1/d1;y1=y1/d1;z1=z1/d1;      
            var x2:Number = od.vert4.x - od.vert1.x;
            var y2:Number = od.vert4.y - od.vert1.y;
            var z2:Number = od.vert4.z - od.vert1.z;
            d1=Math.sqrt(x2*x2+y2*y2+z2*z2);
            x2=x2/d1;y2=y2/d1;z2=z2/d1;
            var x3:Number = od.vert2.x - od.vert1.x;
            var y3:Number = od.vert2.y - od.vert1.y;
            var z3:Number = od.vert2.z - od.vert1.z;
            d1 = Math.sqrt(x3 * x3 + y3 * y3 + z3 * z3);
            x3 = x3 / d1; y3 = y3 / d1; z3 = z3 / d1;
            var t:Number = x2 * x3 + y2 * y3 + z2 * z3;
            t1 = x1 * x2 + y1 * y2 + z1 * z2;
            t2 = x1 * x3 + y1 * y3 + z1 * z3;
            if ((t1>t) && (t2>t)) 
            {
                x1 = x - od.vert3.x;
                y1 = y - od.vert3.y;
                z1 = z - od.vert3.z;
                d1=Math.sqrt(x1*x1+y1*y1+z1*z1);
                x1=x1/d1;y1=y1/d1;z1=z1/d1;      
                x2 = od.vert4.x - od.vert3.x;
                y2 = od.vert4.y - od.vert3.y;
                z2 = od.vert4.z - od.vert3.z;
                d1 = Math.sqrt(x2 * x2 + y2 * y2 + z2 * z2);
                x2 = x2 / d1; y2 = y2 / d1; z2 = z2 / d1;
                x3 = od.vert2.x - od.vert3.x;
                y3 = od.vert2.y - od.vert3.y;
                z3 = od.vert2.z - od.vert3.z;
                d1 = Math.sqrt(x3 * x3 + y3 * y3 + z3 * z3);
                x3 = x3 / d1; y3 = y3 / d1; z3 = z3 / d1;
                t = x2 * x3 + y2 * y3 + z2 * z3;
                t1 = x1 * x2 + y1 * y2 + z1 * z2;
                t2 = x1 * x3 + y1 * y3 + z1 * z3;
                if ((min > d) && (t1 > t) && (t2 > t) && (mode == 0)) 
                {
                    min = d;
                    Ray.setVector(shade.interPoint, x, y, z);
                    Ray.setVector(normalVector, a, b, c);
                    x=ray.me.x-x;
                    y=ray.me.y-y;
                    z=ray.me.z-z;
                    if (x * normalVector.x + y * normalVector.y + z * normalVector.z < 0) {
                        Ray.setVector(normalVector, -normalVector.x, -normalVector.y, -normalVector.z);
                    }
                    index=k;
                    flag=true;
                }
                if ((max>d)&&(t1>t)&&(t2>t)&&(mode>0))flag=true;
            }
        }
        return flag;
    }
}
class Shade 
{
    public var nodes:Nodes;
    public var light:Light;
    public var ray:Ray;
    public var checker:RayTrace;
    public var map:Map;
    private var lightV:Vector3D;
    private var normalV:Vector3D;
    private var sightV:Vector3D;
    private var partV:Vector3D;
    public var interPoint:Vector3D=new Vector3D();
    private var lightElem:Vector3D = new Vector3D();    
    public function Shade(r:Ray, n:Nodes, c:RayTrace, m:Map):void 
    {
        ray = r;
        nodes = n;
        checker = c;
        map = m;
        light = ray.light;
    }
    private function setBModelVector(_x:Number,_y:Number,_z:Number,_index:int):void
    {
        lightV = new Vector3D(light.position.x - _x, light.position.y - _y, light.position.z - _z);
        lightV.normalize();
        normalV = new Vector3D(nodes.normal[_index].x, nodes.normal[_index].y, nodes.normal[_index].z);
        normalV.normalize();
        sightV = new Vector3D( -nodes.sight[_index].x, -nodes.sight[_index].y, -nodes.sight[_index].z);
        sightV.normalize();
        partV = new Vector3D(lightV.x + sightV.x, lightV.y + sightV.y, lightV.z + sightV.z);
        partV.normalize();
    }
    private function calcSpecularReflectionFactor(x:Number,y:Number,z:Number,r:int):void
    {
        setBModelVector(x,y,z,r);
        var pd:Number = lightV.dotProduct(normalV);
        if (pd < 0) 
        {
            pd = 0;
        }
        else if (pd > 1) 
        {
            pd = 1;
        }
        var od:Object3d = ray.getObject3d(nodes.index[r]);
        var dd:Number = scatterCoefficient(od);
        var dir:Number = normalV.dotProduct(sightV);
        var ff:Number = absorption(od);
        var gg:Number = roughly();
        var correction:Number = correctionOfDistance(x, y, z);
        var ps:Number = dd * gg * ff / dir;
        if (ps < 0) 
        {
            ps = 0;
        }
        else if (ps > 1) 
        {
            ps = 1;
        }
        Ray.setVector(lightElem, pd, ps, correction);
    }
    private function scatterCoefficient(od:Object3d):Number 
    {
        var t:Number = normalV.dotProduct(partV);
        return (1.0 / (od.luster * od.luster * t * t * t * t)) * Math.exp( -(1.0 - t * t) / (od.luster * od.luster * t * t));
    }
    private function absorption(od:Object3d):Number 
    {
        var c:Number = sightV.dotProduct(partV);
        var g:Number = Math.sqrt(od.refractiveIndex * od.refractiveIndex + c * c - 1);
        var d1:Number=c+g;
        var d2:Number=g-c;
        return ((d2*d2)/(2*d1*d1))*(((c*d1-1)*(c*d1-1))/((c*d2+1)*(c*d2+1))+1);
    }
    private function roughly():Number 
    {
        var c:Number = sightV.dotProduct(partV);
        var g:Number = normalV.dotProduct(partV);
        var t1:Number = sightV.dotProduct(normalV);
        var t2:Number = normalV.dotProduct(lightV);
        var gr:Number=2*g*t1/c;
        var gi:Number=2*g*t2/c;
        return Math.min(1,Math.min(gr,gi));
    }
    private function correctionOfDistance(x:Number,y:Number,z:Number):Number 
    {
        var w:Number = new Vector3D(light.position.x - x, light.position.y - y, light.position.z - z).length;
        return w / 4 + 0.1;
    }
    public function colorSet():uint 
    {
        colorSet2(0);
        var col:Vector3D = getPixelColor();
        var red:int = Math.min(Math.max(col.x, 0), 255);
        var green:int = Math.min(Math.max(col.y, 0), 255);
        var blue:int = Math.min(Math.max(col.z, 0), 255);
        return (0xff000000 | red << 16 | green << 8 | blue);
    }
    private function colorSet2(p:int):void 
    {
        var r2:Number = 0
        var g2:Number = 0;
        var b2:Number = 0;
        var d2:Number;
        var od1:Object3d=ray.getObject3d(nodes.index[p]);
        var vSight:Vector3D=new Vector3D();
        var vNormal:Vector3D=new Vector3D();
        var vReflection:Vector3D=new Vector3D();
        if (od1.reflectivity * nodes.rate[p] > 0.3) 
        {
            vSight=new Vector3D(-nodes.sight[p].x,-nodes.sight[p].y,-nodes.sight[p].z);
            vSight.normalize();
            d2 = nodes.normal[p].length;
            Ray.setVector(vNormal, nodes.normal[p].x / d2, nodes.normal[p].y / d2, nodes.normal[p].z / d2);
            Ray.setVector(vReflection,
                2 * vNormal.x * vSight.dotProduct(vNormal) - vSight.x,
                2 * vNormal.y * vSight.dotProduct(vNormal) - vSight.y,
                2 * vNormal.z * vSight.dotProduct(vNormal) - vSight.z);
            vReflection.normalize();
            if (checker.seach(vReflection,nodes.node[p].x+0.01*vReflection.x,nodes.node[p].y+0.01*vReflection.y,nodes.node[p].z+0.01*vReflection.z))
            {
                nodes.setData(checker.index,od1.reflectivity*nodes.rate[p],
                interPoint.x,interPoint.y,interPoint.z,    vReflection,checker.normalVector,nodes.n[p]);
            }
        }
        var transmittance:Number = 1 - od1.reflectivity;//透過率
        var vTrans:Vector3D = new Vector3D();
        if (transmittance*nodes.rate[p]>0.3) 
        {
            var c1:Number;
            var c2:Number;
            var n:Number;
            Ray.setVector(vSight, nodes.sight[p].x, nodes.sight[p].y, nodes.sight[p].z);
            vSight.normalize();
            d2 = nodes.normal[p].length;
            Ray.setVector(vNormal,nodes.normal[p].x/d2,nodes.normal[p].y/d2,nodes.normal[p].z/d2);
            if (nodes.n[p] % 2 == 0) 
            {
                n = 1 / od1.refractiveIndex;
            } 
            else 
            {
                n = od1.refractiveIndex;
            }
            c1=vSight.x*vNormal.x+vSight.y*vNormal.y+vSight.z*vNormal.z;
            c2 = Math.sqrt(1 - ((1 - c1 * c1) * n * n));
            Ray.setVector(vTrans,
                vSight.x * n - (c2 - c1 * n) * vNormal.x,
                vSight.y * n - (c2 - c1 * n) * vNormal.y,
                vSight.z * n - (c2 - c1 * n) * vNormal.z);
            vTrans.normalize();
            if (checker.seach(vTrans,nodes.node[p].x+0.0001*vTrans.x,nodes.node[p].y+0.0001*vTrans.y,
                nodes.node[p].z+0.0001*vTrans.z)) 
            {
                nodes.setData(checker.index,transmittance*nodes.rate[p],
                    interPoint.x,interPoint.y,interPoint.z,vTrans,
                    checker.normalVector,nodes.n[p]+1);
            }
        }
        if (nodes.no > p + 1) colorSet2(p + 1);
    }
    private function getPixelColor():Vector3D 
    {
        var col:Vector3D = new Vector3D();
        for (var j:int = 0; j < nodes.no; j++) 
        {
            var od3:Object3d = ray.list[nodes.index[j]];
            var r2:Number = light.ambient * od3.color.x;
            var g2:Number = light.ambient * od3.color.y;
            var b2:Number = light.ambient * od3.color.z;
            if (serchlight(nodes.node[j].x,    nodes.node[j].y,nodes.node[j].z,j)) 
            {
                calcSpecularReflectionFactor(nodes.node[j].x, nodes.node[j].y, nodes.node[j].z, j);
                r2 += (od3.color.x * light.brightness * od3.diffuseReflectance * lightElem.x
                    +light.color.x * light.brightness * od3.specularReflectionRate * lightElem.y) / lightElem.z;
                g2 += (od3.color.y * light.brightness * od3.diffuseReflectance * lightElem.x
                    +light.color.y * light.brightness * od3.specularReflectionRate * lightElem.y) / lightElem.z;
                b2 += (od3.color.z * light.brightness * od3.diffuseReflectance * lightElem.x
                    +light.color.z * light.brightness * od3.specularReflectionRate * lightElem.y) / lightElem.z;
            }
            if (od3.textureNum > 0) 
            {
                var pixelRGB:Vector3D = map.mapping(j, od3);
                col.x +=nodes.rate[j]*(pixelRGB.x+r2);
                col.y +=nodes.rate[j]*(pixelRGB.y+g2);
                col.z +=nodes.rate[j]*(pixelRGB.z+b2);
            }
            else 
            {
                col.x +=nodes.rate[j]*r2;
                col.y +=nodes.rate[j]*g2;
                col.z +=nodes.rate[j]*b2;
            }
        }
        return col;
    }    
    public function serchlight(x:Number, y:Number, z:Number, q:int):Boolean 
    {
        var kogenV:Vector3D = new Vector3D(light.position.x - x, light.position.y - y, light.position.z - z);
        checker.max = kogenV.length;
        kogenV.normalize();
        checker.index=nodes.index[q];
        for (var i:int=0;i<ray.size();i++) 
        {
            var od:Object3d = ray.list[i];
            if (od.op==Object3d.SPHEHE) 
            {
                if (checker.intersectSphere(kogenV,i,x+kogenV.x/100.0,y+kogenV.y/100.0,z+kogenV.z/100.0,1))return false;
            }
            if (od.op==Object3d.RECTANGLE) 
            {
                if (checker.intesectRect(kogenV, i, x + kogenV.x / 100.0, y + kogenV.y / 100.0, z + kogenV.z / 100.0, 1)) return false;
            }
        }  
        return true;
    }
}
class Button extends Sprite
{
    private static const mono:ColorMatrixFilter = new ColorMatrixFilter([
        1 / 3, 1 / 3, 1 / 3, 0, 10, 1 / 3, 1 / 3, 1 / 3, 0, 10,
        1 / 3, 1 / 3, 1 / 3, 0, 10, 0,0,0, 1, 0]);
    private var _hover:Boolean = false;
    public function get hover():Boolean
    {
        return _hover;
    }
    public function set hover(value:Boolean):void
    {
        if(_hover != value)
        {
            _hover = value;
            filters = (_hover ? null : [mono]);
        }
    }
    public function Button(W:Number, H:Number, R:Number, label:String = "", size:int = 11)
    {
        var matrix:Matrix = new Matrix();
        matrix.createGradientBox(W, H, Math.PI / 2);
        var bg:Sprite = new Sprite();
        bg.graphics.beginGradientFill("linear", [0xDDE9F4, 0xD5E4F1, 0xBAD2E8], [1, 1, 1],[0, 120, 136], matrix);
        bg.graphics.drawRoundRect(0, 0, W, H, R, R);
        bg.graphics.endFill();
        bg.filters = [new GlowFilter(0xFFFFBE, .5, 10, 10, 2, 1, true)];
        addChild(bg);
        var line:Sprite = new Sprite();
        line.graphics.lineStyle(3, 0xBAD2E8);
        line.graphics.drawRoundRect(0, 0, W, H, R, R);
        addChild(line);
        filters = [mono];
        buttonMode = true;
        mouseChildren = false;
        if (label != "")
        {
            var textField:TextField = new TextField();
            textField.selectable = false;
            textField.autoSize = "left";
            textField.htmlText = <font size={size} color="#6B8399">{label}</font>.toXMLString();
            textField.x = (W - textField.width) / 2;
            textField.y = (H - textField.height) / 2;
            addChild(textField);
        }
        addEventListener("rollOver", buttonRollOver);
        addEventListener("rollOut", buttonRollOut);
        addEventListener("removed", function(event:Event):void
        {
            removeEventListener("rollOver", buttonRollOver);
            removeEventListener("rollOut", buttonRollOut);
            removeEventListener("removed", arguments.callee);
        });
    }
    protected function buttonRollOver(event:Event):void
    {
        hover = true;
    }
    protected function buttonRollOut(event:Event):void
    {
        hover = false;
    }
}