New Blender XML Exporter/PV3D XML Primitive

Thanks to Dennis Ippel

Many thanks to Dennis Ippel whose creation of the AS3 Blender exporter made my creation of the XML Exporter and XML Papervision Primitive possible (or at least infinitely easier). This is an iteration of his work. Essentially, I rewrote his Python AS3 Exporter to export XML from Blender and then created a Papervision XML Primitive which uses that XML. Links for the XML Exporter and Primitive are given in this article.

Intro

At first glimpse you might be wondering, why would you need an XML exporter for Blender and Papervision XML Primitive?

And there are actually two answers to this question. First, Blender doesn’t have a handy exporter for Papervision. It presently exports to Actionscript (to find out more check it out here ) So, creating an exporter that exports to XML gives you the ability to pick that XML up into an XML primitive. Presently, primitives are created mathematically in Papervision. By using an XML Primitive you can make any object in Blender and use it like a primitive in Papervision. Just by dropping its XML file (and image if textured) into Papervision.

The XML Primitive is simple; it just references the XML file and color or image (if textured) as shown below. All the properties of Papervision primitives apply to it such as translation, rotation, and scaling.

myWidget = new XMLPrimitive(“Widget.xml”, color or bitmap asset);

The second purpose is to create a mechanism for saving and using box models created in Papervision. That’s right you’re going to box model in Papervision.

Click on the image below to see the physics roller in action.

String Roller for Physics Lab

String Roller for Virtual Physics Lab

In the YouTube below, I demonstrate how to use the exporter and xml primitive and discuss how they were made.

YouTube Video – Development and How to Use

How it was made

How to use it

Demos

Demo 1 Widget with Color (no Texture)

Demo 2 Ship with Texture

Downloads

Demo 1 Widget with Blender File (Flex and Flash Code)

Demo 2 Ship with Blender File (Flex and Flash Code)

XMLExporter/XMLPrimitive

Discussion

This xml exporter/primitive was originally made to create widgets for a series of virtual physics experiments at NKU. Creating the widget above using the xml exporter has streamlined the process of making these widgets. There are two ways to create these primtives – textured and untextured.

Two Ways (Textured and Untextured)

Note: Presently the XML Primitive does not except shaded materials. Only untextured and textured primitives created in Blender are allowed.

There are two ways to get a XML primitives out of Blender – textured and untextured. Demo 1 above is the untextured way (but you can still give it a color using the color material) and demo 2 is the textured primitive. An example of a texture object is given below. And if you want to learn how to texture an object in Blender watch the following two videos.

UV Mapping (Texturing an object in Blender)

Part 1 – UV Mapping
http://www.youtube.com/watch?v=gxSXp-vGyV8

Part 2 – UV Mapping
http://www.youtube.com/watch?v=gCNJtSNWXgM

Following the procedure above you can create an object and put a texture on it for XMLExport. You can click the image below to see an animated example of and XML exported primitive. The image below shows a textured ship on the left and its texture map on the right.

Putting a Texture on a Ship

Putting a Texture on a Ship

Important: But regardless of which XML primitive you use (textured or untextured) you must triangulate your object in edit model by pressing Ctrl+t or your objects will have triangular holes in them. An example of the XML generated by the XMLExporter is given below

Installing the Exporter/Primitve

Unzip the exporter/primitive found here

and place the XMLExport python file in the following scripts directory

  • Windows: /Blender Foundation/Blender/.blender/scripts/ (Blender .2.46: C:\Documents and Settings\<username>\Application Data\Blender Foundation\Blender\.blender\scripts)
  • Mac: /Applications/blender/blender.app/Contents/MacOS/.blender/scripts/

then place the XMLPrimitive in the primitive Papervision folder found in the following directory

org/papervision3d/objects/primitives

and that’s it. You are now ready to make an XML Primitive in Blender. Just reference this exported file in your XMLPrimitive as show below and add a color or bitmap depending on if your Primitive is textured or not.

//Use a color for an untextured primitive
var paper2:ColorMaterial = new ColorMaterial(0xFFFF00,1,false);
paper2.doubleSided = true;

//Use a bitmap for an textured primitive
bitmap=new BitmapFileMaterial(“crusor_Cylinder.jpg”);

