diff options
Diffstat (limited to 'release/scripts/obj_import.py')
-rw-r--r-- | release/scripts/obj_import.py | 570 |
1 files changed, 304 insertions, 266 deletions
diff --git a/release/scripts/obj_import.py b/release/scripts/obj_import.py index e19c52b7be1..236b9705d33 100644 --- a/release/scripts/obj_import.py +++ b/release/scripts/obj_import.py @@ -53,19 +53,18 @@ def pathName(path,name): # Strips the slashes from the back of a string # #==============================================# def stripPath(path): - for CH in range(len(path), 0, -1): - if path[CH-1] == "/" or path[CH-1] == "\\": - path = path[CH:] - break - return path + for CH in range(len(path), 0, -1): + if path[CH-1] == "/" or path[CH-1] == "\\": + path = path[CH:] + break + return path #====================================================# # Strips the prefix off the name before writing # - #====================================================# def stripName(name): # name is a string - prefixDelimiter = '.' - return name[ : name.find(prefixDelimiter) ] + prefixDelimiter = '.' + return name[ : name.find(prefixDelimiter) ] from Blender import * @@ -74,27 +73,27 @@ from Blender import * # This gets a mat or creates one of the requested name if none exist. # #==================================================================================# def getMat(matName): - # Make a new mat - try: - return Material.Get(matName) - except: - return Material.New(matName) + # Make a new mat + try: + return Material.Get(matName) + except: + return Material.New(matName) #==================================================================================# # This function sets textures defined in .mtl file # #==================================================================================# def getImg(img_fileName): - for i in Image.Get(): - if i.filename == img_fileName: - return i + for i in Image.Get(): + if i.filename == img_fileName: + return i - # if we are this far it means the image hasnt been loaded. - try: - return Image.Load(img_fileName) - except: - print "unable to open", img_fileName - return + # if we are this far it means the image hasnt been loaded. + try: + return Image.Load(img_fileName) + except: + print "unable to open", img_fileName + return @@ -102,270 +101,309 @@ def getImg(img_fileName): # This function sets textures defined in .mtl file # #==================================================================================# def load_mat_image(mat, img_fileName, type, mesh): - try: - image = Image.Load(img_fileName) - except: - print "unable to open", img_fileName - return + try: + image = Image.Load(img_fileName) + except: + print "unable to open", img_fileName + return - texture = Texture.New(type) - texture.setType('Image') - texture.image = image + texture = Texture.New(type) + texture.setType('Image') + texture.image = image - # 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. - if type == 'Kd': - for f in mesh.faces: - if mesh.materials[f.mat].name == mat.name: - - # the inline usemat command overides the material Image - if not f.image: - f.image = image + # 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. + if type == 'Kd': + for f in mesh.faces: + if mesh.materials[f.mat].name == mat.name: + + # the inline usemat command overides the material Image + if not f.image: + f.image = image - # adds textures for materials (rendering) - if type == 'Ka': - mat.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) - if type == 'Kd': - mat.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.COL) - if type == 'Ks': - mat.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC) + # adds textures for materials (rendering) + if type == 'Ka': + mat.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) + if type == 'Kd': + mat.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.COL) + if type == 'Ks': + mat.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC) #==================================================================================# # This function loads materials from .mtl file (have to be defined in obj file) # #==================================================================================# def load_mtl(dir, mtl_file, mesh): - mtl_fileName = dir + mtl_file - try: - fileLines= open(mtl_fileName, 'r').readlines() - except: - print "unable to open", mtl_fileName - return + # Remove ./ + if mtl_file[:2] == './': + mtl_file= mtl_file[2:] + + mtl_fileName = dir + mtl_file + try: + fileLines= open(mtl_fileName, 'r').readlines() + except: + print "unable to open", mtl_fileName + return - lIdx=0 - while lIdx < len(fileLines): - l = fileLines[lIdx].split() + lIdx=0 + while lIdx < len(fileLines): + l = fileLines[lIdx].split() - # Detect a line that will be ignored - if len(l) == 0: - pass - elif l[0] == '#' or len(l) == 0: - pass - elif l[0] == 'newmtl': - currentMat = getMat(' '.join(l[1:])) - elif l[0] == 'Ka': - currentMat.setMirCol(eval(l[1]), eval(l[2]), eval(l[3])) - elif l[0] == 'Kd': - currentMat.setRGBCol(eval(l[1]), eval(l[2]), eval(l[3])) - elif l[0] == 'Ks': - currentMat.setSpecCol(eval(l[1]), eval(l[2]), eval(l[3])) - elif l[0] == 'Ns': - currentMat.setHardness( int((eval(l[1])*0.51)) ) - elif l[0] == 'd': - currentMat.setAlpha(eval(l[1])) - elif l[0] == 'Tr': - currentMat.setAlpha(eval(l[1])) - elif l[0] == 'map_Ka': - img_fileName = dir + l[1] - load_mat_image(currentMat, img_fileName, 'Ka', mesh) - elif l[0] == 'map_Ks': - img_fileName = dir + l[1] - load_mat_image(currentMat, img_fileName, 'Ks', mesh) - elif l[0] == 'map_Kd': - img_fileName = dir + l[1] - load_mat_image(currentMat, img_fileName, 'Kd', mesh) - lIdx+=1 + # Detect a line that will be ignored + if len(l) == 0: + pass + elif l[0] == '#' or len(l) == 0: + pass + elif l[0] == 'newmtl': + currentMat = getMat(' '.join(l[1:])) + elif l[0] == 'Ka': + currentMat.setMirCol(eval(l[1]), eval(l[2]), eval(l[3])) + elif l[0] == 'Kd': + currentMat.setRGBCol(eval(l[1]), eval(l[2]), eval(l[3])) + elif l[0] == 'Ks': + currentMat.setSpecCol(eval(l[1]), eval(l[2]), eval(l[3])) + elif l[0] == 'Ns': + currentMat.setHardness( int((eval(l[1])*0.51)) ) + elif l[0] == 'd': + currentMat.setAlpha(eval(l[1])) + elif l[0] == 'Tr': + currentMat.setAlpha(eval(l[1])) + elif l[0] == 'map_Ka': + img_fileName = dir + l[1] + load_mat_image(currentMat, img_fileName, 'Ka', mesh) + elif l[0] == 'map_Ks': + img_fileName = dir + l[1] + load_mat_image(currentMat, img_fileName, 'Ks', mesh) + elif l[0] == 'map_Kd': + img_fileName = dir + l[1] + load_mat_image(currentMat, img_fileName, 'Kd', mesh) + lIdx+=1 #==================================================================================# # This loads data from .obj file # #==================================================================================# def load_obj(file): - def applyMat(mesh, f, mat): - # Check weather the 16 mat limit has been met. - if len( mesh.materials ) >= MATLIMIT: - print 'Warning, max material limit reached, using an existing material' - return mesh, f - - mIdx = 0 - for m in mesh.materials: - if m.getName() == mat.getName(): - break - mIdx+=1 - - if mIdx == len(mesh.materials): - mesh.addMaterial(mat) - - f.mat = mIdx + def applyMat(mesh, f, mat): + # Check weather the 16 mat limit has been met. + if len( mesh.materials ) >= MATLIMIT: + print 'Warning, max material limit reached, using an existing material' return mesh, f - - # Get the file name with no path or .obj - fileName = stripName( stripPath(file) ) - - mtl_fileName = '' - - DIR = pathName(file, stripPath(file)) - - fileLines = open(file, 'r').readlines() - - mesh = NMesh.GetRaw() # new empty mesh - - objectName = 'mesh' # If we cant get one, use this - - uvMapList = [] # store tuple uv pairs here - - nullMat = getMat(NULL_MAT) - - currentMat = nullMat # Use this mat. - currentImg = NULL_IMG # Null image is a string, otherwise this should be set to an image object. + + mIdx = 0 + for m in mesh.materials: + if m.getName() == mat.getName(): + break + mIdx+=1 + + if mIdx == len(mesh.materials): + mesh.addMaterial(mat) + + f.mat = mIdx + return mesh, f + + # Get the file name with no path or .obj + fileName = stripName( stripPath(file) ) + + mtl_fileName = '' + + DIR = pathName(file, stripPath(file)) - smooth = 0 + fileLines = open(file, 'r').readlines() + + mesh = NMesh.GetRaw() # new empty mesh + + objectName = 'mesh' # If we cant get one, use this + + uvMapList = [(0,0)] # store tuple uv pairs here + + # This dummy vert makes life a whole lot easier- + # pythons index system then aligns with objs, remove later + vertList = [NMesh.Vert(0, 0, 0)] # store tuple uv pairs here + + # Here we store a boolean list of which verts are used or not + # no we know weather to add them to the current mesh + # This is an issue with global vertex indicies being translated to per mesh indicies + # like blenders, we start with a dummy just like the vert. + # -1 means unused, any other value refers to the local mesh index of the vert. + usedList = [-1] + + nullMat = getMat(NULL_MAT) + + currentMat = nullMat # Use this mat. + currentImg = NULL_IMG # Null image is a string, otherwise this should be set to an image object. - # Main loop - lIdx = 0 - while lIdx < len(fileLines): - l = fileLines[lIdx].split() - - # Detect a line that will be idnored - if len(l) == 0: - pass - elif l[0] == '#' or len(l) == 0: - pass - # VERTEX - elif l[0] == 'v': - # This is a new vert, make a new mesh - mesh.verts.append( NMesh.Vert(eval(l[1]), eval(l[2]), eval(l[3]) ) ) - - elif l[0] == 'vn': - pass - - elif l[0] == 'vt': - # This is a new vert, make a new mesh - uvMapList.append( (eval(l[1]), eval(l[2])) ) - - elif l[0] == 'f': - - # Make a face with the correct material. - f = NMesh.Face() - mesh, f = applyMat(mesh, f, currentMat) - - # Set up vIdxLs : Verts - # Set up vtIdxLs : UV - vIdxLs = [] - vtIdxLs = [] - for v in l[1:]: - # OBJ files can have // or / to seperate vert/texVert/normal - # this is a bit of a pain but we must deal with it. - # Well try // first and if that has a len of 1 then we'll try / - objVert = v.split('//', -1) - if len(objVert) == 1: - objVert = objVert[0].split('/', -1) - - # VERT INDEX - vIdxLs.append(eval(objVert[0]) -1) - # UV - if len(objVert) == 1: - vtIdxLs.append(eval(objVert[0]) -1) # Sticky UV coords - else: - vtIdxLs.append(eval(objVert[1]) -1) # Seperate UV coords - - # Quads only, we could import quads using the method below but it polite to import a quad as a quad.f - if len(vIdxLs) == 4: - f.v.append(mesh.verts[vIdxLs[0]]) - f.v.append(mesh.verts[vIdxLs[1]]) - f.v.append(mesh.verts[vIdxLs[2]]) - f.v.append(mesh.verts[vIdxLs[3]]) - # SMOTH FACE - f.smooth = smooth - # UV MAPPING - if uvMapList: - if vtIdxLs[0] < len(uvMapList): - f.uv.append( uvMapList[ vtIdxLs[0] ] ) - if vtIdxLs[1] < len(uvMapList): - f.uv.append( uvMapList[ vtIdxLs[1] ] ) - if vtIdxLs[2] < len(uvMapList): - f.uv.append( uvMapList[ vtIdxLs[2] ] ) - if vtIdxLs[3] < len(uvMapList): - f.uv.append( uvMapList[ vtIdxLs[3] ] ) - - mesh.faces.append(f) # move the face onto the mesh - # Apply the current image to the face - if currentImg != NULL_IMG: - mesh.faces[-1].image = currentImg + # Main loop + lIdx = 0 + while lIdx < len(fileLines): + l = fileLines[lIdx].split() + + # Detect a line that will be idnored + if len(l) == 0: + pass + elif l[0] == '#' or len(l) == 0: + pass + # VERTEX + elif l[0] == 'v': + # This is a new vert, make a new mesh + vertList.append( NMesh.Vert(eval(l[1]), eval(l[2]), eval(l[3]) ) ) + usedList.append(-1) # Ad the moment this vert is not used by any mesh. + + elif l[0] == 'vn': + pass + + elif l[0] == 'vt': + # This is a new vert, make a new mesh + uvMapList.append( (eval(l[1]), eval(l[2])) ) - elif len(vIdxLs) >= 3: # This handles tri's and fans - for i in range(len(vIdxLs)-2): - f = NMesh.Face() - mesh, f = applyMat(mesh, f, currentMat) - f.v.append(mesh.verts[vIdxLs[0]]) - f.v.append(mesh.verts[vIdxLs[i+1]]) - f.v.append(mesh.verts[vIdxLs[i+2]]) - # SMOTH FACE - f.smooth = smooth - # UV MAPPING - if uvMapList: - if vtIdxLs[0] < len(uvMapList): - f.uv.append( uvMapList[ vtIdxLs[0] ] ) - if vtIdxLs[1] < len(uvMapList): - f.uv.append( uvMapList[ vtIdxLs[i+1] ] ) - if vtIdxLs[2] < len(uvMapList): - f.uv.append( uvMapList[ vtIdxLs[i+2] ] ) - - mesh.faces.append(f) # move the face onto the mesh - # Apply the current image to the face - if currentImg != NULL_IMG: - mesh.faces[-1].image = currentImg - - - # is o the only vert/face delimeter? - # if not we could be screwed. - elif l[0] == 'o': - # Some material stuff - if mtl_fileName != '': - load_mtl(DIR, mtl_fileName, mesh) + elif l[0] == 'f': + + # Make a face with the correct material. + f = NMesh.Face() + mesh, f = applyMat(mesh, f, currentMat) + + # Set up vIdxLs : Verts + # Set up vtIdxLs : UV + # Start with a dummy objects so python accepts OBJs 1 is the first index. + vIdxLs = [] + vtIdxLs = [] + fHasUV = len(uvMapList)-1 # Assume the face has a UV until it sho it dosent, if there are no UV coords then this will start as 0. + for v in l[1:]: + # OBJ files can have // or / to seperate vert/texVert/normal + # this is a bit of a pain but we must deal with it. + objVert = v.split('/', -1) - # Make sure the objects is worth puttong - if len(mesh.verts) > 0: - NMesh.PutRaw(mesh, fileName + '_' + objectName) - # Make new mesh - mesh = NMesh.GetRaw() - - # New mesh name - objectName = '_'.join(l[1:]) # Use join in case of spaces - - # New texture list - uvMapList = [] - - # setting smooth surface on or off - elif l[0] == 's': - if l[1] == 'off': - smooth = 0 - else: - smooth = 1 - - elif l[0] == 'usemtl': - if l[1] == '(null)': - currentMat = getMat(NULL_MAT) - else: - currentMat = getMat(' '.join(l[1:])) # Use join in case of spaces + # Vert Index - OBJ supports negative index assignment (like python) + + vIdxLs.append(eval(objVert[0])) + if fHasUV: + # UV + if len(objVert) == 1: + vtIdxLs.append(eval(objVert[0])) # Sticky UV coords + elif objVert[1] != '': # Its possible that theres no texture vert just he vert and normal eg 1//2 + vtIdxLs.append(eval(objVert[1])) # Seperate UV coords + else: + fHasUV = 0 + + # Dont add a UV to the face if its larger then the UV coord list + # The OBJ file would have to be corrupt or badly written for thi to happen + # but account for it anyway. + if vtIdxLs[-1] > len(uvMapList): + fHasUV = 0 + print 'badly written OBJ file, invalid references to UV Texture coordinates.' + + # Quads only, we could import quads using the method below but it polite to import a quad as a quad. + if len(vIdxLs) == 4: + for i in [0,1,2,3]: + if usedList[vIdxLs[i]] == -1: + mesh.verts.append(vertList[vIdxLs[i]]) + f.v.append(mesh.verts[-1]) + usedList[vIdxLs[i]] = len(mesh.verts)-1 + else: + f.v.append(mesh.verts[usedList[vIdxLs[i]]]) + + # UV MAPPING + if fHasUV: + for i in [0,1,2,3]: + f.uv.append( uvMapList[ vtIdxLs[i] ] ) + mesh.faces.append(f) # move the face onto the mesh + # Apply the current image to the face + if currentImg != NULL_IMG: + mesh.faces[-1].image = currentImg + + elif len(vIdxLs) >= 3: # This handles tri's and fans + for i in range(len(vIdxLs)-2): + f = NMesh.Face() + mesh, f = applyMat(mesh, f, currentMat) + + if usedList[vIdxLs[0]] == -1: + mesh.verts.append(vertList[vIdxLs[0]]) + f.v.append(mesh.verts[-1]) + usedList[vIdxLs[0]] = len(mesh.verts)-1 + else: + f.v.append(mesh.verts[usedList[vIdxLs[0]]]) + + if usedList[vIdxLs[i+1]] == -1: + mesh.verts.append(vertList[vIdxLs[i+1]]) + f.v.append(mesh.verts[-1]) + usedList[vIdxLs[i+1]] = len(mesh.verts)-1 + else: + f.v.append(mesh.verts[usedList[vIdxLs[i+1]]]) + + if usedList[vIdxLs[i+2]] == -1: + mesh.verts.append(vertList[vIdxLs[i+2]]) + f.v.append(mesh.verts[-1]) + usedList[vIdxLs[i+2]] = len(mesh.verts)-1 + else: + f.v.append(mesh.verts[usedList[vIdxLs[i+2]]]) + + # UV MAPPING + if fHasUV: + f.uv.append( uvMapList[ vtIdxLs[0] ] ) + f.uv.append( uvMapList[ vtIdxLs[i+1] ] ) + f.uv.append( uvMapList[ vtIdxLs[i+2] ] ) + mesh.faces.append(f) # move the face onto the mesh + + # Apply the current image to the face + if currentImg != NULL_IMG: + mesh.faces[-1].image = currentImg + + # Object / Group + elif l[0] == 'o' or l[0] == 'g': + + # Reset the used list + ulIdx = 0 + while ulIdx < len(usedList): + usedList[ulIdx] = -1 + ulIdx +=1 + + # Some material stuff + if mtl_fileName != '': + load_mtl(DIR, mtl_fileName, mesh) + + # Make sure the objects is worth putting + if len(mesh.verts) > 1: + mesh.verts.remove(mesh.verts[0]) + ob = NMesh.PutRaw(mesh, fileName + '_' + objectName) + if ob != None: # Name the object too. + ob.name = fileName + '_' + objectName - elif l[0] == 'usemat': - if l[1] == '(null)': - currentImg = NULL_IMG - else: - currentImg = getImg(DIR + ' '.join(l[1:])) # Use join in case of spaces - - - elif l[0] == 'mtllib': - mtl_fileName = l[1] - - lIdx+=1 + # Make new mesh + mesh = NMesh.GetRaw() + # This dummy vert makes life a whole lot easier- + # pythons index system then aligns with objs, remove later + mesh.verts.append( NMesh.Vert(0, 0, 0) ) + + # New mesh name + objectName = '_'.join(l[1:]) # Use join in case of spaces + + + elif l[0] == 'usemtl': + if l[1] == '(null)': + currentMat = getMat(NULL_MAT) + else: + currentMat = getMat(' '.join(l[1:])) # Use join in case of spaces + + elif l[0] == 'usemat': + if l[1] == '(null)': + currentImg = NULL_IMG + else: + currentImg = getImg(DIR + ' '.join(l[1:])) # Use join in case of spaces + + + elif l[0] == 'mtllib': + mtl_fileName = l[1] + + lIdx+=1 - # Some material stuff - if mtl_fileName != '': - load_mtl(DIR, mtl_fileName, mesh) - - # We need to do this to put the last object. - # All other objects will be put alredy - if len(mesh.verts) > 0: - NMesh.PutRaw(mesh, fileName + '_' + objectName) + # Some material stuff + if mtl_fileName != '': + load_mtl(DIR, mtl_fileName, mesh) + + # We need to do this to put the last object. + # All other objects will be put alredy + if len(mesh.verts) > 1: + mesh.verts.remove(mesh.verts[0]) + ob = NMesh.PutRaw(mesh, fileName + '_' + objectName) + if ob != None: # Name the object too. + ob.name = fileName + '_' + objectName -Window.FileSelector(load_obj, 'Import OBJ') +Window.FileSelector(load_obj, 'Import Wavefront OBJ') |