simple environment mapping
+/-: zoom in/out
/**
* Copyright zob ( http://wonderfl.net/user/zob )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/wqTG
*/
package {
import flash.display.Sprite;
import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Shape;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Matrix3D;
import flash.geom.PerspectiveProjection;
import flash.geom.Point;
import flash.geom.Vector3D;
import flash.utils.*;
import flash.geom.Utils3D;
import flash.display.TriangleCulling;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import net.hires.debug.Stats;
import com.bit101.components.HSlider;
import flash.geom.Matrix;
import com.bit101.components.HUISlider;
public class tunnelV02 extends Sprite
{
// terrain
private var W :int = 20;//15;
private var H :int = 30;//30;
private var SW :Number = 500;
private var SH :Number = 600;
private var GW :Number = SW/W;
private var GH :Number = SH/H;
private var MW :Number = 40;
private var MH :Number = 60;
private var TW :Number = (MW)/W-1;
private var TH :Number = (MH)/H-1;
private var TERRIAN_MAP :BitmapData = new BitmapData(MW, MH, false);
private var MAP :BitmapData;
// 3D
private var viewport :Shape = new Shape();
private var world :Matrix3D = new Matrix3D();
private var projected :Vector.<Number> = new Vector.<Number>;
private var projection :PerspectiveProjection = new PerspectiveProjection();
private var TRANS :Matrix3D = new Matrix3D();
private var VERTS :Vector.<Number> = new Vector.<Number>;
private var INDICES :Vector.<int> = new Vector.<int>;
private var UVTS :Vector.<Number> = new Vector.<Number>;
private var NORMS :Vector.<Vector3D> = new Vector.<Vector3D>;
private var offset :Point = new Point();
private var loader :Loader;
private var GRAPHIC_URL :String = "http://assets.wonderfl.net/images/related_images/6/62/6212/6212aece9e0951f179ad346305a6e880f3dde0a6";//"light.jpg";
// interaction
private var matrix :Matrix3D = new Matrix3D();
private var dragging :Boolean = false;
private var drag_mode :Boolean = false;
private var old_mouse :Point = new Point();
private var new_mouse :Point = new Point();
private var trans :Matrix3D = new Matrix3D();
private var zoomer :Number = 750;
private var zoomVelocity :Number = 0;
private var zoomIn :Boolean = false;
private var zoomOut :Boolean = false;
// settings
private var baseX :Number = 5;
private var baseY :Number = 10;
private var Octaves :Number = 1;
private var speed :Number = 1;
private var baseXHSlider :HUISlider;
private var baseYHSlider :HUISlider;
private var octavesHSlider :HUISlider;
private var speedHSlider :HUISlider;
// normal
private var FACES :Vector.<Face3D> = new Vector.<Face3D>;
private var VERTICES :Vector.<Vertex3D> = new Vector.<Vertex3D>;
public function tunnelV02()
{
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, init);
loader.load(new URLRequest(GRAPHIC_URL), new LoaderContext(true));
}
private function init(e:Event):void
{
addChild(new Bitmap(new BitmapData(stage.stageWidth, stage.stageHeight, false, 0xCCCCCC)));
var mouse:MovieClip = new MovieClip();
mouse.addChild(new Bitmap(new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x0)));
viewport.x = stage.stageWidth / 2;
viewport.y = stage.stageHeight / 2;
addChild(viewport);
buildPath();
MAP = Bitmap(loader.content).bitmapData;
matrix.appendRotation(30, Vector3D.X_AXIS);
trans.appendRotation(55, Vector3D.X_AXIS);
trans.appendRotation(-35, Vector3D.Y_AXIS);
var panel:Sprite = new Sprite();
addChild(mouse);
addChild(panel);
addChild(new Stats());
baseXHSlider = new HUISlider(panel, 80, 10, "baseX", updateBaseX);
baseXHSlider.value = baseX;
baseYHSlider = new HUISlider(panel, 80, 25, "baseY", updateBaseY);
baseYHSlider.value = baseY;
octavesHSlider = new HUISlider(panel, 80, 40, "Octaves", updateOctaves);
octavesHSlider.value = (Octaves-1) * 10;
speedHSlider = new HUISlider(panel, 80, 55, "speed", updateSpeed);
speedHSlider.value = speed * 10;
mouse.addEventListener(MouseEvent.MOUSE_DOWN, onmouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onmouseUp);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onmouseMove);
stage.addEventListener(KeyboardEvent.KEY_DOWN, onkeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, onkeyUp);
stage.addEventListener(Event.ENTER_FRAME, processing);
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, init);
}
private function updateBaseX(...arg):void
{
baseX = baseXHSlider.value;
}
private function updateBaseY(...arg):void
{
baseY = baseYHSlider.value;
}
private function updateOctaves(...arg):void
{
Octaves = 1+(octavesHSlider.value/10)/10*9;
}
private function updateSpeed(...arg):void
{
speed = (speedHSlider.value/10);
}
private function buildPath():void
{
var w:int = 0;
var h:int = 0;
var xA :Number = 0;
var xB :Number = 0;
var yA :Number = 0;
var yB :Number = 0;
var zA :Number = 0;
var zB :Number = 0;
var index:int = 0;
var i0:int = 0;
var i1:int = 0;
var i2:int = 0;
var i3:int = 0;
var faceA:Face3D;
var faceB:Face3D;
for(h = 0; h < H+1; h++)
{
for(w = 0; w < W+1; w++)
{
VERTICES.push(new Vertex3D());
index = (W*h + w);
xA = -SW/2 + w*GW;
zB = -SH/2 + (h+1)*GH;
VERTICES[index].read(xA,yA,zB);
}
}
for(h = 0; h < H+1; h++)
{
for(w = 0; w < W+1; w++)
{
xA = -SW/2 + w*GW;
xB = -SW/2 + (w+1)*GW;
zA = -SH/2 + h*GH;
zB = -SH/2 + (h+1)*GH;
VERTS.push(
xA, yA, zB
);
index = (W*h + w);
i0 = (W*h + w);
i1 = (W*h + (w+1));
i2 = (W*(h+1) + w);
i3 = (W*(h+1) + (w+1));
VERTICES[index ].read(xA,yA,zB);
faceA = new Face3D();
faceA.vertex1 = VERTICES[i0];
faceA.vertex2 = VERTICES[i1];
faceA.vertex3 = VERTICES[i2];
VERTICES[i0].faces.push(faceA);
VERTICES[i1].faces.push(faceA);
VERTICES[i2].faces.push(faceA);
FACES.push(faceA);
faceB = new Face3D();
faceB.vertex1 = VERTICES[i1];
faceB.vertex2 = VERTICES[i3];
faceB.vertex3 = VERTICES[i2];
VERTICES[i1].faces.push(faceB);
VERTICES[i3].faces.push(faceB);
VERTICES[i2].faces.push(faceB);
FACES.push(faceB);
if(w+1 < W && h+1 < H)
{
INDICES.push(
i0, i1, i2, // 3
i1, i3, i2 // 6
);
}
UVTS.push(
((w)*TW)/MW, ((h)*TH)/MH, 0
);
NORMS.push(new Vector3D(), new Vector3D(), new Vector3D(), new Vector3D());
}
}
}
private function calcNORMS():void
{
var I:int = 0;
for(I = 0; I < FACES.length; I++)
{
FACES[I].calculateFaceNormal();
}
}
private function processing(e:Event):void
{
if(zoomIn) zoomVelocity+=2;
if(zoomOut) zoomVelocity-=2;
zoomVelocity *= 0.98;
zoomer += zoomVelocity;
TERRIAN_MAP.perlinNoise(baseX,baseY,Octaves,100, false, true, 8, true, [offset, offset]);
var I:int = 0;
var w:int = 0;
var h:int = 0;
var r:Number = 0;
var index:int = 0;
var i0:int = 0;
var i1:int = 0;
var i2:int = 0;
var i3:int = 0;
var VX:Number = 0;
var VY:Number = 0;
var VZ:Number = 0;
var VLEN:Number = 0;
for(h = 0; h < H; h++)
{
for(w = 0; w < W; w++)
{
index = (W*h + w);
r = TERRIAN_MAP.getPixel(w*TW, h*TH) & 0xFF;
VERTICES[index].y = -130 + 200 * (r/0xFF);
}
}
calcNORMS();
for(I = 0; I < VERTICES.length; I++)
{
VERTICES[I].calculateNorm();
VERTICES[I].norm = trans.transformVector(VERTICES[I].norm);
VERTS[I*3 ] = VERTICES[I].x;
VERTS[I*3+1] = VERTICES[I].y;
VERTS[I*3+2] = VERTICES[I].z;
UVTS[I*3 ] = 0.5+VERTICES[I].norm.x*0.5;
UVTS[I*3+1] = 0.5+VERTICES[I].norm.y*0.5;
UVTS[I*3+2] = 0.5+VERTICES[I].norm.z*0.5;
}
offset.y+=speed;
world.identity();
world.append(trans);
world.appendTranslation(0, 0, zoomer);
world.append(projection.toMatrix3D());
var _UVTS:Vector.<Number> = new Vector.<Number>;
matrix.transformVectors(UVTS,_UVTS);
Utils3D.projectVectors(world, VERTS, projected, _UVTS);
viewport.graphics.clear();
viewport.graphics.beginBitmapFill(MAP, null, false, false);
viewport.graphics.drawTriangles(projected, INDICES, _UVTS, TriangleCulling.NONE);
viewport.graphics.endFill();
}
private function onmouseDown(e:MouseEvent):void
{
old_mouse.x = mouseX;
old_mouse.y = mouseY;
dragging = true;
}
private function onmouseMove(e:MouseEvent):void
{
if(dragging)
{
new_mouse.x = mouseX
new_mouse.y = mouseY;
var difference:Point = new_mouse.subtract(old_mouse);
var vector:Vector3D = new Vector3D(difference.x, difference.y, 0);
var rotationAxis:Vector3D = vector.crossProduct(new Vector3D(0,0,1));
rotationAxis.normalize();
var distance:Number = Point.distance(new_mouse, old_mouse);
var rotationMatrix:Matrix3D = new Matrix3D();
rotationMatrix.appendRotation(distance, rotationAxis);
trans.append(rotationMatrix);
var I:int = 0;
var TV:Vector3D = new Vector3D();
old_mouse.x = new_mouse.x;
old_mouse.y = new_mouse.y;
}
}
private function onmouseUp(e:MouseEvent):void
{
dragging = false;
}
private function onkeyDown(e:KeyboardEvent):void
{
switch(e.keyCode)
{
case 107:
zoomIn = true;
break;
case 189:
zoomOut = true;
break;
}
}
private function onkeyUp(e:KeyboardEvent):void
{
switch(e.keyCode)
{
case 107:
zoomIn = false;
break;
case 189:
zoomOut = false;
break;
}
}
}
}
import flash.geom.Vector3D;
class Vertex3D extends Vector3D
{
public var norm:Vector3D = new Vector3D();
public var faces:Vector.<Face3D> = new Vector.<Face3D>;
public function Vertex3D(px:Number = 0, py:Number = 0, pz:Number = 0) {super(px,py,pz);}
public function copy(p:*):void {x=p.x;y=p.y;z=p.z;}
public function read(px:Number = 0, py:Number = 0, pz:Number = 0):void {x=px;y=py;z=pz;}
public function calculateNorm():void
{
var I:int = 0;
norm.x = x; norm.y = y; norm.z = z-10000;
norm.normalize();
for(I = 0; I < faces.length; I++)
{
norm.x += faces[I].norm.x;
norm.y += faces[I].norm.y;
norm.z += faces[I].norm.z;
}
norm.normalize();
}
}
class Face3D
{
public var vertex1:Vertex3D;
public var vertex2:Vertex3D;
public var vertex3:Vertex3D;
public var norm:Vector3D = new Vector3D();
public function Face3D() {}
public function calculateFaceNormal():void
{
var TV2:Vector3D = vertex2.subtract(vertex1);
var TV3:Vector3D = vertex3.subtract(vertex1);
norm = TV2.crossProduct(Vector3D(TV3));
norm.normalize();
}
}