3D line drawing with Papervision

| 4 min read

Back to the line drawing I started in this post.

I wanted to get a snake-like line and I had a try with Papervision3D. It made me able to handle the vertices and then delete the end of the lines.

Draw 1 (demo)

I started from an excellent work from Xero (the.fontvir.us) on the Papervision3D mailing list but instead of using a Lorenz attractor, I used the Tweener Bezier property as I did on the 2D versions.

I set a number of vertices, that is giving me the length of the line. Here is the code:

/*
* Lines3D1
*
* Copyright info: Free to use and change, an notification email will be welcome for a commercial use
* Actionscript: built for actionscript 3.0
* 05-2008
*
* @author Romuald Quantin - romu@soundstep.com - www.soundstep.com
* @version 1.0
* @usage
*
*/


package {

import org.papervision3d.core.geom.renderables.*;
import org.papervision3d.materials.special.*;
import org.papervision3d.core.geom.*;
import org.papervision3d.objects.*;
import org.papervision3d.cameras.*;
import caurina.transitions.Tweener;
import caurina.transitions.properties.CurveModifiers;
import flash.events.*;

public class Lines3D1 extends BaseP3D {

//------------------------------------
// private properties
//------------------------------------

private var sight:DisplayObject3D;
private var lineMaterial:LineMaterial;
private var arrLines:Array = [];
private var _objArray:Array = [];
private var _linesNum:int = 5;
private var _maxRadius:int = 200;
private var _pointNum:uint = 80;
private var _verticesNum:uint = 50;

//------------------------------------
// public properties
//------------------------------------

//------------------------------------
// constructor
//------------------------------------

public function Lines3D1() {
stage.frameRate = 81;
CurveModifiers.init();
super(600, 600);
b.addEventListener(MouseEvent.CLICK, reload);
addChild(b);
}

//
// PRIVATE, PROTECTED
//________________________________________________________________________________________________

override protected function init2D():void {
for (var u:int=0; u<_linesNum; u++) {
var obj:Object = {};
var newPos:Object = getRandomPos();
obj['prevX'] = obj['x'] = newPos['x'];
obj['prevY'] = obj['y'] = newPos['y'];
obj['prevZ'] = obj['z'] = newPos['z'];
obj['color'] = Math.random() * 0xFFFFFF;
_objArray.push(obj);
randomTween(getRandomData(obj));
}
}

override protected function init3D():void {
camera.zoom = 5;
camera.z = -200;
sight = new DisplayObject3D();
camera.target = sight;
lineMaterial = new LineMaterial(Math.random()* 0xFFFFFF);
for (var f:int=0; f<_linesNum; f++) {
var line:Lines3D = new Lines3D(lineMaterial, "line");
arrLines.push(line);
scene.addChild(line, "line");
}
}

override protected function processFrame():void {
for (var h:int=0; h<_linesNum; h++) {
arrLines[h].addLine(new Line3D(arrLines[h], new LineMaterial(_objArray[h]['color'], 1), 3, new Vertex3D(_objArray[h]['prevX'],_objArray[h]['prevY'],_objArray[h]['prevZ']), new Vertex3D(_objArray[h]['x'],_objArray[h]['y'],_objArray[h]['z'])));
_objArray[h]['prevX'] = _objArray[h]['x'];
_objArray[h]['prevY'] = _objArray[h]['y'];
_objArray[h]['prevZ'] = _objArray[h]['z'];
if (arrLines[h].lines.length > _verticesNum) arrLines[h].lines.shift();
camera.x += (((mouseX -(stage.stageWidth*.5))*3)-camera.x)*.01;
camera.y += (((mouseY-(stage.stageHeight*.5))*3)-camera.y)*.01;
}
}

private function randomTween(o:Object):void {
Tweener.addTween(o, {x:o['x1'], y:o['y1'], z:o['z1'], _bezier:o['bezier'], time:o['time'], transition:"linear", onComplete:
function():void {
randomTween(getRandomData(o));
}
});
}

private function getRandomData(o:Object):Object {
o['time'] = Math.random() * (_pointNum*.5) + (_pointNum*.25);
var newPos:Object = getRandomPos();
o['x1'] = newPos['x'];
o['y1'] = newPos['y'];
o['z1'] = newPos['z'];
o['bezier'] = [];
for (var i:int=0; i<_pointNum; i++) {
var newBezierPos:Object = getRandomPos();
o['bezier'].push({
x:newBezierPos['x'],
y:newBezierPos['y'],
z:newBezierPos['z']
});
}
return o;
}

private function getRandomPos():Object {
var angleY:Number = Math.random() * 2 * Math.PI;
var angleXZ:Number = Math.random() * 2 * Math.PI;
var o:Object = {};
o['x'] = Math.cos(angleY) * Math.sin(angleXZ) * _maxRadius;
o['y'] = Math.sin(angleY) * Math.sin(angleXZ) * _maxRadius;
o['z'] = Math.cos(angleXZ) * _maxRadius;
return o;
}

private function reload(e:MouseEvent = null):void {
Tweener.removeAllTweens();
for (var r:int=0; r<_linesNum; r++) {
scene.removeChild(arrLines[r]);
}
_objArray = [];
arrLines = [];
init3D();
init2D();
}

//
// PUBLIC
//________________________________________________________________________________________________

}

}

Draw 2 (demo)

And a bit of fun with the Bitmap layer, the ColorMatrixFilter and the BlurFilter.

/*
* Lines3D2
*
* Copyright info: Free to use and change, an notification email will be welcome for a commercial use
* Actionscript: built for actionscript 3.0
* 05-2008
*
* @author Romuald Quantin - romu@soundstep.com - www.soundstep.com
* @version 1.0
* @usage
*
*/


