Intro
If you are tired of the boring 0’s and 1’s of boolean logic, trilogic is here – 0, 1, and 2. In the 70’s we were sure that by combining enough NOR and NAND gates eventually our cyber machines would achieve consciousness. The problem was that our yes-no machines could not say (think) maybe – it was 0 or 1. But with trilogic you get a third parameter which allows for energy transfer/activation – or a maybe state.
- zero – no
- one – maybe
- two – yes
The Particle Billboarding code uses trilogic to decide when an animation transfers its moving particles. It’s the simplest example I’ve ever seen of trilogic and could act as a stepping stone for understanding this new approach to computing.
The simulation starts with a random distribution and changes to a sphere, disc, torus, ellipsoid, and then loops back to the sphere. But as you roll over the different particles they are energized into orbit. Transferring this energy to the next object uses trilogic. This is the maybe part, dealing with energy distributions is a “maybe term” depending on activation levels. Yes – think of it as a neural net!
The code is simple enough,
if( makingTransition==0){
makingTransition=1;
for(var i:int=0; i<particles.length; i++){
//p.extra["spin"] = 0;
var myX:Number=p.param*Math.cos(p.theta*Math.PI/180);
var myY:Number=p.param*Math.sin(p.theta*Math.PI/180);
var myZ:Number=0;
Tweener.addTween(p, {x:myX, y:myY, z:myZ, time:.5, transition:”easeInOutExpo”, onComplete:setTransNum});
}}
if(makingTransition==2){
p.x=p.param*Math.cos(p.theta*Math.PI/180);
p.y=p.param*Math.sin(p.theta*Math.PI/180);
p.z=0;}
From the code if
makingTransition==0: Stops particle energy friction of present object
makingTransition==1: Transfers particle energy to next object
makingTransition==2: Starts particle energy friction of next object
Check out the code, demo, and development video below.
Web Stuff
Demo: http://www.professionalpapervision.com/demos/web/billboarding/
Download (choose billboarding): http://code.google.com/p/flex3cookbook1/downloads/list
YouTube Video: How it was created.
More Stuff
The code is explained in detail in the book, but I am including it here. It’s not documented, but I will take care of that before the book is released. Click more below to see the entire code (or just download the source from the link provided above).
There are two parts to the code:
- The main code which contains the trilogic and particle orbital equations
- This DIsplayObject3D Modifications required to make the physical dynamics work
Main Code
package
{
import org.papervision3d.view.BasicView;
import flash.display.*;
import flash.events.*;
import org.papervision3d.events.InteractiveScene3DEvent;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.core.geom.Particles;
import org.papervision3d.core.geom.renderables.Particle;
import org.papervision3d.materials.special.MovieAssetParticleMaterial;
import org.papervision3d.scenes.*;
import caurina.transitions.*;
/**
* @author Seb Lee-Delisle
Modified by Lively
*/
public class MainBillBoard extends BasicView
{
public var particleContainer:DisplayObject3D;
private var particles : Array;
private var radius:Number=600;
private var smallRadius:Number=200;
private var switchConst:uint;
public var myFormIs:String;
public var makingTransition:uint=0;
public function MainBillBoard()
{
super(stage.stageWidth, stage.stageHeight, false, true);
init();
}
private function init():void
{
particleContainer = new DisplayObject3D();
particles = new Array();
for(var i:int = 0; i<400; i++)
{
var spm:MovieAssetParticleMaterial = new MovieAssetParticleMaterial(“mySphere”,true);
spm.interactive = true;
spm.smooth = true;
var particles3D:Particles = new Particles(“ParticleContainer”+i);
var p:Particle = new Particle(spm,1,0,0,0);
particles3D.addParticle(p);
particles3D.addEventListener(InteractiveScene3DEvent.OBJECT_OVER, particleOver);
Tweener.addTween(particles3D, {x:Math.random() * 3000 – 1500, y:Math.random() * 3000 – 1500, z:Math.random() * 3000 – 1500, time:6, transition:”easeInOutExpo”});
particles3D.extra = {spin: 0};
particleContainer.addChild(particles3D);
particles.push(particles3D);
}
scene.addChild(particleContainer);
//singleRender();
camera.zoom=3;
Tweener.addTween(this, {delay:6, onComplete:form1});
addEventListener(Event.ENTER_FRAME, frameLoop);
}
private function form1():void{
for(var i:int=0; i<particles.length; i++)
{
var p:Particles = particles[i];
p.param=(1-2*Math.random())*radius;
p.theta=Math.random()*360;
var myX:Number=Math.sqrt(radius*radius-p.param*p.param)*Math.cos(p.theta*Math.PI/180);
var myY:Number=Math.sqrt(radius*radius-p.param*p.param)*Math.sin(p.theta*Math.PI/180);
var myZ:Number=p.param;
Tweener.addTween(p, {x:myX, y:myY, z:myZ, time:1, transition:”easeInOutExpo”});
}// end while
myFormIs=”myForm1″;
makingTransition=0;
Tweener.addTween(this, {delay:15, onComplete:form2});
}
private function form2():void{
trace(“made it to form 2″);
for(var i:int=0; i<particles.length; i++)
{
var p:Particles = particles[i];
p.param=Math.random()*radius/2+100;
p.theta=Math.random()*360;
var myX:Number=p.param*Math.cos(p.theta*Math.PI/180);
var myY:Number=p.param*Math.sin(p.theta*Math.PI/180);
var myZ:Number=0;
Tweener.addTween(p, {x:myX, y:myY, z:myZ, time:1, transition:”easeInOutExpo”});
}// end while
Tweener.addTween(this, {delay:15, onComplete:form3});
myFormIs=”myForm2″;
makingTransition=0;
}
private function form3():void{
for(var i:int=0; i<particles.length; i++)
{
var p:Particles = particles[i];
p.theta=Math.random()*360;
p.phi = Math.random()*360;
var myX:Number=(radius+smallRadius*Math.cos(p.phi*Math.PI/180))*Math.cos(p.theta*Math.PI/180);
var myY:Number=(radius+smallRadius*Math.cos(p.phi*Math.PI/180))*Math.sin(p.theta*Math.PI/180);
var myZ:Number=smallRadius*Math.sin(p.phi*Math.PI/180);
Tweener.addTween(p, {x:myX, y:myY, z:myZ, time:1, transition:”easeInOutExpo”});
}// end while
Tweener.addTween(this, {delay:20, onComplete:form4});
myFormIs=”myForm3″;
makingTransition=0;
}
private function form4():void{
for(var i:int=0; i<particles.length; i++)
{
var p:Particles = particles[i];
p.theta=Math.random()*360;
p.phi = Math.random()*180;
var myX:Number= radius*Math.cos(p.theta*Math.PI/180)*Math.sin(p.phi*Math.PI/180);
var myY:Number= 2*smallRadius*Math.sin(p.theta*Math.PI/180)*Math.sin(p.phi*Math.PI/180);
var myZ:Number= smallRadius*Math.cos(p.phi*Math.PI/180);
Tweener.addTween(p, {x:myX, y:myY, z:myZ, time:1, transition:”easeInOutExpo”});
}// end while
myFormIs=”myForm4″;
makingTransition=0;
Tweener.addTween(this, {delay:20, onComplete:form1});
}
private function particleOver(e : InteractiveScene3DEvent) : void
{
e.displayObject3D.extra["spin"] = 10;
}
private function setTransNum():void{
makingTransition=2;
}
private function frameLoop(e:Event): void
{
particleContainer.rotationY+=((stage.stageWidth/2)-mouseX)/100;
particleContainer.rotationX+=((stage.stageHeight/2)-mouseY)/100;
var drag:Number = 0.99;
for(var i:int=0; i<particles.length; i++)
{
var p:Particles = particles[i];
var spin:Number = p.extra["spin"];
if(spin>0.1)
{
p.extra["spin"]*=drag;
p.theta+=spin;
switch(myFormIs)
{
case “myForm1″:
{
if( makingTransition==0){
makingTransition=1;
for(var i:int=0; i<particles.length; i++){
//p.extra["spin"] = 0;
var myX:Number=Math.sqrt(radius*radius-p.param*p.param)*Math.cos(p.theta*Math.PI/180);
var myY:Number=Math.sqrt(radius*radius-p.param*p.param)*Math.sin(p.theta*Math.PI/180);
var myZ:Number=p.param;
Tweener.addTween(p, {x:myX, y:myY, z:myZ, time:.5, transition:”easeInOutExpo”, onComplete:setTransNum});
}}
if(makingTransition==2){
p.x=Math.sqrt(radius*radius-p.param*p.param)*Math.cos(p.theta*Math.PI/180);
p.y=Math.sqrt(radius*radius-p.param*p.param)*Math.sin(p.theta*Math.PI/180);
p.z=p.param;
}
break;
}// end case
case “myForm2″:
{
if( makingTransition==0){
makingTransition=1;
for(var i:int=0; i<particles.length; i++){
//p.extra["spin"] = 0;
var myX:Number=p.param*Math.cos(p.theta*Math.PI/180);
var myY:Number=p.param*Math.sin(p.theta*Math.PI/180);
var myZ:Number=0;
Tweener.addTween(p, {x:myX, y:myY, z:myZ, time:.5, transition:”easeInOutExpo”, onComplete:setTransNum});
}}
if(makingTransition==2){
p.x=p.param*Math.cos(p.theta*Math.PI/180);
p.y=p.param*Math.sin(p.theta*Math.PI/180);
p.z=0;
}
break;
}// end case
case “myForm3″:
{
if( makingTransition==0){
makingTransition=1;
for(var i:int=0; i<particles.length; i++){
//p.extra["spin"] = 0;
var myX:Number=(radius+smallRadius*Math.cos(p.theta*Math.PI/180))*Math.cos(p.theta*Math.PI/180);
var myY:Number=(radius+smallRadius*Math.cos(p.theta*Math.PI/180))*Math.sin(p.theta*Math.PI/180);
var myZ:Number=smallRadius*Math.sin(p.phi*Math.PI/180);
Tweener.addTween(p, {x:myX, y:myY, z:myZ, time:.5, transition:”easeInOutExpo”, onComplete:setTransNum});
}}
if(makingTransition==2){
p.x =(radius+smallRadius*Math.cos(p.theta*Math.PI/180))*Math.cos(p.theta*Math.PI/180);
p.y =(radius+smallRadius*Math.cos(p.theta*Math.PI/180))*Math.sin(p.theta*Math.PI/180);
p.z =smallRadius*Math.sin(p.phi*Math.PI/180);
}
break;
}// end case
case “myForm4″:
{
if( makingTransition==0){
makingTransition=1;
for(var i:int=0; i<particles.length; i++){
//p.extra["spin"] = 0;
var myX:Number=radius*Math.cos(p.theta*Math.PI/180)*Math.sin(p.theta*Math.PI/360);
var myY:Number= 2*smallRadius*Math.sin(p.theta*Math.PI/180)*Math.sin(p.theta*Math.PI/360);
var myZ:Number=smallRadius*Math.cos(p.theta*Math.PI/360);
Tweener.addTween(p, {x:myX, y:myY, z:myZ, time:.5, transition:”easeInOutExpo”, onComplete:setTransNum});
}}
if(makingTransition==2){
p.x = radius*Math.cos(p.theta*Math.PI/180)*Math.sin(p.theta*Math.PI/360);
p.y = 2*smallRadius*Math.sin(p.theta*Math.PI/180)*Math.sin(p.theta*Math.PI/360);
p.z = smallRadius*Math.cos(p.theta*Math.PI/360);
}
break;
}// end case
default:
{
break;
}
}
}
else
{
p.extra["spin"] = 0;
}
}
singleRender();
}
}
}
DisplayObject3D Changes
//Display Object Parameters
private var _theta :Number;
private var _phi :Number;
private var _param :Number;
//Get and Set Methods
//theta
public function get theta():Number
{
return this._theta;
}
public function set theta( value:Number ):void
{
this._theta = value;
}
//phi
public function get phi():Number
{
return this._phi;
}
public function set phi( value:Number ):void
{
this._phi = value;
}
//param
public function get param():Number
{
return this._param;
}
public function set param( value:Number ):void
{
this._param = value;
}

November 21, 2008 at 8:42 am |
[...] opposed to using billboarding, this program illustrates real 3D orbiting particles. The particles shown below are recycled after [...]
March 3, 2009 at 1:48 pm |
[...] Example 1 low number physics http://professionalpapervision.wordpress.com/2008/11/21/real-orbiting-3d-particles-taking-out-the-trash/ Example 2 high number – billboarding physics http://professionalpapervision.wordpress.com/2008/11/02/trilogic-particle-billboarding-flash-source/ [...]