Adding Simple Blender Models to CS4

Intro

One of my colleagues, Barbara Kaskosz just released a series of CS4 examples which I have been modifying to accept xml and blender models. Her examples can be found at

http://www.flashandmath.com/

Barbara is a gifted coder, great person, and real honor to know – adding to her work is a head-rush for me! Click on the image below to run the CS4 Blender example.

Extending Barbara's Simple 3D Draw

Extending Barbara's Simple 3D Draw

Above is an example of a Blender model created in my Blender XML exporter brought into Barbara’s 3D Draw program.

Web Stuff

Demo

Download Source Code

Discussion

Here are the steps I followed to enhance Barbara’s Simple 3D draw to accept Blender objects (this example does not included textured models I will be releasing that in an upcoming post).

  • I downloaded her code example Simple 3D Dynamic Drawing in Flash CS4 (use her Icosahedron example) and removed all the comments. The comments were great but they got in the way when I started to recode the example.
  • I then converted her timeline ActionScript code into a class package and ran it in Flex as an ActionScript Package. I’ve included that package in my download files.
  • Then I created a (non-textured) model in Blender and exported it using my XML Blender Exporter. I then placed that XML model file in Flex. (To learn how to model in Blender just click on my 3D modeling link in this blog. There are tons of getting started in Blender tutorials.)
  • Then I add the AS3 code needed to import the Blender XML model into Barbara’s Simple 3D program .

var externalXML:XML;
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest(“testShip2.xml”);
loader.load(request);
loader.addEventListener(Event.COMPLETE, onComplete);

function onComplete(event:Event):void
{
var loader:URLLoader = event.target as URLLoader;
if (loader != null)
{
externalXML = new XML(loader.data);
setVertices(externalXML);
}else{

trace(“loader is not a URLLoader!”);

}
}

  • I then combined her setVertices() and setFaces() functions and placed an externalXML argument in the new combined setVertices(myData_xml:XML) function to bring in the XML data. I then split the CVS XML data into arrays and loaded the vertices and face indices XML data into Barbara’s vertsVec[i] and faceVec[i] vector arrays. In addition a scale factor was added to scale the Blender model.

private function setVertices(myData_xml:XML):void {
var mySlitVert:Array=
myData_xml.myPrimSet[0].myVertices.split(“,”);
var mySlitFace:Array=
myData_xml.myPrimSet[0].myFaces.split(“,”);

numVertices=(mySlitVert.length-1)/3;
var myScale:Number=40;
var i:int;
for(i=0;i<=numVertices;i++){
vertsVec[i]= new Vector3D(mySlitVert[i*3]*myScale,mySlitVert[i*3+1]*myScale,
mySlitVert[i*3+2]*myScale); }

numFaces = (mySlitFace.length-1)/3;
var j:int;
for(j=0;j<=numFaces;j++){
facesVec[j]=
[mySlitFace[j*3],mySlitFace[j*3+1],mySlitFace[j*3+2]];
facesColors[j]=Math.random()*0xffffff;
}
}

  • Finally, I added a color vector array and randomly populated it . The colors were then applied to the Blender model faces. Everything else was the same as Barbara’s code.

facesColors[j]=Math.random()*0xffffff;

Click the more button below to see the entire code and the Icosahedron class package.

Source Code

