Tuesday, July 21, 2009

Improved Blender Export

Thanks to some help from some readers, I've got a new and improved version of the Blender Export Script for Objective-C. This new version works correctly regardless of whether there's a texture. If you've used vertex paint, it will export the vertex colors. If you have neither vertex colors or a mapped texture, then it will just export the vertices and normals. It will also update the drawing code as appropriate to the data that's been exported.

Also, new with this version, you don't need to triangulate the faces, nor do you need to apply modifiers. Those will happen automatically in the export without affecting your original model. That should make it easier to update and maintain the models you use in your iPhone apps.

You can download the new script from the link above. I'm including the script here for the curious:

Note of warning: I have not tested this script very thoroughly, so caveat emptor! Fixes and improvement suggestions welcome, as always.


Name: 'Objective-C Header (.h)'
Blender: 244
Group: 'Export'
Tooltip: 'Exports header file for use with the OpenGL ES template for iPhone available from http://iphonedevelopment.blogspot.com/'

import Blender
from Blender import *
import bpy
import bpy
import os

def write_obj(filepath):
out = file(filepath, 'w')
sce = bpy.data.scenes.active
ob = sce.objects.active
mesh = Mesh.New()

editmode = Window.EditMode()
if editmode: Window.EditMode(0)
has_quads = False
for f in mesh.faces:
if len(f) == 4:
has_quads = True

if has_quads:
oldmode = Mesh.Mode()

mesh.sel = True
tempob = sce.objects.new(mesh)
mesh.quadToTriangle(0) # more=0 shortest length
oldmode = Mesh.Mode(oldmode)


objectname = ob.getData(True)
basename = objectname.capitalize()

out.write('#import "OpenGLCommon.h"\n\n\n')

if (mesh.faceUV):
out.write('static const TexturedVertexData3D %sVertexData[] = {\n' % basename)
for face in mesh.faces:
for (vert, uvert) in zip(face.verts, face.uv):
out.write('\t{/*v:*/{%f, %f, %f}, ' % (vert.co.x, vert.co.y, vert.co.z) )
out.write('/*n:*/{%f, %f, %f}, ' % (vert.no.x, vert.no.y, vert.no.z))
out.write('/*t:*/{%f, %f}' % ( uvert.x, uvert.y ) )
elif (mesh.vertexColors):
out.write('static const ColoredVertexData3D %sVertexData[] = {\n' % basename)
for face in mesh.faces:
for (vert, color) in zip(face.verts, face.col):
out.write('\t{/*v:*/{%f, %f, %f}, ' % (vert.co.x, vert.co.y, vert.co.z) )
out.write('/*n:*/{%f, %f, %f}, ' % (vert.no.x, vert.no.y, vert.no.z))
out.write('/*c:*/{%f, %f, %f, %f}' % ( color.r / 255.0, color.g / 255.0, color.b / 255.0, color.a / 255.0) )
out.write('static const VertexData3D %sVertexData[] = {\n' % basename)
for face in mesh.faces:
for vert in face.verts:
out.write('\t{/*v:*/{%f, %f, %f}, ' % (vert.co.x, vert.co.y, vert.co.z) )
out.write('/*n:*/{%f, %f, %f} ' % (vert.no.x, vert.no.y, vert.no.z))

if editmode: Window.EditMode(1)
out.write('#define k%sNumberOfVertices\t%i\n' % (basename, len(mesh.faces) * 3) )

