3D Gasket 3
w/s: move front/ back
a/d: move right/ left
space/shift: move up/down
e/q: up/down light level
arrows: rotate
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;
import flash.events.Event;
import flash.events.KeyboardEvent;
[SWF(width="512",height="512",backgroundColor="0x000000",frameRate="60")]
public class Gasket4D extends Sprite
{
private static const SIZE:Number = 512;
private static const ZERO:Vector3D = new Vector3D(0, 0, 0);
private static const CAMERA_SPEED:Number = SIZE / 128;
private static const LIGHT_SPEED:Number = SIZE / 64;
private static const ROTATION_SPEED:Number = 2;
private static const DOTS_PER_FRAME:Number = 32768;
private var canvas:BitmapData;
private var bitmap:Bitmap;
private var points:Vector.<Vector3D>;
private var buffer:Vector.<uint>;
private var camera:Vector3D;
private var viewAngle:Number;
private var cameraV:Vector3D;
private var light:Number;
private var lightV:Number;
private var rotationMatrix:Matrix3D;
private var rotationV:Vector3D;
private var keyBuffer:Array;
public function Gasket4D()
{
graphics.beginFill(0x000000);
graphics.drawRect(0, 0, SIZE, SIZE);
graphics.endFill();
canvas = new BitmapData(SIZE, SIZE, false, 0);
bitmap = new Bitmap(canvas);
addChild(bitmap);
points=new Vector.<Vector3D>();
points.push(new Vector3D( SIZE / 4, -SIZE / 4, SIZE / 4));
points.push(new Vector3D(-SIZE / 4, -SIZE / 4, -SIZE / 4));
points.push(new Vector3D( SIZE / 4, SIZE / 4, -SIZE / 4));
points.push(new Vector3D(-SIZE / 4, SIZE / 4, SIZE / 4));
buffer = new Vector.<uint>(SIZE * SIZE, true);
camera = new Vector3D(0, 0, SIZE / 2);
viewAngle = Math.PI / 3;
cameraV = new Vector3D(0, 0, 0);
light = 256;
lightV = 0;
rotationMatrix = new Matrix3D();
rotationV = new Vector3D(0, 0, 0);
keyBuffer = [];
addEventListener(Event.ENTER_FRAME,onEnterFrame);
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
}
private function onEnterFrame(e:Event):void
{
var numPoints:int = points.length;
// move camera
cameraV.x = (keyBuffer[68] ? CAMERA_SPEED : 0) - (keyBuffer[65] ? CAMERA_SPEED : 0);
cameraV.y = (keyBuffer[16] ? CAMERA_SPEED : 0) - (keyBuffer[32] ? CAMERA_SPEED : 0);
cameraV.z = (keyBuffer[83] ? CAMERA_SPEED : 0) - (keyBuffer[87] ? CAMERA_SPEED : 0);
camera = camera.add(cameraV);
// change light level
lightV = (keyBuffer[69] ? LIGHT_SPEED : 0) - (keyBuffer[81] ? LIGHT_SPEED : 0);
light += lightV;
if(light < 0)
{
light = 0;
}
// rotate
rotationV.x = (keyBuffer[40] ? ROTATION_SPEED : 0) - (keyBuffer[38] ? ROTATION_SPEED : 0);
rotationV.y = (keyBuffer[37] ? ROTATION_SPEED : 0) - (keyBuffer[39] ? ROTATION_SPEED : 0);
if(!rotationV.equals(ZERO))
{
rotationMatrix.identity();
rotationMatrix.appendRotation(rotationV.x, Vector3D.X_AXIS);
rotationMatrix.appendRotation(rotationV.y, Vector3D.Y_AXIS);
for(var j:int = 0; j < numPoints; j++)
{
points[j] = rotationMatrix.transformVector(points[j]);
}
}
// if moved, clear buffer
if(!cameraV.equals(ZERO) || lightV != 0 || !rotationV.equals(ZERO))
{
buffer = new Vector.<uint>(SIZE * SIZE, true);
}
// draw dots
var dot:Vector3D = new Vector3D(0, 0, 0);
var screen:Number = Math.tan(Math.PI / 2 - viewAngle / 2) * SIZE / 2;
for(var i:int = 0; i < DOTS_PER_FRAME; i++)
{
// move to the midpoint of the dot and a point chosen at random from four
var r:int = Math.floor(Math.random() * numPoints);
var point:Vector3D = points[r];
dot.x = (dot.x + point.x) / 2;
dot.y = (dot.y + point.y) / 2;
dot.z = (dot.z + point.z) / 2;
// projection
if(dot.z < camera.z)
{
var cz:Number = screen / (camera.z - dot.z);
var x2D:int = SIZE / 2 + Math.round((dot.x - camera.x) * cz);
var y2D:int = SIZE / 2 + Math.round((dot.y - camera.y) * cz);
if(x2D >= 0 && x2D < SIZE && y2D >= 0 && y2D < SIZE)
{
// calculate light level
var b:Number = Math.min(255, light * SIZE * SIZE
/ (4 * Math.PI * (Math.pow(camera.x - dot.x, 2) + Math.pow(camera.y - dot.y, 2) + Math.pow(camera.z - dot.z, 2))));
// z-buffer-like
if((buffer[x2D + y2D * SIZE] & 0xff) < b)
{
buffer[x2D + y2D * SIZE] = (b << 16) | (b << 8) | (b << 0);
}
}
}
}
// set buffer to canvas
canvas.setVector(canvas.rect, buffer);
}
private function onKeyDown(e:KeyboardEvent):void
{
keyBuffer[e.keyCode] = true;
}
private function onKeyUp(e:KeyboardEvent):void
{
keyBuffer[e.keyCode] = false;
}
}
}