PV3D Bezier Ribbons
PV3D Bezier Ribbons
* @author Marco Di Giuseppe
* @see http://designmarco.com
* @since 5/6/09
/**
* Copyright marco ( http://wonderfl.net/user/marco )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/cfep
*/
/**
* PV3D Bezier Ribbons
* @author Marco Di Giuseppe
* @see http://designmarco.com
* @since 5/6/09
*/
package
{
import flash.events.Event;
import flash.events.MouseEvent;
import org.papervision3d.view.BasicView;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.objects.DisplayObject3D;
import net.hires.debug.Stats;
[SWF(width="465", height="465", backgroundColor="0x000000", frameRate="60")]
public class BezierRibbons extends BasicView
{
private static const NUM_RIBBONS:int = 3;
private var mouseDown:Boolean;
private var ribbons:Array;
private var ribbonColors:Array;
private var xpos:Number;
private var ypos:Number;
private var ribbon:Ribbon;
public var holder:DisplayObject3D;
public function BezierRibbons()
{
super(465, 465);
init();
}
private function init():void
{
camera.focus = 11;
camera.zoom = 100;
holder = new DisplayObject3D();
scene.addChild(holder);
ribbonColors = [0xFF0000, 0xFFFFFF, 0x33CCFF];
ribbons = [];
var i:int = NUM_RIBBONS;
while( --i > -1 )
{
ribbon = new Ribbon(this, ribbonColors[i]);
ribbons[ribbons.length] = ribbon;
}
stage.addEventListener(Event.ENTER_FRAME, render, false, 0, true);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseHandler, false, 0, true);
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseHandler, false, 0, true);
addChild(new Stats());
}
private function render(event:Event):void
{
xpos = ((stage.mouseX - stage.stageWidth * 0.5) / stage.stageWidth) * 180;
ypos = ((stage.mouseY - stage.stageHeight * 0.5) / stage.stageHeight) * 180;
if (mouseDown)
{
holder.rotationY += (xpos - holder.rotationY) * 0.2;
holder.rotationX += (ypos - holder.rotationX) * 0.2;
holder.rotationZ += (ypos - holder.rotationZ) * 0.2;
}
else holder.roll(0.1);
singleRender();
}
private function mouseHandler(event:MouseEvent):void
{
mouseDown = !mouseDown;
}
public function reset():void
{
var i:int = NUM_RIBBONS;
while( --i > -1 )
{
ribbons[i].remove();
}
init();
}
}
}
import flash.utils.Timer;
import flash.events.TimerEvent;
import org.papervision3d.core.geom.renderables.Vertex3D;
import org.papervision3d.objects.DisplayObject3D;
class Ribbon extends DisplayObject3D
{
private static const RIBBON_LENGTH:Number = 300;
private static const RIBBON_WIDTH:Number = 3;
private static const CURVE_QUALITY:int = 50;
private static const NUM_CURVES:int = 5;
private var ribbon:BezierRibbons;
private var stepId:int;
private var curves:Array;
private var points:Array;
private var color:uint;
private var cLen:int;
private var curve:Curve;
public function Ribbon(ribbon:BezierRibbons, color:uint)
{
this.ribbon = ribbon;
this.color = color;
this.ribbon.holder.addChild(this);
curves = [];
points = [];
points[points.length] = new Vertex3D();
points[points.length] = new Vertex3D();
points[points.length] = new Vertex3D();
var timer:Timer = new Timer(10);
timer.addEventListener(TimerEvent.TIMER, onRender, false, 0, true);
timer.start();
addCurve();
}
public function onRender(event:TimerEvent):void
{
cLen = curves.length;
curves[cLen - 1].addLine();
if (cLen > NUM_CURVES - 1) curves[0].removeLine();
if (stepId++ > CURVE_QUALITY) addCurve();
}
private function addCurve():void
{
addNextPoint();
var pLen:int = points.length;
var nextPt:Vertex3D = points[pLen - 1];
var curPt:Vertex3D = points[pLen - 2];
var lastPt:Vertex3D = points[pLen - 3];
var xx:Number = (curPt.x + lastPt.x) * 0.5;
var yy:Number = (curPt.y + lastPt.y) * 0.5;
var zz:Number = (curPt.z + lastPt.z) * 0.5;
var mx:Number = (curPt.x + nextPt.x) * 0.5;
var my:Number = (curPt.y + nextPt.y) * 0.5;
var mz:Number = (curPt.z + nextPt.z) * 0.5;
var lastMidPt:Vertex3D = new Vertex3D(xx, yy, zz);
var midPt:Vertex3D = new Vertex3D(mx, my, mz);
curve = new Curve(lastMidPt, midPt, curPt, color, RIBBON_WIDTH, CURVE_QUALITY);
curves[curves.length] = curve;
addChild(curve);
var oldCurve:Curve;
var cLen:int = curves.length;
if (cLen > NUM_CURVES)
{
oldCurve = curves.shift();
removeChild(oldCurve);
oldCurve.remove();
points.shift();
}
stepId = 0;
}
private function addNextPoint():void
{
var xdelta:Number = randomInRange(0, RIBBON_LENGTH);
if (Math.random() < 0.5) xdelta = -xdelta;
var ydelta:Number = randomInRange(0, RIBBON_LENGTH);
if (Math.random() < 0.5) ydelta = -ydelta;
var zdelta:Number = randomInRange(0, RIBBON_LENGTH);
if (Math.random() < 0.5) zdelta = -zdelta;
var nextPt:Vertex3D = new Vertex3D(xdelta, ydelta, zdelta);
points[points.length] = nextPt;
}
public function float(min:Number, max:Number = NaN):Number
{
if (isNaN(max))
{
max = min;
min = 0;
}
return Math.random() * (max - min) + min;
}
public function randomInRange(min:Number, max:Number):int
{
return int((max - min) * float(2) + min);
}
public function remove():void
{
var i:int = curves.length;
while( --i > -1 )
{
curves[i].remove();
}
delete(this);
}
}
import org.papervision3d.core.geom.TriangleMesh3D;
import org.papervision3d.core.geom.renderables.Triangle3D;
import org.papervision3d.core.geom.renderables.Vertex3D;
import org.papervision3d.core.math.NumberUV;
import org.papervision3d.materials.ColorMaterial;
class Curve extends TriangleMesh3D
{
private var stepId:int;
private var width:Number;
private var quality:int;
private var startPt:Vertex3D;
private var endPt:Vertex3D;
private var controlPt:Vertex3D;
public function Curve( startPt:Vertex3D, endPt:Vertex3D, controlPt:Vertex3D, color:uint, width:Number, quality:int)
{
this.startPt = startPt;
this.endPt = endPt;
this.controlPt = controlPt;
this.width = width;
this.quality = quality;
var cm:ColorMaterial = new ColorMaterial(color);
cm.doubleSided = cm.tiled = cm.smooth = true;
super(cm, [], [], null);
}
public function addLine():void
{
var t:Number = stepId / quality;
var p0:Vertex3D = getOffsetPoint(t, 0);
var p3:Vertex3D = getOffsetPoint(t, width);
stepId++;
t = stepId / quality;
var p1:Vertex3D = getOffsetPoint(t, 0);
var p2:Vertex3D = getOffsetPoint(t, width);
addLineToMesh(p0, p1, p2, p3);
}
public function addLineToMesh(aV:Vertex3D, bV:Vertex3D, cV:Vertex3D, dV:Vertex3D):void
{
var vertices:Array = this.geometry.vertices;
var faces:Array = this.geometry.faces;
vertices[vertices.length] = aV;
vertices[vertices.length] = bV;
vertices[vertices.length] = cV;
vertices[vertices.length] = dV;
var uvA:NumberUV = new NumberUV(0, 0);
faces[faces.length] = new Triangle3D(this, [aV, bV, cV], null, [uvA, uvA, uvA]);
faces[faces.length] = new Triangle3D(this, [aV, cV, dV], null, [uvA, uvA, uvA]);
}
public function removeLine():void
{
this.geometry.vertices.shift();
this.geometry.vertices.shift();
this.geometry.vertices.shift();
this.geometry.vertices.shift();
this.geometry.faces.shift();
this.geometry.faces.shift();
}
private function getOffsetPoint( t:Number, k:Number ):Vertex3D
{
var p0:Vertex3D = startPt;
var p1:Vertex3D = controlPt;
var p2:Vertex3D = endPt;
var xt:Number = ( 1 - t ) * ( 1 - t ) * p0.x + 2 * t * ( 1 - t ) * p1.x + t * t * p2.x;
var yt:Number = ( 1 - t ) * ( 1 - t ) * p0.y + 2 * t * ( 1 - t ) * p1.y + t * t * p2.y;
var zt:Number = ( 1 - t ) * ( 1 - t ) * p0.z + 2 * t * ( 1 - t ) * p1.z + t * t * p2.z;
var xd:Number = t * (p0.x - 2 * p1.x + p2.x) - p0.x + p1.x;
var yd:Number = t * (p0.y - 2 * p1.y + p2.y) - p0.y + p1.y;
var zd:Number = t * (p0.z - 2 * p1.z + p2.z) - p0.z + p1.z;
var dd:Number = Math.pow(xd * xd + yd * yd + zd * zd, .33);
return new Vertex3D(xt + ( k * yd ) / dd, yt - ( k * xd ) / dd, zt - ( k * xd ) / dd);
}
public function remove():void
{
delete(this);
}
}