In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

レイトレーシング

レイトレーシング習作
参考文献:Javaではじめるレイトレーシング入門(森北出版)
ボタンはhttp://d.hatena.ne.jp/nitoyon/20090423/as3_simple_buttonを使わせて頂きました。
/**
 * Copyright termat ( http://wonderfl.net/user/termat )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/3R1U
 */

/**
	レイトレーシング習作
	参考文献: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 = "500", height = "500", 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;
	}
}