forked from: BumpMap
this is part of larger experiment... don't ask.
package
{
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import sandy.core.*;
import sandy.core.data.*;
import sandy.core.scenegraph.*;
import sandy.primitive.*;
import sandy.materials.*;
import sandy.view.*;
// this is part of larger experiment... don't ask.
[SWF (width=465, height=465, backgroundColor=0, frameRate=20)]
public class Test extends BasicView
{
private const S:int = 150;
private const Q:int = 10;
private const Y:Number = 30;
private var angle:Number = 0;
private var texture:BitmapData;
private var lmap:BitmapData, nmap:BitmapData, tmap:BitmapData;
private var blur:BlurFilter = new BlurFilter (4, 4, 4);
public function Test()
{
super (); init (465, 465); render ();
// planes suck - use hexagonal grid instead
var p:Plane3D = addHorizontalPlane (S, S, Q,
new Point3D (0, -0.6 * S, 0));
texture = new BitmapData (S, S, false, 0);
p.appearance = makeBitmapAppearance (texture);
// build random terrain
// this is not really smooth terrain, but whatever
var r:Number = 0;
for each (var v:Vertex in p.geometry.aVertex) {
r = 0.5 * (r + Math.random ()); v.y = Y * r;
}
// update face normals
for each (var face:Polygon in p.aPolygons) face.updateNormal ();
// render terrain heightmap
renderHeightMap (p, graphics, S);
// render normal map
// this is not really normal map, but something close
var xmap:BitmapData = new BitmapData (S, S, false, 0);
xmap.draw (this); xmap.applyFilter (xmap, xmap.rect, xmap.rect.topLeft,
new ConvolutionFilter (3, 3, [0, 0, 0, -1, 0, +1, 0, 0, 0], 1, 128));
var ymap:BitmapData = new BitmapData (S, S, false, 0);
ymap.draw (this); ymap.applyFilter (ymap, ymap.rect, ymap.rect.topLeft,
new ConvolutionFilter (3, 3, [0, -1, 0, 0, 0, 0, 0, +1, 0], 1, 128));
nmap = new BitmapData (S, S, false, 0);
nmap.copyChannel (xmap, xmap.rect, nmap.rect.topLeft,
BitmapDataChannel.RED, BitmapDataChannel.RED); // r<-x
nmap.copyChannel (ymap, ymap.rect, nmap.rect.topLeft,
BitmapDataChannel.GREEN, BitmapDataChannel.GREEN); // g<-y
var zmap:BitmapData = new BitmapData (S, S, false, 0);
zmap.draw (nmap, null, new ColorTransform ( -1, -1, 1, 1, 255, 255));
zmap.draw (nmap, null, null, BlendMode.LIGHTEN); // r<-abs(x), g<-abs(y)
zmap.applyFilter (zmap, zmap.rect, zmap.rect.topLeft, new ColorMatrixFilter (
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.5, -0.5, 0, 0, 3*128-1, 0, 0, 0, 1, 0]));
nmap.copyChannel (zmap, zmap.rect, nmap.rect.topLeft,
BitmapDataChannel.BLUE, BitmapDataChannel.BLUE); // b<-z
var b:Bitmap = new Bitmap (nmap); b.x = S; addChild (b);
// noisy texture
tmap = new BitmapData (S, S, false, 0);
tmap.noise (123, 200, 255, 7, true);
tmap.draw (tmap, null, new ColorTransform (1, 0xEF / 255.0, 0x7F / 255.0));
// make light map
lmap = new BitmapData (S, S, false, 0);
b = new Bitmap (lmap); b.x = 2 * S; addChild (b);
// "sun"
graphics.beginFill (0xFFEF7F); graphics.drawCircle (465 * 0.5, 465 * 0.5, 10);
}
override public function simpleRender(e:Event = null):void {
// spin light (map coords)
angle = mouseX / 100;
var light:Point3D = new Point3D (Math.sin (angle), Math.cos (angle), 0.25); light.normalize ();
// face light (real coords)
camera.x = +2 * S * light.x;
camera.y = +2 * S * light.z;
camera.z = -2 * S * light.y;
camera.lookAt (0, 0, 0);
// http://wonderfl.kayac.com/code/4e95875560faedfc67621c179095d5c73ce2a594
lmap.applyFilter(nmap, nmap.rect, nmap.rect.topLeft, new ColorMatrixFilter([
2 * light.x, 2 * light.y, 2 * light.z, 0, (light.x + light.y + light.z) * -0xFF,
2 * light.x, 2 * light.y, 2 * light.z, 0, (light.x + light.y + light.z) * -0xFF,
2 * light.x, 2 * light.y, 2 * light.z, 0, (light.x + light.y + light.z) * -0xFF,
0, 0, 0, 1, 0
]));
lmap.applyFilter (lmap, lmap.rect, lmap.rect.topLeft, blur);
texture.draw (tmap); texture.draw (lmap, null, null, BlendMode.MULTIPLY);
super.simpleRender (e);
}
private function renderHeightMap (p:Plane3D, g:Graphics, s:int):void {
for each (var t:Polygon in p.aPolygons)
renderHeightMapElement (t, g, s);
}
private var m1:Matrix = new Matrix;
private var m2:Matrix = new Matrix;
private function renderHeightMapElement (t:Polygon, g:Graphics, s:int):void {
var h0:Number = t.a.y / Y;
var h1:Number = t.b.y / Y;
var h2:Number = t.c.y / Y;
var v0:Number = -100, v1:Number = 0, v2:Number = 100;
var u0:Number = (h0 - 0.5) * (32768 * 0.05);
var u1:Number = (h1 - 0.5) * (32768 * 0.05);
var u2:Number = (h2 - 0.5) * (32768 * 0.05);
var uv:UVCoord = UVCoord (t.aUVCoord [0]); m2.tx = uv.u * s; m2.ty = uv.v * s;
if ( (int (u0 * 0.1) == int (u1 * 0.1)) && (int (u1 * 0.1) == int (u2 * 0.1)) ) {
// solid color case
g.beginFill ( 0x10101 * Math.round (0xFF * h0) );
} else {
// gradient case
if ((u2 - u1) * (u1 - u0) > 0) {
var tmp:Number = v1; v1 = v2; v2 = tmp;
}
m1.a = u1 - u0; m1.b = v1 - v0;
m1.c = u2 - u0; m1.d = v2 - v0;
m1.tx = u0; m1.ty = v0;
m1.invert ();
uv = UVCoord (t.aUVCoord [1]);
m2.a = uv.u * s - m2.tx; m2.b = uv.v * s - m2.ty;
uv = UVCoord (t.aUVCoord [2]);
m2.c = uv.u * s - m2.tx; m2.d = uv.v * s - m2.ty;
m1.concat (m2);
g.beginGradientFill ("linear", [0, 0xFFFFFF], [1, 1], [0, 255], m1);
}
g.moveTo (m2.tx, m2.ty); for each (uv in t.aUVCoord) g.lineTo (uv.u * s, uv.v * s);
g.endFill ();
}
}
}