TriLogic Particle Billboarding (Flash Source)

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.

Trilogic used to transfer animation to different states.

Trilogic used to transfer animation to different states.

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:

  1. The main code which contains the trilogic and particle orbital equations
  2. 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;
}


2 Responses to TriLogic Particle Billboarding (Flash Source)

  1. […] opposed to using billboarding, this program illustrates real 3D orbiting particles. The particles shown below are recycled after […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: