There’s been some great experimentation with 3d lines and ribbons in Papervision3D, notably Felix Turner’s Ribbon3D and of course the Audi A5 website.
A project I’m currently working on requires the drawing of ribbons in 3D space, and it’s such a simple yet beautiful effect that I thought it was time to have a quick go at it myself.
Looking at some of the available source code though, I felt that there was a slight lack of simplicity, but more importantly a clear API. This no doubt is due to the fact that the aforementioned experiments were just that, experiments, and therefore not built with usability in mind. None-the-less, I wanted a Ribbon3D class which shared a similar looking constructor to that of the native Papervision classes, and which could easily be used in projects and manipulated in the same intuitive manner as the other 3D objects in the Papervision library.
There are some unused methods which I have kept in the source code, as they can create some great effects with pseudo depth of field and colour, but were somewhat processor intensive for the sake of the demo.
As I mentioned, the API is simple and I hope makes sense. The constructor looks like that of any other DisplayObject3D; you pass in a material of your choice, the width of the ribbon and the length (how many segments can be added before the oldest is removed)
var ribbon:Ribbon3D = new Ribbon3D( material, width, length );
scene.addChild( ribbon );
One point of contention was how to make the ribbon grow. I wanted to be able to draw the ribbons using tweens, and so using a method such as addSegment or growTo seemed unnecessarily cumbersome as it would involve using a callback whenever the tween progresses. So too did using alternative members, such as tx, ty, tz etc, as again this would diverge from the standard DisplayObject3D API.
I eventually decided to override the getters and setters for the x, y and z properties, meaning that you can tween an instance of the Ribbon3D class as you would any other DisplayObject3D (including bezier tweens as in the example above) and it will grow to follow the tween. I was hesitant to implement this, as it means that moving or shifting the ribbon as a whole cannot be done in the normal way, however I concluded that the normal use of such a class would be to create trails or patterns, and so moving the whole ribbon around would rarely be required. That said, I have included a moveTo(x,y,z) method if this needs to be done.
So making an instance of Ribbon3D grow is as simple as:
TweenEngine.tween( ribbon, 2, { x:100, y:100, z:100, bezierThrough:yourBezier } );
Because the x, y and z properties can be set separately, you have to call the draw method manually, from within the Timer or EnterFrame event you are using to render your Papervision viewport, for example:
private function render3D ( e:Event ):void
{
// Tell the Ribbon3D to update it's mesh
ribbon.draw();
// Render the Papervision scene
renderer.renderScene ( scene, camera, viewport );
}
I have also left the material property open, so instead of passing in a colour and therefore having to use a ColorMaterial, you can use any of the wonderful Papervision materials, such as the FlatShadeMaterial, which I’ve used in the demo to give the ribbons a bit of extra depth.
I’m looking forward to playing with physics and collision detection in Papervision, as a swarm of boids with ribbon trails that don’t intersect (you can see the clipping sometimes in the demo) would be good to see. I’m slowly building a library of 2D steering behaviours so when and if I get round to learning the math required to port them to 3D I’ll have a stab at it and post the results.
Download: Ribbon3D Class Download: Ribbon3D DemoNote: I have included the build of Papervision3D GreatWhite (rev 682-14.2.08) that I used, as the SVN repository is being updated frequently and may temporarily have adverse effects on the demo. Not included in the zip is the tweening engine I used, TweenMax, which you can read about and download here.

Hey Justin,
First of all, thanks and congrats for all this great stuff!
I’ve decided to take sometime to play around with your Ribbon class, which is really nice, and I’m trying to make it work on a transparent background, but I can’t figure out why it just doesn’t work properly if I comment the background.draw() code piece and take the layer out. Could you give me a clue please? I’ve uploaded my testing file to http://www.izaias.com/download/Ribbon3dDemo.zip. It’s not that clean but it’s hopefully understandable.
Much appreciated.
Hey Justin, nevermind. I’ve got it.
I am working on a version of your script that allow the ribbons to follow a defined path, and to do so I need to understand your code. There is a thing that I cannot understand in this code, starting at line 174 in Ribbon3dDemo.as
[code]
for (var i:int = 0; i < d * .6 << 0; i++)
b.push( {
x:random( -UNIVERSE, UNIVERSE ),
y:random( -UNIVERSE, UNIVERSE ),
z:random( -UNIVERSE, UNIVERSE )
} );
[/code]
I have some truble trying to understand that bitwise shift operator, since I know that the second parameter of that operator state the number of position of the shift, but you use 0, so I cannot understand. Perhaps it is something related to the 0-based system, so that is a 1 position shifting?
Anyway thank you for sharing!
Hi Zeta.
The 0 bitwise shift simple floors the number, so it is the same as Math.floor() but faster to compute. You could also cast the number to an integer, which is also fast:
However looking at this code now, it is foolish to evaluate this expression at every iteration, so perhaps you should use:
what have i forgot? i import the classes, then this is my code:
var material:FlatShadeMaterial = new FlatShadeMaterial( light, 0x98014E, 0×333333);
material.doubleSided = true;
var light:PointLight3D = new PointLight3D();
scene.addChild( light );
var ribbon:Ribbon3D = new Ribbon3D( pretoMaterial, 500, 100 );
container.addChild( ribbon );
ribbon.draw();
scene.addChild(container);
then i render this, but nothing happens.
what i forgot to do?
Are you remembering to call
before every render cycle?
I really like the colours you have used with your 3d ribbons