いっしょにとれーしんぐ
いつもスゴい!
Ambient Occlusion Rendering forked from: Ambient Occlusion Rendering
- // forked from keim_at_Si's Ambient Occlusion Rendering
- // Ambient Occlusion Bench Flash10 porting
- // Original version of AO bench was written by Syoyo Fujita.
- // http://lucille.atso-net.jp/aobench/
- // In original Flash10 porting, it takes 7 times slower than the Proce55ing.
- // (refer from http://lucille.atso-net.jp/blog/?p=638).
- // And now, it seems to be same speed as the Proce55ing does.
- //----------------------------------------------------------------------
- package {
- import flash.display.*;
- import flash.text.*;
- import flash.events.*;
- [SWF(frameRate = "1000", backgroundColor = "#808080")]
- public class main extends Sprite {
- private var _tf:TextField = new TextField();
- private var _screen:BitmapData = new BitmapData(WIDTH, HEIGHT, false, 0xffffff);
- private var _renderY:int;
- function main() {
- _tf.autoSize = 'left';
- _tf.htmlText = "<font color='#ffffff'>Rendering...</font>";
- addChild(_tf);
- with(addChild(new Bitmap(_screen))){ x = y = 104.5; }
- _renderY = 0;
- addEventListener("enterFrame", _startRender);
- }
- private function _startRender(e:Event) : void {
- // rendering
- render.rasterRendering(_renderY);
- // copy pixels
- _screen.lock();
- for (var x:int=0; x<WIDTH; x++) _screen.setPixel(x, _renderY, render.output[x]);
- _screen.unlock();
- // increment
- _renderY++;
- if (_renderY == 256) {
- // finish rendering
- _tf.htmlText = "<font color='#ffffff'>Rendering time : " + String(render.renderingTime/1000) + "[sec]</font>";
- removeEventListener("enterFrame", _startRender);
- }
- }
- }
- }
- import flash.display.*;
- import flash.geom.*;
- import flash.utils.getTimer;
- // global variables
- //--------------------------------------------------------------------------------
- const WIDTH :int = 256;
- const HEIGHT:int = 256;
- const NSUBSAMPLES:int = 2;
- const NAO_SAMPLES:int = 2;
- var render:Render = new Render();
- // structures
- //--------------------------------------------------------------------------------
- class Isect {
- public var t:Number = 0;
- public var p:Vector3D = new Vector3D();
- public var n:Vector3D = new Vector3D();
- public var hit:int = 0;
- }
- class Ray {
- public var org:Vector3D = new Vector3D();
- public var dir:Vector3D = new Vector3D();
- }
- class Sphere {
- public var center:Vector3D;
- public var radius2:Number;
- function Sphere(center:Vector3D, radius:Number) {
- this.center = center;
- this.radius2 = radius*radius;
- }
- }
- class Plane {
- public var p:Vector3D;
- public var n:Vector3D;
- public var pn:Number;
- function Plane(p:Vector3D, n:Vector3D) {
- this.p = p;
- this.n = n;
- this.pn = n.x*p.x + n.y*p.y + n.z*p.z;
- }
- }
- // render
- //--------------------------------------------------------------------------------
- class Render {
- // variables
- //--------------------------------------------------
- public var output:Vector.<uint>;
- public var renderingTime:int;
- private var spheres:Vector.<Sphere> = new Vector.<Sphere>(3, true);
- private var plane:Plane;
- // constructor
- //--------------------------------------------------
- function Render() {
- _initScene();
- renderingTime = 0;
- output = new Vector.<uint>(WIDTH, true);
- }
- // rendering
- //--------------------------------------------------
- public function rasterRendering(y:int) : void {
- var t:int = getTimer();
- _render(output, WIDTH, HEIGHT, y);
- renderingTime += getTimer() - t;
- }
- // privates
- //--------------------------------------------------
- // initialize scene
- private function _initScene() : void {
- spheres[0] = new Sphere(new Vector3D(-2.0, 0.0, -3.5), 0.5);
- spheres[1] = new Sphere(new Vector3D(-0.5, 0.0, -3.0), 0.5);
- spheres[2] = new Sphere(new Vector3D( 1.0, 0.0, -2.2), 0.5);
- plane = new Plane(new Vector3D(0.0, -0.5, 0.0), new Vector3D(0.0, 1.0, 0.0));
- }
- // render
- private var ray:Ray = new Ray();
- private var isect:Isect = new Isect();
- private function _render(line:Vector.<uint>, w:int, h:int, y:int) : void {
- var idx:int, x:int, u:int, v:int, du:Number, dv:Number, pixel:uint, ao:Vector3D,
- hw :Number = w*0.5, hh :Number = h*0.5,
- ihw:Number = 1/hw, ihh:Number = 1/hh,
- step:Number = 1/NSUBSAMPLES,
- occlusionPerPixel:Number = 1/(NSUBSAMPLES*NSUBSAMPLES),
- color:Vector3D = new Vector3D();
- // scan all pixels
- idx = 0;
- for (x = 0; x < w; x++) {
- // initialize pixel color
- color.x = 0;
- color.y = 0;
- color.z = 0;
- // sub samplings
- for (v = 0, dv = 0; v < NSUBSAMPLES; v++, dv += step) {
- for (u = 0, du = 0; u < NSUBSAMPLES; u++, du += step) {
- // initialize ray vectors
- ray.org.x = 0.0;
- ray.org.y = 0.0;
- ray.org.z = 0.0;
- ray.dir.x = (x + du - hw) * ihw;
- ray.dir.y = -(y + dv - hh) * ihh;
- ray.dir.z = -1.0;
- ray.dir.normalize();
- // check ray intersections
- isect.p.x = isect.p.y = isect.p.z = 0.0;
- isect.n.x = isect.n.y = isect.n.z = 0.0;
- isect.t = 1.0e+17;
- isect.hit = 0;
- _intersectBySphere(isect, ray, spheres[0]);
- _intersectBySphere(isect, ray, spheres[1]);
- _intersectBySphere(isect, ray, spheres[2]);
- _intersectByPlane (isect, ray, plane);
- // when the ray is intersected, calculate ambient occlusion color.
- if (isect.hit) {
- color.incrementBy(_ambientOcclusion(isect));
- }
- }
- }
- // calculate gray scale
- color.scaleBy(occlusionPerPixel);
- pixel = 0xff000000;
- pixel |= (color.x >= 1) ? 255 : (color.x <= 0) ? 0 : int(color.x * 255);
- pixel |= ((color.y >= 1) ? 255 : (color.y <= 0) ? 0 : int(color.x * 255)) << 8;
- pixel |= ((color.z >= 1) ? 255 : (color.z <= 0) ? 0 : int(color.x * 255)) << 16;
- output[idx] = pixel;
- // increment index
- idx++;
- }
- }
- // calculate ambient occlusion
- private var aoRay:Ray = new Ray();
- private var aoIsect:Isect = new Isect();
- private var aoColor:Vector3D = new Vector3D();
- private var basis0:Vector3D = new Vector3D();
- private var basis1:Vector3D = new Vector3D();
- private var basis2:Vector3D = new Vector3D();
- private function _ambientOcclusion(isect:Isect) : Vector3D {
- var i:int, j:int, th:Number, ph:Number,
- x:Number, y:Number, z:Number,
- rx:Number, ry:Number, rz:Number,
- ntheta:int = NAO_SAMPLES,
- nphi:int = NAO_SAMPLES,
- occlusionPerSample:Number = 1 / (ntheta*nphi),
- eps:Number = 0.0001,
- occlusion:Number = 1.0;
- // calculate transform matrix from local to global.
- // the "local" coordinate is based on the normal vector at intersected point.
- basis2 = isect.n;
- basis1.x = 0.0;
- basis1.y = 0.0;
- basis1.z = 0.0;
- if ((isect.n.x < 0.6) && (isect.n.x > -0.6)) basis1.x = 1.0;
- else if ((isect.n.y < 0.6) && (isect.n.y > -0.6)) basis1.y = 1.0;
- else if ((isect.n.z < 0.6) && (isect.n.z > -0.6)) basis1.z = 1.0;
- else basis1.x = 1.0;
- vcross(basis0, basis1, basis2).normalize();
- vcross(basis1, basis2, basis0).normalize();
- // calculate the origin of the second ray
- aoRay.org.x = isect.p.x + eps * isect.n.x;
- aoRay.org.y = isect.p.y + eps * isect.n.y;
- aoRay.org.z = isect.p.z + eps * isect.n.z;
- // calculate the ambient occlusion at intersected point
- for (j = 0; j < ntheta; j++) {
- for (i = 0; i < nphi; i++) {
- // calculate the direction of the second ray
- th = Math.sqrt(Math.random());
- ph = 6.283185307179586 * Math.random();
- x = Math.cos(ph) * th;
- y = Math.sin(ph) * th;
- z = Math.sqrt(1.0 - th * th);
- // transform second ray vector from local to global
- aoRay.dir.x = x * basis0.x + y * basis1.x + z * basis2.x;
- aoRay.dir.y = x * basis0.y + y * basis1.y + z * basis2.y;
- aoRay.dir.z = x * basis0.z + y * basis1.z + z * basis2.z;
- // check second ray intersections
- aoIsect.p.x = aoIsect.p.y = aoIsect.p.z = 0.0;
- aoIsect.n.x = aoIsect.n.y = aoIsect.n.z = 0.0;
- aoIsect.t = 1.0e+17;
- aoIsect.hit = 0;
- _intersectBySphere(aoIsect, aoRay, spheres[0]);
- _intersectBySphere(aoIsect, aoRay, spheres[1]);
- _intersectBySphere(aoIsect, aoRay, spheres[2]);
- _intersectByPlane (aoIsect, aoRay, plane);
- // when the second ray is intersected, increase the occlusion.
- if (aoIsect.hit) occlusion -= occlusionPerSample;
- }
- }
- // return result
- aoColor.x = occlusion;
- aoColor.y = occlusion;
- aoColor.z = occlusion;
- return aoColor;
- // cross product
- function vcross(c:Vector3D, v0:Vector3D, v1:Vector3D) : Vector3D {
- c.x = v0.y * v1.z - v0.z * v1.y;
- c.y = v0.z * v1.x - v0.x * v1.z;
- c.z = v0.x * v1.y - v0.y * v1.x;
- return c;
- }
- }
- // check ray intersection by sphere
- private function _intersectBySphere(isect:Isect, ray:Ray, sph:Sphere) : void {
- var rsx:Number = ray.org.x - sph.center.x,
- rsy:Number = ray.org.y - sph.center.y,
- rsz:Number = ray.org.z - sph.center.z,
- B:Number = rsx*ray.dir.x + rsy*ray.dir.y + rsz*ray.dir.z,
- C:Number = rsx*rsx + rsy*rsy + rsz*rsz - sph.radius2,
- D:Number = B * B - C;
- // when the ray is intersected by the sphere,
- if (D > 0.0) {
- var t:Number = -B - Math.sqrt(D);
- if ((t > 0.0) && (t < isect.t)) {
- // calculate cross point and normal vector.
- isect.t = t;
- isect.hit = 1;
- isect.p.x = ray.org.x + ray.dir.x * t;
- isect.p.y = ray.org.y + ray.dir.y * t;
- isect.p.z = ray.org.z + ray.dir.z * t;
- isect.n.x = isect.p.x - sph.center.x;
- isect.n.y = isect.p.y - sph.center.y;
- isect.n.z = isect.p.z - sph.center.z;
- isect.n.normalize();
- }
- }
- }
- // check ray intersection by plane
- private function _intersectByPlane(isect:Isect, ray:Ray, pln:Plane) : void {
- var v:Number = pln.n.x*ray.dir.x + pln.n.y*ray.dir.y + pln.n.z*ray.dir.z;
- // when parallel with plane
- if (v>-1.0e-17 && v<1.0e-17) return;
- var t:Number = -(pln.n.x*ray.org.x + pln.n.y*ray.org.y + pln.n.z*ray.org.z - pln.pn) / v;
- // when the ray is intersected by the plane,
- if ((t > 0.0) && (t < isect.t)) {
- // calculate cross point and normal vector.
- isect.t = t;
- isect.hit = 1;
- isect.p.x = ray.org.x + ray.dir.x * t;
- isect.p.y = ray.org.y + ray.dir.y * t;
- isect.p.z = ray.org.z + ray.dir.z * t;
- isect.n.x = pln.n.x;
- isect.n.y = pln.n.y;
- isect.n.z = pln.n.z;
- }
- }
- }
Ambient Occlusion Rendering forked from: Ambient Occlusion Rendering
- // forked from keim_at_Si's Ambient Occlusion Rendering
- // Ambient Occlusion Bench Flash10 porting
- // Original version of AO bench was written by Syoyo Fujita.
- // http://lucille.atso-net.jp/aobench/
- // In original Flash10 porting, it takes 7 times slower than the Proce55ing.
- // (refer from http://lucille.atso-net.jp/blog/?p=638).
- // And now, it seems to be same speed as the Proce55ing does.
- //----------------------------------------------------------------------
- package {
- import flash.display.*;
- import flash.text.*;
- import flash.events.*;
- [SWF(frameRate = "1000", backgroundColor = "#808080")]
- public class main extends Sprite {
- private var _tf:TextField = new TextField();
- private var _screen:BitmapData = new BitmapData(WIDTH, HEIGHT, false, 0xffffff);
- private var _renderY:int;
- function main() {
- _tf.autoSize = 'left';
- _tf.htmlText = "<font color='#ffffff'>Rendering...</font>";
- addChild(_tf);
- with(addChild(new Bitmap(_screen))){ x = y = 104.5; }
- _renderY = 0;
- addEventListener("enterFrame", _startRender);
- }
- private function _startRender(e:Event) : void {
- // rendering
- render.rasterRendering(_renderY);
- // copy pixels
- _screen.lock();
- for (var x:int=0; x<WIDTH; x++) _screen.setPixel(x, _renderY, render.output[x]);
- _screen.unlock();
- // increment
- _renderY++;
- if (_renderY == 256) {
- // finish rendering
- _tf.htmlText = "<font color='#ffffff'>Rendering time : " + String(render.renderingTime/1000) + "[sec]</font>";
- removeEventListener("enterFrame", _startRender);
- }
- }
- }
- }
- import flash.display.*;
- import flash.geom.*;
- import flash.utils.getTimer;
- // global variables
- //--------------------------------------------------------------------------------
- const WIDTH :int = 256;
- const HEIGHT:int = 256;
- const NSUBSAMPLES:int = 2;
- const NAO_SAMPLES:int = 8;
- var render:Render = new Render();
- // structures
- //--------------------------------------------------------------------------------
- class Isect {
- public var t:Number = 0;
- public var p:Vector3D = new Vector3D();
- public var n:Vector3D = new Vector3D();
- public var hit:int = 0;
- }
- class Ray {
- public var org:Vector3D = new Vector3D();
- public var dir:Vector3D = new Vector3D();
- }
- class Sphere {
- public var center:Vector3D;
- public var radius2:Number;
- function Sphere(center:Vector3D, radius:Number) {
- this.center = center;
- this.radius2 = radius*radius;
- }
- }
- class Plane {
- public var p:Vector3D;
- public var n:Vector3D;
- public var pn:Number;
- function Plane(p:Vector3D, n:Vector3D) {
- this.p = p;
- this.n = n;
- this.pn = n.x*p.x + n.y*p.y + n.z*p.z;
- }
- }
- // render
- //--------------------------------------------------------------------------------
- class Render {
- // variables
- //--------------------------------------------------
- public var output:Vector.<uint>;
- public var renderingTime:int;
- private var spheres:Vector.<Sphere> = new Vector.<Sphere>(3, true);
- private var plane:Plane;
- // constructor
- //--------------------------------------------------
- function Render() {
- _initScene();
- renderingTime = 0;
- output = new Vector.<uint>(WIDTH, true);
- }
- // rendering
- //--------------------------------------------------
- public function rasterRendering(y:int) : void {
- var t:int = getTimer();
- _render(output, WIDTH, HEIGHT, y);
- renderingTime += getTimer() - t;
- }
- // privates
- //--------------------------------------------------
- // initialize scene
- private function _initScene() : void {
- spheres[0] = new Sphere(new Vector3D(-2.0, 0.0, -3.5), 0.5);
- spheres[1] = new Sphere(new Vector3D(-0.5, 0.0, -3.0), 0.5);
- spheres[2] = new Sphere(new Vector3D( 1.0, 0.0, -2.2), 0.5);
- plane = new Plane(new Vector3D(0.0, -0.5, 0.0), new Vector3D(0.0, 1.0, 0.0));
- }
- // render
- private var ray:Ray = new Ray();
- private var isect:Isect = new Isect();
- private function _render(line:Vector.<uint>, w:int, h:int, y:int) : void {
- var idx:int, x:int, u:int, v:int, du:Number, dv:Number, pixel:uint, ao:Vector3D,
- hw :Number = w*0.5, hh :Number = h*0.5,
- ihw:Number = 1/hw, ihh:Number = 1/hh,
- step:Number = 1/NSUBSAMPLES,
- occlusionPerPixel:Number = 1/(NSUBSAMPLES*NSUBSAMPLES),
- color:Vector3D = new Vector3D();
- // scan all pixels
- idx = 0;
- for (x = 0; x < w; x++) {
- // initialize pixel color
- color.x = 0;
- color.y = 0;
- color.z = 0;
- // sub samplings
- for (v = 0, dv = 0; v < NSUBSAMPLES; v++, dv += step) {
- for (u = 0, du = 0; u < NSUBSAMPLES; u++, du += step) {
- // initialize ray vectors
- ray.org.x = 0.0;
- ray.org.y = 0.0;
- ray.org.z = 0.0;
- ray.dir.x = (x + du - hw) * ihw;
- ray.dir.y = -(y + dv - hh) * ihh;
- ray.dir.z = -1.0;
- ray.dir.normalize();
- // check ray intersections
- isect.p.x = isect.p.y = isect.p.z = 0.0;
- isect.n.x = isect.n.y = isect.n.z = 0.0;
- isect.t = 1.0e+17;
- isect.hit = 0;
- _intersectBySphere(isect, ray, spheres[0]);
- _intersectBySphere(isect, ray, spheres[1]);
- _intersectBySphere(isect, ray, spheres[2]);
- _intersectByPlane (isect, ray, plane);
- // when the ray is intersected, calculate ambient occlusion color.
- if (isect.hit) {
- color.incrementBy(_ambientOcclusion(isect));
- }
- }
- }
- // calculate gray scale
- color.scaleBy(occlusionPerPixel);
- pixel = 0xff000000;
- pixel |= (color.x >= 1) ? 255 : (color.x <= 0) ? 0 : int(color.x * 255);
- pixel |= ((color.y >= 1) ? 255 : (color.y <= 0) ? 0 : int(color.x * 255)) << 8;
- pixel |= ((color.z >= 1) ? 255 : (color.z <= 0) ? 0 : int(color.x * 255)) << 16;
- output[idx] = pixel;
- // increment index
- idx++;
- }
- }
- // calculate ambient occlusion
- private var aoRay:Ray = new Ray();
- private var aoIsect:Isect = new Isect();
- private var aoColor:Vector3D = new Vector3D();
- private var basis0:Vector3D = new Vector3D();
- private var basis1:Vector3D = new Vector3D();
- private var basis2:Vector3D = new Vector3D();
- private function _ambientOcclusion(isect:Isect) : Vector3D {
- var i:int, j:int, th:Number, ph:Number,
- x:Number, y:Number, z:Number,
- rx:Number, ry:Number, rz:Number,
- ntheta:int = NAO_SAMPLES,
- nphi:int = NAO_SAMPLES,
- occlusionPerSample:Number = 1 / (ntheta*nphi),
- eps:Number = 0.0001,
- occlusion:Number = 1.0;
- // calculate transform matrix from local to global.
- // the "local" coordinate is based on the normal vector at intersected point.
- basis2 = isect.n;
- basis1.x = 0.0;
- basis1.y = 0.0;
- basis1.z = 0.0;
- if ((isect.n.x < 0.6) && (isect.n.x > -0.6)) basis1.x = 1.0;
- else if ((isect.n.y < 0.6) && (isect.n.y > -0.6)) basis1.y = 1.0;
- else if ((isect.n.z < 0.6) && (isect.n.z > -0.6)) basis1.z = 1.0;
- else basis1.x = 1.0;
- vcross(basis0, basis1, basis2).normalize();
- vcross(basis1, basis2, basis0).normalize();
- // calculate the origin of the second ray
- aoRay.org.x = isect.p.x + eps * isect.n.x;
- aoRay.org.y = isect.p.y + eps * isect.n.y;
- aoRay.org.z = isect.p.z + eps * isect.n.z;
- // calculate the ambient occlusion at intersected point
- for (j = 0; j < ntheta; j++) {
- for (i = 0; i < nphi; i++) {
- // calculate the direction of the second ray
- th = Math.sqrt(Math.random());
- ph = 6.283185307179586 * Math.random();
- x = Math.cos(ph) * th;
- y = Math.sin(ph) * th;
- z = Math.sqrt(1.0 - th * th);
- // transform second ray vector from local to global
- aoRay.dir.x = x * basis0.x + y * basis1.x + z * basis2.x;
- aoRay.dir.y = x * basis0.y + y * basis1.y + z * basis2.y;
- aoRay.dir.z = x * basis0.z + y * basis1.z + z * basis2.z;
- // check second ray intersections
- aoIsect.p.x = aoIsect.p.y = aoIsect.p.z = 0.0;
- aoIsect.n.x = aoIsect.n.y = aoIsect.n.z = 0.0;
- aoIsect.t = 1.0e+17;
- aoIsect.hit = 0;
- _intersectBySphere(aoIsect, aoRay, spheres[0]);
- _intersectBySphere(aoIsect, aoRay, spheres[1]);
- _intersectBySphere(aoIsect, aoRay, spheres[2]);
- _intersectByPlane (aoIsect, aoRay, plane);
- // when the second ray is intersected, increase the occlusion.
- if (aoIsect.hit) occlusion -= occlusionPerSample;
- }
- }
- // return result
- aoColor.x = occlusion;
- aoColor.y = occlusion;
- aoColor.z = occlusion;
- return aoColor;
- // cross product
- function vcross(c:Vector3D, v0:Vector3D, v1:Vector3D) : Vector3D {
- c.x = v0.y * v1.z - v0.z * v1.y;
- c.y = v0.z * v1.x - v0.x * v1.z;
- c.z = v0.x * v1.y - v0.y * v1.x;
- return c;
- }
- }
- // check ray intersection by sphere
- private function _intersectBySphere(isect:Isect, ray:Ray, sph:Sphere) : void {
- var rsx:Number = ray.org.x - sph.center.x,
- rsy:Number = ray.org.y - sph.center.y,
- rsz:Number = ray.org.z - sph.center.z,
- B:Number = rsx*ray.dir.x + rsy*ray.dir.y + rsz*ray.dir.z,
- C:Number = rsx*rsx + rsy*rsy + rsz*rsz - sph.radius2,
- D:Number = B * B - C;
- // when the ray is intersected by the sphere,
- if (D > 0.0) {
- var t:Number = -B - Math.sqrt(D);
- if ((t > 0.0) && (t < isect.t)) {
- // calculate cross point and normal vector.
- isect.t = t;
- isect.hit = 1;
- isect.p.x = ray.org.x + ray.dir.x * t;
- isect.p.y = ray.org.y + ray.dir.y * t;
- isect.p.z = ray.org.z + ray.dir.z * t;
- isect.n.x = isect.p.x - sph.center.x;
- isect.n.y = isect.p.y - sph.center.y;
- isect.n.z = isect.p.z - sph.center.z;
- isect.n.normalize();
- }
- }
- }
- // check ray intersection by plane
- private function _intersectByPlane(isect:Isect, ray:Ray, pln:Plane) : void {
- var v:Number = pln.n.x*ray.dir.x + pln.n.y*ray.dir.y + pln.n.z*ray.dir.z;
- // when parallel with plane
- if (v>-1.0e-17 && v<1.0e-17) return;
- var t:Number = -(pln.n.x*ray.org.x + pln.n.y*ray.org.y + pln.n.z*ray.org.z - pln.pn) / v;
- // when the ray is intersected by the plane,
- if ((t > 0.0) && (t < isect.t)) {
- // calculate cross point and normal vector.
- isect.t = t;
- isect.hit = 1;
- isect.p.x = ray.org.x + ray.dir.x * t;
- isect.p.y = ray.org.y + ray.dir.y * t;
- isect.p.z = ray.org.z + ray.dir.z * t;
- isect.n.x = pln.n.x;
- isect.n.y = pln.n.y;
- isect.n.z = pln.n.z;
- }
- }
- }
Ambient Occlusion Rendering forked from: Ambient Occlusion Rendering
- // forked from keim_at_Si's Ambient Occlusion Rendering
- // Ambient Occlusion Bench Flash10 porting
- // Original version of AO bench was written by Syoyo Fujita.
- // http://lucille.atso-net.jp/aobench/
- // In original Flash10 porting, it takes 7 times slower than the Proce55ing.
- // (refer from http://lucille.atso-net.jp/blog/?p=638).
- // And now, it seems to be same speed as the Proce55ing does.
- //----------------------------------------------------------------------
- package {
- import flash.display.*;
- import flash.text.*;
- import flash.events.*;
- [SWF(frameRate = "1000", backgroundColor = "#808080")]
- public class main extends Sprite {
- private var _tf:TextField = new TextField();
- private var _screen:BitmapData = new BitmapData(WIDTH, HEIGHT, false, 0xffffff);
- private var _renderY:int;
- function main() {
- _tf.autoSize = 'left';
- _tf.htmlText = "<font color='#ffffff'>Rendering...</font>";
- addChild(_tf);
- with(addChild(new Bitmap(_screen))){ x = y = 104.5; }
- _renderY = 0;
- addEventListener("enterFrame", _startRender);
- }
- private function _startRender(e:Event) : void {
- // rendering
- render.rasterRendering(_renderY);
- // copy pixels
- _screen.lock();
- for (var x:int=0; x<WIDTH; x++) _screen.setPixel(x, _renderY, render.output[x]);
- _screen.unlock();
- // increment
- _renderY++;
- if (_renderY == 256) {
- // finish rendering
- _tf.htmlText = "<font color='#ffffff'>Rendering time : " + String(render.renderingTime/1000) + "[sec]</font>";
- removeEventListener("enterFrame", _startRender);
- }
- }
- }
- }
- import flash.display.*;
- import flash.geom.*;
- import flash.utils.getTimer;
- // global variables
- //--------------------------------------------------------------------------------
- const WIDTH :int = 256;
- const HEIGHT:int = 256;
- const NSUBSAMPLES:int = 2
- const NAO_SAMPLES:int = 8;
- var render:Render = new Render();
- // structures
- //--------------------------------------------------------------------------------
- class Isect {
- public var t:Number = 0;
- public var p:Vector3D = new Vector3D();
- public var n:Vector3D = new Vector3D();
- public var hit:int = 0;
- }
- class Ray {
- public var org:Vector3D = new Vector3D();
- public var dir:Vector3D = new Vector3D();
- }
- class Sphere {
- public var center:Vector3D;
- public var radius2:Number;
- function Sphere(center:Vector3D, radius:Number) {
- this.center = center;
- this.radius2 = radius*radius;
- }
- }
- class Plane {
- public var p:Vector3D;
- public var n:Vector3D;
- public var pn:Number;
- function Plane(p:Vector3D, n:Vector3D) {
- this.p = p;
- this.n = n;
- this.pn = n.x*p.x + n.y*p.y + n.z*p.z;
- }
- }
- // render
- //--------------------------------------------------------------------------------
- class Render {
- // variables
- //--------------------------------------------------
- public var output:Vector.<uint>;
- public var renderingTime:int;
- private var spheres:Vector.<Sphere> = new Vector.<Sphere>(3, true);
- private var plane:Plane;
- // constructor
- //--------------------------------------------------
- function Render() {
- _initScene();
- renderingTime = 0;
- output = new Vector.<uint>(WIDTH, true);
- }
- // rendering
- //--------------------------------------------------
- public function rasterRendering(y:int) : void {
- var t:int = getTimer();
- _render(output, WIDTH, HEIGHT, y);
- renderingTime += getTimer() - t;
- }
- // privates
- //--------------------------------------------------
- // initialize scene
- private function _initScene() : void {
- spheres[0] = new Sphere(new Vector3D(-2.0, 0.0, -3.5), 0.5);
- spheres[1] = new Sphere(new Vector3D(-0.4, 0.0, -3.0), 1.1);
- spheres[2] = new Sphere(new Vector3D( 1.0, 0.0, -2.2), 0.5);
- plane = new Plane(new Vector3D(0.0, -0.5, 0.0), new Vector3D(0.0, 1.0, 0.0));
- }
- // render
- private var ray:Ray = new Ray();
- private var isect:Isect = new Isect();
- private function _render(line:Vector.<uint>, w:int, h:int, y:int) : void {
- var idx:int, x:int, u:int, v:int, du:Number, dv:Number, pixel:uint, ao:Vector3D,
- hw :Number = w*0.5, hh :Number = h*0.5,
- ihw:Number = 1/hw, ihh:Number = 1/hh,
- step:Number = 1/NSUBSAMPLES,
- occlusionPerPixel:Number = 1/(NSUBSAMPLES*NSUBSAMPLES),
- color:Vector3D = new Vector3D();
- // scan all pixels
- idx = 0;
- for (x = 0; x < w; x++) {
- // initialize pixel color
- color.x = 0;
- color.y = 0;
- color.z = 0;
- // sub samplings
- for (v = 0, dv = 0; v < NSUBSAMPLES; v++, dv += step) {
- for (u = 0, du = 0; u < NSUBSAMPLES; u++, du += step) {
- // initialize ray vectors
- ray.org.x = 0.0;
- ray.org.y = 0.0;
- ray.org.z = 0.0;
- ray.dir.x = (x + du - hw) * ihw;
- ray.dir.y = -(y + dv - hh) * ihh;
- ray.dir.z = -1.0;
- ray.dir.normalize();
- // check ray intersections
- isect.p.x = isect.p.y = isect.p.z = 0.0;
- isect.n.x = isect.n.y = isect.n.z = 0.0;
- isect.t = 1.0e+17;
- isect.hit = 0;
- _intersectBySphere(isect, ray, spheres[0]);
- // _intersectBySphere(isect, ray, spheres[1]);
- //_intersectBySphere(isect, ray, spheres[2]);
- _intersectByPlane (isect, ray, plane);
- // when the ray is intersected, calculate ambient occlusion color.
- if (isect.hit) {
- color.incrementBy(_ambientOcclusion(isect));
- }
- }
- }
- // calculate gray scale
- color.scaleBy(occlusionPerPixel);
- pixel = 0xff000000;
- pixel |= (color.x >= 1) ? 255 : (color.x <= 0) ? 0 : int(color.x * 255);
- pixel |= ((color.y >= 1) ? 255 : (color.y <= 0) ? 0 : int(color.x * 255)) << 8;
- pixel |= ((color.z >= 1) ? 255 : (color.z <= 0) ? 0 : int(color.x * 255)) << 16;
- output[idx] = pixel;
- // increment index
- idx++;
- }
- }
- // calculate ambient occlusion
- private var aoRay:Ray = new Ray();
- private var aoIsect:Isect = new Isect();
- private var aoColor:Vector3D = new Vector3D();
- private var basis0:Vector3D = new Vector3D();
- private var basis1:Vector3D = new Vector3D();
- private var basis2:Vector3D = new Vector3D();
- private function _ambientOcclusion(isect:Isect) : Vector3D {
- var i:int, j:int, th:Number, ph:Number,
- x:Number, y:Number, z:Number,
- rx:Number, ry:Number, rz:Number,
- ntheta:int = NAO_SAMPLES,
- nphi:int = NAO_SAMPLES,
- occlusionPerSample:Number = 1 / (ntheta*nphi),
- eps:Number = 0.0001,
- occlusion:Number = 1.0;
- // calculate transform matrix from local to global.
- // the "local" coordinate is based on the normal vector at intersected point.
- basis2 = isect.n;
- basis1.x = 0.0;
- basis1.y = 0.0;
- basis1.z = 0.0;
- if ((isect.n.x < 0.6) && (isect.n.x > -0.6)) basis1.x = 1.0;
- else if ((isect.n.y < 0.6) && (isect.n.y > -0.6)) basis1.y = 1.0;
- else if ((isect.n.z < 0.6) && (isect.n.z > -0.6)) basis1.z = 1.0;
- else basis1.x = 1.0;
- vcross(basis0, basis1, basis2).normalize();
- vcross(basis1, basis2, basis0).normalize();
- // calculate the origin of the second ray
- aoRay.org.x = isect.p.x + eps * isect.n.x;
- aoRay.org.y = isect.p.y + eps * isect.n.y;
- aoRay.org.z = isect.p.z + eps * isect.n.z;
- // calculate the ambient occlusion at intersected point
- for (j = 0; j < ntheta; j++) {
- for (i = 0; i < nphi; i++) {
- // calculate the direction of the second ray
- th = Math.sqrt(Math.random());
- ph = 6.283185307179586 * Math.random();
- x = Math.cos(ph) * th;
- y = Math.sin(ph) * th;
- z = Math.sqrt(1.0 - th * th);
- // transform second ray vector from local to global
- aoRay.dir.x = x * basis0.x + y * basis1.x + z * basis2.x;
- aoRay.dir.y = x * basis0.y + y * basis1.y + z * basis2.y;
- aoRay.dir.z = x * basis0.z + y * basis1.z + z * basis2.z;
- // check second ray intersections
- aoIsect.p.x = aoIsect.p.y = aoIsect.p.z = 0.0;
- aoIsect.n.x = aoIsect.n.y = aoIsect.n.z = 0.0;
- aoIsect.t = 1.0e+17;
- aoIsect.hit = 0;
- _intersectBySphere(aoIsect, aoRay, spheres[0]);
- // _intersectBySphere(aoIsect, aoRay, spheres[1]);
- // _intersectBySphere(aoIsect, aoRay, spheres[2]);
- _intersectByPlane (aoIsect, aoRay, plane);
- // when the second ray is intersected, increase the occlusion.
- if (aoIsect.hit) occlusion -= occlusionPerSample;
- }
- }
- // return result
- aoColor.x = occlusion;
- aoColor.y = occlusion;
- aoColor.z = occlusion;
- return aoColor;
- // cross product
- function vcross(c:Vector3D, v0:Vector3D, v1:Vector3D) : Vector3D {
- c.x = v0.y * v1.z - v0.z * v1.y;
- c.y = v0.z * v1.x - v0.x * v1.z;
- c.z = v0.x * v1.y - v0.y * v1.x;
- return c;
- }
- }
- // check ray intersection by sphere
- private function _intersectBySphere(isect:Isect, ray:Ray, sph:Sphere) : void {
- var R:Number = sph.radius2 / 2;
- var rsx:Number = ray.org.x - sph.center.x,
- rsy:Number = ray.org.y - sph.center.y,
- rsz:Number = ray.org.z - sph.center.z,
- B:Number = rsx*rsx*rsx*rsx + rsy*rsy*rsy*rsy + rsz*rsz*rsz*rsz,
- C:Number = rsx*rsx*rsx*rsx + rsy*rsy*rsy*rsy + rsz*rsz*rsz*rsz - 10 * R * R * (rsx*rsx + rsy*rsy + rsz*rsz) + 10 * Math.pow(R,4),
- D:Number = B * B - C;
- //x^4 + y^4 + z^4 - 10*R^2*(x^2 + y^2 + z^2) + 40 * R^4
- // when the ray is intersected by the sphere,
- if (D > 0.0) {
- var t:Number = C//Math.sqrt(D);
- if ((t > 0.0) && (t < isect.t)) {
- // calculate cross point and normal vector.
- isect.t = t;
- isect.hit = 1;
- isect.p.x = ray.org.x + ray.dir.x * t;
- isect.p.y = ray.org.y + ray.dir.y * t;
- isect.p.z = ray.org.z + ray.dir.z * t;
- isect.n.x = isect.p.x - sph.center.x;
- isect.n.y = isect.p.y - sph.center.y;
- isect.n.z = isect.p.z - sph.center.z;
- isect.n.normalize();
- }
- }
- }
- // check ray intersection by plane
- private function _intersectByPlane(isect:Isect, ray:Ray, pln:Plane) : void {
- var v:Number = pln.n.x*ray.dir.x + pln.n.y*ray.dir.y + pln.n.z*ray.dir.z;
- // when parallel with plane
- if (v>-1.0e-17 && v<1.0e-17) return;
- var t:Number = -(pln.n.x*ray.org.x + pln.n.y*ray.org.y + pln.n.z*ray.org.z - pln.pn) / v;
- // when the ray is intersected by the plane,
- if ((t > 0.0) && (t < isect.t)) {
- // calculate cross point and normal vector.
- isect.t = t;
- isect.hit = 1;
- isect.p.x = ray.org.x + ray.dir.x * t;
- isect.p.y = ray.org.y + ray.dir.y * t;
- isect.p.z = ray.org.z + ray.dir.z * t;
- isect.n.x = pln.n.x;
- isect.n.y = pln.n.y;
- isect.n.z = pln.n.z;
- }
- }
- }
Ambient Occlusion Rendering forked from: Ambient Occlusion Rendering
- // forked from keim_at_Si's Ambient Occlusion Rendering
- // Ambient Occlusion Bench Flash10 porting
- // Original version of AO bench was written by Syoyo Fujita.
- // http://lucille.atso-net.jp/aobench/
- // In original Flash10 porting, it takes 7 times slower than the Proce55ing.
- // (refer from http://lucille.atso-net.jp/blog/?p=638).
- // And now, it seems to be same speed as the Proce55ing does.
- //----------------------------------------------------------------------
- package {
- import flash.display.*;
- import flash.text.*;
- import flash.events.*;
- [SWF(frameRate = "1000", backgroundColor = "#808080")]
- public class main extends Sprite {
- private var _tf:TextField = new TextField();
- private var _screen:BitmapData = new BitmapData(WIDTH, HEIGHT, false, 0xffffff);
- private var _renderY:int;
- function main() {
- _tf.autoSize = 'left';
- _tf.htmlText = "<font color='#ffffff'>Rendering...</font>";
- addChild(_tf);
- with(addChild(new Bitmap(_screen))){ x = y = 104.5; }
- _renderY = 0;
- addEventListener("enterFrame", _startRender);
- }
- private function _startRender(e:Event) : void {
- // rendering
- render.rasterRendering(_renderY);
- // copy pixels
- _screen.lock();
- for (var x:int=0; x<WIDTH; x++) _screen.setPixel(x, _renderY, render.output[x]);
- _screen.unlock();
- // increment
- _renderY++;
- if (_renderY == 256) {
- // finish rendering
- _tf.htmlText = "<font color='#ffffff'>Rendering time : " + String(render.renderingTime/1000) + "[sec]</font>";
- removeEventListener("enterFrame", _startRender);
- }
- }
- }
- }
- import flash.display.*;
- import flash.geom.*;
- import flash.utils.getTimer;
- // global variables
- //--------------------------------------------------------------------------------
- const WIDTH :int = 256;
- const HEIGHT:int = 256;
- const NSUBSAMPLES:int = 2;
- const NAO_SAMPLES:int = 8;
- var render:Render = new Render();
- // structures
- //--------------------------------------------------------------------------------
- class Isect {
- public var t:Number = 0;
- public var p:Vector3D = new Vector3D();
- public var n:Vector3D = new Vector3D();
- public var hit:int = 0;
- }
- class Ray {
- public var org:Vector3D = new Vector3D();
- public var dir:Vector3D = new Vector3D();
- }
- class Sphere {
- public var center:Vector3D;
- public var radius2:Number;
- function Sphere(center:Vector3D, radius:Number) {
- this.center = center;
- this.radius2 = radius*radius;
- }
- }
- class Plane {
- public var p:Vector3D;
- public var n:Vector3D;
- public var pn:Number;
- function Plane(p:Vector3D, n:Vector3D) {
- this.p = p;
- this.n = n;
- this.pn = n.x*p.x + n.y*p.y + n.z*p.z;
- }
- }
- // render
- //--------------------------------------------------------------------------------
- class Render {
- // variables
- //--------------------------------------------------
- public var output:Vector.<uint>;
- public var renderingTime:int;
- private var spheres:Vector.<Sphere> = new Vector.<Sphere>(3, true);
- private var plane:Plane;
- // constructor
- //--------------------------------------------------
- function Render() {
- _initScene();
- renderingTime = 0;
- output = new Vector.<uint>(WIDTH, true);
- }
- // rendering
- //--------------------------------------------------
- public function rasterRendering(y:int) : void {
- var t:int = getTimer();
- _render(output, WIDTH, HEIGHT, y);
- renderingTime += getTimer() - t;
- }
- // privates
- //--------------------------------------------------
- // initialize scene
- private function _initScene() : void {
- spheres[0] = new Sphere(new Vector3D(-2.0, 0.0, -3.5), 0.5);
- spheres[1] = new Sphere(new Vector3D(-0.5, 0.0, -3.0), 0.5);
- spheres[2] = new Sphere(new Vector3D( 1.0, 0.0, -2.2), 0.5);
- plane = new Plane(new Vector3D(0.0, -0.5, 0.0), new Vector3D(0.0, 1.0, 0.0));
- }
- // render
- private var ray:Ray = new Ray();
- private var isect:Isect = new Isect();
- private function _render(line:Vector.<uint>, w:int, h:int, y:int) : void {
- var idx:int, x:int, u:int, v:int, du:Number, dv:Number, pixel:uint, ao:Vector3D,
- hw :Number = w*0.5, hh :Number = h*0.5,
- ihw:Number = 1/hw, ihh:Number = 1/hh,
- step:Number = 1/NSUBSAMPLES,
- occlusionPerPixel:Number = 1/(NSUBSAMPLES*NSUBSAMPLES),
- color:Vector3D = new Vector3D();
- // scan all pixels
- idx = 0;
- for (x = 0; x < w; x++) {
- // initialize pixel color
- color.x = 0;
- color.y = 0;
- color.z = 0;
- // sub samplings
- for (v = 0, dv = 0; v < NSUBSAMPLES; v++, dv += step) {
- for (u = 0, du = 0; u < NSUBSAMPLES; u++, du += step) {
- // initialize ray vectors
- ray.org.x = 0.0;
- ray.org.y = 0.0;
- ray.org.z = 0.0;
- ray.dir.x = (x + du - hw) * ihw;
- ray.dir.y = -(y + dv - hh) * ihh;
- ray.dir.z = -1.0;
- ray.dir.normalize();
- // check ray intersections
- isect.p.x = isect.p.y = isect.p.z = 0.0;
- isect.n.x = isect.n.y = isect.n.z = 0.0;
- isect.t = 1.0e+17;
- isect.hit = 0;
- _intersectBySphere(isect, ray, spheres[0]);
- _intersectBySphere(isect, ray, spheres[1]);
- _intersectBySphere(isect, ray, spheres[2]);
- _intersectByPlane (isect, ray, plane);
- // when the ray is intersected, calculate ambient occlusion color.
- if (isect.hit) {
- color.incrementBy(_ambientOcclusion(isect));
- }
- }
- }
- // calculate gray scale
- color.scaleBy(occlusionPerPixel);
- pixel = 0xff000000;
- pixel |= (color.x >= 1) ? 255 : (color.x <= 0) ? 0 : int(color.x * 255);
- pixel |= ((color.y >= 1) ? 255 : (color.y <= 0) ? 0 : int(color.x * 255)) << 8;
- pixel |= ((color.z >= 1) ? 255 : (color.z <= 0) ? 0 : int(color.x * 255)) << 16;
- output[idx] = pixel;
- // increment index
- idx++;
- }
- }
- // calculate ambient occlusion
- private var aoRay:Ray = new Ray();
- private var aoIsect:Isect = new Isect();
- private var aoColor:Vector3D = new Vector3D();
- private var basis0:Vector3D = new Vector3D();
- private var basis1:Vector3D = new Vector3D();
- private var basis2:Vector3D = new Vector3D();
- private function _ambientOcclusion(isect:Isect) : Vector3D {
- var i:int, j:int, th:Number, ph:Number,
- x:Number, y:Number, z:Number,
- rx:Number, ry:Number, rz:Number,
- ntheta:int = NAO_SAMPLES,
- nphi:int = NAO_SAMPLES,
- occlusionPerSample:Number = 1 / (ntheta*nphi),
- eps:Number = 0.0001,
- occlusion:Number = 1.0;
- // calculate transform matrix from local to global.
- // the "local" coordinate is based on the normal vector at intersected point.
- basis2 = isect.n;
- basis1.x = 0.0;
- basis1.y = 0.0;
- basis1.z = 0.0;
- if ((isect.n.x < 0.6) && (isect.n.x > -0.6)) basis1.x = 1.0;
- else if ((isect.n.y < 0.6) && (isect.n.y > -0.6)) basis1.y = 1.0;
- else if ((isect.n.z < 0.6) && (isect.n.z > -0.6)) basis1.z = 1.0;
- else basis1.x = 1.0;
- vcross(basis0, basis1, basis2).normalize();
- vcross(basis1, basis2, basis0).normalize();
- // calculate the origin of the second ray
- aoRay.org.x = isect.p.x + eps * isect.n.x;
- aoRay.org.y = isect.p.y + eps * isect.n.y;
- aoRay.org.z = isect.p.z + eps * isect.n.z;
- // calculate the ambient occlusion at intersected point
- for (j = 0; j < ntheta; j++) {
- for (i = 0; i < nphi; i++) {
- // calculate the direction of the second ray
- th = Math.sqrt(Math.random());
- ph = 6.283185307179586 * Math.random();
- x = Math.cos(ph) * th;
- y = Math.sin(ph) * th;
- z = Math.sqrt(1.0 - th * th);
- // transform second ray vector from local to global
- aoRay.dir.x = x * basis0.x + y * basis1.x + z * basis2.x;
- aoRay.dir.y = x * basis0.y + y * basis1.y + z * basis2.y;
- aoRay.dir.z = x * basis0.z + y * basis1.z + z * basis2.z;
- // check second ray intersections
- aoIsect.p.x = aoIsect.p.y = aoIsect.p.z = 0.0;
- aoIsect.n.x = aoIsect.n.y = aoIsect.n.z = 0.0;
- aoIsect.t = 1.0e+17;
- aoIsect.hit = 0;
- _intersectBySphere(aoIsect, aoRay, spheres[0]);
- _intersectBySphere(aoIsect, aoRay, spheres[1]);
- _intersectBySphere(aoIsect, aoRay, spheres[2]);
- _intersectByPlane (aoIsect, aoRay, plane);
- // when the second ray is intersected, increase the occlusion.
- if (aoIsect.hit) occlusion -= occlusionPerSample;
- }
- }
- // return result
- aoColor.x = occlusion;
- aoColor.y = occlusion;
- aoColor.z = occlusion;
- return aoColor;
- // cross product
- function vcross(c:Vector3D, v0:Vector3D, v1:Vector3D) : Vector3D {
- c.x = v0.y * v1.z - v0.z * v1.y;
- c.y = v0.z * v1.x - v0.x * v1.z;
- c.z = v0.x * v1.y - v0.y * v1.x;
- return c;
- }
- }
- // check ray intersection by sphere
- private function _intersectBySphere(isect:Isect, ray:Ray, sph:Sphere) : void {
- var rsx:Number = ray.org.x - sph.center.x,
- rsy:Number = ray.org.y - sph.center.y,
- rsz:Number = ray.org.z - sph.center.z,
- B:Number = rsx*ray.dir.x + rsy*ray.dir.y + rsz*ray.dir.z,
- C:Number = rsx*rsx + rsy*rsy + rsz*rsz - sph.radius2,
- D:Number = B * B - C;
- // when the ray is intersected by the sphere,
- if (D > 0.0) {
- var t:Number = -B - Math.sqrt(D);
- if ((t > 0.0) && (t < isect.t)) {
- // calculate cross point and normal vector.
- isect.t = t;
- isect.hit = 1;
- isect.p.x = ray.org.x + ray.dir.x * t;
- isect.p.y = ray.org.y + ray.dir.y * t;
- isect.p.z = ray.org.z + ray.dir.z * t;
- isect.n.x = isect.p.x - sph.center.x;
- isect.n.y = isect.p.y - sph.center.y;
- isect.n.z = isect.p.z - sph.center.z;
- isect.n.normalize();
- }
- }
- }
- // check ray intersection by plane
- private function _intersectByPlane(isect:Isect, ray:Ray, pln:Plane) : void {
- var v:Number = pln.n.x*ray.dir.x + pln.n.y*ray.dir.y + pln.n.z*ray.dir.z;
- // when parallel with plane
- if (v>-1.0e-17 && v<1.0e-17) return;
- var t:Number = -(pln.n.x*ray.org.x + pln.n.y*ray.org.y + pln.n.z*ray.org.z - pln.pn) / v;
- // when the ray is intersected by the plane,
- if ((t > 0.0) && (t < isect.t)) {
- // calculate cross point and normal vector.
- isect.t = t;
- isect.hit = 1;
- isect.p.x = ray.org.x + ray.dir.x * t;
- isect.p.y = ray.org.y + ray.dir.y * t;
- isect.p.z = ray.org.z + ray.dir.z * t;
- isect.n.x = pln.n.x;
- isect.n.y = pln.n.y;
- isect.n.z = pln.n.z;
- }
- }
- }
Ambient Occlusion Rendering forked from: Ambient Occlusion Rendering
- // forked from keim_at_Si's Ambient Occlusion Rendering
- // Ambient Occlusion Bench Flash10 porting
- // Original version of AO bench was written by Syoyo Fujita.
- // http://lucille.atso-net.jp/aobench/
- // In original Flash10 porting, it takes 7 times slower than the Proce55ing.
- // (refer from http://lucille.atso-net.jp/blog/?p=638).
- // And now, it seems to be same speed as the Proce55ing does.
- //----------------------------------------------------------------------
- package {
- import flash.display.*;
- import flash.text.*;
- import flash.events.*;
- [SWF(frameRate = "1000", backgroundColor = "#808080")]
- public class main extends Sprite {
- private var _tf:TextField = new TextField();
- private var _screen:BitmapData = new BitmapData(WIDTH, HEIGHT, false, 0xffffff);
- private var _renderY:int;
- function main() {
- _tf.autoSize = 'left';
- _tf.htmlText = "<font color='#ffffff'>Rendering...</font>";
- addChild(_tf);
- with(addChild(new Bitmap(_screen))){ x = y = 104.5; }
- _renderY = 0;
- addEventListener("enterFrame", _startRender);
- }
- private function _startRender(e:Event) : void {
- // rendering
- render.rasterRendering(_renderY);
- // copy pixels
- _screen.lock();
- for (var x:int=0; x<WIDTH; x++) _screen.setPixel(x, _renderY, render.output[x]);
- _screen.unlock();
- // increment
- _renderY++;
- if (_renderY == 256) {
- // finish rendering
- _tf.htmlText = "<font color='#ffffff'>Rendering time : " + String(render.renderingTime/1000) + "[sec]</font>";
- removeEventListener("enterFrame", _startRender);
- }
- }
- }
- }
- import flash.display.*;
- import flash.geom.*;
- import flash.utils.getTimer;
- // global variables
- //--------------------------------------------------------------------------------
- const WIDTH :int = 256;
- const HEIGHT:int = 256;
- const NSUBSAMPLES:int = 2;
- const NAO_SAMPLES:int = 8;
- var render:Render = new Render();
- // structures
- //--------------------------------------------------------------------------------
- class Isect {
- public var t:Number = 0;
- public var p:Vector3D = new Vector3D();
- public var n:Vector3D = new Vector3D();
- public var hit:int = 0;
- }
- class Ray {
- public var org:Vector3D = new Vector3D();
- public var dir:Vector3D = new Vector3D();
- }
- class Sphere {
- public var center:Vector3D;
- public var radius2:Number;
- function Sphere(center:Vector3D, radius:Number) {
- this.center = center;
- this.radius2 = radius*radius;
- }
- }
- class Plane {
- public var p:Vector3D;
- public var n:Vector3D;
- public var pn:Number;
- function Plane(p:Vector3D, n:Vector3D) {
- this.p = p;
- this.n = n;
- this.pn = n.x*p.x + n.y*p.y + n.z*p.z;
- }
- }
- // render
- //--------------------------------------------------------------------------------
- class Render {
- // variables
- //--------------------------------------------------
- public var output:Vector.<uint>;
- public var renderingTime:int;
- private var spheres:Vector.<Sphere> = new Vector.<Sphere>(3, true);
- private var plane:Plane;
- // constructor
- //--------------------------------------------------
- function Render() {
- _initScene();
- renderingTime = 0;
- output = new Vector.<uint>(WIDTH, true);
- }
- // rendering
- //--------------------------------------------------
- public function rasterRendering(y:int) : void {
- var t:int = getTimer();
- _render(output, WIDTH, HEIGHT, y);
- renderingTime += getTimer() - t;
- }
- // privates
- //--------------------------------------------------
- // initialize scene
- private function _initScene() : void {
- spheres[0] = new Sphere(new Vector3D(-2.0, 0.0, -3.5), 0.5);
- spheres[1] = new Sphere(new Vector3D(-0.5, 0.0, -3.0), 0.5);
- spheres[2] = new Sphere(new Vector3D( 1.0, 0.0, -2.2), 0.5);
- plane = new Plane(new Vector3D(0.0, -0.5, 0.0), new Vector3D(0.0, 1.0, 0.0));
- }
- // render
- private var ray:Ray = new Ray();
- private var isect:Isect = new Isect();
- private function _render(line:Vector.<uint>, w:int, h:int, y:int) : void {
- var idx:int, x:int, u:int, v:int, du:Number, dv:Number, pixel:uint, ao:Vector3D,
- hw :Number = w*0.5, hh :Number = h*0.5,
- ihw:Number = 1/hw, ihh:Number = 1/hh,
- step:Number = 1/NSUBSAMPLES,
- occlusionPerPixel:Number = 1/(NSUBSAMPLES*NSUBSAMPLES),
- color:Vector3D = new Vector3D();
- var rayOrg:Vector3D = ray.org;
- var rayDir:Vector3D = ray.dir;
- // scan all pixels
- idx = 0;
- for (x = 0; x < w; x++) {
- // initialize pixel color
- color.x = 0;
- color.y = 0;
- color.z = 0;
- // sub samplings
- for (v = 0, dv = 0; v < NSUBSAMPLES; v++, dv += step) {
- for (u = 0, du = 0; u < NSUBSAMPLES; u++, du += step) {
- // initialize ray vectors
- rayOrg.x = 0.0;
- rayOrg.y = 0.0;
- rayOrg.z = 0.0;
- rayDir.x = (x + du - hw) * ihw;
- rayDir.y = -(y + dv - hh) * ihh;
- rayDir.z = -1.0;
- rayDir.normalize();
- // check ray intersections
- isect.p.x = isect.p.y = isect.p.z = 0.0;
- isect.n.x = isect.n.y = isect.n.z = 0.0;
- isect.t = 1.0e+17;
- isect.hit = 0;
- _intersectBySphere(isect, ray, spheres[0]);
- _intersectBySphere(isect, ray, spheres[1]);
- _intersectBySphere(isect, ray, spheres[2]);
- _intersectByPlane (isect, ray, plane);
- // when the ray is intersected, calculate ambient occlusion color.
- if (isect.hit) {
- color.incrementBy(_ambientOcclusion(isect));
- }
- }
- }
- // calculate gray scale
- color.scaleBy(occlusionPerPixel);
- pixel = 0xff000000;
- pixel |= (color.x >= 1) ? 255 : (color.x <= 0) ? 0 : int(color.x * 255);
- pixel |= ((color.y >= 1) ? 255 : (color.y <= 0) ? 0 : int(color.x * 255)) << 8;
- pixel |= ((color.z >= 1) ? 255 : (color.z <= 0) ? 0 : int(color.x * 255)) << 16;
- output[idx] = pixel;
- // increment index
- idx++;
- }
- }
- // calculate ambient occlusion
- private var aoRay:Ray = new Ray();
- private var aoIsect:Isect = new Isect();
- private var aoColor:Vector3D = new Vector3D();
- private var basis0:Vector3D = new Vector3D();
- private var basis1:Vector3D = new Vector3D();
- private var basis2:Vector3D = new Vector3D();
- private function _ambientOcclusion(isect:Isect) : Vector3D {
- var i:int, j:int, th:Number, ph:Number,
- x:Number, y:Number, z:Number,
- rx:Number, ry:Number, rz:Number,
- ntheta:int = NAO_SAMPLES,
- nphi:int = NAO_SAMPLES,
- occlusionPerSample:Number = 1 / (ntheta*nphi),
- eps:Number = 0.0001,
- occlusion:Number = 1.0;
- // calculate transform matrix from local to global.
- // the "local" coordinate is based on the normal vector at intersected point.
- basis2 = isect.n;
- basis1.x = 0.0;
- basis1.y = 0.0;
- basis1.z = 0.0;
- if ((isect.n.x < 0.6) && (isect.n.x > -0.6)) basis1.x = 1.0;
- else if ((isect.n.y < 0.6) && (isect.n.y > -0.6)) basis1.y = 1.0;
- else if ((isect.n.z < 0.6) && (isect.n.z > -0.6)) basis1.z = 1.0;
- else basis1.x = 1.0;
- basis0.x = basis1.y * basis2.z - basis1.z * basis2.y;
- basis0.y = basis1.z * basis2.x - basis1.x * basis2.z;
- basis0.z = basis1.x * basis2.y - basis1.y * basis2.x;
- basis0.normalize();
- basis1.x = basis2.y * basis0.z - basis2.z * basis0.y;
- basis1.y = basis2.z * basis0.x - basis2.x * basis0.z;
- basis1.z = basis2.x * basis0.y - basis2.y * basis0.x;
- basis1.normalize();
- // calculate the origin of the second ray
- aoRay.org.x = isect.p.x + eps * isect.n.x;
- aoRay.org.y = isect.p.y + eps * isect.n.y;
- aoRay.org.z = isect.p.z + eps * isect.n.z;
- var mc:Function = Math.cos;
- var ms:Function = Math.sin;
- var mq:Function = Math.sqrt;
- // calculate the ambient occlusion at intersected point
- for (j = 0; j < ntheta; j++) {
- for (i = 0; i < nphi; i++) {
- // calculate the direction of the second ray
- th = Math.sqrt(Math.random());
- ph = 6.283185307179586 * Math.random();
- x = mc(ph) * th;
- y = ms(ph) * th;
- z = mq(1.0 - th * th);
- // transform second ray vector from local to global
- aoRay.dir.x = x * basis0.x + y * basis1.x + z * basis2.x;
- aoRay.dir.y = x * basis0.y + y * basis1.y + z * basis2.y;
- aoRay.dir.z = x * basis0.z + y * basis1.z + z * basis2.z;
- // check second ray intersections
- aoIsect.p.x = aoIsect.p.y = aoIsect.p.z = 0.0;
- aoIsect.n.x = aoIsect.n.y = aoIsect.n.z = 0.0;
- aoIsect.t = 1.0e+17;
- aoIsect.hit = 0;
- _intersectBySphere(aoIsect, aoRay, spheres[0]);
- _intersectBySphere(aoIsect, aoRay, spheres[1]);
- _intersectBySphere(aoIsect, aoRay, spheres[2]);
- _intersectByPlane (aoIsect, aoRay, plane);
- // when the second ray is intersected, increase the occlusion.
- if (aoIsect.hit) occlusion -= occlusionPerSample;
- }
- }
- // return result
- aoColor.x = occlusion;
- aoColor.y = occlusion;
- aoColor.z = occlusion;
- return aoColor;
- // cross product
- function vcross(c:Vector3D, v0:Vector3D, v1:Vector3D) : Vector3D {
- c.x = v0.y * v1.z - v0.z * v1.y;
- c.y = v0.z * v1.x - v0.x * v1.z;
- c.z = v0.x * v1.y - v0.y * v1.x;
- return c;
- }
- }
- // check ray intersection by sphere
- private function _intersectBySphere(isect:Isect, ray:Ray, sph:Sphere) : void {
- var rayOrg:Vector3D = ray.org;
- var rayDir:Vector3D = ray.dir;
- var sphCenter:Vector3D = sph.center;
- var rsx:Number = rayOrg.x - sphCenter.x,
- rsy:Number = rayOrg.y - sphCenter.y,
- rsz:Number = rayOrg.z - sphCenter.z,
- B:Number = rsx*rayDir.x + rsy*rayDir.y + rsz*rayDir.z,
- C:Number = rsx*rsx + rsy*rsy + rsz*rsz - sph.radius2,
- D:Number = B * B - C;
- // when the ray is intersected by the sphere,
- if (D > 0.0) {
- var t:Number = -B - Math.sqrt(D);
- if ((t > 0.0) && (t < isect.t)) {
- // calculate cross point and normal vector.
- isect.t = t;
- isect.hit = 1;
- isect.p.x = rayOrg.x + rayDir.x * t;
- isect.p.y = rayOrg.y + rayDir.y * t;
- isect.p.z = rayOrg.z + rayDir.z * t;
- isect.n.x = isect.p.x - sphCenter.x;
- isect.n.y = isect.p.y - sphCenter.y;
- isect.n.z = isect.p.z - sphCenter.z;
- isect.n.normalize();
- }
- }
- }
- // check ray intersection by plane
- private function _intersectByPlane(isect:Isect, ray:Ray, pln:Plane) : void {
- var v:Number = pln.n.x*ray.dir.x + pln.n.y*ray.dir.y + pln.n.z*ray.dir.z;
- // when parallel with plane
- if (v>-1.0e-17 && v<1.0e-17) return;
- var t:Number = -(pln.n.x*ray.org.x + pln.n.y*ray.org.y + pln.n.z*ray.org.z - pln.pn) / v;
- // when the ray is intersected by the plane,
- if ((t > 0.0) && (t < isect.t)) {
- // calculate cross point and normal vector.
- isect.t = t;
- isect.hit = 1;
- isect.p.x = ray.org.x + ray.dir.x * t;
- isect.p.y = ray.org.y + ray.dir.y * t;
- isect.p.z = ray.org.z + ray.dir.z * t;
- isect.n.x = pln.n.x;
- isect.n.y = pln.n.y;
- isect.n.z = pln.n.z;
- }
- }
- }
notice:





