This is the script I am running - it’s tailored to load Poser based .obj files, but run it and load any obj file that has multiple material groups (usemtl) - do the import twice and Blender will crash. If you # out the Material.New(Name) it doesn’t crash.
#!BPY
"""Registration info for Blender menus:
Name: 'OBJ...'
Blender: 232
Group: 'Import'
Tip: 'Import Wavefront File Format (*.obj)'
"""
#=========================================================================
# Wavefront OBJ Importer/Exporter v1.2
# This is a complete OBJ importer and exporter script
# All Rights Reserved
# [email protected]
#Version mise a jour pour Blender 228 par jm soler
#
#=========================================================================
# DESCRIPTION: This script allows for full importing and exporting of
# .obj files. uv texture coordinates and normals can be exported and
# imported. .obj groups and materials can also be converted to and
# from material indexes in Blender.
#
# INSTALLATION:
# You need the FULL python installation to run this script. You can
# down load the latest version of PYTHON from http://www.python.org.
#
# INSTRUCTIONS (You definitely want to read this!):
# Once the script is loaded in Blender, hit alt-p. This will bring up
# the main interface panel. You will have a choise of exporting or
# importing an .obj module. If you are exporting you must have at least
# one mesh selected in Blender, or you will get an error.
# You can change the export filename by entering the path and filename
# in the dialog. If you do not enter a path, the path will default to
# your blender directory. You can change the default path in the script <==== NOTE
# itself by modifying the variable 'Filename' at the top of the script.
#
# IMPORTING:
# If your OBJ model has uv mapping coordinates, and you want to use them <===== NOTE
# in Blender, you can access them in two ways. The best way is through Blender's
# realtime UV coordinates which you enable simply by selecting the UV option in
# the material edit window. This gives you an exact version of the uv coordinates.
# An older method is to select the "stick" option in the material edit window. I
# really don't know why anyone would want to use this option since it cannot handle
# seams and texture overlap, but I left it in just in case someone could use it for
# something.
#
# If your OBJ contains groups, once it has been imported, it may still appear
# to lack any material indexes. If this happens, it can be remedied <=== NOTE
# by going to the mesh editor window, clicking on the mesh selection button, and
# reselecting the mesh you have just imported. You will now have as many
# materials attached to your object as there are groups. You can then select
# different groups by doing a material select when you are in edit mode.
#
# Finally, you might have problems with certain parts of the object not displaying
# after you go in and out of edit mode the first time. To fix this, simply go into
# edit mode again, and select the "remove doubles" option.
#
#
# HISTORY:
# Nov 13, 2001: Initial Release
# Nov 16, 2001: Version 1.1 - no longer need to pre-define dummy materials
# Dec 13, 2001: Version 1.2 - now imports into realtime UV (the UV button in the material edit window), and
# exports realtime UV. This format is more compatible with the native .OBJ uv format. Should eliminate
# texture misalignments and seams. Simply press the UV button in the material edit window after importing.
#
# GetRaw
#================================
# ===============================
# Setup our runtime constants
# ===============================
DEBUG=1 #Set this to "1" to see extra messages
MESHVERSION=3 # If the export file doesn't work,
FILEVERSION=3 # try changing these to "2"
EVENT_PATHCHANGE= 1
EVENT_IMPORT= 2
EVENT_IMPORT_CONT= 3
EVENT_OPTIONS= 4
EVENT_EXPORT= 7
EVENT_EXPORT_CHK= 5
EVENT_EXPORT_CANCEL= 6
EVENT_QUIT= 8
EVENT_EXPORT_ERR= 9
EVENT_TYPE= 10
EVENT_DONE= 11
EVENT_IMPORT_SELECT= 12
# ===============================
# Import our libraries
# ===============================
#import string
#import os
#import struct
try:
import nt
os=nt
os.sep='\\'
except:
import posix
os=posix
os.sep='/'
def isdir(path):
try:
st = os.stat(path)
return 1
except:
return 0
def split(pathname):
k0=pathname.split(os.sep)
directory=pathname.replace(k0[len(k0)-1],'')
Name=k0[len(k0)-1]
return directory, Name
def join(l0,l1):
return l0+os.sep+l1
os.isdir=isdir
os.split=split
os.join=join
import math
import Blender
#import Blender210
from Blender import *
from Blender import Types, Object, NMesh, Camera, Lamp
from Blender.Draw import *
from Blender.BGL import *
from Blender import Material
from Blender import Window
from math import pi
# ===============================
# Input Variables
# ===============================
Filename = "C:\\Program Files\\Curious Labs\\Poser4\\Runtime\\Geometries\
ewMaleCasHi\
ewMaleCasHi.obj"
gFilename=Create(Filename)
gAlert = 0
gNewMeshCreated = 0
type = 1
exporttype = 1
returncode = 0
operation = "Export"
center = [0,0,0]
rotation = [0,0,0]
Transform = []
multiflag = 0
#================================
# def Fileselect function:
#================================
def ImportFunctionselet(filename):
global gFilename
global ExportOptions
global ExportType
global type
global exporttype
global operation
global gAlert
gFilename.val=filename
ImportFunction(filename, type)
operation = "Import"
#================================
def ExitGUI ():
#================================
Exit()
#================================
def EventGUI (event):
#================================
global gFilename
global ExportOptions
global ExportType
global type
global exporttype
global operation
global gAlert
if (event==EVENT_IMPORT):
ImportFunction(gFilename.val, type)
operation = "Import"
if (event==EVENT_IMPORT_SELECT):
Window.FileSelector (ImportFunctionselet, 'IMPORT FILE')
if (event==EVENT_IMPORT_CONT):
gAlert = 0
operation = "Import"
Draw ()
if (event==EVENT_EXPORT):
#ExportFunction(gFilename.val, type)
operation = "Export"
if (event==EVENT_EXPORT_CHK):
#ExportFunctionOK(gFilename.val, type)
Draw ()
if (event==EVENT_EXPORT_CANCEL):
gAlert = 0
Draw ()
if (event==EVENT_OPTIONS):
type = ExportOptions.val
Draw ()
if (event==EVENT_TYPE):
exporttype = ExportType.val
Draw ()
if (event==EVENT_EXPORT_ERR):
gAlert = 0
Draw ()
if (event==EVENT_DONE):
gAlert = 0
Draw ()
if (event==EVENT_QUIT):
ExitGUI()
#================================
def DrawGUI():
#================================
global type
global exporttype
global operation
glClearColor (0.6,0.6,0.6,0)
glClear (GL_COLOR_BUFFER_BIT)
global gFilename
global gAlert
global ExportOptions
global ExportType
if (gAlert==0):
# Add in the copyright notice and title
glRasterPos2d(32, 380)
Text("Wavefront OBJ Importer/Exporter")
glRasterPos2d(32, 350)
Text("Copyright (C) Chris Lynch 2001")
gFilename=String ("Filename: ",EVENT_PATHCHANGE,32,250,320,32,gFilename.val,255,"Full pathname and filename")
#Button ("Export",EVENT_EXPORT,32,200,100,32)
Button ("Import",EVENT_IMPORT,252,200,100,32)
Button ("Select Import",EVENT_IMPORT_SELECT,355,200,100,32)
glRasterPos2d(32, 165)
#Text("Select Export Options:")
#options = "Export Options %t| Default %x1| Material Layers %x2| Obj Groups %x3| Standard %x4"
#ExportOptions = Menu (options,EVENT_OPTIONS,200,150,150,32, type)
Button ("Done",EVENT_QUIT,142,50,100,32)
glRasterPos2d(32, 115)
#Text("Export using ")
#options = "Export Type %t| Mesh Coordinates %x1| Object Coordinates %x2"
#ExportType = Menu (options,EVENT_TYPE,170,100,180,32, exporttype)
Button ("Done",EVENT_QUIT,142,50,100,32)
elif (gAlert==1):
glRasterPos2i (32,250)
Text (gFilename.val+ " already exists. Save anyway?")
Button ("Save",EVENT_EXPORT_CHK,150,200,50,32)
Button ("Cancel",EVENT_EXPORT_CANCEL,250,200,50,32)
gAlert = 0
elif (gAlert==2):
glRasterPos2i (32,250)
Text (gFilename.val+ " cannot be found. Check directory and filename.")
Button ("Continue",EVENT_IMPORT_CONT,32,190,70,32)
gAlert = 0
elif gAlert == 3:
glRasterPos2i (32,250)
Text ("No objects selected to export. You must select one or more objects.")
Button ("Continue",EVENT_EXPORT_ERR,192,200,70,32)
gAlert = 0
elif gAlert == 5:
glRasterPos2i (32,250)
Text ("Invalid directory path.")
Button ("Continue",EVENT_EXPORT_ERR,192,200,70,32)
gAlert = 0
elif gAlert == 6:
glRasterPos2i (32,250)
Text ("Importing. Please wait....")
else:
glRasterPos2i (32,250)
Text (str(operation)+ " of " +str(gFilename.val)+ " done.")
Button ("Continue",EVENT_DONE,192,200,70,32)
#================================
def RegisterGUI ():
#================================
Register (DrawGUI,None,EventGUI)
#================================
# MAIN SCRIPT
#================================
# Opens a file, writes data in it
# and closes it up.
#================================
RegisterGUI()
#================================
def ImportFunction (importName, type):
#================================
global gFilename
global gAlert
gAlert = 6
Draw ()
try:
FILE=open (importName,"r")
directory, Name = os.split(gFilename.val)
words = Name.split(".")
Name = words[0]
ObjImport(FILE, Name, gFilename.val)
FILE.close()
# Rotate the mesh
print "Rotating mesh"
ob = Object.Get('Mesh')
ob.setEuler(pi/2, 0, 0)
# Position the camera
print "Positioning camera"
camera = Object.Get('Camera')
camera.setLocation(0.0, -1.5, 0.4)
camera.setEuler(pi/2, 0, 0)
camera.setSize(0.2, 0.2, 0.2)
# Setup the lamp
print "Setting lamp"
lamp = Object.Get('Lamp')
lamp.setLocation(0.0, -5.0, 0.5)
gAlert = 4
Draw ()
except IOError:
gAlert=2
Draw ()
#=========================
def ObjImport(file, Name, filename):
#=========================
global gNewMeshCreated
vcount = 0
vncount = 0
vtcount = 0
fcount = 0
gcount = 0
setcount = 0
groupflag = 0
objectflag = 0
mtlflag = 0
baseindex = 0
basevtcount = 0
basevncount = 0
matindex = 0
pointList = []
uvList = []
normalList = []
faceList = []
materialList = []
imagelist = []
uv = []
lines = file.readlines()
linenumber = 1
for line in lines:
words = line.split()
if words and words[0] == "#":
pass # ignore comments
elif words and words[0] == "v":
vcount = vcount + 1
x = float(words[1])
y = float(words[2])
z = float(words[3])
pointList.append([x, y, z])
elif words and words[0] == "vt":
vtcount = vtcount + 1
u = float(words[1])
v = float(words[2])
uvList.append([u, v])
elif words and words[0] == "vn":
vncount = vncount + 1
i = float(words[1])
j = float(words[2])
k = float(words[3])
normalList.append([i, j, k])
elif words and words[0] == "f":
fcount = fcount + 1
vi = [] # vertex indices
ti = [] # texture indices
ni = [] # normal indices
words = words[1:]
lcount = len(words)
for index in (xrange(lcount)):
if words[index].find( "/") == -1:
vindex = int(words[index])
if vindex < 0: vindex = baseindex + vindex + 1
vi.append(vindex)
else:
vtn = words[index].split( "/")
vindex = int(vtn[0])
if vindex < 0: vindex = baseindex + vindex + 1
vi.append(vindex)
if len(vtn) > 1 and vtn[1]:
tindex = int(vtn[1])
if tindex < 0: tindex = basevtcount +tindex + 1
ti.append(tindex)
if len(vtn) > 2 and vtn[2]:
nindex = int(vtn[2])
if nindex < 0: nindex = basevncount +nindex + 1
ni.append(nindex)
faceList.append([vi, ti, ni, matindex])
elif words and words[0] == "o":
ObjectName = words[1]
objectflag = 1
#print "Name is %s" % ObjectName
elif words and words[0] == "g":
groupflag = 1
index = len(words)
if objectflag == 0:
objectflag = 1
if index > 1:
ObjectName = words[1].join("_")
GroupName = words[1].join("_")
else:
ObjectName = "Default"
GroupName = "Default"
#print "Object name is %s" % ObjectName
#print "Group name is %s" % GroupName
else:
if index > 1:
GroupName = join(words[1],"_")
else:
GroupName = "Default"
#print "Group name is %s" % GroupName
# if mtlflag == 0:
# matindex = AddMeshMaterial(GroupName,materialList, matindex)
gcount = gcount + 1
if fcount > 0:
baseindex = vcount
basevncount = vncount
basevtcount = vtcount
elif words and words[0] == "mtllib":
# try to export materials
print "Ignoring mtllib ",filename
elif words and words[0] == "usemtl":
# if mtlflag == 1:
name = words[1]
matindex = AddMeshMaterial(name, materialList, matindex)
elif words:
print "%s: %s" % (linenumber, words)
linenumber = linenumber + 1
file.close()
# import in Blender
print "import into Blender ..."
mesh = NMesh.GetRaw ()
i = 0
while i < vcount:
x, y, z = pointList[i]
vert=NMesh.Vert(x, y, z)
mesh.verts.append(vert)
i=i+1
if vtcount > 0:
#mesh.hasFaceUV() = 1
print ("Object has uv coordinates")
if len(materialList) > 0:
for m in materialList:
print m
try:
M=Material.Get(m)
print M
mesh.materials.append(M)
print "SetMode " + str(M.getMode())
M.setMode('TexFace')
except:
print "Material.Get failed"
pass
total = len(faceList)
i = 0
for f in faceList:
if i%1000 == 0:
print ("Progress = "+ str(i)+"/"+ str(total))
i = i + 1
vi, ti, ni, matindex = f
face=NMesh.Face()
if len(materialList) > 0:
face.mat = matindex
limit = len(vi)
setcount = setcount + len(vi)
c = 0
while c < limit:
m = vi[c]-1
if vtcount > 0 and len(ti) > c:
n = ti[c]-1
if vncount > 0 and len(ni) > c:
p = ni[c]-1
if vtcount > 0:
try:
u, v = uvList[n]
except:
pass
"""
# multiply uv coordinates by 2 and add 1. Apparently blender uses uv range of 1 to 3 (not 0 to 1).
mesh.verts[m].uvco[0] = (u*2)+1
mesh.verts[m].uvco[1] = (v*2)+1
"""
if vncount > 0:
if p > len(normalList):
print("normal len = " +str(len(normalList))+ " vector len = " +str(len(pointList)))
print("p = " +str(p))
x, y, z = normalList[p]
mesh.verts[m].no[0] = x
mesh.verts[m].no[1] = y
mesh.verts[m].no[2] = z
c = c+1
if len(vi) < 5:
for index in vi:
face.v.append (mesh.verts[index-1])
if vtcount > 0:
for index in ti:
u, v = uvList[index-1]
face.uv.append((u,v))
if len(imagelist)>0:
face.image=imagelist[0]
#print
if vcount>0:
face.smooth=1
mesh.faces.append(face)
print "all other (general) polygons ..."
for f in faceList:
vi, ti, ni, matindex = f
if len(vi) > 4:
# export the polygon as edges
print ("Odd face, vertices = "+ str(len(vi)))
for i in range(len(vi)-2):
face = NMesh.Face()
if len(materialList) > 0:
face.mat = matindex
face.v.append(mesh.verts[vi[0]-1])
face.v.append(mesh.verts[vi[i+1]-1])
face.v.append(mesh.verts[vi[i+2]-1])
if vtcount > 0:
if len(ti) > i+2:
u, v = uvList[ti[0]-1]
face.uv.append((u,v))
u, v = uvList[ti[i+1]-1]
face.uv.append((u,v))
u, v = uvList[ti[i+2]-1]
face.uv.append((u,v))
mesh.faces.append(face)
#print "Object = "
print "Doing PutRaw with name = " + Name
NMesh.PutRaw(mesh, Name,1)
print ("Total number of vertices is "+ str(vcount))
print ("Total number of faces is "+ str(len(faceList)))
print ("Total number of sets is "+ str(setcount))
print("Finished importing " +str(Name)+ ".obj")
#=========================================
def AddMeshMaterial(name, materialList, matindex):
#=========================================
index = 0
found = 0
limit = len(materialList)
while index < limit:
if materialList[index] == name:
matindex = index
found = 1
index = limit
index = index + 1
if found == 0:
materialList.append(name)
matindex = len(materialList)-1
# Now add a new material
Material.New(name)
return matindex