out.write('// Drawing Code:\n')
out.write('// glEnableClientState(GL_VERTEX_ARRAY);\n')
if (mesh.faceUV):
out.write('// glEnableClientState(GL_TEXTURE_COORD_ARRAY);\n')
elif (mesh.vertexColors):
out.write('// glEnableClientState(GL_COLOR_ARRAY);\n')
out.write('// glEnable(GL_COLOR_MATERIAL)\n')
out.write('// glEnableClientState(GL_NORMAL_ARRAY);\n')
out.write('// glVertexPointer(3, GL_FLOAT, sizeof(TexturedVertexData3D), &%sVertexData[0].vertex);\n' % basename)
out.write('// glNormalPointer(GL_FLOAT, sizeof(TexturedVertexData3D), &%sVertexData[0].normal);\n' % basename)
if (mesh.faceUV):
out.write('// glTexCoordPointer(2, GL_FLOAT, sizeof(TexturedVertexData3D), &%sVertexData[0].texCoord);\n' % basename)
elif (mesh.vertexColors):
out.write('// glColorPointer(4, GL_FLOAT, sizeof(ColoredVertexData3D), &%sVertexData[0].color);\n' % basename)
out.write('// glDrawArrays(GL_TRIANGLES, 0, k%sNumberOfVertices);\n' % basename)
out.write('// glDisableClientState(GL_VERTEX_ARRAY);\n')
if (mesh.faceUV):
out.write('// glDisableClientState(GL_TEXTURE_COORD_ARRAY);\n')
elif (mesh.vertexColors):
out.write('// glDisableClientState(GL_NORMAL_ARRAY);\n')
out.write('// glDisable(GL_COLOR_MATERIAL);\n')
out.write('// glDisableClientState(GL_NORMAL_ARRAY);\n\n\n')


filename = os.path.splitext(Blender.Get('filename'))[0]
Blender.Window.FileSelector(write_obj, "Export", '%s.h' % filename)

Thanks to Scott Lyons and Dennis Ippel for their Python and Blender API smarts. I couldn't have gotten this far without their help.


Mike said...

Thanks for the great OpenGL articles. I am guessing you are aware of SIO2 and it's superb Blender exporter (http://www.sio2interactive.com/HOME/HOME.html). If not, you should definitely give it a look.

Audra said...

I am new to Blender, but I've been trying out some tutorials to get a basic model with texture. My texture doesn't look the way I want it to yet, but it is certainly on my model when I render. When I use this exporter though, I get no texture coordinates at all (just v and n). Are you supporting only certain types of textures, or are there certain steps I might not be taking correctly? What step in the process sets mesh.faceUV? Thanks!

Jeff LaMarche said...

If you've selected your object in edit mode and typed U then selected "unwrap", you should have texture coordinates. If you don't unwrap texture coordinates, then there's no FaceUV because every face would be (0.0, 1.0). If you've mapped a texture, and it's not showing up, the only other thing I might suggest is to make sure you've saved since unwrapped the texture.

Although I haven't tested this script extensively, I have done a few rather complex models, including a model with 76,000+ vertices that was texture mapped, with complex seams, and it worked, so I don't know why you're not getting any texture coordinates :(

Audra said...

Using the unwrap method for UV texture coordinates, I was finally able to get some texture coordinate in my output file using a cube geometry (although I'm having a hard time figuring out how to place seams so more complicated models unwrap nicely...need to watch more tutorials). I had previously been following a tutorial that used a completely different approach. It just added a material with a loaded texture image and selected "Tube" in the Map Input menu. Honestly, I'm still just figuring this out, but I did have textures rendered and they didn't export when I applied them this way.

Audra said...

Hi Jeff-
This exporter has been very useful! I was curious if you were planning on continuing to expand it to include indexed triangles or triangle strips?

davidcann said...

Note that if you export an object without a texture, in the "Drawing Code" written to the end of the header file, you'll need to change "sizeof(TexturedVertexData3D)" to "sizeof(VertexData3D)" or else it will draw incorrectly, of course.

Nicolas Duhamel said...

first, thank you so much for this script, as it really kicks ass (there are not so much stuff to export from blender to xcode on the web...)

I made a textured cube (UV map texture, unwraped correctly). The model appears as expected in Blender, but if i export and display it (i'm using the template "ship" project, just replaced the ship file), the model is good, but the texture is not. It appears on part of the cube, but some areas are blank and the rest is not aligned as expected.
Is there precaution to take when modeling or texturing?

Nicolas Duhamel said...

Ok i think i have identified the problem.
I've done tests with checker texture to see what is the problem, and it happens that the texture is loaded upside down. So if i do a vertical mirror transform on the texture with Gimp, the texture is mapped correctly on the object.
I've checked the normals of my object on blender but they are good.
Any idea where that comes from? (i can provide mesh and texture if you want)

Nicolas Duhamel said...

Sorry to "flood" this topic, but i'd really like someone to tell me why the texture is loaded upside down (or maybe UV coordinates exported upside down)
There are so many parameters in blender, i believe it is there in front of me, some option to check that flips the UV coordinates.
Many thanks in advance.

Nicolas Duhamel said...

Hi again,
couldn't find the problem so I changed the script, by modifying this line:
out.write('/*t:*/{%f, %f}' % ( uvert.x, 1-uvert.y ) )
Now it works great.
Appart from another problem !!
Vertex normals are wrong when I open the model on the iphone. Also i've veryfied by manual computing that the normal generated by blender are wrong for the vertice.
Take a simple brick 1x1x0.1
vertex normals should be something like {0.577 0.577 0.577}. Well they're not! the are more like {0.40 0.40 0.81}.
Haven't found out yet how to solve this as it seems to be a blender problem...

Martin Cote said...

Am I the only one who has problems with the script? I export a sphere from Blender, but what OpenGL draws is really not the same thing. Every polygon seems to be randomly rotated.

Please advise.

rstar said...

@Nicolas Duhamel – Thanks for the tip. I wonder why it wasn't working.

Winston said...

@Nicolas Duhamel - did you ever figure out how to solve the Blender vertex normals issue? I'm having the same problem. In Blender, once you start modifying a primitive mesh and you turn on vertex normals, you can see that some of them are just not right. But I don't see anyway to modify them manually. Otherwise, this exporter works beautifully for me.

wj said...

@Martin Cote - sounds like some normals may be flipped. From Blender you can try to "re-calculate normals outside" or something like that. You may want to try a simple cube first and see if that works.

Un Fan said...

Well, I tried everything in Blender, recalculating normals, swapping U,V coordinates... The thing is, normals appear to be good when you visualize them in Blender.
So what i did is I changed the script itself to fit my code. I haven't any explanation to why the normal were messed up in my objects when the demo ship model was good, but modifying the script was the only solution i found, and it worked so...

Abhinav said...

I am new to blender and ever time i try to run the script i keep getting the following error

"ImportError: No module named Blender"

Could you help in this regards..

Thanks a lot

alabama said...

Hello Jeff. I use that ncie script to export information about the models with vertex paint. Models made in 3dMax, and converted to a blend (Models were created and converted not by me). When export from Blender to the h file information about vertex paint are not extracted. Instead, the information about the coordinates of the texture is extracted (h file contains static
const TexturedVertexData3D but not ColoredVertexData3D).
In what may be the problem? Is it possible that this is due to the fact that the models were converted into a format blend in 3DMax?

alabama said...

Hello Jeff!
I solved the problem.
Now came another problem.
I want to use that model in my program: http://rapidshare.com/files/386752101/flower.blend.html
When visualizing the model with OpenGL on the model surface are visible artifacts. The screenshots can be seen: http://rapidshare.com/files/386752657/Screenshots.zip.html
I trying to solve that problem last two weeks, but I have no success. For now I have no ideas how this problem can be solved. Can you help me with solution?

Edwin said...

scrub m65 kamagra attorney lawyer body scrub field jacket lovegra marijuana attorney injury lawyer

JeansPilot said...

JeansPilot offers the chance to buy a large variety of men’s and women’s jeans clothing from the world famous Italian Brands.
Online jeans clothing store looks for original fashion clothing sales and clearances of worldwide known designers. We participate in fashion auctions to get the lowest possible price for Top quality Clothes, Shoes and Accessories.
Buy Jeans

Volare said...

Artifacts are because in your glFrustom, you must set the near to something like 5 or 10, when it's too close to 0, you will see artifacts...

h4ns said...

What youre saying is completely true. I know that everybody must say the same thing, but I just think that you put it in a way that everyone can understand. I also love the images you put in here. They fit so well with what youre trying to say. Im sure youll reach so many people with what youve got to say.

Arsenal vs Huddersfield Town live streaming
Arsenal vs Huddersfield Town live streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Notts County vs Manchester City Live Streaming
Notts County vs Manchester City Live Streaming
Bologna vs AS Roma Live Streaming
Bologna vs AS Roma Live Streaming
Juventus vs Udinese Live Streaming
Juventus vs Udinese Live Streaming
Napoli vs Sampdoria Live Streaming
Napoli vs Sampdoria Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
AS Monaco vs Marseille Live Streaming
AS Monaco vs Marseille Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Technology News | News Today | Live Streaming TV Channels