2004-06-21 12:01:23 +00:00
#!BPY
2004-06-07 01:34:15 +00:00
2004-06-21 12:01:23 +00:00
"""
Name : ' Wavefront (.obj)... '
2005-06-13 17:21:30 +00:00
Blender : 232
2004-06-08 04:43:40 +00:00
Group : ' Export '
2004-06-21 12:01:23 +00:00
Tooltip : ' Save a Wavefront OBJ File '
"""
2004-06-07 01:34:15 +00:00
2004-12-12 13:42:49 +00:00
__author__ = " Campbell Barton, Jiri Hnidek "
2004-11-07 16:31:13 +00:00
__url__ = [ " blender " , " elysiun " ]
2005-10-11 02:32:58 +00:00
__version__ = " 1.0 "
2004-11-07 16:31:13 +00:00
__bpydoc__ = """ \
This script is an exporter to OBJ file format .
Usage :
2006-09-25 05:12:37 +00:00
Select the objects you wish to export and run this script from " File->Export " menu .
Selecting the default options from the popup box will be good in most cases .
All objects that can be represented as a mesh ( mesh , curve , metaball , surface , text3d )
will be exported as mesh data .
2004-11-07 16:31:13 +00:00
"""
2004-06-21 12:01:23 +00:00
# --------------------------------------------------------------------------
2006-01-29 19:17:53 +00:00
# OBJ Export v1.0 by Campbell Barton (AKA Ideasman)
2004-06-21 12:01:23 +00:00
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# 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 *****
# --------------------------------------------------------------------------
2005-05-30 02:26:40 +00:00
2006-01-29 19:17:53 +00:00
import Blender
from Blender import Mesh , Scene , Window , sys , Image , Draw
2006-04-07 00:47:39 +00:00
import BPyMesh
2006-10-01 14:02:51 +00:00
import BPyObject
reload ( BPyObject )
2006-09-25 05:12:37 +00:00
import BPyMessages
2006-01-29 19:17:53 +00:00
# Returns a tuple - path,extension.
# 'hello.obj' > ('hello', '.obj')
def splitExt ( path ) :
dotidx = path . rfind ( ' . ' )
if dotidx == - 1 :
return path , ' '
else :
return path [ : dotidx ] , path [ dotidx : ]
2004-06-21 12:01:23 +00:00
2005-10-11 02:32:58 +00:00
def fixName ( name ) :
if name == None :
return ' None '
else :
return name . replace ( ' ' , ' _ ' )
2006-01-29 19:17:53 +00:00
# Used to add the scene name into the filename without using odd chars
def saneFilechars ( name ) :
for ch in ' / \\ ~!@#$ % ^&*()+=[]; \' : " ,./<>? \t \r \n ' :
name = name . replace ( ch , ' _ ' )
return name
2005-10-11 02:32:58 +00:00
global MTL_DICT
# A Dict of Materials
# (material.name, image.name):matname_imagename # matname_imagename has gaps removed.
MTL_DICT = { }
2004-06-21 12:01:23 +00:00
2006-01-29 19:17:53 +00:00
def write_mtl ( filename ) :
2005-10-11 02:32:58 +00:00
global MTL_DICT
2006-01-29 19:17:53 +00:00
world = Blender . World . GetCurrent ( )
2005-10-11 02:32:58 +00:00
if world :
worldAmb = world . getAmb ( )
else :
worldAmb = ( 0 , 0 , 0 ) # Default value
2004-06-21 12:01:23 +00:00
file = open ( filename , " w " )
2006-04-07 00:47:39 +00:00
file . write ( ' # Blender3D MTL File: %s \n ' % Blender . Get ( ' filename ' ) . split ( ' \\ ' ) [ - 1 ] . split ( ' / ' ) [ - 1 ] )
2005-10-11 02:32:58 +00:00
file . write ( ' # Material Count: %i \n ' % len ( MTL_DICT ) )
# Write material/image combinations we have used.
for key , mtl_mat_name in MTL_DICT . iteritems ( ) :
# Get the Blender data for the material and the image.
# Having an image named None will make a bug, dont do it :)
file . write ( ' newmtl %s \n ' % mtl_mat_name ) # Define a new material: matname_imgname
if key [ 0 ] == None :
#write a dummy material here?
file . write ( ' Ns 0 \n ' )
2006-04-07 00:47:39 +00:00
file . write ( ' Ka %.6f %.6f %.6f \n ' % tuple ( [ c for c in worldAmb ] ) ) # Ambient, uses mirror colour,
2005-10-11 02:32:58 +00:00
file . write ( ' Kd 0.8 0.8 0.8 \n ' )
file . write ( ' Ks 0.8 0.8 0.8 \n ' )
file . write ( ' d 1 \n ' ) # No alpha
file . write ( ' illum 2 \n ' ) # light normaly
2004-06-21 12:01:23 +00:00
else :
2006-01-29 19:17:53 +00:00
mat = Blender . Material . Get ( key [ 0 ] )
2006-04-07 00:47:39 +00:00
file . write ( ' Ns %.6f \n ' % ( ( mat . getHardness ( ) - 1 ) * 1.9607843137254901 ) ) # Hardness, convert blenders 1-511 to MTL's
file . write ( ' Ka %.6f %.6f %.6f \n ' % tuple ( [ c * mat . getAmb ( ) for c in worldAmb ] ) ) # Ambient, uses mirror colour,
file . write ( ' Kd %.6f %.6f %.6f \n ' % tuple ( [ c * mat . getRef ( ) for c in mat . getRGBCol ( ) ] ) ) # Diffuse
file . write ( ' Ks %.6f %.6f %.6f \n ' % tuple ( [ c * mat . getSpec ( ) for c in mat . getSpecCol ( ) ] ) ) # Specular
file . write ( ' Ni %.6f \n ' % mat . getIOR ( ) ) # Refraction index
file . write ( ' d %.6f \n ' % mat . getAlpha ( ) ) # Alpha (obj uses 'd' for dissolve)
2005-10-11 02:32:58 +00:00
# 0 to disable lighting, 1 for ambient & diffuse only (specular color set to black), 2 for full lighting.
2006-01-29 19:17:53 +00:00
if mat . getMode ( ) & Blender . Material . Modes [ ' SHADELESS ' ] :
2005-10-11 02:32:58 +00:00
file . write ( ' illum 0 \n ' ) # ignore lighting
elif mat . getSpec ( ) == 0 :
file . write ( ' illum 1 \n ' ) # no specular.
else :
file . write ( ' illum 2 \n ' ) # light normaly
# Write images!
if key [ 1 ] != None : # We have an image on the face!
img = Image . Get ( key [ 1 ] )
file . write ( ' map_Kd %s \n ' % img . filename . split ( ' \\ ' ) [ - 1 ] . split ( ' / ' ) [ - 1 ] ) # Diffuse mapping image
elif key [ 0 ] != None : # No face image. if we havea material search for MTex image.
for mtex in mat . getTextures ( ) :
2006-01-29 19:17:53 +00:00
if mtex and mtex . tex . type == Blender . Texture . Types . IMAGE :
2005-10-11 02:32:58 +00:00
try :
filename = mtex . tex . image . filename . split ( ' \\ ' ) [ - 1 ] . split ( ' / ' ) [ - 1 ]
file . write ( ' map_Kd %s \n ' % filename ) # Diffuse mapping image
break
except :
# Texture has no image though its an image type, best ignore.
pass
file . write ( ' \n \n ' )
2004-06-21 12:01:23 +00:00
file . close ( )
2006-01-29 19:17:53 +00:00
def copy_file ( source , dest ) :
file = open ( source , ' rb ' )
data = file . read ( )
file . close ( )
file = open ( dest , ' wb ' )
file . write ( data )
file . close ( )
2005-10-11 02:32:58 +00:00
2006-01-29 19:17:53 +00:00
def copy_images ( dest_dir ) :
if dest_dir [ - 1 ] != sys . sep :
dest_dir + = sys . sep
2005-10-11 02:32:58 +00:00
2006-01-29 19:17:53 +00:00
# Get unique image names
uniqueImages = { }
for matname , imagename in MTL_DICT . iterkeys ( ) : # Only use image name
2006-04-07 00:47:39 +00:00
# Get Texface images
2006-01-29 19:17:53 +00:00
if imagename != None :
uniqueImages [ imagename ] = None # Should use sets here. wait until Python 2.4 is default.
2006-04-07 00:47:39 +00:00
# Get MTex images
if matname != None :
mat = Material . Get ( matname )
2006-12-16 10:39:08 +00:00
for mtex in mat . getTex * The ambient and emit data we can retrieve from Blender are single values , that this script copies to an RGB triplet , giving shades of gray . A config option can be set to export RGB mirror color as either or both .
* In AC3D 4 " compatibility mode " :
* * Shininess of materials is taken from the shader specularity value in Blender , mapped from [ 0.0 , 2.0 ] to [ 0 , 128 ] .
* * Crease angle is exported , but in Blender it is limited to [ 1 , 80 ] , since there are other more powerful ways to control surface smoothing . In AC3D 4.0 crease ' s range is [0.0, 180.0].
* Blender groups are not supported yet . tures ( ) :
2006-04-10 21:42:18 +00:00
if mtex and mtex . tex . type == Blender . Texture . Types . IMAGE :
try :
uniqueImages [ mtex . tex . image . name ] = None
except :
pass
2006-01-29 19:17:53 +00:00
# Now copy images
copyCount = 0
for imageName in uniqueImages . iterkeys ( ) :
bImage = Image . Get ( imageName )
image_path = sys . expandpath ( bImage . filename )
if sys . exists ( image_path ) :
# Make a name for the target path.
dest_image_path = dest_dir + image_path . split ( ' \\ ' ) [ - 1 ] . split ( ' / ' ) [ - 1 ]
if not sys . exists ( dest_image_path ) : # Image isnt alredy there
print ' \t Copying " %s " > " %s " ' % ( image_path , dest_image_path )
copy_file ( image_path , dest_image_path )
copyCount + = 1
print ' \t Copied %d images ' % copyCount
2006-07-06 12:25:04 +00:00
def veckey3d ( v ) :
return round ( v . x , 6 ) , round ( v . y , 6 ) , round ( v . z , 6 )
def veckey2d ( v ) :
return round ( v . x , 6 ) , round ( v . y , 6 )
2006-01-29 19:17:53 +00:00
def write ( filename , objects , \
2006-07-06 12:25:04 +00:00
EXPORT_TRI = False , EXPORT_EDGES = False , EXPORT_NORMALS = False , EXPORT_NORMALS_HQ = False , \
2006-01-29 19:17:53 +00:00
EXPORT_UV = True , EXPORT_MTL = True , EXPORT_COPY_IMAGES = False , \
2006-08-06 11:32:12 +00:00
EXPORT_APPLY_MODIFIERS = True , EXPORT_ROTX90 = True , EXPORT_BLEN_OBS = True , \
2006-01-29 19:17:53 +00:00
EXPORT_GROUP_BY_OB = False , EXPORT_GROUP_BY_MAT = False ) :
'''
Basic write function . The context and options must be alredy set
This can be accessed externaly
eg .
write ( ' c: \\ test \\ foobar.obj ' , Blender . Object . GetSelected ( ) ) # Using default options.
'''
print ' OBJ Export path: " %s " ' % filename
global MTL_DICT
temp_mesh_name = ' ~tmp-mesh '
2006-04-03 16:14:24 +00:00
2004-09-19 10:41:04 +00:00
time1 = sys . time ( )
2005-05-30 02:26:40 +00:00
scn = Scene . GetCurrent ( )
2004-06-21 12:01:23 +00:00
2004-09-19 10:41:04 +00:00
file = open ( filename , " w " )
2005-08-01 03:06:24 +00:00
2004-09-19 10:41:04 +00:00
# Write Header
2006-09-25 05:12:37 +00:00
file . write ( ' # Blender3D v %s OBJ File: %s \n ' % ( Blender . Get ( ' version ' ) , Blender . Get ( ' filename ' ) . split ( ' / ' ) [ - 1 ] . split ( ' \\ ' ) [ - 1 ] ) )
2006-01-29 19:17:53 +00:00
file . write ( ' # www.blender3d.org \n ' )
2004-09-19 10:41:04 +00:00
# Tell the obj file what material file to use.
2005-10-11 02:32:58 +00:00
mtlfilename = ' %s .mtl ' % ' . ' . join ( filename . split ( ' . ' ) [ : - 1 ] )
2005-05-30 02:26:40 +00:00
file . write ( ' mtllib %s \n ' % ( mtlfilename . split ( ' \\ ' ) [ - 1 ] . split ( ' / ' ) [ - 1 ] ) )
2006-01-29 19:17:53 +00:00
2006-04-02 01:46:10 +00:00
# Get the container mesh. - used for applying modifiers and non mesh objects.
containerMesh = meshName = tempMesh = None
for meshName in Blender . NMesh . GetNames ( ) :
if meshName . startswith ( temp_mesh_name ) :
tempMesh = Mesh . Get ( meshName )
if not tempMesh . users :
containerMesh = tempMesh
if not containerMesh :
containerMesh = Mesh . New ( temp_mesh_name )
2006-10-01 14:02:51 +00:00
if EXPORT_ROTX90 :
mat_xrot90 = Blender . Mathutils . RotationMatrix ( - 90 , 4 , ' x ' )
2006-04-02 01:46:10 +00:00
del meshName
2006-10-01 14:02:51 +00:00
del tempMesh
2006-01-29 19:17:53 +00:00
2004-09-19 10:41:04 +00:00
# Initialize totals, these are updated each object
2005-10-11 02:32:58 +00:00
totverts = totuvco = totno = 1
2005-05-30 02:26:40 +00:00
2005-08-01 03:06:24 +00:00
globalUVCoords = { }
2005-10-11 02:32:58 +00:00
globalNormals = { }
2005-08-01 03:06:24 +00:00
2004-09-19 10:41:04 +00:00
# Get all meshs
2006-10-01 14:02:51 +00:00
for ob_main in objects :
for ob , ob_mat in BPyObject . getDerivedObjects ( ob_main ) :
# Will work for non meshes now! :)
# getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None)
me = BPyMesh . getMeshFromObject ( ob , containerMesh , EXPORT_APPLY_MODIFIERS , False , scn )
if not me :
continue
faceuv = me . faceUV
2006-01-29 19:17:53 +00:00
2006-10-01 14:02:51 +00:00
# We have a valid mesh
if EXPORT_TRI and me . faces :
# Add a dummy object to it.
oldmode = Mesh . Mode ( )
Mesh . Mode ( Mesh . SelectModes [ ' FACE ' ] )
quadcount = 0
for f in me . faces :
if len ( f ) == 4 :
f . sel = True
quadcount + = 1
if quadcount :
tempob = Blender . Object . New ( ' Mesh ' )
tempob . link ( me )
scn . link ( tempob )
me . quadToTriangle ( 0 ) # more=0 shortest length
oldmode = Mesh . Mode ( oldmode )
scn . unlink ( tempob )
Mesh . Mode ( oldmode )
2006-01-29 19:17:53 +00:00
2006-10-01 14:02:51 +00:00
# Make our own list so it can be sorted to reduce context switching
faces = [ f for f in me . faces ]
if EXPORT_EDGES :
edges = me . edges
else :
edges = [ ]
if not ( len ( faces ) + len ( edges ) + len ( me . verts ) ) : # Make sure there is somthing to write
continue # dont bother with this mesh.
if EXPORT_ROTX90 :
me . transform ( ob_mat * mat_xrot90 )
else :
me . transform ( ob_mat )
# High Quality Normals
if EXPORT_NORMALS and EXPORT_NORMALS_HQ and faces :
BPyMesh . meshCalcNormals ( me )
# # Crash Blender
#materials = me.getMaterials(1) # 1 == will return None in the list.
materials = me . materials
materialNames = [ ]
if materials :
for mat in materials :
if mat : # !=None
materialNames . append ( mat . name )
else :
materialNames . append ( None )
# Cant use LC because some materials are None.
# materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken.
# Possible there null materials, will mess up indicies
# but at least it will export, wait until Blender gets fixed.
materialNames . extend ( ( 16 - len ( materialNames ) ) * [ None ] )
2006-01-29 19:17:53 +00:00
2006-10-01 14:02:51 +00:00
# Sort by Material, then images
# so we dont over context switch in the obj file.
if faceuv and EXPORT_UV :
faces . sort ( lambda a , b : cmp ( ( a . mat , a . image , a . smooth ) , ( b . mat , b . image , b . smooth ) ) )
elif len ( materials ) > 1 :
faces . sort ( lambda a , b : cmp ( ( a . mat , a . smooth ) , ( b . mat , b . smooth ) ) )
else :
# no materials
faces . sort ( lambda a , b : cmp ( a . smooth , b . smooth ) )
# Set the default mat to no material and no image.
contextMat = ( 0 , 0 ) # Can never be this, so we will label a new material teh first chance we get.
contextSmooth = None # Will either be true or false, set bad to force initialization switch.
if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB :
obnamestring = ' %s _ %s ' % ( fixName ( ob . name ) , fixName ( ob . getData ( 1 ) ) )
if EXPORT_BLEN_OBS :
file . write ( ' o %s \n ' % obnamestring ) # Write Object name
else : # if EXPORT_GROUP_BY_OB:
file . write ( ' g %s \n ' % obnamestring )
# Vert
for v in me . verts :
2006-08-06 11:32:12 +00:00
file . write ( ' v %.6f %.6f %.6f \n ' % tuple ( v . co ) )
2006-10-01 14:02:51 +00:00
# UV
if faceuv and EXPORT_UV :
for f in faces :
for uvKey in f . uv :
uvKey = veckey2d ( uvKey )
if not globalUVCoords . has_key ( uvKey ) :
globalUVCoords [ uvKey ] = totuvco
totuvco + = 1
file . write ( ' vt %.6f %.6f 0.0 \n ' % uvKey )
# NORMAL, Smooth/Non smoothed.
if EXPORT_NORMALS :
for f in faces :
if f . smooth :
2006-12-12 07:28:20 +00:00
for v in f :
2006-10-01 14:02:51 +00:00
noKey = veckey3d ( v . no )
if not globalNormals . has_key ( noKey ) :
globalNormals [ noKey ] = totno
totno + = 1
file . write ( ' vn %.6f %.6f %.6f \n ' % noKey )
else :
# Hard, 1 normal from the face.
noKey = veckey3d ( f . no )
2006-01-29 19:17:53 +00:00
if not globalNormals . has_key ( noKey ) :
globalNormals [ noKey ] = totno
totno + = 1
2006-08-06 11:32:12 +00:00
file . write ( ' vn %.6f %.6f %.6f \n ' % noKey )
2005-10-11 02:32:58 +00:00
2006-10-01 14:02:51 +00:00
uvIdx = 0
for f in faces :
f_v = f . v
if faceuv :
f_uv = f . uv
# MAKE KEY
if EXPORT_UV and faceuv and f . image : # Object is always true.
key = materialNames [ min ( f . mat , len ( materialNames ) - 1 ) ] , f . image . name
#key = materialNames[f.mat], f.image.name
2006-01-29 19:17:53 +00:00
else :
2006-10-01 14:02:51 +00:00
key = materialNames [ min ( f . mat , len ( materialNames ) - 1 ) ] , None # No image, use None instead.
#key = materialNames[f.mat], None # No image, use None instead.
# CHECK FOR CONTEXT SWITCH
if key == contextMat :
pass # Context alredy switched, dont do anythoing
else :
if key [ 0 ] == None and key [ 1 ] == None :
# Write a null material, since we know the context has changed.
matstring = ' (null) '
file . write ( ' usemtl (null) \n ' ) # mat, image
2006-01-29 19:17:53 +00:00
2006-10-01 14:02:51 +00:00
else :
try : # Faster to try then 2x dict lookups.
# We have the material, just need to write the context switch,
matstring = MTL_DICT [ key ]
except KeyError :
# First add to global dict so we can export to mtl
# Then write mtl
# Make a new names from the mat and image name,
# converting any spaces to underscores with fixName.
# If none image dont bother adding it to the name
if key [ 1 ] == None :
matstring = MTL_DICT [ key ] = ' %s ' % fixName ( key [ 0 ] )
else :
matstring = MTL_DICT [ key ] = ' %s _ %s ' % ( fixName ( key [ 0 ] ) , fixName ( key [ 1 ] ) )
if EXPORT_GROUP_BY_MAT :
file . write ( ' g %s _ %s _ %s \n ' % ( fixName ( ob . name ) , fixName ( ob . getData ( 1 ) ) , matstring ) ) # can be mat_image or (null)
file . write ( ' usemtl %s \n ' % matstring ) # can be mat_image or (null)
contextMat = key
2006-01-29 19:17:53 +00:00
2006-10-01 14:02:51 +00:00
if f . smooth != contextSmooth :
if contextSmooth : # on now off
file . write ( ' s off \n ' )
else : # was off now on
file . write ( ' s 1 \n ' )
contextSmooth = f . smooth
2005-10-11 02:32:58 +00:00
2006-10-01 14:02:51 +00:00
file . write ( ' f ' )
if faceuv and EXPORT_UV :
if EXPORT_NORMALS :
if f . smooth : # Smoothed, use vertex normals
for vi , v in enumerate ( f_v ) :
file . write ( ' %d / %d / %d ' % ( \
v . index + totverts , \
globalUVCoords [ veckey2d ( f_uv [ vi ] ) ] , \
globalNormals [ veckey3d ( v . no ) ] ) ) # vert, uv, normal
else : # No smoothing, face normals
no = globalNormals [ veckey3d ( f . no ) ]
for vi , v in enumerate ( f_v ) :
file . write ( ' %d / %d / %d ' % ( \
v . index + totverts , \
globalUVCoords [ veckey2d ( f_uv [ vi ] ) ] , \
no ) ) # vert, uv, normal
else : # No Normals
2006-06-07 02:10:10 +00:00
for vi , v in enumerate ( f_v ) :
2006-10-01 14:02:51 +00:00
file . write ( ' %d / %d ' % ( \
2006-01-29 19:17:53 +00:00
v . index + totverts , \
2006-10-01 14:02:51 +00:00
globalUVCoords [ veckey2d ( f_uv [ vi ] ) ] ) ) # vert, uv
2006-01-29 19:17:53 +00:00
2006-10-01 14:02:51 +00:00
else : # No UV's
if EXPORT_NORMALS :
if f . smooth : # Smoothed, use vertex normals
for v in f_v :
file . write ( ' %d // %d ' % ( \
v . index + totverts , \
globalNormals [ veckey3d ( v . no ) ] ) )
else : # No smoothing, face normals
no = globalNormals [ veckey3d ( f . no ) ]
for v in f_v :
file . write ( ' %d // %d ' % ( \
v . index + totverts , \
no ) )
else : # No Normals
2006-06-07 02:10:10 +00:00
for v in f_v :
2006-10-01 14:02:51 +00:00
file . write ( ' %d ' % ( \
v . index + totverts ) )
file . write ( ' \n ' )
2006-09-25 05:12:37 +00:00
2006-10-01 14:02:51 +00:00
# Write edges.
if EXPORT_EDGES :
LOOSE = Mesh . EdgeFlags . LOOSE
for ed in edges :
if ed . flag & LOOSE :
file . write ( ' f %d %d \n ' % ( ed . v1 . index + totverts , ed . v2 . index + totverts ) )
# Make the indicies global rather then per mesh
totverts + = len ( me . verts )
me . verts = None
2004-09-19 10:41:04 +00:00
file . close ( )
2005-10-11 02:32:58 +00:00
# Now we have all our materials, save them
2006-01-29 19:17:53 +00:00
if EXPORT_MTL :
write_mtl ( mtlfilename )
if EXPORT_COPY_IMAGES :
dest_dir = filename
# Remove chars until we are just the path.
while dest_dir and dest_dir [ - 1 ] not in ' \\ / ' :
dest_dir = dest_dir [ : - 1 ]
if dest_dir :
copy_images ( dest_dir )
else :
print ' \t Error: " %s " could not be used as a base for an image path. ' % filename
print " OBJ Export time: %.2f " % ( sys . time ( ) - time1 )
2005-10-11 02:32:58 +00:00
2004-08-04 06:16:46 +00:00
2006-01-29 19:17:53 +00:00
def write_ui ( filename ) :
EXPORT_APPLY_MODIFIERS = Draw . Create ( 1 )
2006-08-06 11:32:12 +00:00
EXPORT_ROTX90 = Draw . Create ( 1 )
2006-01-29 19:17:53 +00:00
EXPORT_TRI = Draw . Create ( 0 )
2006-10-01 14:02:51 +00:00
EXPORT_EDGES = Draw . Create ( 1 )
2006-01-29 19:17:53 +00:00
EXPORT_NORMALS = Draw . Create ( 0 )
2006-07-06 12:25:04 +00:00
EXPORT_NORMALS_HQ = Draw . Create ( 0 )
2006-01-29 19:17:53 +00:00
EXPORT_UV = Draw . Create ( 1 )
EXPORT_MTL = Draw . Create ( 1 )
EXPORT_SEL_ONLY = Draw . Create ( 1 )
EXPORT_ALL_SCENES = Draw . Create ( 0 )
EXPORT_ANIMATION = Draw . Create ( 0 )
EXPORT_COPY_IMAGES = Draw . Create ( 0 )
EXPORT_BLEN_OBS = Draw . Create ( 1 )
EXPORT_GROUP_BY_OB = Draw . Create ( 0 )
EXPORT_GROUP_BY_MAT = Draw . Create ( 0 )
# Get USER Options
pup_block = [ \
2006-12-15 22:14:33 +00:00
( ' Context... ' ) , \
( ' Selection Only ' , EXPORT_SEL_ONLY , ' Only export objects in visible selection. Else export whole scene. ' ) , \
2006-12-16 10:39:08 +00:00
( ' All Scenes ' , EXPORT_ALL_SCENES , ' Each scene as a separate OBJ file. ' ) , \
2006-12-15 22:14:33 +00:00
( ' Animation ' , EXPORT_ANIMATION , ' Each frame as a numbered OBJ file. ' ) , \
( ' Object Prefs... ' ) , \
2006-01-29 19:17:53 +00:00
( ' Apply Modifiers ' , EXPORT_APPLY_MODIFIERS , ' Use transformed mesh data from each object. May break vert order for morph targets. ' ) , \
2006-08-06 11:32:12 +00:00
( ' Rotate X90 ' , EXPORT_ROTX90 , ' Rotate on export so Blenders UP is translated into OBJs UP ' ) , \
2006-12-15 22:14:33 +00:00
( ' ' ) , \
( ' Extra Data... ' ) , \
2006-01-29 19:17:53 +00:00
( ' Edges ' , EXPORT_EDGES , ' Edges not connected to faces. ' ) , \
( ' Normals ' , EXPORT_NORMALS , ' Export vertex normal data (Ignored on import). ' ) , \
2006-07-06 12:25:04 +00:00
( ' High Quality Normals ' , EXPORT_NORMALS_HQ , ' Calculate high quality normals for rendering. ' ) , \
2006-01-29 19:17:53 +00:00
( ' UVs ' , EXPORT_UV , ' Export texface UV coords. ' ) , \
2006-04-03 21:48:18 +00:00
( ' Materials ' , EXPORT_MTL , ' Write a separate MTL file with the OBJ. ' ) , \
2006-01-29 19:17:53 +00:00
( ' Copy Images ' , EXPORT_COPY_IMAGES , ' Copy image files to the export directory, never overwrite. ' ) , \
2006-12-15 22:14:33 +00:00
( ' Triangulate ' , EXPORT_TRI , ' Triangulate quads. ' ) , \
2006-01-29 19:17:53 +00:00
( ' Grouping... ' ) , \
2006-07-06 12:25:04 +00:00
( ' Objects ' , EXPORT_BLEN_OBS , ' Export blender objects as " OBJ objects " . ' ) , \
( ' Object Groups ' , EXPORT_GROUP_BY_OB , ' Export blender objects as " OBJ Groups " . ' ) , \
2006-01-29 19:17:53 +00:00
( ' Material Groups ' , EXPORT_GROUP_BY_MAT , ' Group by materials. ' ) , \
]
if not Draw . PupBlock ( ' Export... ' , pup_block ) :
return
2006-09-25 05:12:37 +00:00
Window . EditMode ( 0 )
2006-01-29 19:17:53 +00:00
Window . WaitCursor ( 1 )
EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS . val
2006-08-06 11:32:12 +00:00
EXPORT_ROTX90 = EXPORT_ROTX90 . val
2006-01-29 19:17:53 +00:00
EXPORT_TRI = EXPORT_TRI . val
EXPORT_EDGES = EXPORT_EDGES . val
EXPORT_NORMALS = EXPORT_NORMALS . val
2006-07-06 12:25:04 +00:00
EXPORT_NORMALS_HQ = EXPORT_NORMALS_HQ . val
2006-01-29 19:17:53 +00:00
EXPORT_UV = EXPORT_UV . val
EXPORT_MTL = EXPORT_MTL . val
EXPORT_SEL_ONLY = EXPORT_SEL_ONLY . val
EXPORT_ALL_SCENES = EXPORT_ALL_SCENES . val
EXPORT_ANIMATION = EXPORT_ANIMATION . val
EXPORT_COPY_IMAGES = EXPORT_COPY_IMAGES . val
EXPORT_BLEN_OBS = EXPORT_BLEN_OBS . val
EXPORT_GROUP_BY_OB = EXPORT_GROUP_BY_OB . val
EXPORT_GROUP_BY_MAT = EXPORT_GROUP_BY_MAT . val
base_name , ext = splitExt ( filename )
context_name = [ base_name , ' ' , ' ' , ext ] # basename, scene_name, framenumber, extension
# Use the options to export the data using write()
# def write(filename, objects, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False, EXPORT_APPLY_MODIFIERS=True):
orig_scene = Scene . GetCurrent ( )
if EXPORT_ALL_SCENES :
export_scenes = Scene . Get ( )
else :
export_scenes = [ orig_scene ]
# Export all scenes.
for scn in export_scenes :
scn . makeCurrent ( ) # If alredy current, this is not slow.
context = scn . getRenderingContext ( )
orig_frame = Blender . Get ( ' curframe ' )
if EXPORT_ALL_SCENES : # Add scene name into the context_name
context_name [ 1 ] = ' _ %s ' % saneFilechars ( scn . name ) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied.
# Export an animation?
if EXPORT_ANIMATION :
2006-09-25 05:12:37 +00:00
scene_frames = xrange ( context . startFrame ( ) , context . endFrame ( ) + 1 ) # up to and including the end frame.
2006-01-29 19:17:53 +00:00
else :
scene_frames = [ orig_frame ] # Dont export an animation.
# Loop through all frames in the scene and export.
for frame in scene_frames :
if EXPORT_ANIMATION : # Add frame to the filename.
context_name [ 2 ] = ' _ %.6d ' % frame
Blender . Set ( ' curframe ' , frame )
if EXPORT_SEL_ONLY :
2006-12-15 22:14:33 +00:00
export_objects = scn . objects . context
2006-01-29 19:17:53 +00:00
else :
2006-09-25 05:12:37 +00:00
export_objects = scn . objects # scn.getChildren()
full_path = ' ' . join ( context_name )
2006-01-29 19:17:53 +00:00
2006-09-25 05:12:37 +00:00
if BPyMessages . Warning_SaveOver ( full_path ) :
# EXPORT THE FILE.
write ( full_path , export_objects , \
EXPORT_TRI , EXPORT_EDGES , EXPORT_NORMALS , \
EXPORT_NORMALS_HQ , EXPORT_UV , EXPORT_MTL , \
EXPORT_COPY_IMAGES , EXPORT_APPLY_MODIFIERS , \
EXPORT_ROTX90 , EXPORT_BLEN_OBS , \
EXPORT_GROUP_BY_OB , EXPORT_GROUP_BY_MAT )
2006-01-29 19:17:53 +00:00
Blender . Set ( ' curframe ' , orig_frame )
# Restore old active scene.
orig_scene . makeCurrent ( )
Window . WaitCursor ( 0 )
2005-10-11 02:32:58 +00:00
2006-01-29 19:17:53 +00:00
if __name__ == ' __main__ ' :
Window . FileSelector ( write_ui , ' Export Wavefront OBJ ' , sys . makename ( ext = ' .obj ' ) )