package {
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.*;
import flash.geom.*;

import flash.net.*;

public class Test4 extends Sprite
{

private var numVertices:int;
private var numFaces:int;

private var vertsVec:Vector.<Vector3D>=new Vector.<Vector3D>();
private var facesVec:Vector.<Array>=new Vector.<Array>();
private var facesColors:Vector.<Number>= new Vector.<Number>();

private var fLen:Number=500;

private var spBoard:Sprite=new Sprite();
private var shBack:Shape=new Shape();
private var spObject:Sprite=new Sprite();
private var spObjImage:Sprite=new Sprite();
private var doRotate:Boolean=false;
private var prevX:Number;
private var prevY:Number;

//The ‘velocity’ variables are related to auto rotation.

private var velX:Number=1;
private var velY:Number=2;
private var velMag:Number=5;

public var myFileGet:String;
public var xmlReq:URLRequest;
public var xmlLoader:URLLoader;
public var myData_xml:XML;

public var iFacNum:Number;
public function Test4()
{

this.addChild(spBoard);

spBoard.x=180;spBoard.y=205;

spBoard.filters=[ new DropShadowFilter() ];

spBoard.addChild(shBack);

spBoard.addChild(spObjImage);

spObject.rotationX=0;

spObject.rotationY=0;

spObject.rotationZ=0;

drawBack();

var externalXML:XML;
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest(“testShip2.xml”);

loader.load(request);
loader.addEventListener(Event.COMPLETE, onComplete);

function onComplete(event:Event):void
{
var loader:URLLoader = event.target as URLLoader;
if (loader != null)
{
externalXML = new XML(loader.data);

//setVertsVec(externalXML);

setVertices(externalXML);

}
else
{
trace(“loader is not a URLLoader!”);

}}
rotateObj(0,0,0);
addList();
}

private function drawBack():void {
shBack.graphics.beginFill(0×000000);
shBack.graphics.drawRect(-160,-160,320,320);
shBack.graphics.endFill();

}
private function setVertices(myData_xml:XML):void {

var mySlitVert:Array=myData_xml.myPrimSet[0].myVertices.split(“,”);
var mySlitFace:Array=myData_xml.myPrimSet[0].myFaces.split(“,”);
numVertices=(mySlitVert.length-1)/3;
var myScale:Number=40;

var i:int;
for(i=0;i<=numVertices;i++){
vertsVec[i]= new Vector3D(mySlitVert[i*3]*myScale,mySlitVert[i*3+1]*myScale,mySlitVert[i*3+2]*myScale);
}

numFaces = (mySlitFace.length-1)/3;

var j:int;
for(j=0;j<=numFaces;j++){
facesVec[j]=[mySlitFace[j*3],mySlitFace[j*3+1],mySlitFace[j*3+2]];
facesColors[j]=Math.random()*0xffffff;

}}

//There are no changes in rotateObj function.

private function rotateObj(rotx:Number,roty:Number,rotz:Number):void {

var i:int;
var j:int;
var distArray:Array=[];
var dispVec:Vector.<Point>=new Vector.<Point>();
var newVertsVec:Vector.<Vector3D>=new Vector.<Vector3D>();
var zAverage:Number;

var dist:Number;
var curFace:int;
var curFaceLen:int;
var curObjMat:Matrix3D;
spObject.transform.matrix3D.appendRotation(rotx,Vector3D.X_AXIS);
spObject.transform.matrix3D.appendRotation(roty,Vector3D.Y_AXIS);
spObject.transform.matrix3D.appendRotation(rotz,Vector3D.Z_AXIS);
curObjMat=spObject.transform.matrix3D.clone();
spObjImage.graphics.clear();
for(i=0;i<numVertices;i++){
newVertsVec[i]=curObjMat.deltaTransformVector(vertsVec[i]);

}

for(i=0;i<numVertices;i++){
newVertsVec[i].w=(fLen+newVertsVec[i].z)/fLen;
newVertsVec[i].project();
}

for(i=0;i<numFaces;i++){
curFaceLen=facesVec[i].length;
zAverage=0;
for(j=0;j<curFaceLen;j++){
zAverage+=newVertsVec[facesVec[i][j]].z;
}

zAverage/=curFaceLen;
dist=zAverage;
distArray[i]=[dist,i];
}

distArray.sort(byDist);
for(i=0;i<numVertices;i++){
dispVec[i]=new Point();
dispVec[i].x=newVertsVec[i].x;
dispVec[i].y=newVertsVec[i].y;
}

for(i=0;i<numFaces;i++){
spObjImage.graphics.lineStyle(1,0xCC0000);
curFace=distArray[i][1];
curFaceLen=facesVec[curFace].length;
spObjImage.graphics.beginFill(facesColors[curFace],0.7);
spObjImage.graphics.moveTo(dispVec[facesVec[curFace][0]].x,dispVec[facesVec[curFace][0]].y);
for(j=1;j<curFaceLen;j++){
spObjImage.graphics.lineTo(dispVec[facesVec[curFace][j]].x,dispVec[facesVec[curFace][j]].y);
}
spObjImage.graphics.lineTo(dispVec[facesVec[curFace][0]].x,dispVec[facesVec[curFace][0]].y);
spObjImage.graphics.endFill();
}}

private function byDist(v:Array,w:Array):Number {
if (v[0]>w[0]){
return -1;
} else if (v[0]<w[0]){
return 1;
} else {
return 0;
}

}

private function addList():void{
spBoard.addEventListener(MouseEvent.ROLL_OUT,boardOut);
spBoard.addEventListener(MouseEvent.MOUSE_MOVE,boardMove);
spBoard.addEventListener(MouseEvent.MOUSE_DOWN,boardDown);
spBoard.addEventListener(MouseEvent.MOUSE_UP,boardUp);
this.addEventListener(Event.ENTER_FRAME,whenEnterFrame);
}

private function boardOut(e:MouseEvent):void {
doRotate=false;
}

private function boardDown(e:MouseEvent):void {
prevX=spBoard.mouseX;
prevY=spBoard.mouseY;
velX=0;
velY=0;
velMag=0;
doRotate=true;
}

private function boardUp(e:MouseEvent):void {
doRotate=false;
}

private function boardMove(e:MouseEvent):void {
var locX:Number=prevX;
var locY:Number=prevY;

if(doRotate){
prevX=spBoard.mouseX;
prevY=spBoard.mouseY;
velX=-2*(prevX-locX);
velY=2*(prevY-locY);
velMag=Math.abs(velX)+Math.abs(velY);
rotateObj(prevY-locY,-(prevX-locX),0);

e.updateAfterEvent();}}

private function whenEnterFrame(e:Event):void {
if(!doRotate && velMag>0){
rotateObj(velY,velX,0);
}}
}
}

