/**
* Copyright makc3d ( http://wonderfl.net/user/makc3d )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/ffFX
*/
// forked from makc3d's Metaballs 3D
package com.specail {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Vector3D;
import flash.media.SoundMixer;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.utils.ByteArray;
import flash.utils.getTimer;
[SWF(width=465,height=465)]
/**
* Ok, looks like I don't have right idea to improve this,
* so maybe someone of you, oh wonderfl people, will..?
*
* P.S. click anywhere for next track.
*/
public class MetaBalls3D extends Sprite {
private var texture:BitmapData;
private var sphere:BauerSphere;
private var metaballs:MetaBalls;
private var canvas:Shape;
private var waves:Wave2;
private var player:BeatPortPlayer;
public function MetaBalls3D () {
BeatPortPlayer (player = new BeatPortPlayer).play ();
waves = new Wave2;
waves.w1 = new Wave;
waves.w2 = new Wave;
graphics.beginFill (0);
graphics.drawRect (0, 0, 465, 465);
addChild (canvas = new Shape);
canvas.x = 465 / 2;
canvas.y = 465 / 2;
texture = new BitmapData (67, 68, false, 0);
var loader:Loader = new Loader;
loader.contentLoaderInfo.addEventListener (Event.COMPLETE, gotImage);
loader.load (
new URLRequest ("images/ball.jpg")
//new LoaderContext (true)
);
sphere = new BauerSphere;
sphere.debug = false;
sphere.build (2000);
metaballs = new MetaBalls;
metaballs.a = 0;
addEventListener (Event.ENTER_FRAME, draw);
stage.addEventListener (MouseEvent.CLICK, nextTrack);
}
private function nextTrack (e:MouseEvent):void {
player.next ();
}
private function gotImage (e:Event):void {
texture.draw (LoaderInfo (e.target).content);
//----Ray--
addChild(LoaderInfo (e.target).content);
var $txt:TextField = new TextField();
$txt.defaultTextFormat = new TextFormat("微軟正黑體", 13, 0XFFFFFF);
$txt.text = "只有使用這1張圖,ps.帶耳機才知道水球會隨著音頻變化";
$txt.width = 400;
$txt.y = 70;
addChild($txt);
}
private var m:Matrix4 = new Matrix4;
private var s:Number = 0;
private var ba:ByteArray = new ByteArray;
private function draw (e:Event):void {
// animate waves
waves.w1.P = 5e-3 * getTimer ();
waves.w2.P = waves.w1.P;
// update wave amplitudes based on sound
var aLt:Number = 0, aLt2:Number = 0;
var aRt:Number = 0, aRt2:Number = 0;
if (!SoundMixer.areSoundsInaccessible ()) {
var i:int;
SoundMixer.computeSpectrum (ba, true);
// left
ba.position = 0;
for (i = 0; i < 64; i++) { aLt += ba.readFloat (); } for (i = 64; i < 128; i++) { aLt2 += ba.readFloat (); } aLt /= 100; aLt2 /= 100; // right ba.position = 4 * 256; for (i = 0; i < 64; i++) { aRt += ba.readFloat (); } for (i = 64; i < 128; i++) { aRt2 += ba.readFloat (); } aRt /= 100; aRt2 /= 100; waves.w1.A = maxOrMix (waves.w1.A, 0.1 * aLt); waves.w1.A2 = maxOrMix (waves.w1.A2, 10 * aLt2); waves.w2.A = maxOrMix (waves.w2.A, 0.1 * aRt); waves.w2.A2 = maxOrMix (waves.w2.A2, 10 * aRt2); } // swing balls metaballs.a = 1 + Math.sin (2.1e-3 * getTimer ()); // rotate scene m.rotate (3.3e-4 * getTimer ()); var ranges:Vector.
if (ranges.length > 1) {
// render sphere twice
if (m.Zz < 0) { morphSphere (ranges [0], waves.w1); sphere.transformVertices (m); sphere.render (canvas.graphics, texture); morphSphere (ranges [1], waves.w2); sphere.transformVertices (m); sphere.render (canvas.graphics, texture, false); } else { morphSphere (ranges [1], waves.w2); sphere.transformVertices (m); sphere.render (canvas.graphics, texture); morphSphere (ranges [0], waves.w1); sphere.transformVertices (m); sphere.render (canvas.graphics, texture, false); } } else { // render sphere once morphSphere (ranges [0], waves); sphere.transformVertices (m); sphere.render (canvas.graphics, texture); } } private function maxOrMix (a0:Number, a1:Number):Number { if (a0 < a1) return a1; return 0.9 * a0 + 0.1 * a1; } private var p:Point = new Point, q:Vector3D = new Vector3D; private function morphSphere (range:Range, wave:Wave):void { var aa:Number = (metaballs.a - 4 / 3) / 0.3; var cc:Number = 1.6 / (1 + aa * aa) - 0.8; // 0 to 0.8 to 0 when aa is -1 to 0 to +1 sphere.resetVertices (); var i:int, L:int = sphere.tvertices.length; for (i = 0; i < L; i++) { var v:Vector3D = sphere.tvertices [i]; p.x = v.x; p.y = v.y; var vz:Number = v.z; if (cc > 0) {
// to get better triangulation near a = 4/3 map z to 0.2*z*z + 0.8*z
if (vz < 0) { vz = (1 - cc) * vz - cc * vz * vz; } else { vz = (1 - cc) * vz + cc * vz * vz; } } var t:Number = 0.5 + 0.5 * vz; // shape as metaball v.z = range.x (t); p.normalize (metaballs.y (v.z)); v.x = p.x; v.y = p.y; // metaball normal p.normalize (1); q.x = p.x; q.y = p.y; q.z = -metaballs.y1 (); q.normalize (); // apply wave modifier q.scaleBy (wave.f (t)); v.incrementBy (q); } } } } class Wave { public var A:Number = 0, A2:Number = 0; public var P:Number = 0; public function f (t:Number):Number { var X:Number = 2 * t - 1; var Y:Number = ((X < 1) && (X > -1)) ? 0.5 + 0.5 * X * X : ((X > 0) ? X : -X);
var S:Number = Math.sin (10 * Y - P) / Y;
var C:Number = Math.cos (10000 * X);
return A * S * S * (1 + A2 * C * C);
}
}
class Wave2 extends Wave {
public var w1:Wave;
public var w2:Wave;
override public function f (t:Number):Number {
if (t < 0.5) return w1.f (2 * t); return w2.f (2 * t - 1); } } import flash.display.BitmapData; import flash.display.Graphics; import flash.display.TriangleCulling; import flash.geom.Vector3D; class Matrix4 { public var Xx:Number = 1, Yx:Number = 0, Zx:Number = 0, Tx:Number = 0; public var Xy:Number = 0, Yy:Number = 1, Zy:Number = 0, Ty:Number = 0; public var Xz:Number = 0, Yz:Number = 0, Zz:Number = 1, Tz:Number = 5; public function rotate (a:Number):void { Xx = Math.cos (a); Xz = Math.sin (a); Zx = -Math.sin (a); Zz = Math.cos (a); } } class BauerSphere { public var debug:Boolean; // original public var overtices:Vector.
// transformed
public var tvertices:Vector.
// face normals
public var faceNormals:Vector.
// face map
public var faceMap:Vector.
// faces
public var faceList1:Vector.
public var faceList2:Vector.
public var xy:Vector.
public var uv:Vector.
public function addFace (a:int, b:int, c:int):void {
var L:int = faceNormals.length;
faceMap [a].push (L);
faceMap [b].push (L);
faceMap [c].push (L);
faceNormals.push (new Vector3D);
faceList1.push (a, b, c);
faceList2.unshift (c, a, b);
}
public function build (N:int = 456):void {
overtices = new Vector.
tvertices = new Vector.
faceNormals = new
faceMap = new
faceList1 = new
faceList2 = new
xy = new Vector.
uv = new Vector.
// uniformly distributed directions:
// Bauer, Robert, "Distribution of Points on a Sphere with Application to Star Catalogs",
// Journal of Guidance, Control, and Dynamics, January-February 2000, vol.23 no.1 (130-137).
var radius:Number = 1;
for (var i:int = 1; i <= N; i++) { var phi:Number = Math.acos ( -1 + (2 * i -1) / N); var theta:Number = Math.sqrt (N * Math.PI) * phi; var rxy:Number = radius * Math.sin (phi); overtices [i - 1] = new Vector3D ( -rxy * Math.sin (theta), rxy * Math.cos (theta), radius * Math.cos (phi) ); tvertices [i - 1] = overtices [i - 1].clone (); faceMap [i - 1] = new
}
// make faces (and edges), 1st and last by hand
addFace (0, 1, 2);
var lastEdgeA:int = 0;
var lastEdgeB:int = 2;
while ((lastEdgeB < N - 1) (lastEdgeA < N - 3)) { var vA:Vector3D = tvertices [lastEdgeA]; var vB:Vector3D = tvertices [lastEdgeB]; var vA1:Vector3D = tvertices [lastEdgeA + 1]; var vB1:Vector3D; if (lastEdgeB < N - 1) vB1 = tvertices [lastEdgeB + 1]; var canIncA:Boolean = (lastEdgeA < lastEdgeB - 2) && (lastEdgeA < N - 3) && // only if B-A-A1 angle < 90° (vB.subtract (vA).dotProduct (vA1.subtract (vA)) > 0);
var canIncB:Boolean = (vB1 != null) &&
(lastEdgeB < N - 1) && // only if B1-B-A angle < 90° (vB1.subtract (vB).dotProduct (vA.subtract (vB)) > 0);
if (!(canIncA canIncB)) break;
if ( canIncA && canIncB ) {
// prefer shortest edge
canIncA = (
vB1.subtract (vA).lengthSquared > vA1.subtract (vB).lengthSquared
);
}
if (canIncA) {
// add face A-B-A1
addFace (lastEdgeA, lastEdgeB, lastEdgeA + 1);
// inc A
lastEdgeA++;
} else {
// add face A-B-B1
addFace (lastEdgeA, lastEdgeB, lastEdgeB + 1);
// inc B
lastEdgeB++;
}
}
// last face
addFace (N - 1, N - 2, N - 3);
if (debug) trace ("Sphere stats:", tvertices.length, "vertices,", faceNormals.length, "faces");
}
public function resetVertices ():void {
var N:int = overtices.length;
for (var i:int = 0; i < N; i++) { var t:Vector3D = tvertices [i]; var o:Vector3D = overtices [i]; t.x = o.x; t.y = o.y; t.z = o.z; } } public function transformVertices (m:Matrix4):void { var N:int = overtices.length; for (var i:int = 0; i < N; i++) { var t:Vector3D = tvertices [i]; var x:Number = t.x; var y:Number = t.y; var z:Number = t.z; t.x = m.Xx * x + m.Yx * y + m.Zx * z + m.Tx; t.y = m.Xy * x + m.Yy * y + m.Zy * z + m.Ty; t.z = m.Xz * x + m.Yz * y + m.Zz * z + m.Tz; } // update face normals N = faceNormals.length; for (i = 0; i < N; i++) { var i3:int = i * 3; var a:Vector3D = tvertices [faceList1 [i3]]; var b:Vector3D = tvertices [faceList1 [i3 + 1]]; var c:Vector3D = tvertices [faceList1 [i3 + 2]]; var x1:Number = b.x - a.x, y1:Number = b.y - a.y, z1:Number = b.z - a.z; var x2:Number = c.x - a.x, y2:Number = c.y - a.y, z2:Number = c.z - a.z; t = faceNormals [i]; t.x = y1 * z2 - y2 * z1; t.y = z1 * x2 - z2 * x1; t.z = x1 * y2 - x2 * y1; } } public var normal:Vector3D = new Vector3D; public function render (gfx:Graphics, bd:BitmapData, clear:Boolean = true):void { var focalLength:Number = 400; var N:int = tvertices.length; for (var i:int = 0; i < N; i++) { var j:int = 2 * i; var t:Vector3D = tvertices [i]; // project var zoom:Number = focalLength / t.z; xy [j] = t.x * zoom; xy [j + 1] = t.y * zoom; // estimate vertex normals normal.scaleBy (0); var map:Vector.
var mapL:int = map.length;
for (var k:int = 0; k < mapL; k++) { normal.incrementBy (faceNormals [map [k]]); } normal.normalize (); // env. mapping uv [j] = 0.5 + 0.5 * normal.x; uv [j + 1] = 0.5 + 0.5 * normal.y; } if (clear) gfx.clear (); if (debug) gfx.lineStyle (0, 0xFF0000); gfx.beginBitmapFill (bd, null, true, true); gfx.drawTriangles (xy, // half-assed distance sorting (tvertices[1].z > tvertices[tvertices.length - 2].z) ? faceList1 : faceList2,
uv, TriangleCulling.POSITIVE);
}
}
class Range {
public var a:Number;
public var b:Number;
public function Range (from:Number = 0, to:Number = 0) {
a = from; b = to;
}
public function x (t:Number):Number {
return a + (b - a) * t;
}
}
/**
* Metaballs calculator.
* @see http://wonderfl.net/c/1TYy/read
*/
class MetaBalls {
private var a1:Number, a2:Number, b2:Number;
private var d1:Number, d2:Number;
public function get a ():Number {
return a1;
}
public function set a (A:Number):void {
a1 = A;
a2 = A * A;
b2 = 1 + (A + a2) / 4; b2 *= b2;
d1 = 3 * a2 - A - 4;
d2 = 5 * a2 + A + 4;
}
private var x1:Number, x2:Number;
private var s1:Number, s2:Number;
public function y (x:Number):Number {
x1 = x;
x2 = x * x;
s1 = Math.sqrt (Math.max (0, 4 * a2 * x2 + b2));
s2 = Math.sqrt (Math.max (0, s1 - a2 - x2));
return s2;
}
/** 1st derivative, dy/dx. y(x) is expected to be called 1st. */
public function y1 ():Number {
return (2 * a2 * x1 / s1 - x1) / s2;
}
private var r1:Vector.
private var r2:Vector.
public function ranges ():Vector.
var S2:Number = 0.5 * Math.sqrt (d2);
if (d1 > 0) {
var S1:Number = 0.5 * Math.sqrt (d1);
r2 [0].a = -S2; r2 [0].b = -S1;
r2 [1].a = S1; r2 [1].b = S2;
return r2;
}
r1 [0].a = -S2; r1 [0].b = S2;
return r1;
}
}
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundLoaderContext;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
class BeatPortPlayer {
private var gid:int;
private var count:int, sound:Sound, channel:SoundChannel;
public function next ():void {
}
/**
* Plays random samples by genre non-stop.
* @see http://api.beatport.com/catalog/genres?format=xml&v=1.0
*/
public function play ():void {
var $urlreqest:URLRequest = new URLRequest("music/jSix.mp3");
sound = new Sound($urlreqest);
sound.play();
}
}

沒有留言:
張貼留言
我的留言版