Would it be possible for someone to make a tutorial on how to write a file importation script, or does it depend too much on what file-type you’re trying to import? I am BRAND new to Python, so it would have to be written with the Python noob in mind.
ok, here’s a little mini-tut just for you.
(import will come after I finish this, it’s easier to understand so I’m doing it first for others benefit)
first off, download this:
it’s the api docs, it’ll save your life…
now, setting yourself up. Open blender, split the window and make the one on the right ‘text editor’ Then right click anywhere in this window and hit “add new” to make a new text file.
things to find out:
the format of the file to export too
what it can export (lights? materials?)
For this description I’ll assume the format is:
v = 1,1,1 # a vertice
v = 2,2,2
v = 4,2,4
f = 0,1,2 # a face, made from the first,second and third vertice
pretty simple huh? alot of formats are just in a text file with text like that.
First thing, we need to import blender to get the data from it. our first line:
# this is a comment, it's ignored but makes your code more readable import Blender # this line imports the data from blender
now, we need to export a mesh that’s linked to a selected object right?
from Blender import Object, Mesh
so, first the object:
#this gets the object: obj = Object.GetSelected() #this function returns the selected object and assigns it to the variable 'obj'
next the mesh:
me = obj.getData(0,1) #the parameters are 'nameonly' and 'mesh' #nameonly would return just the name, we want the object, so it's set to false #mesh set to true makes it return a mesh.
ok, now the mesh data contains two variables that contain the faces and verts (theres more but we don’t need them now, browse through the api docs if you want).
the verts are accessed by using whatever.verts and the faces whatever.faces
lets test this, at the end type:
then select some random object and execute your script. (alt-p i think)
go to the terminal (that ‘other window’ that opens in windows machines, linux may not show it) and look at the bottom. it should say somehting like this:
now from this we can see that there’s several lists (actually sequences, but lets not mince terms in a beginners tut) inside a bigger list, it might be easier to understand if you look at it like this:
in this example there’s four verts, each with their x, y, and z coordinates.
so, to iteratively access all the verts we’ll use a loop.
a loop is a function where what’s inside is done over and over to all the variables specified, in this case all our verts.
but before we begin looping, we need to know how to write a file.
this will open a file for writing:
fileToWrite = open("exported.whatever", "w") #exported.whatever is the name of the file to make, w means open for writing
now lets add a header!
fileToWrite.write("/created by a script! /<insert name here> is a python whiz!") # the is a line end, it's the same as pressing the return or enter key
now, the loop: watch the indenting! it’s important to get it right
for vert in me.verts: # vert will become each, in turn, vertice data # in other words, the first run through, vert will equal [1,4,3] then, in the next, [6,3,4] and so on. #---indent one tabfileToWrite.write("v = %f,%f,%f" % (vert,vert,vert)
now, this requires a bit of explenation. first, “for” starts the list, it means, for each of these, do this:, vert in me.verts will mean, for each vertice in this list, assign that vertice’s value to the variable ‘vert’ and do this:
then, fileToWrite.write() will write to the file,
the %'s are string formatting.
in a string you can put in those and it’ll be replaced by the corresponding values at the end, in other words,
print “hello, my name is %s. I have %i kids” % (“bob”, 15)
would print “hello, my name is bob. I have 15 kids”
the operators I use most are %i (replace with an integer), %s (replace with a string of characters) and, %f (replace with a float -a decimal number).
for explanation: 5 would be an int, while 5.32 would be a float… see the differance?
so, for the first vert [1,4,3] it would replace the first %f with 1, the next with 4, and the last with 3. which would then write:
v = 1,4,3
now, that takes care of the vertices, next comes the faces.
it’s exactly the same:
for face in me.faces:fileToWrite.write("f = %i,%i,%i" % (face,face,face)
we can use %i because the vertice number would be an int (there’s no vertice number 1.53, that’d be like saying “bring me the 3.35th car in the lot”)
fileToWrite.close() #frees memory
that should do it! if you execute it then, it’ll create a text file in the same directory of the blendfile that’s formatted correctly!
try modifying this script for the following formats:
vert = 5,2,3 vert = 2,3.3,74 vert = 2,3,5 face = vert 0, vert 1, vert 2
<verts> 1,2,3 5,2,4 3,5,2 </verts> <faces> 0,1,2 </faces>
<vertices><vert 1,2,3 color 1,1,1> <vert 2,2,1 color 1,.75,.5> <vert 5,5,2.2 color .6,.2,1> </vertices> <faces><face>[INDENT]<verts 0,1,2> <edge 0,1> <edge 1,2> <edge 2,0> </face> [/INDENT]</faces>
hint: for the last one, look into the api docs I told you to download, there you can find the vertex color data.
oh, and with me.verts and me.faces it’s not that hard to figure out that me.edges is there too.
c’ya next time! maybe tomarrow I’ll write an import tutorial
mods: if you like this, why not sticky it?
jessethemid, great response, perhaps you could extend the wiki
the export wiki is really good, I didn’t know about it or I’d just have told him about it.
however, the import wiki is not very well explained, perhaps I’ll write up a little something
oh, an btw: if you see any errors in my response plz tell me, I did it from memory since my computer’s out, so I’m not sure whether there’s any errors or not.
edit: just had an idea: why don’t we have a python workshop like the modelling one? I know there’s alot of blenderers that want to learn python but could use a more ‘hands on’ approach than a tut. I’ll start one if you think it’d be a good idea.
haha, just found two typos!
open for righting changed to open for writing
and fileToWrite.close changed to fileToWrite.close() [wow, that woulda been confusing]
Thanks, looking forward to the import tutorial. .w3d is the format I’m trying to import.
w3d as in westwood 3d? like c&c and lotr?
or w3d as in shockwave?
do you have an example file?
if so, email it to me at [email protected] and I’ll take a look.
ok, starting work on import tutorial, it’ll be in the next post.
ok, first thing’s first, we need to figure out the specs of our file format.
you need an example file, if you have one, open it with a simple text editor (like wordpad or gedit)
if it’s a bunch of jibberish… I don’t know enough to import it because it’s a binary file.
but, if it’s text, you can import it easily.
for this tutorial I’m going to use the .xmesh format as an example. It’s an xml base format.
here’s some important pieces from my example file:
the starting lines, a material:
<Mesh scale="1.000000" reverse="0" forcetexture="0" sharevert="0" polygonoffset="0.000000" blend="ONE ZERO" texture="hyperion_vs_wings.png" > <Material power="96.078430" cullface="1" reflect="1" lighting="1" usenormals="1"> <Ambient Red="0.000000" Green="0.000000" Blue="0.000000" Alpha="1.000000"/> <Diffuse Red="0.640000" Green="0.640000" Blue="0.640000" Alpha="1.000000"/> <Emissive Red="0.000000" Green="0.000000" Blue="0.000000" Alpha="1.000000"/> <Specular Red="0.500000" Green="0.500000" Blue="0.500000" Alpha="1.000000"/> </Material>
take a moment before going on to try and figure out all we can learn from this, then move on.
so? what’d you figure out?
here’s what I get:
<Mesh scale="1.000000" reverse="0" forcetexture="0" sharevert="0" polygonoffset="0.000000" blend="ONE ZERO" texture="hyperion_vs_wings.png" >
Mesh scale = blender’s object scale, we’ll use that
reverse, forcetexture, sharevert, and polygonoffset we won’t use
blend is for alpha mapping, we dont need it.
<Material power="96.078430" cullface="1" reflect="1" lighting="1" usenormals="1">
material power? whats that mean? we’ll skip it.
blender has no cullface feature so we’ll skip it
reflect tells us whether to turn on raymirr
lighting tells us whether it’s shadeless or shaded?
<Ambient Red="0.000000" Green="0.000000" Blue="0.000000" Alpha="1.000000"/> <Diffuse Red="0.640000" Green="0.640000" Blue="0.640000" Alpha="1.000000"/> <Emissive Red="0.000000" Green="0.000000" Blue="0.000000" Alpha="1.000000"/> <Specular Red="0.500000" Green="0.500000" Blue="0.500000" Alpha="1.000000"/> </Material>
hmm, blender’s differant then this.
ambient we don’t have to worry about
diffuse is the color, alpha (under diffuse) is the ref power
emissive can be mapped to emit, but just the alpha, not color (blender uses the diffuse color)
specular is reflection color and amount. (yes, it is.) in this case, set raymirr to 1 and color to grey.
also, as you can see, the entire mesh is enclosed in <Mesh> tags, so we can just write <Mesh + stuff> at the start and </Mesh> at the end.
now, the next part, here’s the points and faces (simplified by me):
all points are enclosed within the two <points> and </points> tags
<Points> <Point> <Location x="-26.250002" y="10.716940" z="-6.584096" s="0.000000" t="0.000000"/> <Normal i="0.792685" j="-0.508281" k="0.336602"/> </point> </points>
and faces, again all enclosed in the two tags at the start and end:
<Polygons> <Quad flatshade="0"> <Vertex point="34" s="0.152926" t="0.856734"/> <Vertex point="124" s="0.163280" t="0.809744"/> <Vertex point="183" s="0.078858" t="0.808152"/> <Vertex point="116" s="0.062930" t="0.855938"/> </Quad> </polygons>
you know the drill, try thinking it out before going on.
here’s what it tells me:
-all points are inclosed in one set of tags: <points> points </points>
-individual points are enclosed in tags:<point> stuff </point>
-each point contains two tags, location and normal.
-we’ll ignore normal for this tutorial, we can just recalc at the end.
-location is formatted as x = “somenumber” y = “somenumber” z = “somenumber”, s = “0.000000” t = “0.000000”
-I don’t know what the s and t are… so we’ll just put 0.000000 for each.
-all faces are inclosed like this: <polygons> stuff </polygons>
-individual faces are inclosed in quad or tri tags, we’ll treat them the same since blender knows the differance.
-again, I have no idea what s and t are so we’ll skip 'em
-points per face are defined in their own tags <vertex point=“number” s=? t=?>
so, now we know the format, lets get started!
ok, same start, except this time we need material and texture also:
# imports, we'll need access to blenders mat,tex,mesh and obj blocks import Blender from Blender import Mesh, Object, Texture, Material # remember to add docstrings! # docstrings are comments that explain your script
this time we’ll use functions! functions are little programs that can be called from within. We make them using def which stands for define.
from the previous tut, you are probably familiar with calling functions. when we used open(name, mode) that’s a function! just not within out code. we also can make them.
now, a little planning is involved, in this case, there’s three things we could use functions to do: get the vertices, get the faces, get the material
a function to get the material would be pointless since it only has to be done once, so we’ll make functions to get the verts only.
every function needs data fed to it. in open() we fed it the name of the file, and the mode to open it.
so what would we need for verts?
well, we’d need an blender mesh to append to, and the line of the xml about the point (the <location> tag)
now, read the docstrings, they explain the function.
<b>def </b>addVerts(me, loc): # watch indenting, one tab# loc will equal something like: #<Location x="-26.250002" y="10.716940" z="-6.584096" s="0.000000" t="0.000000"/> #so, we need to extract "-26.25002" etc. # strip() will remove unwanted characters loc = loc.strip("<>/Location ") # loc will now be 'x="" y="" z="" s="" t=""' loclist = loc.split(" ") #this will seperate them by spaces x = float(loclist.strip(' x="" ')) #should strip it down to a float. y = float(loclist.strip(' y="" ')) #should strip it down to a float. z = float(loclist.strip(' z="" ')) #should strip it down to a float. # we are ignoring loclist and  because they're s and t # now to add it to the mesh: me.verts.extend(x,y,z)
now on to the faces function!
yay! the faces function:
same as with verts, we need the mesh and a list of the lines needed, in the main function we’ll use split like in the verts to get a list of each vert:
["<Vertex point=“1” s=“0 t=“0”>”,"<Vertex point=“2” s=“0 t=“0”>”, etc,"
<b> def</b> addFaces(me, vertlist):# loop to strip down to the point values for each for vert in vertlist:[INDENT]vert = vert.strip("<>/Vertex ") #same as before vlist = vert.split(" ") #same as before, seperate it vert = vlist #vert will now be 'point="whatever"' vert = int(vert.strip('point=""')) # now just int. #vertlist will now be a list of ints that are vert numbers, #just what blender needs #add faces me.faces.extend(vertlist) [/INDENT]
yay! we now have a function that will make faces. not hard is it?
eh, sorry it’s getting so long… ah well, all I’ve said needs to be said
anyway, now on to the main function.
first we need to load the file:
<b>def </b>main(path):f = open(path, "r") #open for reading me = Mesh.New('imported') Blender.Window.Waitcursor(1) #turn on the wait cursor linelist = f.readlines() #get a list of the lines of the file for i in range(len(linelist)): #start a loop, using range makes it #so we can keep track of the indexes of the list[INDENT]line = linelist[i].strip(" ") line = line.lower() if line == "<point>":[INDENT]addVerts(me, linelist[i+1].strip(" ") #add verts, using the location tag #that is right below the point tag. elif line[0:5] == "<quad":addFaces(me, linelist[i+1:i+5]) #linelist[i+1:i+5] will be a list of the #four verts after the tag elif line[0:5] == "<mesh": #check if the first 5 letters are for the mesh tagline = line.strip(' <>/mesh scale= "')#get #rid of unneccesary scale = float(line[0,9]) #gets the scale ind = line.rfind("texture") #now, line[ind] will be the t in the last #texture, or -1 if not found if ind != -1:[INDENT]tex = line[ind+9:] #will give #us the image name [/INDENT]elif line[0:9] == "<material":#get whether to turn on raymirr ind = line.rfind("reflect") if ind != -1:[INDENT]mirror = int(line[ind + 9]) #could use bool, but int's #easier... for me [/INDENT]#get whether to turn on shadeless #0 is on, 1 is off ind = line.rfind("lighting") if ind != -1:[INDENT]shade = int(line[ind = 10]) # ambient, one below the 'mat' line amb = linelist[i+1] amb = amb.lower() amb = amb.strip(" <>/ambient ") # you know the drill #will be set to spec color speccollist = amb.split(" ") speccol = float(speccollist.strip(' "red=" ')) speccol = float(speccollist.strip(' "green=" ')) speccol = float(speccollist.strip(' "blue=" ')) specamt = float(speccollist.strip(' "alpha=" ')) # Diffuse, will be set to 'col' diff = linelist[i+2] diff = diff.lower() diff = diff.strip(" <>/diffuse ") diffcollist = diff.split(" ") [/INDENT][/INDENT][/INDENT]
more to come tomarrow.
ok, you can post now, I’ve put in enough placeholders to finish… just the main function to go now.
ah, i think someone’s doing a little BFME modding…
great tut in process!
Well, close. I am looking for a BFME mod, but the main reason I wanted the models was so I could have a good orthographic reference for a balrog. The new sculpt tool seems to be ideal, but I still need more organic modeling experience. I agree that jesse made a great tutorial (thanks buddy!), but unfortunately it hasn’t solved my problem. I sent him a sample file and it has turned out to be a binary rather than a simple text file, which he doubts can be imported with a python script. Any help?
ah i see…unfortunately i have as much python experience as u do - beginner.
i was just saying that cuz i once i tried out some actual BFME mesh-editing modding using gmax…but i didn’t really know how to use it so it didnt work :rolleyes:.
sorry for being offtopic; i hope someone can help u out.