//Reference the XML generated file and your texture or color
mcylinder = new XMLPrimitive(“Widget.xml”,paper2);

An example of the type of export code you will be seeing is given below.

XMLExporter Code

The XML generated for this primitive is shown below;

<?xml version=’1.0′ encoding=’utf-8′?>
<myData>
<myPrimSet>
<myVertices>
0.707107,-0.280624,0.707107,0.965926,…
</myVertices>
<myFaces>
24,0,1,24,1,2,24,2,3,24,3,4,…
</myFaces>
<myParams>
0.000000,0.000000,0.000000,…
</myParams>

</myData>

To see the code for the Python exporter or XML Primitive click the more button below;

Python XMLExporter

#!BPY
“””
Name: ‘XML Exporter (.xml) …’
Blender: 240
Group: ‘Export’
Tooltip: ‘Export geometry to ActionScript 3.0 Class (.as)’
“””

# ————————————————————————–
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2007-2008 Dennis Ippel
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place – Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# ————————————————————————–

__author__ = “Dennis Ippel (Modified by Mike Lively to export XML into the Master Cylinder for Papervision)”
__url__ = (“http://www.professionalpapervision.com&#8221;)
__version__ = “0.1″

__bpydoc__ = “””

For more information please go to:

http://www.professionalpapervision.com

“””

#triangulate: go into edit mode, select all faces and press ctrl+t

from Blender import Scene, Mesh, Window, Get, sys
import BPyMessages
import bpy
import math
from math import *
from Blender.BGL import *
from Blender.Draw import *

EVENT_NOEVENT = 1
EVENT_DRAW = 2
EVENT_EXIT = 3
EVENT_EXPORT = 4
EVENT_BROWSEFILE = 5

as_package_name = Create(“”)
as_class_name = Create(“”)
as_output_string = “”
as_filename = “”
fileButton = Create(“”)
engine_menu = Create(1)

def export_papervision2(me):
as_output_string = “<?xml version=’1.0′ encoding=’utf-8′?>\n”
as_output_string += “<myData>\n”
as_output_string += “<myPrimSet>\n”
as_output_string += “<myVertices>\n”

for v in me.verts:
#global as_output_string
as_output_string += “%f,%f,%f,” % (v.co.x, v.co.z, v.co.y)

as_output_string += “\n”
as_output_string += “</myVertices>\n”
as_output_string += “<myFaces>\n”
for f in me.faces:
if me.faceUV:
as_output_string += “%i,%i,%i,%f,%f,%f,%f,%f,%f,%f,%f,%f,” % (f.verts[0].index, f.verts[1].index, f.verts[2].index, f.uv[0][0], f.uv[0][1], f.uv[1][0], f.uv[1][1], f.uv[2][0], f.uv[2][1], f.no.x, f.no.y, f.no.z )
my_mat=”1″
if not me.faceUV:
as_output_string += “%i,%i,%i,” % (f.verts[0].index, f.verts[1].index, f.verts[2].index)
my_mat=”0″

as_output_string += my_mat
as_output_string += “\n”
as_output_string += “</myFaces>\n”
as_output_string += “<myParams>\n”
as_output_string += “%f,” % ob_translate[0]
as_output_string += “%f,” % ob_translate[2]
as_output_string += “%f,” % ob_translate[1]

as_output_string += “%f,” % ob_rotX
as_output_string += “%f,” % ob_rotZ
as_output_string += “%f,” % ob_rotY

as_output_string += “%f,” % ob_scaleX
as_output_string += “%f,” % ob_scaleZ
as_output_string += “%f” % ob_scaleY

as_output_string += “\n”
as_output_string += “</myParams>\n”
as_output_string += “</myPrimSet>\n”

as_output_string += “<myPrimSet>\n”
as_output_string += “<myVertices>\n”

for v in me.verts:
#global as_output_string
as_output_string += “%f,%f,%f,” % (v.co.x, v.co.z, v.co.y)

as_output_string += “\n”
as_output_string += “</myVertices>\n”
as_output_string += “<myFaces>\n”
for f in me.faces:
if me.faceUV:
as_output_string += “%i,%i,%i,%f,%f,%f,%f,%f,%f,%f,%f,%f,” % (f.verts[0].index, f.verts[1].index, f.verts[2].index, f.uv[0][0], f.uv[0][1], f.uv[1][0], f.uv[1][1], f.uv[2][0], f.uv[2][1], f.no.x, f.no.y, f.no.z )
if not me.faceUV:
as_output_string += “%i,%i,%i,” % (f.verts[0].index, f.verts[1].index, f.verts[2].index)

as_output_string += my_mat
as_output_string += “\n”
as_output_string += “</myFaces>\n”
as_output_string += “<myParams>\n”
as_output_string += “%f,” % ob_translate[0]
as_output_string += “%f,” % ob_translate[2]
as_output_string += “%f,” % ob_translate[1]

as_output_string += “%f,” % ob_rotX
as_output_string += “%f,” % ob_rotZ
as_output_string += “%f,” % ob_rotY

as_output_string += “%f,” % ob_scaleX
as_output_string += “%f,” % ob_scaleZ
as_output_string += “%f” % ob_scaleY

as_output_string += “\n”
as_output_string += “</myParams>\n”
as_output_string += “</myPrimSet>\n”

as_output_string += “</myData>\n”

save_file(as_output_string)

def save_file(file_contents):
try:
f = open(fileButton.val, ‘w’)
f.write(file_contents)
f.close()
PupMenu(“Export Successful”)
except:
PupMenu(“Export failed | Check the console for more info”)
raise # throw the exception

Exit()

def main():
# Gets the current scene, there can be many scenes in 1 blend file.
sce = bpy.data.scenes.active

# Get the active object, there can only ever be 1
# and the active object is always the editmode object.
ob_act = sce.objects.active

if not ob_act or ob_act.type != ‘Mesh’:
BPyMessages.Error_NoMeshActive()
return

#get transformations
global ob_translate, ob_mtrx, ob_rotX, ob_rotY, ob_rotZ, ob_scaleX, ob_scaleY, ob_scaleZ
ob_translate = ob_act.getLocation(‘worldspace’)
ob_mtrx = ob_act.matrix.rotationPart()
ob_rotX = ob_act.RotX * (180 / pi)
ob_rotY = ob_act.RotY * (180 / pi)
ob_rotZ = ob_act.RotZ * (180 / pi)
ob_scaleX = ob_act.SizeX
ob_scaleY = ob_act.SizeY
ob_scaleZ = ob_act.SizeZ

# Saves the editmode state and go’s out of
# editmode if its enabled, we cant make
# changes to the mesh data while in editmode.
is_editmode = Window.EditMode()
if is_editmode: Window.EditMode(0)

Window.WaitCursor(1)
me = ob_act.getData(mesh=1) # old NMesh api is default
t = sys.time()

# Restore editmode if it was enabled
if is_editmode: Window.EditMode(1)

print ‘XML Exporter Script finished in %.2f seconds’ % (sys.time()-t)
Window.WaitCursor(0)

# This lets you can import the script without running it
if __name__ == ‘__main__’:
main()

def event(evt, val):
if (evt == QKEY and not val):
Exit()

def bevent(evt):
global EVENT_NOEVENT,EVENT_DRAW,EVENT_EXIT

if (evt == EVENT_EXIT):
Exit()
elif (evt== EVENT_DRAW):
Redraw()
elif (evt== EVENT_EXPORT):
sce = bpy.data.scenes.active
ob_act = sce.objects.active
me = ob_act.getData(mesh=1) # old NMesh api is default

if (engine_menu.val == 1 ):
export_papervision2(me)

elif (evt== EVENT_BROWSEFILE):
expFileName = as_class_name.val + “.xml”
Window.FileSelector(FileSelected,”Export .as”, expFileName)
Redraw(1)

def FileSelected(fileName):
global fileButton

if fileName != ”:
# check if file exists
#if sys.exists(fileName) != 1:
# cutils.Debug.Debug(‘File(%s) does not exist’ % (fileName),’ERROR’)
# return False

fileButton.val = fileName
else:
cutils.Debug.Debug(‘ERROR: filename is empty’,’ERROR’)

######################################################
# GUI drawing
######################################################
def draw():

global fileButton, expFileName
global as_class_name, engine_menu, engine_name
global EVENT_NOEVENT,EVENT_DRAW,EVENT_EXIT,EVENT_EXPORT
expFileName = “”
########## Titles
glClear(GL_COLOR_BUFFER_BIT)
glRasterPos2i(40, 240)
Text(“XML Exporter https://professionalpapervision.wordpress.com/ – remember to triangulate your objects in edit mode using ctrl+t.”, “large”)
engine_name = “Papervision3D 2.0%x1″
as_class_name = String(“XML File Name: “, EVENT_NOEVENT, 40, 150, 250, 20, as_class_name.val, 300)
engine_menu = Menu(engine_name, EVENT_NOEVENT, 40, 100, 200, 40, engine_menu.val, “Choose your engine”)

fileButton = String(‘File location: ‘, EVENT_NOEVENT, 40, 70, 250, 20, fileButton.val, 255)
PushButton(‘…’, EVENT_BROWSEFILE, 300, 70, 30, 20, ‘browse file’)

######### Draw and Exit Buttons
Button(“Export”,EVENT_EXPORT , 40, 20, 80, 18)
Button(“Exit”,EVENT_EXIT , 140, 20, 80, 18)

Register(draw, event, bevent)

XMLPrimitive

package org.papervision3d.objects.primitives {

import flash.events.Event;
import flash.net.*;

import org.papervision3d.core.geom.TriangleMesh3D;
import org.papervision3d.core.geom.renderables.Triangle3D;
import org.papervision3d.core.geom.renderables.Vertex3D;
import org.papervision3d.core.math.Number3D;
import org.papervision3d.core.math.NumberUV;
import org.papervision3d.core.proto.MaterialObject3D;

public class XMLPrimitive extends TriangleMesh3D {
private var ve:Array;
private var fa:Array;

public var myFileGet:String;
public var xmlReq:URLRequest;
public var xmlLoader:URLLoader;
public var myData_xml:XML;
public var iFacNum:Number;
public var myMaterial:MaterialObject3D;

public function XMLPrimitive(myFileGet:String, material :MaterialObject3D=null, initObject:Object=null ) {
super( material, new Array(), new Array(),null, initObject );
ve = this.geometry.vertices;
fa = this.geometry.faces;

var externalXML:XML;
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest(myFileGet);

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);

buildCylinder(externalXML);

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

this.geometry.ready = true;
}

private function buildCylinder(myData_xml:XML):void
{

ve = this.geometry.vertices;
fa = this.geometry.faces;
var mySlitVert:Array=myData_xml.myPrimSet[0].myVertices.split(“,”);
var mySlitFace:Array=myData_xml.myPrimSet[0].myFaces.split(“,”);
this.geometry.ready = true;

var j:int;
var iVerNum:int=(mySlitVert.length-1)/3;
for (j=0;j<iVerNum;j++) {

v(mySlitVert[j*3],mySlitVert[j*3+1],mySlitVert[j*3+2]);

}

//if statement for material or no material

if(mySlitFace[mySlitFace.length-1]==0){

var k:int;
iFacNum=(mySlitFace.length-1)/3;
for (k=0;k<iFacNum;k++) {

f2(mySlitFace[k*3],mySlitFace[k*3+1],mySlitFace[k*3+2]);

}
}else{
var n:int;
iFacNum=(mySlitFace.length-1)/12;
for (n=0;n<iFacNum;n++) {

f(mySlitFace[n*12], mySlitFace[n*12+1], mySlitFace[n*12+2], mySlitFace[n*12+3], mySlitFace[n*12+4], mySlitFace[n*12+5], mySlitFace[n*12+6], mySlitFace[n*12+7], mySlitFace[n*12+8], mySlitFace[n*12+9], mySlitFace[n*12+10], mySlitFace[n*12+11]);

}

}

}

public function v(x:Number, y:Number, z:Number):void {
ve.push(new Vertex3D(x, y, z));
}
//Function for material on prims
public function f(vertexIndex1:Number, vertexIndex2:Number, vertexIndex3:Number, uv00:Number, uv01:Number, uv10:Number, uv11:Number, uv20:Number, uv21:Number, normalx:Number, normaly:Number, normalz:Number):void {
var face : Triangle3D = new Triangle3D(this, [ve[vertexIndex1], ve[vertexIndex2], ve[vertexIndex3]], material, [ new NumberUV(uv00, uv01), new NumberUV(uv10, uv11), new NumberUV(uv20, uv21) ] );
face.faceNormal = new Number3D(normalx,normaly,normalz);
fa.push(face);

}

public function f2(vertexIndex1:Number, vertexIndex2:Number, vertexIndex3:Number):void {
fa.push(new Triangle3D(this, [ve[vertexIndex1], ve[vertexIndex2], ve[vertexIndex3]], material, []));

}

}
}

About these ads

12 Responses to New Blender XML Exporter/PV3D XML Primitive

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

  2. Anthony says:

    Thank you very much!!! You saved my job!!!

    I’m 17 and i figured it out with your tutorials.

    So if a 17 year old can learn from your tutorials then they are GOOD!

    ….now i need to figure out interactivity with tweener :/
    looks like another allnighter! :D

  3. [...] parser which allows you to bring Blender models into CS4. It uses the drawTriangles method, the Blender XML Exporter created in a previous post, and a one-to-one mapping scheme of vertex and uv data [...]

  4. Hi,

    nice post.
    Got a few questions though ?

    What is the main advantage you get from switching to xml instead of an as3 class ?

    In my opinion tweaking the class to your needs seems easier than using xml because:

    1. an xml export will more than likely be larger in file size than the as3 class version
    2. since it’s an as class, it get’s compiled ( gain a bit of file size again ) + you don’t need a loader for the xml, you don’t need to parse anything ( faster ).

    Why all these extra steps ?

    • Mike Lively says:

      Usability…why does anyone use XML…it talks to everything…otherwise use byte code.

      I train a number of graphic designers who need a canned approach (honestly I need one to) that doesn’t require a ton of programming. Also, I do a ton of data driven apps that requires simple 3D models…this does the trick.

      And the XML approach mimics more closely what is being done in Papervision3D. I just create an XML prim that sucks up the data and use it just like any other prim in Papervision3D.

      Finally I had another goal in mind, I used this same approach to bring models into CS4 – where the as3 class would no longer work without a huge amount of rewriting…see the post on the CS4 Animated Shuttle.

      This was a really good question…thanks for asking.

  5. [...] as in the Blender case, we built an XML exporter for 3DSMax and Papervision3D XML primitive to suck up the data (We also [...]

  6. [...] Posts Papervision Planetarium (Flex Code – NOMAD constellations)New Blender XML Exporter/PV3D XML PrimitiveCreating a Spherical Panorama in PapervisionBuilding a 3D Flash Engine in 19 Lines of Code3D [...]

  7. Adam Bannach says:

    I was attempting to implement your XMLPrimitive.as in my flartoolkit project, and am getting an issue with the call to super. It throws this error:
    1137: Incorrect number of arguments. Expected no more than 4.

    • Mike Lively says:

      If you really get stuck, send me your code I’ll take a look at it this weekend…livelym1@nku.edu…or (if not so stuck) it may be the version of Papervision3D you are using…track down the error in Flex…Papervision3D is changing and there are easy errors here and there to fix…I commonly use Flex to find them…

  8. Adam Bannach says:

    I’m downloading the free flex sdk right now and will take a look at it. I’m assuming that it is a papervision3d version issue. I downloaded the flartoolkit starter kit which was pre packaged with papervision. Thanks for the quick response I’ll get back to you as soon as I figure this out.

    • Mike Lively says:

      Great – I had this problem before with different versions and have ended up commenting out or remove items to get it to work. I wrote the exporter in a pinch, it follow exactly what was done for the AS3 exporter except that it uses XML. I’m presently finishing up a Collada 1.4 exporter that should be a little more robust and work for a variety of modeling programs…let me know if I can help…

  9. Mike Lively says:

    It’s like I said, wrong version of PV3D. When branch CS4 got put up a bunch of us though it was the progenitor of PapervisionX – it wasn’t – so you just remove the 5th parameter in the super statement and it runs…I’ll put up a fix soon.

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: