2006-09-04 04:23:55 +00:00
#!BPY
"""
Name : ' Wavefront (.obj)... '
2008-10-19 15:53:22 +00:00
Blender : 248
2006-09-04 04:23:55 +00:00
Group : ' Import '
Tooltip : ' Load a Wavefront OBJ File, Shift: batch import all dir. '
"""
2006-11-03 20:04:56 +00:00
__author__ = " Campbell Barton " , " Jiri Hnidek "
2008-10-19 15:53:22 +00:00
__url__ = [ ' http://wiki.blender.org/index.php/Scripts/Manual/Import/wavefront_obj ' , ' blender.org ' , ' blenderartists.org ' ]
__version__ = " 2.1 "
2006-09-04 04:23:55 +00:00
__bpydoc__ = """ \
2006-09-25 05:12:37 +00:00
This script imports a Wavefront OBJ files to Blender .
2006-09-04 04:23:55 +00:00
Usage :
Run this script from " File->Import " menu and then load the desired OBJ file .
2006-09-25 05:12:37 +00:00
Note , This loads mesh objects and materials only , nurbs and curves are not supported .
2006-09-04 04:23:55 +00:00
"""
2007-02-14 01:03:32 +00:00
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Script copyright (C) Campbell J Barton 2007
#
# 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 *****
# --------------------------------------------------------------------------
2006-09-04 04:23:55 +00:00
from Blender import *
2007-03-27 14:49:37 +00:00
import bpy
2006-09-04 04:23:55 +00:00
import BPyMesh
import BPyImage
2006-09-26 04:39:46 +00:00
import BPyMessages
2006-09-04 04:23:55 +00:00
2006-11-02 17:42:30 +00:00
try : import os
except : os = False
2006-09-25 05:12:37 +00:00
# Generic path functions
2006-09-04 04:23:55 +00:00
def stripFile ( path ) :
''' Return directory, where the file is '''
lastSlash = max ( path . rfind ( ' \\ ' ) , path . rfind ( ' / ' ) )
if lastSlash != - 1 :
path = path [ : lastSlash ]
return ' %s %s ' % ( path , sys . sep )
def stripPath ( path ) :
2006-09-25 05:12:37 +00:00
''' Strips the slashes from the back of a string '''
2006-09-04 04:23:55 +00:00
return path . split ( ' / ' ) [ - 1 ] . split ( ' \\ ' ) [ - 1 ]
def stripExt ( name ) : # name is a string
''' Strips the prefix off the name before writing '''
index = name . rfind ( ' . ' )
if index != - 1 :
return name [ : index ]
else :
return name
# end path funcs
2006-09-25 05:12:37 +00:00
2006-09-04 04:23:55 +00:00
def line_value ( line_split ) :
2006-09-25 05:12:37 +00:00
'''
Returns 1 string represneting the value for this line
None will be returned if theres only 1 word
'''
2006-09-04 04:23:55 +00:00
length = len ( line_split )
if length == 1 :
return None
elif length == 2 :
return line_split [ 1 ]
elif length > 2 :
return ' ' . join ( line_split [ 1 : ] )
2006-09-20 05:03:53 +00:00
def obj_image_load ( imagepath , DIR , IMAGE_SEARCH ) :
'''
Mainly uses comprehensiveImageLoad
but tries to replace ' _ ' with ' ' for Max ' s exporter replaces spaces with underscores.
'''
2006-09-20 17:11:45 +00:00
2006-09-20 05:03:53 +00:00
if ' _ ' in imagepath :
image = BPyImage . comprehensiveImageLoad ( imagepath , DIR , PLACE_HOLDER = False , RECURSIVE = IMAGE_SEARCH )
if image : return image
# Did the exporter rename the image?
image = BPyImage . comprehensiveImageLoad ( imagepath . replace ( ' _ ' , ' ' ) , DIR , PLACE_HOLDER = False , RECURSIVE = IMAGE_SEARCH )
if image : return image
# Return an image, placeholder if it dosnt exist
image = BPyImage . comprehensiveImageLoad ( imagepath , DIR , PLACE_HOLDER = True , RECURSIVE = IMAGE_SEARCH )
return image
2006-09-04 04:23:55 +00:00
2006-09-20 05:03:53 +00:00
def create_materials ( filepath , material_libs , unique_materials , unique_material_images , IMAGE_SEARCH ) :
2006-09-25 05:12:37 +00:00
'''
Create all the used materials in this obj ,
assign colors and images to the materials from all referenced material libs
'''
2006-09-04 04:23:55 +00:00
DIR = stripFile ( filepath )
#==================================================================================#
# This function sets textures defined in .mtl file #
#==================================================================================#
def load_material_image ( blender_material , context_material_name , imagepath , type ) :
2007-04-18 14:40:01 +00:00
texture = bpy . data . textures . new ( type )
2006-09-04 04:23:55 +00:00
texture . setType ( ' Image ' )
# Absolute path - c:\.. etc would work here
2006-09-20 05:03:53 +00:00
image = obj_image_load ( imagepath , DIR , IMAGE_SEARCH )
2006-11-27 23:59:53 +00:00
has_data = image . has_data
2006-10-05 11:15:22 +00:00
texture . image = image
2006-09-04 04:23:55 +00:00
# Adds textures for materials (rendering)
if type == ' Kd ' :
2006-11-27 23:59:53 +00:00
if has_data and image . depth == 32 :
2006-10-05 11:15:22 +00:00
# Image has alpha
blender_material . setTexture ( 0 , texture , Texture . TexCo . UV , Texture . MapTo . COL | Texture . MapTo . ALPHA )
texture . setImageFlags ( ' MipMap ' , ' InterPol ' , ' UseAlpha ' )
blender_material . mode | = Material . Modes . ZTRANSP
blender_material . alpha = 0.0
else :
blender_material . setTexture ( 0 , texture , Texture . TexCo . UV , Texture . MapTo . COL )
2006-09-04 04:23:55 +00:00
# adds textures to faces (Textured/Alt-Z mode)
# Only apply the diffuse texture to the face if the image has not been set with the inline usemat func.
2006-11-27 23:59:53 +00:00
unique_material_images [ context_material_name ] = image , has_data # set the texface image
2006-09-04 04:23:55 +00:00
elif type == ' Ka ' :
blender_material . setTexture ( 1 , texture , Texture . TexCo . UV , Texture . MapTo . CMIR ) # TODO- Add AMB to BPY API
elif type == ' Ks ' :
blender_material . setTexture ( 2 , texture , Texture . TexCo . UV , Texture . MapTo . SPEC )
elif type == ' Bump ' :
blender_material . setTexture ( 3 , texture , Texture . TexCo . UV , Texture . MapTo . NOR )
elif type == ' D ' :
blender_material . setTexture ( 4 , texture , Texture . TexCo . UV , Texture . MapTo . ALPHA )
2006-10-05 11:15:22 +00:00
blender_material . mode | = Material . Modes . ZTRANSP
blender_material . alpha = 0.0
# Todo, unset deffuse material alpha if it has an alpha channel
2006-09-04 04:23:55 +00:00
elif type == ' refl ' :
blender_material . setTexture ( 5 , texture , Texture . TexCo . UV , Texture . MapTo . REF )
# Add an MTL with the same name as the obj if no MTLs are spesified.
temp_mtl = stripExt ( stripPath ( filepath ) ) + ' .mtl '
2006-09-20 17:11:45 +00:00
if sys . exists ( DIR + temp_mtl ) and temp_mtl not in material_libs :
2006-09-04 04:23:55 +00:00
material_libs . append ( temp_mtl )
del temp_mtl
#Create new materials
for name in unique_materials . iterkeys ( ) :
2007-04-18 14:40:01 +00:00
unique_materials [ name ] = bpy . data . materials . new ( name )
2006-09-04 04:23:55 +00:00
2006-11-27 23:59:53 +00:00
unique_material_images [ name ] = None , False # assign None to all material images to start with, add to later.
2006-09-04 04:23:55 +00:00
unique_materials [ None ] = None
for libname in material_libs :
mtlpath = DIR + libname
if not sys . exists ( mtlpath ) :
#print '\tError Missing MTL: "%s"' % mtlpath
pass
else :
#print '\t\tloading mtl: "%s"' % mtlpath
context_material = None
2008-09-25 13:17:56 +00:00
mtl = open ( mtlpath , ' rU ' )
2007-05-29 04:15:45 +00:00
for line in mtl : #.xreadlines():
2006-09-04 04:23:55 +00:00
if line . startswith ( ' newmtl ' ) :
context_material_name = line_value ( line . split ( ) )
if unique_materials . has_key ( context_material_name ) :
context_material = unique_materials [ context_material_name ]
else :
context_material = None
elif context_material :
# we need to make a material to assign properties to it.
line_split = line . split ( )
2008-09-25 13:17:56 +00:00
line_lower = line . lower ( ) . lstrip ( )
2006-10-05 11:15:22 +00:00
if line_lower . startswith ( ' ka ' ) :
2006-09-04 04:23:55 +00:00
context_material . setMirCol ( ( float ( line_split [ 1 ] ) , float ( line_split [ 2 ] ) , float ( line_split [ 3 ] ) ) )
2006-10-05 11:15:22 +00:00
elif line_lower . startswith ( ' kd ' ) :
2006-09-04 04:23:55 +00:00
context_material . setRGBCol ( ( float ( line_split [ 1 ] ) , float ( line_split [ 2 ] ) , float ( line_split [ 3 ] ) ) )
2006-10-05 11:15:22 +00:00
elif line_lower . startswith ( ' ks ' ) :
2006-09-04 04:23:55 +00:00
context_material . setSpecCol ( ( float ( line_split [ 1 ] ) , float ( line_split [ 2 ] ) , float ( line_split [ 3 ] ) ) )
2006-10-05 11:15:22 +00:00
elif line_lower . startswith ( ' ns ' ) :
2006-09-04 04:23:55 +00:00
context_material . setHardness ( int ( ( float ( line_split [ 1 ] ) * 0.51 ) ) )
2006-10-05 11:15:22 +00:00
elif line_lower . startswith ( ' ni ' ) : # Refraction index
2006-09-04 04:23:55 +00:00
context_material . setIOR ( max ( 1 , min ( float ( line_split [ 1 ] ) , 3 ) ) ) # Between 1 and 3
2006-10-05 11:15:22 +00:00
elif line_lower . startswith ( ' d ' ) or line_lower . startswith ( ' tr ' ) :
2006-09-04 04:23:55 +00:00
context_material . setAlpha ( float ( line_split [ 1 ] ) )
2006-10-05 11:15:22 +00:00
elif line_lower . startswith ( ' map_ka ' ) :
2006-09-04 04:23:55 +00:00
img_filepath = line_value ( line . split ( ) )
2007-03-29 14:35:01 +00:00
if img_filepath :
load_material_image ( context_material , context_material_name , img_filepath , ' Ka ' )
2006-10-05 11:15:22 +00:00
elif line_lower . startswith ( ' map_ks ' ) :
2006-09-04 04:23:55 +00:00
img_filepath = line_value ( line . split ( ) )
2007-03-29 14:35:01 +00:00
if img_filepath :
load_material_image ( context_material , context_material_name , img_filepath , ' Ks ' )
2006-10-05 11:15:22 +00:00
elif line_lower . startswith ( ' map_kd ' ) :
2006-09-04 04:23:55 +00:00
img_filepath = line_value ( line . split ( ) )
2007-03-29 14:35:01 +00:00
if img_filepath :
load_material_image ( context_material , context_material_name , img_filepath , ' Kd ' )
2006-10-05 11:15:22 +00:00
elif line_lower . startswith ( ' map_bump ' ) :
2006-09-04 04:23:55 +00:00
img_filepath = line_value ( line . split ( ) )
2007-03-29 14:35:01 +00:00
if img_filepath :
load_material_image ( context_material , context_material_name , img_filepath , ' Bump ' )
2006-10-05 11:15:22 +00:00
elif line_lower . startswith ( ' map_d ' ) or line_lower . startswith ( ' map_tr ' ) : # Alpha map - Dissolve
2006-09-04 04:23:55 +00:00
img_filepath = line_value ( line . split ( ) )
2007-03-29 14:35:01 +00:00
if img_filepath :
load_material_image ( context_material , context_material_name , img_filepath , ' D ' )
2006-09-04 04:23:55 +00:00
2006-10-05 11:15:22 +00:00
elif line_lower . startswith ( ' refl ' ) : # Reflectionmap
2006-09-04 04:23:55 +00:00
img_filepath = line_value ( line . split ( ) )
2007-03-29 14:35:01 +00:00
if img_filepath :
load_material_image ( context_material , context_material_name , img_filepath , ' refl ' )
2006-09-04 04:23:55 +00:00
mtl . close ( )
2006-10-05 11:15:22 +00:00
2007-01-13 03:07:04 +00:00
2007-04-14 17:44:50 +00:00
def split_mesh ( verts_loc , faces , unique_materials , filepath , SPLIT_OB_OR_GROUP , SPLIT_MATERIALS ) :
2006-09-25 05:12:37 +00:00
'''
Takes vert_loc and faces , and seperates into multiple sets of
2007-01-13 03:07:04 +00:00
( verts_loc , faces , unique_materials , dataname )
2006-09-25 05:12:37 +00:00
This is done so objects do not overload the 16 material limit .
'''
2007-01-13 03:07:04 +00:00
filename = stripExt ( stripPath ( filepath ) )
2007-04-14 17:44:50 +00:00
if not SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS :
2007-01-13 03:07:04 +00:00
# use the filename for the object name since we arnt chopping up the mesh.
return [ ( verts_loc , faces , unique_materials , filename ) ]
2006-09-04 04:23:55 +00:00
2007-01-13 03:07:04 +00:00
def key_to_name ( key ) :
# if the key is a tuple, join it to make a string
if type ( key ) == tuple :
return ' %s _ %s ' % key
elif not key :
return filename # assume its a string. make sure this is true if the splitting code is changed
else :
return key
2006-09-04 04:23:55 +00:00
# Return a key that makes the faces unique.
2007-04-14 17:44:50 +00:00
if SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS :
2006-09-04 04:23:55 +00:00
def face_key ( face ) :
return face [ 4 ] # object
2007-04-15 05:01:34 +00:00
elif not SPLIT_OB_OR_GROUP and SPLIT_MATERIALS :
2006-09-04 04:23:55 +00:00
def face_key ( face ) :
return face [ 2 ] # material
else : # Both
def face_key ( face ) :
2007-01-13 03:07:04 +00:00
return face [ 4 ] , face [ 2 ] # object,material
2006-09-04 04:23:55 +00:00
face_split_dict = { }
2007-01-26 06:02:21 +00:00
oldkey = - 1 # initialize to a value that will never match the key
2006-09-04 04:23:55 +00:00
for face in faces :
key = face_key ( face )
if oldkey != key :
# Check the key has changed.
try :
2007-01-13 03:07:04 +00:00
verts_split , faces_split , unique_materials_split , vert_remap = face_split_dict [ key ]
2006-09-04 04:23:55 +00:00
except KeyError :
faces_split = [ ]
verts_split = [ ]
unique_materials_split = { }
vert_remap = [ - 1 ] * len ( verts_loc )
2007-01-13 03:07:04 +00:00
face_split_dict [ key ] = ( verts_split , faces_split , unique_materials_split , vert_remap )
2007-04-15 05:01:34 +00:00
2006-09-04 04:23:55 +00:00
oldkey = key
face_vert_loc_indicies = face [ 0 ]
# Remap verts to new vert list and add where needed
for enum , i in enumerate ( face_vert_loc_indicies ) :
if vert_remap [ i ] == - 1 :
new_index = len ( verts_split )
vert_remap [ i ] = new_index # set the new remapped index so we only add once and can reference next time.
face_vert_loc_indicies [ enum ] = new_index # remap to the local index
verts_split . append ( verts_loc [ i ] ) # add the vert to the local verts
else :
face_vert_loc_indicies [ enum ] = vert_remap [ i ] # remap to the local index
matname = face [ 2 ]
if matname and not unique_materials_split . has_key ( matname ) :
unique_materials_split [ matname ] = unique_materials [ matname ]
faces_split . append ( face )
# remove one of the itemas and reorder
2007-01-13 03:07:04 +00:00
return [ ( value [ 0 ] , value [ 1 ] , value [ 2 ] , key_to_name ( key ) ) for key , value in face_split_dict . iteritems ( ) ]
2006-09-04 04:23:55 +00:00
2007-04-14 17:44:50 +00:00
def create_mesh ( scn , new_objects , has_ngons , CREATE_FGONS , CREATE_EDGES , verts_loc , verts_tex , faces , unique_materials , unique_material_images , unique_smooth_groups , dataname ) :
2006-09-25 05:12:37 +00:00
'''
Takes all the data gathered and generates a mesh , adding the new object to new_objects
deals with fgons , sharp edges and assigning materials
'''
2006-09-04 04:23:55 +00:00
if not has_ngons :
CREATE_FGONS = False
if unique_smooth_groups :
sharp_edges = { }
smooth_group_users = dict ( [ ( context_smooth_group , { } ) for context_smooth_group in unique_smooth_groups . iterkeys ( ) ] )
context_smooth_group_old = - 1
# Split fgons into tri's
fgon_edges = { } # Used for storing fgon keys
if CREATE_EDGES :
edges = [ ]
context_object = None
# reverse loop through face indicies
for f_idx in xrange ( len ( faces ) - 1 , - 1 , - 1 ) :
face_vert_loc_indicies , \
face_vert_tex_indicies , \
context_material , \
context_smooth_group , \
context_object = faces [ f_idx ]
len_face_vert_loc_indicies = len ( face_vert_loc_indicies )
if len_face_vert_loc_indicies == 1 :
faces . pop ( f_idx ) # cant add single vert faces
2007-01-26 06:02:21 +00:00
elif not face_vert_tex_indicies or len_face_vert_loc_indicies == 2 : # faces that have no texture coords are lines
2006-09-04 04:23:55 +00:00
if CREATE_EDGES :
2006-11-25 17:34:57 +00:00
# generators are better in python 2.4+ but can't be used in 2.3
# edges.extend( (face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1) )
edges . extend ( [ ( face_vert_loc_indicies [ i ] , face_vert_loc_indicies [ i + 1 ] ) for i in xrange ( len_face_vert_loc_indicies - 1 ) ] )
2007-01-26 06:02:21 +00:00
faces . pop ( f_idx )
2006-09-04 04:23:55 +00:00
else :
# Smooth Group
2007-01-26 06:02:21 +00:00
if unique_smooth_groups and context_smooth_group :
2006-09-04 04:23:55 +00:00
# Is a part of of a smooth group and is a face
if context_smooth_group_old is not context_smooth_group :
edge_dict = smooth_group_users [ context_smooth_group ]
context_smooth_group_old = context_smooth_group
for i in xrange ( len_face_vert_loc_indicies ) :
i1 = face_vert_loc_indicies [ i ]
i2 = face_vert_loc_indicies [ i - 1 ]
if i1 > i2 : i1 , i2 = i2 , i1
try :
edge_dict [ i1 , i2 ] + = 1
except KeyError :
edge_dict [ i1 , i2 ] = 1
# FGons into triangles
if has_ngons and len_face_vert_loc_indicies > 4 :
ngon_face_indices = BPyMesh . ngon ( verts_loc , face_vert_loc_indicies )
faces . extend ( \
[ ( \
[ face_vert_loc_indicies [ ngon [ 0 ] ] , face_vert_loc_indicies [ ngon [ 1 ] ] , face_vert_loc_indicies [ ngon [ 2 ] ] ] , \
[ face_vert_tex_indicies [ ngon [ 0 ] ] , face_vert_tex_indicies [ ngon [ 1 ] ] , face_vert_tex_indicies [ ngon [ 2 ] ] ] , \
context_material , \
context_smooth_group , \
context_object ) \
for ngon in ngon_face_indices ] \
)
# edges to make fgons
if CREATE_FGONS :
edge_users = { }
for ngon in ngon_face_indices :
for i in ( 0 , 1 , 2 ) :
i1 = face_vert_loc_indicies [ ngon [ i ] ]
i2 = face_vert_loc_indicies [ ngon [ i - 1 ] ]
if i1 > i2 : i1 , i2 = i2 , i1
try :
edge_users [ i1 , i2 ] + = 1
except KeyError :
edge_users [ i1 , i2 ] = 1
for key , users in edge_users . iteritems ( ) :
if users > 1 :
fgon_edges [ key ] = None
# remove all after 3, means we dont have to pop this one.
faces . pop ( f_idx )
# Build sharp edges
if unique_smooth_groups :
for edge_dict in smooth_group_users . itervalues ( ) :
for key , users in edge_dict . iteritems ( ) :
if users == 1 : # This edge is on the boundry of a group
sharp_edges [ key ] = None
# mat the material names to an index
material_mapping = dict ( [ ( name , i ) for i , name in enumerate ( unique_materials . keys ( ) ) ] )
materials = [ None ] * len ( unique_materials )
for name , index in material_mapping . iteritems ( ) :
materials [ index ] = unique_materials [ name ]
2007-04-18 14:40:01 +00:00
me = bpy . data . meshes . new ( dataname )
2006-09-04 04:23:55 +00:00
me . materials = materials [ 0 : 16 ] # make sure the list isnt too big.
#me.verts.extend([(0,0,0)]) # dummy vert
me . verts . extend ( verts_loc )
face_mapping = me . faces . extend ( [ f [ 0 ] for f in faces ] , indexList = True )
if verts_tex and me . faces :
me . faceUV = 1
# TEXMODE= Mesh.FaceModes['TEX']
context_material_old = - 1 # avoid a dict lookup
mat = 0 # rare case it may be un-initialized.
me_faces = me . faces
2006-10-05 11:15:22 +00:00
ALPHA = Mesh . FaceTranspModes . ALPHA
2006-09-04 04:23:55 +00:00
for i , face in enumerate ( faces ) :
2007-01-26 06:02:21 +00:00
if len ( face [ 0 ] ) < 2 :
2007-04-14 17:44:50 +00:00
pass #raise "bad face"
elif len ( face [ 0 ] ) == 2 :
2006-09-04 04:23:55 +00:00
if CREATE_EDGES :
edges . append ( face [ 0 ] )
else :
face_index_map = face_mapping [ i ]
if face_index_map != None : # None means the face wasnt added
2007-01-26 06:02:21 +00:00
blender_face = me_faces [ face_index_map ]
2006-09-04 04:23:55 +00:00
face_vert_loc_indicies , \
face_vert_tex_indicies , \
context_material , \
context_smooth_group , \
context_object = face
2007-01-26 06:02:21 +00:00
2006-09-04 04:23:55 +00:00
if context_smooth_group :
blender_face . smooth = True
if context_material :
if context_material_old is not context_material :
mat = material_mapping [ context_material ]
if mat > 15 :
mat = 15
context_material_old = context_material
blender_face . mat = mat
if verts_tex :
if context_material :
2006-11-27 23:59:53 +00:00
image , has_data = unique_material_images [ context_material ]
2006-09-04 04:23:55 +00:00
if image : # Can be none if the material dosnt have an image.
blender_face . image = image
2006-11-27 23:59:53 +00:00
if has_data and image . depth == 32 :
2006-10-05 11:15:22 +00:00
blender_face . transp | = ALPHA
2006-09-04 04:23:55 +00:00
# BUG - Evil eekadoodle problem where faces that have vert index 0 location at 3 or 4 are shuffled.
if len ( face_vert_loc_indicies ) == 4 :
if face_vert_loc_indicies [ 2 ] == 0 or face_vert_loc_indicies [ 3 ] == 0 :
face_vert_tex_indicies = face_vert_tex_indicies [ 2 ] , face_vert_tex_indicies [ 3 ] , face_vert_tex_indicies [ 0 ] , face_vert_tex_indicies [ 1 ]
else : # length of 3
if face_vert_loc_indicies [ 2 ] == 0 :
face_vert_tex_indicies = face_vert_tex_indicies [ 1 ] , face_vert_tex_indicies [ 2 ] , face_vert_tex_indicies [ 0 ]
# END EEEKADOODLE FIX
# assign material, uv's and image
for ii , uv in enumerate ( blender_face . uv ) :
uv . x , uv . y = verts_tex [ face_vert_tex_indicies [ ii ] ]
del me_faces
2006-10-05 11:15:22 +00:00
del ALPHA
2006-09-04 04:23:55 +00:00
# Add edge faces.
me_edges = me . edges
if CREATE_FGONS and fgon_edges :
FGON = Mesh . EdgeFlags . FGON
for ed in me . findEdges ( fgon_edges . keys ( ) ) :
if ed != None :
me_edges [ ed ] . flag | = FGON
del FGON
if unique_smooth_groups and sharp_edges :
SHARP = Mesh . EdgeFlags . SHARP
for ed in me . findEdges ( sharp_edges . keys ( ) ) :
if ed != None :
me_edges [ ed ] . flag | = SHARP
del SHARP
if CREATE_EDGES :
2007-01-26 06:02:21 +00:00
me_edges . extend ( edges )
del me_edges
2006-09-04 04:23:55 +00:00
2006-12-28 22:56:24 +00:00
me . calcNormals ( )
2006-09-04 04:23:55 +00:00
ob = scn . objects . new ( me )
2006-09-05 06:45:39 +00:00
new_objects . append ( ob )
2006-09-04 04:23:55 +00:00
def get_float_func ( filepath ) :
'''
find the float function for this obj file
- weather to replace commas or not
'''
2007-08-01 18:04:44 +00:00
file = open ( filepath , ' rU ' )
2007-05-29 04:15:45 +00:00
for line in file : #.xreadlines():
2006-09-04 04:23:55 +00:00
if line . startswith ( ' v ' ) : # vn vt v
if ' , ' in line :
return lambda f : float ( f . replace ( ' , ' , ' . ' ) )
elif ' . ' in line :
return float
2007-12-19 07:44:37 +00:00
# incase all vert values were ints
return float
2006-09-04 04:23:55 +00:00
2006-09-20 05:03:53 +00:00
def load_obj ( filepath , CLAMP_SIZE = 0.0 , CREATE_FGONS = True , CREATE_SMOOTH_GROUPS = True , CREATE_EDGES = True , SPLIT_OBJECTS = True , SPLIT_GROUPS = True , SPLIT_MATERIALS = True , IMAGE_SEARCH = True ) :
2006-09-25 05:12:37 +00:00
'''
Called by the user interface or another script .
load_obj ( path ) - should give acceptable results .
This function passes the file and sends the data off
to be split into objects and then converted into mesh objects
'''
2006-09-04 04:23:55 +00:00
print ' \n importing obj " %s " ' % filepath
time_main = sys . time ( )
verts_loc = [ ]
verts_tex = [ ]
faces = [ ] # tuples of the faces
material_libs = [ ] # filanems to material libs this uses
# Get the string to float conversion func for this file- is 'float' for almost all files.
float_func = get_float_func ( filepath )
# Context variables
context_material = None
context_smooth_group = None
context_object = None
has_ngons = False
# has_smoothgroups= False - is explicit with len(unique_smooth_groups) being > 0
# Until we can use sets
unique_materials = { }
unique_material_images = { }
unique_smooth_groups = { }
# unique_obects= {} - no use for this variable since the objects are stored in the face.
# when there are faces that end with \
# it means they are multiline-
# since we use xreadline we cant skip to the next line
# so we need to know weather
multi_line_face = False
print ' \t passing obj file " %s " ... ' % filepath ,
time_sub = sys . time ( )
2008-09-25 13:17:56 +00:00
file = open ( filepath , ' rU ' )
2007-05-29 04:15:45 +00:00
for line in file : #.xreadlines():
2006-09-04 04:23:55 +00:00
if line . startswith ( ' v ' ) :
line_split = line . split ( )
# rotate X90: (x,-z,y)
verts_loc . append ( ( float_func ( line_split [ 1 ] ) , - float_func ( line_split [ 3 ] ) , float_func ( line_split [ 2 ] ) ) )
elif line . startswith ( ' vn ' ) :
pass
elif line . startswith ( ' vt ' ) :
line_split = line . split ( )
verts_tex . append ( ( float_func ( line_split [ 1 ] ) , float_func ( line_split [ 2 ] ) ) )
# Handel faces lines (as faces) and the second+ lines of fa multiline face here
# use 'f' not 'f ' because some objs (very rare have 'fo ' for faces)
elif line . startswith ( ' f ' ) or ( line . startswith ( ' l ' ) and CREATE_EDGES ) or multi_line_face :
if multi_line_face :
# use face_vert_loc_indicies and face_vert_tex_indicies previously defined and used the obj_face
line_split = line . split ( )
multi_line_face = False
else :
line_split = line [ 2 : ] . split ( )
face_vert_loc_indicies = [ ]
face_vert_tex_indicies = [ ]
# Instance a face
faces . append ( ( \
face_vert_loc_indicies , \
face_vert_tex_indicies , \
context_material , \
context_smooth_group , \
context_object \
) )
if line_split [ - 1 ] [ - 1 ] == ' \\ ' :
multi_line_face = True
if len ( line_split [ - 1 ] ) == 1 :
line_split . pop ( ) # remove the \ item
else :
line_split [ - 1 ] = line_split [ - 1 ] [ : - 1 ] # remove the \ from the end last number
isline = line . startswith ( ' l ' )
for v in line_split :
obj_vert = v . split ( ' / ' )
vert_loc_index = int ( obj_vert [ 0 ] ) - 1
# Make relative negative vert indicies absolute
if vert_loc_index < 0 :
vert_loc_index = len ( verts_loc ) + vert_loc_index + 1
face_vert_loc_indicies . append ( vert_loc_index )
if not isline :
if len ( obj_vert ) > 1 and obj_vert [ 1 ] :
# formatting for faces with normals and textures us
# loc_index/tex_index/nor_index
vert_tex_index = int ( obj_vert [ 1 ] ) - 1
# Make relative negative vert indicies absolute
if vert_tex_index < 0 :
vert_tex_index = len ( verts_tex ) + vert_tex_index + 1
face_vert_tex_indicies . append ( vert_tex_index )
else :
# dummy
face_vert_tex_indicies . append ( 0 )
if len ( face_vert_loc_indicies ) > 4 :
has_ngons = True
elif line . startswith ( ' s ' ) :
if CREATE_SMOOTH_GROUPS :
context_smooth_group = line_value ( line . split ( ) )
if context_smooth_group == ' off ' :
context_smooth_group = None
elif context_smooth_group : # is not None
unique_smooth_groups [ context_smooth_group ] = None
elif line . startswith ( ' o ' ) :
if SPLIT_OBJECTS :
context_object = line_value ( line . split ( ) )
# unique_obects[context_object]= None
elif line . startswith ( ' g ' ) :
if SPLIT_GROUPS :
context_object = line_value ( line . split ( ) )
# print 'context_object', context_object
# unique_obects[context_object]= None
elif line . startswith ( ' usemtl ' ) :
context_material = line_value ( line . split ( ) )
unique_materials [ context_material ] = None
elif line . startswith ( ' mtllib ' ) : # usemap or usemat
material_libs . extend ( line . split ( ) [ 1 : ] ) # can have multiple mtllib filenames per line
''' # How to use usemap? depricated?
elif line . startswith ( ' usema ' ) : # usemap or usemat
context_image = line_value ( line . split ( ) )
'''
file . close ( )
time_new = sys . time ( )
print ' %.4f sec ' % ( time_new - time_sub )
time_sub = time_new
print ' \t loading materials and images... ' ,
2006-09-20 05:03:53 +00:00
create_materials ( filepath , material_libs , unique_materials , unique_material_images , IMAGE_SEARCH )
2006-09-04 04:23:55 +00:00
time_new = sys . time ( )
print ' %.4f sec ' % ( time_new - time_sub )
time_sub = time_new
# deselect all
2007-04-18 14:40:01 +00:00
scn = bpy . data . scenes . active
2007-04-14 17:44:50 +00:00
scn . objects . selected = [ ]
2006-09-05 06:45:39 +00:00
new_objects = [ ] # put new objects here
2006-09-04 04:23:55 +00:00
2007-01-26 06:02:21 +00:00
print ' \t building geometry... \n \t verts: %i faces: %i materials: %i smoothgroups: %i ... ' % ( len ( verts_loc ) , len ( faces ) , len ( unique_materials ) , len ( unique_smooth_groups ) ) ,
2006-09-04 04:23:55 +00:00
# Split the mesh by objects/materials, may
2007-04-14 17:44:50 +00:00
if SPLIT_OBJECTS or SPLIT_GROUPS : SPLIT_OB_OR_GROUP = True
else : SPLIT_OB_OR_GROUP = False
for verts_loc_split , faces_split , unique_materials_split , dataname in split_mesh ( verts_loc , faces , unique_materials , filepath , SPLIT_OB_OR_GROUP , SPLIT_MATERIALS ) :
2006-09-04 04:23:55 +00:00
# Create meshes from the data
2007-04-14 17:44:50 +00:00
create_mesh ( scn , new_objects , has_ngons , CREATE_FGONS , CREATE_EDGES , verts_loc_split , verts_tex , faces_split , unique_materials_split , unique_material_images , unique_smooth_groups , dataname )
2006-09-05 06:45:39 +00:00
axis_min = [ 1000000000 ] * 3
axis_max = [ - 1000000000 ] * 3
if CLAMP_SIZE :
# Get all object bounds
for ob in new_objects :
for v in ob . getBoundBox ( ) :
for axis , value in enumerate ( v ) :
if axis_min [ axis ] > value : axis_min [ axis ] = value
if axis_max [ axis ] < value : axis_max [ axis ] = value
# Scale objects
max_axis = max ( axis_max [ 0 ] - axis_min [ 0 ] , axis_max [ 1 ] - axis_min [ 1 ] , axis_max [ 2 ] - axis_min [ 2 ] )
scale = 1.0
while CLAMP_SIZE < max_axis * scale :
scale = scale / 10.0
for ob in new_objects :
ob . setSize ( scale , scale , scale )
2006-09-04 04:23:55 +00:00
time_new = sys . time ( )
2006-09-05 06:45:39 +00:00
print ' %.4f sec ' % ( time_new - time_sub )
2006-09-04 04:23:55 +00:00
print ' finished importing: " %s " in %.4f sec. ' % ( filepath , ( time_new - time_main ) )
DEBUG = True
2006-11-02 17:42:30 +00:00
def load_obj_ui ( filepath , BATCH_LOAD = False ) :
2006-09-26 04:39:46 +00:00
if BPyMessages . Error_NoFile ( filepath ) :
return
2008-10-19 15:53:22 +00:00
global CREATE_SMOOTH_GROUPS , CREATE_FGONS , CREATE_EDGES , SPLIT_OBJECTS , SPLIT_GROUPS , SPLIT_MATERIALS , CLAMP_SIZE , IMAGE_SEARCH , KEEP_VERT_ORDER
2007-01-26 07:01:30 +00:00
2006-09-04 04:23:55 +00:00
CREATE_SMOOTH_GROUPS = Draw . Create ( 0 )
CREATE_FGONS = Draw . Create ( 1 )
CREATE_EDGES = Draw . Create ( 1 )
2008-10-19 15:53:22 +00:00
SPLIT_OBJECTS = Draw . Create ( 0 )
SPLIT_GROUPS = Draw . Create ( 0 )
SPLIT_MATERIALS = Draw . Create ( 0 )
2006-09-05 06:45:39 +00:00
CLAMP_SIZE = Draw . Create ( 10.0 )
2006-09-20 05:03:53 +00:00
IMAGE_SEARCH = Draw . Create ( 1 )
2008-10-19 15:53:22 +00:00
KEEP_VERT_ORDER = Draw . Create ( 1 )
2006-09-05 06:45:39 +00:00
2006-09-04 04:23:55 +00:00
# Get USER Options
2008-10-19 15:53:22 +00:00
# Note, Works but not pretty, instead use a more complicated GUI
'''
2006-09-04 04:23:55 +00:00
pup_block = [ \
2007-01-26 07:01:30 +00:00
' Import... ' , \
2006-09-04 04:23:55 +00:00
( ' Smooth Groups ' , CREATE_SMOOTH_GROUPS , ' Surround smooth groups by sharp edges ' ) , \
( ' Create FGons ' , CREATE_FGONS , ' Import faces with more then 4 verts as fgons. ' ) , \
( ' Lines ' , CREATE_EDGES , ' Import lines and faces with 2 verts as edges ' ) , \
2007-04-14 17:44:50 +00:00
' Separate objects from obj... ' , \
2007-01-26 07:01:30 +00:00
( ' Object ' , SPLIT_OBJECTS , ' Import OBJ Objects into Blender Objects ' ) , \
( ' Group ' , SPLIT_GROUPS , ' Import OBJ Groups into Blender Objects ' ) , \
( ' Material ' , SPLIT_MATERIALS , ' Import each material into a seperate mesh (Avoids > 16 per mesh error) ' ) , \
' Options... ' , \
2008-09-17 04:07:58 +00:00
( ' Keep Vert Order ' , KEEP_VERT_ORDER , ' Keep vert and face order, disables some other options. ' ) , \
2006-09-05 06:45:39 +00:00
( ' Clamp Scale: ' , CLAMP_SIZE , 0.0 , 1000.0 , ' Clamp the size to this maximum (Zero to Disable) ' ) , \
2006-09-20 05:03:53 +00:00
( ' Image Search ' , IMAGE_SEARCH , ' Search subdirs for any assosiated images (Warning, may be slow) ' ) , \
2006-09-04 04:23:55 +00:00
]
if not Draw . PupBlock ( ' Import OBJ... ' , pup_block ) :
return
2008-09-17 04:07:58 +00:00
if KEEP_VERT_ORDER . val :
2007-01-26 07:01:30 +00:00
SPLIT_OBJECTS . val = False
SPLIT_GROUPS . val = False
SPLIT_MATERIALS . val = False
2008-10-19 15:53:22 +00:00
'''
# BEGIN ALTERNATIVE UI *******************
if True :
EVENT_NONE = 0
EVENT_EXIT = 1
EVENT_REDRAW = 2
EVENT_IMPORT = 3
GLOBALS = { }
GLOBALS [ ' EVENT ' ] = EVENT_REDRAW
#GLOBALS['MOUSE'] = Window.GetMouseCoords()
GLOBALS [ ' MOUSE ' ] = [ i / 2 for i in Window . GetScreenSize ( ) ]
def obj_ui_set_event ( e , v ) :
GLOBALS [ ' EVENT ' ] = e
def do_split ( e , v ) :
global SPLIT_OBJECTS , SPLIT_GROUPS , SPLIT_MATERIALS , KEEP_VERT_ORDER
if SPLIT_OBJECTS . val or SPLIT_GROUPS . val or SPLIT_MATERIALS . val :
KEEP_VERT_ORDER . val = 0
else :
KEEP_VERT_ORDER . val = 1
def do_vertorder ( e , v ) :
global SPLIT_OBJECTS , SPLIT_GROUPS , SPLIT_MATERIALS , KEEP_VERT_ORDER
if KEEP_VERT_ORDER . val :
SPLIT_OBJECTS . val = SPLIT_GROUPS . val = SPLIT_MATERIALS . val = 0
else :
if not ( SPLIT_OBJECTS . val or SPLIT_GROUPS . val or SPLIT_MATERIALS . val ) :
KEEP_VERT_ORDER . val = 1
def do_help ( e , v ) :
url = __url__ [ 0 ]
print ' Trying to open web browser with documentation at this address... '
print ' \t ' + url
try :
import webbrowser
webbrowser . open ( url )
except :
print ' ...could not open a browser window. '
def obj_ui ( ) :
ui_x , ui_y = GLOBALS [ ' MOUSE ' ]
# Center based on overall pup size
ui_x - = 165
ui_y - = 90
global CREATE_SMOOTH_GROUPS , CREATE_FGONS , CREATE_EDGES , SPLIT_OBJECTS , SPLIT_GROUPS , SPLIT_MATERIALS , CLAMP_SIZE , IMAGE_SEARCH , KEEP_VERT_ORDER
Draw . Label ( ' Import... ' , ui_x + 9 , ui_y + 159 , 220 , 21 )
Draw . BeginAlign ( )
CREATE_SMOOTH_GROUPS = Draw . Toggle ( ' Smooth Groups ' , EVENT_NONE , ui_x + 9 , ui_y + 139 , 110 , 20 , CREATE_SMOOTH_GROUPS . val , ' Surround smooth groups by sharp edges ' )
CREATE_FGONS = Draw . Toggle ( ' NGons as FGons ' , EVENT_NONE , ui_x + 119 , ui_y + 139 , 110 , 20 , CREATE_FGONS . val , ' Import faces with more then 4 verts as fgons ' )
CREATE_EDGES = Draw . Toggle ( ' Lines as Edges ' , EVENT_NONE , ui_x + 229 , ui_y + 139 , 110 , 20 , CREATE_EDGES . val , ' Import lines and faces with 2 verts as edges ' )
Draw . EndAlign ( )
Draw . Label ( ' Separate objects by OBJ... ' , ui_x + 9 , ui_y + 110 , 220 , 20 )
Draw . BeginAlign ( )
SPLIT_OBJECTS = Draw . Toggle ( ' Object ' , EVENT_REDRAW , ui_x + 9 , ui_y + 89 , 70 , 21 , SPLIT_OBJECTS . val , ' Import OBJ Objects into Blender Objects ' , do_split )
SPLIT_GROUPS = Draw . Toggle ( ' Group ' , EVENT_REDRAW , ui_x + 79 , ui_y + 89 , 70 , 21 , SPLIT_GROUPS . val , ' Import OBJ Groups into Blender Objects ' , do_split )
SPLIT_MATERIALS = Draw . Toggle ( ' Material ' , EVENT_REDRAW , ui_x + 149 , ui_y + 89 , 70 , 21 , SPLIT_MATERIALS . val , ' Import each material into a seperate mesh (Avoids > 16 per mesh error) ' , do_split )
Draw . EndAlign ( )
# Only used for user feedback
KEEP_VERT_ORDER = Draw . Toggle ( ' Keep Vert Order ' , EVENT_REDRAW , ui_x + 229 , ui_y + 89 , 110 , 21 , KEEP_VERT_ORDER . val , ' Keep vert and face order, disables split options, enable for morph targets ' , do_vertorder )
Draw . Label ( ' Options... ' , ui_x + 9 , ui_y + 60 , 211 , 20 )
CLAMP_SIZE = Draw . Number ( ' Clamp Scale: ' , EVENT_NONE , ui_x + 9 , ui_y + 39 , 211 , 21 , CLAMP_SIZE . val , 0.0 , 1000.0 , ' Clamp the size to this maximum (Zero to Disable) ' )
IMAGE_SEARCH = Draw . Toggle ( ' Image Search ' , EVENT_NONE , ui_x + 229 , ui_y + 39 , 110 , 21 , IMAGE_SEARCH . val , ' Search subdirs for any assosiated images (Warning, may be slow) ' )
Draw . BeginAlign ( )
Draw . PushButton ( ' Online Help ' , EVENT_REDRAW , ui_x + 9 , ui_y + 9 , 110 , 21 , ' Load the wiki page for this script ' , do_help )
Draw . PushButton ( ' Cancel ' , EVENT_EXIT , ui_x + 119 , ui_y + 9 , 110 , 21 , ' ' , obj_ui_set_event )
Draw . PushButton ( ' Import ' , EVENT_IMPORT , ui_x + 229 , ui_y + 9 , 110 , 21 , ' Import with these settings ' , obj_ui_set_event )
Draw . EndAlign ( )
# hack so the toggle buttons redraw. this is not nice at all
while GLOBALS [ ' EVENT ' ] not in ( EVENT_EXIT , EVENT_IMPORT ) :
2008-10-22 08:21:43 +00:00
Draw . UIBlock ( obj_ui , 0 )
2008-10-19 15:53:22 +00:00
if GLOBALS [ ' EVENT ' ] != EVENT_IMPORT :
return
# END ALTERNATIVE UI *********************
2007-01-26 07:01:30 +00:00
2006-09-04 04:23:55 +00:00
Window . WaitCursor ( 1 )
2006-11-02 17:42:30 +00:00
if BATCH_LOAD : # load the dir
try :
files = [ f for f in os . listdir ( filepath ) if f . lower ( ) . endswith ( ' .obj ' ) ]
except :
2007-01-26 07:01:30 +00:00
Window . WaitCursor ( 0 )
2006-11-02 17:42:30 +00:00
Draw . PupMenu ( ' Error % t|Could not open path ' + filepath )
return
if not files :
2007-01-26 07:01:30 +00:00
Window . WaitCursor ( 0 )
2006-11-02 17:42:30 +00:00
Draw . PupMenu ( ' Error % t|No files at path ' + filepath )
return
for f in files :
2007-04-18 14:40:01 +00:00
scn = bpy . data . scenes . new ( stripExt ( f ) )
2006-11-02 17:42:30 +00:00
scn . makeCurrent ( )
load_obj ( sys . join ( filepath , f ) , \
CLAMP_SIZE . val , \
CREATE_FGONS . val , \
CREATE_SMOOTH_GROUPS . val , \
CREATE_EDGES . val , \
SPLIT_OBJECTS . val , \
SPLIT_GROUPS . val , \
SPLIT_MATERIALS . val , \
IMAGE_SEARCH . val , \
)
else : # Normal load
load_obj ( filepath , \
CLAMP_SIZE . val , \
CREATE_FGONS . val , \
CREATE_SMOOTH_GROUPS . val , \
CREATE_EDGES . val , \
SPLIT_OBJECTS . val , \
SPLIT_GROUPS . val , \
SPLIT_MATERIALS . val , \
IMAGE_SEARCH . val , \
)
2006-09-04 04:23:55 +00:00
Window . WaitCursor ( 0 )
2006-11-02 17:42:30 +00:00
def load_obj_ui_batch ( file ) :
load_obj_ui ( file , True )
2006-09-04 04:23:55 +00:00
DEBUG = False
2006-11-02 17:42:30 +00:00
2006-09-04 04:23:55 +00:00
if __name__ == ' __main__ ' and not DEBUG :
2006-11-02 17:42:30 +00:00
if os and Window . GetKeyQualifiers ( ) & Window . Qual . SHIFT :
Window . FileSelector ( load_obj_ui_batch , ' Import OBJ Dir ' , ' ' )
else :
Window . FileSelector ( load_obj_ui , ' Import a Wavefront OBJ ' , ' *.obj ' )
2006-09-05 06:45:39 +00:00
2006-09-04 04:23:55 +00:00
'''
# For testing compatibility
else :
# DEBUG ONLY
TIME = sys . time ( )
import os
print ' Searching for files '
os . system ( ' find /fe/obj -iname " *.obj " > /tmp/temp3ds_list ' )
print ' ...Done '
2008-09-25 13:17:56 +00:00
file = open ( ' /tmp/temp3ds_list ' , ' rU ' )
2006-09-04 04:23:55 +00:00
lines = file . readlines ( )
file . close ( )
def between ( v , a , b ) :
if v < = max ( a , b ) and v > = min ( a , b ) :
return True
return False
for i , _obj in enumerate ( lines ) :
2007-01-26 07:01:30 +00:00
if between ( i , 0 , 20 ) :
2006-09-04 04:23:55 +00:00
_obj = _obj [ : - 1 ]
print ' Importing ' , _obj , ' \n NUMBER ' , i , ' of ' , len ( lines )
_obj_file = _obj . split ( ' / ' ) [ - 1 ] . split ( ' \\ ' ) [ - 1 ]
2007-04-18 14:40:01 +00:00
newScn = bpy . data . scenes . new ( _obj_file )
2006-09-04 04:23:55 +00:00
newScn . makeCurrent ( )
load_obj ( _obj , False )
print ' TOTAL TIME: %.6f ' % ( sys . time ( ) - TIME )
'''
#load_obj('/test.obj')
#load_obj('/fe/obj/mba1.obj')