れいとれもどき1
package {
import flash.display.Sprite;
import net.hires.debug.Stats;
[SWF(width=465, height=465, backgroundColor="#808080", frameRate="20")]
public class Test extends Sprite {
public function Test() {
stage.addChild(new Stats());
g_main = this;
setup();
}
}
}
// import
import flash.display.*;
import flash.geom.*;
import flash.text.*;
import flash.events.*;
import flash.utils.*;
// constants
const DISP_L:uint = 100;
const DISP_L_HALF:uint = 50;
const AMBIENT:Number = 0.2;
const ATTENUATION_CONST:Number = 1.0;
const ATTENUATION_LINEAR:Number = 0.5;
const ATTENUATION_QUAD:Number = 0.3;
const BG_COLOR:uint = 0x101060;
// global variables
var g_main:Sprite;
var g_bitmap:Bitmap;
var g_bitmapData:BitmapData;
var g_scene:RenderScene;
var g_bal:Sphere;
var g_ang:Number;
// clamp x to range min~max
function clamp(x:Number, min:Number, max:Number) : Number {
return Math.min(Math.max(x, min), max);
}
function setup() : void {
g_ang = 0.0;
g_bitmapData = new BitmapData(DISP_L, DISP_L, false);
g_bitmap = new Bitmap(g_bitmapData);
g_bitmap.scaleX = 465 / DISP_L;
g_bitmap.scaleY = 465 / DISP_L;
g_bitmap.smoothing=true;
g_main.addChild(g_bitmap);
setup_scene();
g_main.stage.addEventListener(Event.ENTER_FRAME,
function(e:Event) : void {
update();
});
}
function setup_scene() : void {
g_scene = new RenderScene();
g_scene.addLight(new Light(new Vector3D(0, 50, 50), 300.5));
g_scene.addObject(new Sphere
(new Vector3D(20, 0, 100),
10,
new Vector3D(1, 1, 0)));
g_scene.addObject(new Sphere
(new Vector3D(-20, 0, 100),
10,
new Vector3D(1, 0, 0)));
g_bal = new Sphere(new Vector3D(0, 0, 200), 15, new Vector3D(0.5, 0.5, 0.5));
g_scene.addObject(g_bal);
}
function update() : void {
g_ang += 0.5;
g_bal.pos().x = Math.cos(g_ang) * 15.0;
g_bal.pos().y = 20.0;
g_bal.pos().z = Math.sin(g_ang) * 15.0 + 100;
g_bitmapData.lock();
g_scene.render(g_bitmapData);
g_bitmapData.unlock();
}
class RenderScene {
private var m_light:Array;
private var m_obj:Array;
public function RenderScene() {
m_obj = new Array();
m_light = new Array();
}
public function addLight(l:Light) : void {
m_light.push(l);
}
public function addObject(o:Sphere) : void {
m_obj.push(o);
}
public function render(b:BitmapData) : void {
for (var x:int = 0; x < DISP_L; x++) {
for (var y:int = 0; y < DISP_L; y++) {
var rx:Number = x - DISP_L_HALF;
var ry:Number = y - DISP_L_HALF;
b.setPixel(x, y, pixel(rx, ry));
}
}
}
public function pixel(x:Number, y:Number) : uint {
var rayDir:Vector3D = new Vector3D(0, 0, 1);
var rayPos:Vector3D = new Vector3D(x, y, 0);
var minObj:Sphere;
var minD:Number;
m_obj.forEach(function (o:*, i:int, arr:Array) : void {
var d:Number = o.distanceRay(rayPos, rayDir);
if (d > 0) {
if (minObj == null || (d < minD)) {
minObj = o;
minD = d;
}
}
});
if (minObj != null) {
var rd:Vector3D = rayDir.clone();
rd.scaleBy(minD);
var p:Vector3D = rayPos.add(rd);
var color:Vector3D = minObj.color().clone();
color.scaleBy(AMBIENT);
m_light.forEach(function (l:*, i:int, arr:Array) : void {
var lv:Vector3D = l.pos().subtract(p);
var ld:Number = lv.length;
lv.normalize();
var blocked:Boolean = false;
m_obj.forEach(function (o:*, i:int, arr:Array) : void {
if (o == minObj) return;
var d:Number = o.distanceRay(p, lv);
if (d > 0 && d < ld) {
blocked = true;
return;
}
});
if (!blocked) {
var n:Vector3D = minObj.normal(p);
var ln:Number = lv.dotProduct(n);
if (ln > 0) {
var lc:Vector3D = minObj.color().clone();
var illuminance:Number = l.illuminance() * ln;
illuminance = illuminance / (ATTENUATION_CONST
+ ld * ATTENUATION_LINEAR
+ ld * ld * ATTENUATION_QUAD);
lc.scaleBy(illuminance);
color = color.add(lc);
}
}
});
var red:uint = clamp(color.x * 255, 0, 255);
var green:uint = clamp(color.y * 255, 0, 255);
var blue:uint = clamp(color.z * 255, 0, 255);
return (red << 16) | (green << 8) | blue;
}
return BG_COLOR;
}
}
class Sphere {
private var m_pos:Vector3D;
private var m_len:Number;
private var m_color:Vector3D;
public function Sphere(pos:Vector3D, len:Number, color:Vector3D) {
m_pos = pos;
m_len = len;
m_color = color;
}
public function pos() : Vector3D {
return m_pos;
}
public function len() : Number {
return m_len;
}
public function color() : Vector3D {
return m_color;
}
public function distanceRay(pos:Vector3D, dir:Vector3D) : Number {
var r:Number = m_len;
var ev:Vector3D = m_pos.subtract(pos);
var e2:Number = ev.lengthSquared;
var a:Number = ev.dotProduct(dir);
var p:Number = (r * r - e2 + a * a);
if (p < 0) {
return -1;
}
var t:Number = a - Math.sqrt(p);
return t;
}
public function normal(pos:Vector3D) : Vector3D {
var sub:Vector3D = pos.subtract(m_pos);
sub.normalize();
return sub;
}
}
class Light {
private var m_pos:Vector3D;
private var m_illuminance:Number;
public function Light(pos:Vector3D, illuminance:Number) : void {
m_pos = pos;
m_illuminance = illuminance;
}
public function pos() : Vector3D {
return m_pos;
}
public function illuminance() : Number {
return m_illuminance;
}
}