package {

import flash.geom.Point;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.filters.BlurFilter;
import flash.filters.ColorMatrixFilter;
import org.papervision3d.core.geom.renderables.*;
import org.papervision3d.materials.special.*;
import org.papervision3d.core.geom.*;
import org.papervision3d.objects.*;
import org.papervision3d.cameras.*;
import caurina.transitions.Tweener;
import caurina.transitions.properties.CurveModifiers;
import flash.events.*;

public class Lines3D2 extends BaseP3D {

//------------------------------------
// private properties
//------------------------------------

private var sight:DisplayObject3D;
private var lineMaterial:LineMaterial;
private var arrLines:Array = [];
private var _objArray:Array = [];
private var _linesNum:int = 5;
private var _maxRadius:int = 200;
private var _pointNum:uint = 80;
private var _verticesNum:uint = 30;
private var _cmf:ColorMatrixFilter;
private var _bf:BlurFilter;
private var _bmd:BitmapData;
private var _bm:Bitmap;

//------------------------------------
// public properties
//------------------------------------

//------------------------------------
// constructor
//------------------------------------

public function Lines3D2() {
stage.frameRate = 81;
CurveModifiers.init();
super(600, 600);
b.addEventListener(MouseEvent.CLICK, reload);
addChild(b);
}

//
// PRIVATE, PROTECTED
//________________________________________________________________________________________________

override protected function init2D():void {
_cmf = new ColorMatrixFilter([1.05,0,0,0,0,
0,1.05,0,0,0,
0,0,1.05,0,0,
0,0,0,.54,0]);
_bf = new BlurFilter(5, 5, 2);
createCanvas();
for (var u:int=0; u<_linesNum; u++) {
var obj:Object = {};
var newPos:Object = getRandomPos();
obj['prevX'] = obj['x'] = newPos['x'];
obj['prevY'] = obj['y'] = newPos['y'];
obj['prevZ'] = obj['z'] = newPos['z'];
obj['color'] = Math.random() * 0xFFFFFF;
_objArray.push(obj);
randomTween(getRandomData(obj));
}
}

override protected function init3D():void {
camera.zoom = 5;
camera.z = -200;
sight = new DisplayObject3D();
camera.target = sight;
lineMaterial = new LineMaterial(Math.random()* 0xFFFFFF);
for (var f:int=0; f<_linesNum; f++) {
var line:Lines3D = new Lines3D(lineMaterial, "line");
arrLines.push(line);
scene.addChild(line, "line");
}
}

private function createCanvas():void {
_bmd = new BitmapData(600, 600, true, 0x000000);
_bm = new Bitmap(_bmd);
addChild(_bm);
}

override protected function processFrame():void {
for (var h:int=0; h<_linesNum; h++) {
arrLines[h].addLine(new Line3D(arrLines[h], new LineMaterial(_objArray[h]['color'], 1), 3, new Vertex3D(_objArray[h]['prevX'],_objArray[h]['prevY'],_objArray[h]['prevZ']), new Vertex3D(_objArray[h]['x'],_objArray[h]['y'],_objArray[h]['z'])));
_objArray[h]['prevX'] = _objArray[h]['x'];
_objArray[h]['prevY'] = _objArray[h]['y'];
_objArray[h]['prevZ'] = _objArray[h]['z'];
if (arrLines[h].lines.length > _verticesNum) arrLines[h].lines.shift();
camera.x += (((mouseX -(stage.stageWidth*.5))*3)-camera.x)*.01;
camera.y += (((mouseY-(stage.stageHeight*.5))*3)-camera.y)*.01;
}
_bmd.applyFilter(_bmd, _bmd.rect, new Point(0, 0), _cmf);
_bmd.applyFilter(_bmd, _bmd.rect, new Point(0, 0), _bf);
_bmd.draw(this);
}

private function randomTween(o:Object):void {
Tweener.addTween(o, {x:o['x1'], y:o['y1'], z:o['z1'], _bezier:o['bezier'], time:o['time'], transition:"linear", onComplete:
function():void {
randomTween(getRandomData(o));
}
});
}

private function getRandomData(o:Object):Object {
o['time'] = Math.random() * (_pointNum*.5) + (_pointNum*.25);
var newPos:Object = getRandomPos();
o['x1'] = newPos['x'];
o['y1'] = newPos['y'];
o['z1'] = newPos['z'];
o['bezier'] = [];
for (var i:int=0; i<_pointNum; i++) {
var newBezierPos:Object = getRandomPos();
o['bezier'].push({
x:newBezierPos['x'],
y:newBezierPos['y'],
z:newBezierPos['z']
});
}
return o;
}

private function getRandomPos():Object {
var angleY:Number = Math.random() * 2 * Math.PI;
var angleXZ:Number = Math.random() * 2 * Math.PI;
var o:Object = {};
o['x'] = Math.cos(angleY) * Math.sin(angleXZ) * _maxRadius;
o['y'] = Math.sin(angleY) * Math.sin(angleXZ) * _maxRadius;
o['z'] = Math.cos(angleXZ) * _maxRadius;
return o;
}

private function reload(e:MouseEvent = null):void {
Tweener.removeAllTweens();
for (var r:int=0; r<_linesNum; r++) {
scene.removeChild(arrLines[r]);
}
removeChild(_bm);
_objArray = [];
arrLines = [];
init3D();
init2D();
}

//
// PUBLIC
//________________________________________________________________________________________________

}

}

Get a random point in a sphere

maxRadius = 200
angleY = Math.random() * 2 * Math.PI
angleXZ = Math.random() * 2 * Math.PI
x = Math.cos(angleY) * Math.sin(angleXZ) * maxRadius
y = Math.sin(angleY) * Math.sin(angleXZ) * maxRadius
z = Math.cos(angleXZ) * maxRadius`

Get the source here.