Barbara’s Icosahedron Converted to a Class Package

package {

import flash.display.Sprite;
import flash.display.Shape;
import flash.events.MouseEvent;
import flash.geom.*;
import flash.events.Event;
import flash.filters.*;

public class Test extends Sprite
{

private var numVertices:int=12;

private var numFaces:int=20;

private var objRad:Number=100;

private var vertsVec:Vector.<Vector3D>=new Vector.<Vector3D>();

private var facesVec:Vector.<Array>=new Vector.<Array>();

private var fLen:Number=500;

private var spBoard:Sprite=new Sprite();

private var shBack:Shape=new Shape();

private var spObject:Sprite=new Sprite();

private var spObjImage:Sprite=new Sprite();

private var doRotate:Boolean=false;

private var prevX:Number;

private var prevY:Number;

//The ‘velocity’ variables are related to auto rotation.

private var velX:Number=1;

private var velY:Number=2;

private var velMag:Number=5;

private var facesColors:Array=[0xFF1200,0xFF4200,0xFF7900,0xFFAA00,0xFFC800,0xFFFF00,0xC3FF00,0x9BFF00,0x50FF00,0x00FF00,0x00FFA5,0x00FFD9,0x00EDFF,0x00B7FF,0x0070FF,0x002FFF,0x1E00FF,0x5500FF,0x8B00FF,0xDA00FF];

public function Test()
{

this.addChild(spBoard);

spBoard.x=180;

spBoard.y=205;

spBoard.filters=[ new DropShadowFilter() ];

spBoard.addChild(shBack);

spBoard.addChild(spObjImage);

spObject.rotationX=0;

spObject.rotationY=0;

spObject.rotationZ=0;

drawBack();

setVertices();

setFaces();

rotateObj(0,0,0);

addList();
}

private function drawBack():void {

shBack.graphics.beginFill(0×000000);

shBack.graphics.drawRect(-160,-160,320,320);

shBack.graphics.endFill();

}
private function setVertices():void {

vertsVec[0]=new Vector3D(0,0,objRad);

vertsVec[1]=new Vector3D(0.894*objRad,0,0.447*objRad);

vertsVec[2]=new Vector3D(0.276*objRad,0.851*objRad,0.447*objRad);

vertsVec[3]=new Vector3D(-0.724*objRad,0.526*objRad,0.447*objRad);

vertsVec[4]=new Vector3D(-0.724*objRad,-0.526*objRad,0.447*objRad);

vertsVec[5]=new Vector3D(0.276*objRad,-0.851*objRad,0.447*objRad);

vertsVec[6]=new Vector3D(0.724*objRad,0.526*objRad,-0.447*objRad);

vertsVec[7]=new Vector3D(-0.276*objRad,0.851*objRad,-0.447*objRad);

vertsVec[8]=new Vector3D(-0.894*objRad,0,-0.447*objRad);

vertsVec[9]=new Vector3D(-0.276*objRad,-0.851*objRad,-0.447*objRad);

vertsVec[10]=new Vector3D(0.724*objRad,-0.526*objRad,-0.447*objRad);

vertsVec[11]=new Vector3D(0,0,-1*objRad);
}
private function setFaces():void {

facesVec[0]=[0,1,2];

facesVec[1]=[0,2,3];

facesVec[2]=[0,3,4];

facesVec[3]=[0,4,5];

facesVec[4]=[0,5,1];

facesVec[5]=[11,6,7];

facesVec[6]=[11,7,8];

facesVec[7]=[11,8,9];

facesVec[8]=[11,9,10];

facesVec[9]=[11,10,6];

facesVec[10]=[1,2,6];

facesVec[11]=[2,3,7];

facesVec[12]=[3,4,8];

facesVec[13]=[4,5,9];

facesVec[14]=[5,1,10];

facesVec[15]=[6,7,2];

facesVec[16]=[7,8,3];

facesVec[17]=[8,9,4];

facesVec[18]=[9,10,5];

facesVec[19]=[10,6,1];

}

//There are no changes in rotateObj function.

private function rotateObj(rotx:Number,roty:Number,rotz:Number):void {

var i:int;

var j:int;

var distArray:Array=[];

var dispVec:Vector.<Point>=new Vector.<Point>();

var newVertsVec:Vector.<Vector3D>=new Vector.<Vector3D>();

var zAverage:Number;

var dist:Number;

var curFace:int;

var curFaceLen:int;

var curObjMat:Matrix3D;

spObject.transform.matrix3D.appendRotation(rotx,Vector3D.X_AXIS);

spObject.transform.matrix3D.appendRotation(roty,Vector3D.Y_AXIS);

spObject.transform.matrix3D.appendRotation(rotz,Vector3D.Z_AXIS);

curObjMat=spObject.transform.matrix3D.clone();

spObjImage.graphics.clear();

for(i=0;i<numVertices;i++){

newVertsVec[i]=curObjMat.deltaTransformVector(vertsVec[i]);

}

for(i=0;i<numVertices;i++){

newVertsVec[i].w=(fLen+newVertsVec[i].z)/fLen;

newVertsVec[i].project();
}

for(i=0;i<numFaces;i++){

curFaceLen=facesVec[i].length;

zAverage=0;

for(j=0;j<curFaceLen;j++){

zAverage+=newVertsVec[facesVec[i][j]].z;

}

zAverage/=curFaceLen;

dist=zAverage;

distArray[i]=[dist,i];

}

distArray.sort(byDist);

for(i=0;i<numVertices;i++){

dispVec[i]=new Point();

dispVec[i].x=newVertsVec[i].x;

dispVec[i].y=newVertsVec[i].y;

}

for(i=0;i<numFaces;i++){

spObjImage.graphics.lineStyle(1,0xCC0000);

curFace=distArray[i][1];

curFaceLen=facesVec[curFace].length;

spObjImage.graphics.beginFill(facesColors[curFace],0.7);

spObjImage.graphics.moveTo(dispVec[facesVec[curFace][0]].x,dispVec[facesVec[curFace][0]].y);

for(j=1;j<curFaceLen;j++){

spObjImage.graphics.lineTo(dispVec[facesVec[curFace][j]].x,dispVec[facesVec[curFace][j]].y);

}

spObjImage.graphics.lineTo(dispVec[facesVec[curFace][0]].x,dispVec[facesVec[curFace][0]].y);

spObjImage.graphics.endFill();

}

}

private function byDist(v:Array,w:Array):Number {

if (v[0]>w[0]){

return -1;

} else if (v[0]<w[0]){

return 1;

} else {

return 0;
}

}

private function addList():void{

spBoard.addEventListener(MouseEvent.ROLL_OUT,boardOut);

spBoard.addEventListener(MouseEvent.MOUSE_MOVE,boardMove);

spBoard.addEventListener(MouseEvent.MOUSE_DOWN,boardDown);

spBoard.addEventListener(MouseEvent.MOUSE_UP,boardUp);

this.addEventListener(Event.ENTER_FRAME,whenEnterFrame);

}

private function boardOut(e:MouseEvent):void {

doRotate=false;

}

private function boardDown(e:MouseEvent):void {

prevX=spBoard.mouseX;

prevY=spBoard.mouseY;

velX=0;

velY=0;

velMag=0;

doRotate=true;

}

private function boardUp(e:MouseEvent):void {

doRotate=false;

}

private function boardMove(e:MouseEvent):void {

var locX:Number=prevX;

var locY:Number=prevY;

if(doRotate){

prevX=spBoard.mouseX;

prevY=spBoard.mouseY;

velX=-2*(prevX-locX);

velY=2*(prevY-locY);

velMag=Math.abs(velX)+Math.abs(velY);

rotateObj(prevY-locY,-(prevX-locX),0);

e.updateAfterEvent();

}
}

private function whenEnterFrame(e:Event):void {

if(!doRotate && velMag>0){

rotateObj(velY,velX,0);

}

}

}
}

About these ads

One Response to Adding Simple Blender Models to CS4

  1. [...] Flash & Math and Dorking Around 3D in Flash (and in one of my previous post) have suggested individual triangle sorting routines, and Dorking Around 3D in Flash has a working [...]

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

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: