forked from bartvdbraak/blender
Moved ngon creating function from obj_import into BPyMesh so other importers can use it.
Exporter free's mesh vertex data each run (was causing memory errors when exporting fluidsim meshes... poke ken for Mesh.Unlink() since many meshes are still created) Exporter had an indentation error also. Added an NMesh wrapper around Mesh for importers to use, so as to work around slow 1 by 1 adding of data. used in upcoming flt_importer update. Mesh cleanup now has the dangerous option to perform a cleanup on ALL mesh data. (needed it for a project)
This commit is contained in:
parent
4043934d2c
commit
9c322c7e86
@ -32,10 +32,15 @@ def dict2MeshWeight(me, groupNames, vWeightDict):
|
||||
# Clear the vert group.
|
||||
currentGroupNames= me.getVertGroupNames()
|
||||
for group in currentGroupNames:
|
||||
me.removeVertGroup(group)
|
||||
if group not in groupNames:
|
||||
me.removeVertGroup(group) # messes up the active group.
|
||||
else:
|
||||
me.removeVertsFromGroup(group)
|
||||
|
||||
# Add clean unused vert groupNames back
|
||||
currentGroupNames= me.getVertGroupNames()
|
||||
for group in groupNames:
|
||||
if group not in currentGroupNames:
|
||||
me.addVertGroup(group)
|
||||
|
||||
add_ = Blender.Mesh.AssignModes.ADD
|
||||
@ -45,7 +50,7 @@ def dict2MeshWeight(me, groupNames, vWeightDict):
|
||||
vertList[0]= i
|
||||
for group, weight in vWeightDict[i].iteritems():
|
||||
try:
|
||||
me.assignVertsToGroup(group, vertList, weight, add_)
|
||||
me.assignVertsToGroup(group, vertList, min(1, max(0, weight)), add_)
|
||||
except:
|
||||
pass # vert group is not used anymore.
|
||||
|
||||
@ -126,3 +131,235 @@ def getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=Tru
|
||||
print 'Cant assign materials to', type
|
||||
|
||||
return mesh
|
||||
|
||||
type_tuple= type( (0,) )
|
||||
type_list= type( [] )
|
||||
def ngon(from_data, indices):
|
||||
'''
|
||||
takes a polyline of indices (fgon)
|
||||
and returns a list of face indicie lists.
|
||||
Designed to be used for importers that need indices for an fgon to create from existing verts.
|
||||
|
||||
from_data is either a mesh, or a list/tuple of vectors.
|
||||
'''
|
||||
Mesh= Blender.Mesh
|
||||
Window= Blender.Window
|
||||
Scene= Blender.Scene
|
||||
Object= Blender.Object
|
||||
|
||||
if len(indices) < 4:
|
||||
return [indices]
|
||||
temp_mesh_name= '~NGON_TEMP~'
|
||||
is_editmode= Window.EditMode()
|
||||
if is_editmode:
|
||||
Window.EditMode(0)
|
||||
try:
|
||||
temp_mesh = Mesh.Get(temp_mesh_name)
|
||||
if temp_mesh.users!=0:
|
||||
temp_mesh = Mesh.New(temp_mesh_name)
|
||||
except:
|
||||
temp_mesh = Mesh.New(temp_mesh_name)
|
||||
|
||||
if type(from_data) in (type_tuple, type_list):
|
||||
# From a list/tuple of vectors
|
||||
temp_mesh.verts.extend( [from_data[i] for i in indices] )
|
||||
temp_mesh.edges.extend( [(temp_mesh.verts[i], temp_mesh.verts[i-1]) for i in xrange(len(temp_mesh.verts))] )
|
||||
else:
|
||||
# From a mesh
|
||||
temp_mesh.verts.extend( [from_data.verts[i].co for i in indices] )
|
||||
temp_mesh.edges.extend( [(temp_mesh.verts[i], temp_mesh.verts[i-1]) for i in xrange(len(temp_mesh.verts))] )
|
||||
|
||||
|
||||
oldmode = Mesh.Mode()
|
||||
Mesh.Mode(Mesh.SelectModes['VERTEX'])
|
||||
for v in temp_mesh.verts:
|
||||
v.sel= 1
|
||||
|
||||
# Must link to scene
|
||||
scn= Scene.GetCurrent()
|
||||
temp_ob= Object.New('Mesh')
|
||||
temp_ob.link(temp_mesh)
|
||||
scn.link(temp_ob)
|
||||
temp_mesh.fill()
|
||||
scn.unlink(temp_ob)
|
||||
Mesh.Mode(oldmode)
|
||||
|
||||
new_indices= [ [v.index for v in f.v] for f in temp_mesh.faces ]
|
||||
|
||||
if not new_indices: # JUST DO A FAN, Cant Scanfill
|
||||
print 'Warning Cannot scanfill!- Fallback on a triangle fan.'
|
||||
new_indices = [ [indices[0], indices[i-1], indices[i]] for i in xrange(2, len(indices)) ]
|
||||
else:
|
||||
# Use real scanfill.
|
||||
# See if its flipped the wrong way.
|
||||
flip= None
|
||||
for fi in new_indices:
|
||||
if flip != None:
|
||||
break
|
||||
for i, vi in enumerate(fi):
|
||||
if vi==0 and fi[i-1]==1:
|
||||
flip= False
|
||||
break
|
||||
elif vi==1 and fi[i-1]==0:
|
||||
flip= True
|
||||
break
|
||||
|
||||
if not flip:
|
||||
for fi in new_indices:
|
||||
fi.reverse()
|
||||
|
||||
if is_editmode:
|
||||
Window.EditMode(1)
|
||||
|
||||
# Save some memory and forget about the verts.
|
||||
# since we cant unlink the mesh.
|
||||
temp_mesh.verts= None
|
||||
|
||||
return new_indices
|
||||
|
||||
|
||||
|
||||
# EG
|
||||
'''
|
||||
scn= Scene.GetCurrent()
|
||||
me = scn.getActiveObject().getData(mesh=1)
|
||||
ind= [v.index for v in me.verts if v.sel] # Get indices
|
||||
|
||||
indices = ngon(me, ind) # fill the ngon.
|
||||
|
||||
# Extand the faces to show what the scanfill looked like.
|
||||
print len(indices)
|
||||
me.faces.extend([[me.verts[ii] for ii in i] for i in indices])
|
||||
'''
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# NMesh wrapper
|
||||
Vector= Blender.Mathutils.Vector
|
||||
class NMesh(object):
|
||||
__slots__= 'verts', 'faces', 'edges', 'faceUV', 'materials', 'realmesh'
|
||||
def __init__(self, mesh):
|
||||
'''
|
||||
This is an NMesh wrapper that
|
||||
mesh is an Mesh as returned by Blender.Mesh.New()
|
||||
This class wraps NMesh like access into Mesh
|
||||
|
||||
Running NMesh.update() - with this wrapper,
|
||||
Will update the realmesh.
|
||||
'''
|
||||
self.verts= []
|
||||
self.faces= []
|
||||
self.edges= []
|
||||
self.faceUV= False
|
||||
self.materials= []
|
||||
self.realmesh= mesh
|
||||
|
||||
def addFace(self, nmf):
|
||||
self.faces.append(nmf)
|
||||
|
||||
def Face(self, v=[]):
|
||||
return NMFace(v)
|
||||
def Vert(self, x,y,z):
|
||||
return NMVert(x,y,z)
|
||||
|
||||
def hasFaceUV(self, flag):
|
||||
if flag:
|
||||
self.faceUV= True
|
||||
else:
|
||||
self.faceUV= False
|
||||
|
||||
def addMaterial(self, mat):
|
||||
self.materials.append(mat)
|
||||
|
||||
def update(self, recalc_normals=False): # recalc_normals is dummy
|
||||
mesh= self.realmesh
|
||||
mesh.verts= None # Clears the
|
||||
|
||||
# Add in any verts from faces we may have not added.
|
||||
for nmf in self.faces:
|
||||
for nmv in nmf.v:
|
||||
if nmv.index==-1:
|
||||
nmv.index= len(self.verts)
|
||||
self.verts.append(nmv)
|
||||
|
||||
|
||||
mesh.verts.extend([nmv.co for nmv in self.verts])
|
||||
for i, nmv in enumerate(self.verts):
|
||||
nmv.index= i
|
||||
mv= mesh.verts[i]
|
||||
mv.sel= nmv.sel
|
||||
|
||||
good_faces= [nmf for nmf in self.faces if len(nmf.v) in (3,4)]
|
||||
#print len(good_faces), 'AAA'
|
||||
|
||||
|
||||
#mesh.faces.extend([nmf.v for nmf in self.faces])
|
||||
mesh.faces.extend([[mesh.verts[nmv.index] for nmv in nmf.v] for nmf in good_faces])
|
||||
if len(mesh.faces):
|
||||
if self.faceUV:
|
||||
mesh.faceUV= 1
|
||||
|
||||
#for i, nmf in enumerate(self.faces):
|
||||
for i, nmf in enumerate(good_faces):
|
||||
mf= mesh.faces[i]
|
||||
if self.faceUV:
|
||||
if len(nmf.uv) == len(mf.v):
|
||||
mf.uv= [Vector(uv[0], uv[1]) for uv in nmf.uv]
|
||||
if len(nmf.col) == len(mf.v):
|
||||
for c, i in enumerate(mf.col):
|
||||
c.r, c.g, c.b= nmf.col[i].r, nmf.col[i].g, nmf.col[i].b
|
||||
if nmf.image:
|
||||
mf.image= nmf.image
|
||||
|
||||
mesh.materials= self.materials[:16]
|
||||
|
||||
class NMVert(object):
|
||||
__slots__= 'co', 'index', 'no', 'sel', 'uvco'
|
||||
def __init__(self, x,y,z):
|
||||
self.co= Vector(x,y,z)
|
||||
self.index= None # set on appending.
|
||||
self.no= Vector(0,0,1) # dummy
|
||||
self.sel= 0
|
||||
self.uvco= None
|
||||
class NMFace(object):
|
||||
__slots__= 'col', 'flag', 'hide', 'image', 'mat', 'materialIndex', 'mode', 'normal',\
|
||||
'sel', 'smooth', 'transp', 'uv', 'v'
|
||||
|
||||
def __init__(self, v=[]):
|
||||
self.col= []
|
||||
self.flag= 0
|
||||
self.hide= 0
|
||||
self.image= None
|
||||
self.mat= 0 # materialIndex needs support too.
|
||||
self.mode= 0
|
||||
self.normal= Vector(0,0,1)
|
||||
self.uv= []
|
||||
self.sel= 0
|
||||
self.smooth= 0
|
||||
self.transp= 0
|
||||
self.uv= []
|
||||
self.v= [] # a list of nmverts.
|
||||
|
||||
class NMCol(object):
|
||||
__slots__ = 'r', 'g', 'b', 'a'
|
||||
def __init__(self):
|
||||
self.r= 255
|
||||
self.g= 255
|
||||
self.b= 255
|
||||
self.a= 255
|
||||
|
@ -179,13 +179,12 @@ def main():
|
||||
if is_editmode and (not actob.sel):
|
||||
obsel.append(actob)
|
||||
|
||||
meshes= [ob.getData(mesh=1) for ob in obsel if ob.getType() == 'Mesh']
|
||||
|
||||
|
||||
#====================================#
|
||||
# Popup menu to select the functions #
|
||||
#====================================#
|
||||
|
||||
CLEAN_ALL_DATA= Draw.Create(0)
|
||||
CLEAN_VERTS_FREE= Draw.Create(1)
|
||||
CLEAN_EDGE_NOFACE= Draw.Create(0)
|
||||
CLEAN_EDGE_SMALL= Draw.Create(0)
|
||||
@ -213,13 +212,13 @@ def main():
|
||||
('Weight Normalize', CLEAN_WEIGHT_NORMALIZE, 'Make the sum total of vertex weights accross vgroups 1.0 for each vertex.'),\
|
||||
'',\
|
||||
('limit: ', limit, 0.001, 1.0, 'Limit used for the area and length tests above (a higher limit will remove more data).'),\
|
||||
'',\
|
||||
('All Mesh Data', CLEAN_ALL_DATA, 'Warning! Operate on ALL mesh objects in your Blend file. Use with care'),\
|
||||
]
|
||||
|
||||
|
||||
if not Draw.PupBlock('Clean Selected Meshes...', pup_block):
|
||||
return
|
||||
|
||||
|
||||
CLEAN_VERTS_FREE= CLEAN_VERTS_FREE.val
|
||||
CLEAN_EDGE_NOFACE= CLEAN_EDGE_NOFACE.val
|
||||
CLEAN_EDGE_SMALL= CLEAN_EDGE_SMALL.val
|
||||
@ -230,9 +229,19 @@ def main():
|
||||
CLEAN_VWEIGHT= CLEAN_VWEIGHT.val
|
||||
CLEAN_WEIGHT_NORMALIZE= CLEAN_WEIGHT_NORMALIZE.val
|
||||
limit= limit.val
|
||||
CLEAN_ALL_DATA= CLEAN_ALL_DATA.val
|
||||
|
||||
if is_editmode: Window.EditMode(0)
|
||||
|
||||
if CLEAN_ALL_DATA:
|
||||
if CLEAN_GROUP or CLEAN_VWEIGHT or CLEAN_WEIGHT_NORMALIZE:
|
||||
# For groups we need the objects linked to the mesh
|
||||
meshes= [ob.getData(mesh=1) for ob in Object.Get() if ob.getType() == 'Mesh']
|
||||
else:
|
||||
meshes= Mesh.Get()
|
||||
else:
|
||||
meshes= [ob.getData(mesh=1) for ob in obsel if ob.getType() == 'Mesh']
|
||||
|
||||
rem_face_count= rem_edge_count= rem_vert_count= rem_material_count= rem_group_count= rem_vweight_count= 0
|
||||
|
||||
for me in meshes:
|
||||
|
@ -463,6 +463,7 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False):
|
||||
|
||||
# Make the indicies global rather then per mesh
|
||||
totverts += len(m.verts)
|
||||
m.verts= None
|
||||
file.close()
|
||||
|
||||
|
||||
|
@ -73,91 +73,7 @@ def stripExt(name): # name is a string
|
||||
from Blender import *
|
||||
import BPyImage
|
||||
reload(BPyImage)
|
||||
|
||||
# takes a polyline of indicies (fgon)
|
||||
# and returns a list of face indicie lists.
|
||||
def ngon(from_mesh, indicies):
|
||||
if len(indicies) < 4:
|
||||
return [indicies]
|
||||
temp_mesh_name= '~NGON_TEMP~'
|
||||
is_editmode= Window.EditMode()
|
||||
if is_editmode:
|
||||
Window.EditMode(0)
|
||||
try:
|
||||
temp_mesh = Mesh.Get(temp_mesh_name)
|
||||
if temp_mesh.users!=0:
|
||||
temp_mesh = Mesh.New(temp_mesh_name)
|
||||
except:
|
||||
temp_mesh = Mesh.New(temp_mesh_name)
|
||||
|
||||
|
||||
temp_mesh.verts.extend( [from_mesh.verts[i].co for i in indicies] )
|
||||
temp_mesh.edges.extend( [(temp_mesh.verts[i], temp_mesh.verts[i-1]) for i in xrange(len(temp_mesh.verts))] )
|
||||
|
||||
oldmode = Mesh.Mode()
|
||||
Mesh.Mode(Mesh.SelectModes['VERTEX'])
|
||||
for v in temp_mesh.verts:
|
||||
v.sel= 1
|
||||
|
||||
# Must link to scene
|
||||
scn= Scene.GetCurrent()
|
||||
temp_ob= Object.New('Mesh')
|
||||
temp_ob.link(temp_mesh)
|
||||
scn.link(temp_ob)
|
||||
temp_mesh.fill()
|
||||
scn.unlink(temp_ob)
|
||||
Mesh.Mode(oldmode)
|
||||
|
||||
new_indicies= [ [v.index for v in f.v] for f in temp_mesh.faces ]
|
||||
|
||||
if not new_indicies: # JUST DO A FAN, Cant Scanfill
|
||||
print 'Warning Cannot scanfill!- Fallback on a triangle fan.'
|
||||
new_indicies = [ [indicies[0], indicies[i-1], indicies[i]] for i in xrange(2, len(indicies)) ]
|
||||
else:
|
||||
# Use real scanfill.
|
||||
# See if its flipped the wrong way.
|
||||
flip= None
|
||||
for fi in new_indicies:
|
||||
if flip != None:
|
||||
break
|
||||
for i, vi in enumerate(fi):
|
||||
if vi==0 and fi[i-1]==1:
|
||||
flip= False
|
||||
break
|
||||
elif vi==1 and fi[i-1]==0:
|
||||
flip= True
|
||||
break
|
||||
|
||||
if not flip:
|
||||
for fi in new_indicies:
|
||||
fi.reverse()
|
||||
|
||||
if is_editmode:
|
||||
Window.EditMode(1)
|
||||
|
||||
# Save some memory and forget about the verts.
|
||||
# since we cant unlink the mesh.
|
||||
temp_mesh.verts= None
|
||||
|
||||
return new_indicies
|
||||
|
||||
|
||||
|
||||
# EG
|
||||
'''
|
||||
scn= Scene.GetCurrent()
|
||||
me = scn.getActiveObject().getData(mesh=1)
|
||||
ind= [v.index for v in me.verts if v.sel] # Get indicies
|
||||
|
||||
indicies = ngon(me, ind) # fill the ngon.
|
||||
|
||||
# Extand the faces to show what the scanfill looked like.
|
||||
print len(indicies)
|
||||
me.faces.extend([[me.verts[ii] for ii in i] for i in indicies])
|
||||
'''
|
||||
|
||||
|
||||
|
||||
import BPyMesh
|
||||
|
||||
try:
|
||||
import os
|
||||
@ -416,12 +332,12 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0, IMPORT_FGO
|
||||
materialDict[k]= Material.New(k)
|
||||
|
||||
|
||||
# Make a list of all unused vert indicies that we can copy from
|
||||
# Make a list of all unused vert indices that we can copy from
|
||||
VERT_USED_LIST= [-1]*len_vertList
|
||||
|
||||
# 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
|
||||
# This is an issue with global vertex indices being translated to per mesh indices
|
||||
# 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.
|
||||
|
||||
@ -435,7 +351,7 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0, IMPORT_FGO
|
||||
#meshDict= {} # The 3 variables below are stored in a tuple within this dict for each mesh
|
||||
currentMesh= NMesh.GetRaw() # The NMesh representation of the OBJ group/Object
|
||||
#currentUsedVertList= {} # A Dict of smooth groups, each smooth group has a list of used verts and they are generated on demand so as to save memory.
|
||||
currentMaterialMeshMapping= {} # Used to store material indicies so we dont have to search the mesh for materials every time.
|
||||
currentMaterialMeshMapping= {} # Used to store material indices so we dont have to search the mesh for materials every time.
|
||||
|
||||
# Every mesh has a null smooth group, this is used if there are no smooth groups in the OBJ file.
|
||||
# and when for faces where no smooth group is used.
|
||||
@ -456,7 +372,7 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0, IMPORT_FGO
|
||||
badObjFaceTexCo= 0
|
||||
|
||||
|
||||
#currentMesh.verts.append(vertList[0]) # So we can sync with OBJ indicies where 1 is the first item.
|
||||
#currentMesh.verts.append(vertList[0]) # So we can sync with OBJ indices where 1 is the first item.
|
||||
if len_uvMapList > 1:
|
||||
currentMesh.hasFaceUV(1) # Turn UV's on if we have ANY texture coords in this obj file.
|
||||
|
||||
@ -591,7 +507,7 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0, IMPORT_FGO
|
||||
|
||||
# Vert Index - OBJ supports negative index assignment (like python)
|
||||
index= int(objVert[0])-1
|
||||
# Account for negative indicies.
|
||||
# Account for negative indices.
|
||||
if index < 0:
|
||||
if IMPORT_RELATIVE_VERTS: # non standard
|
||||
index= VERT_COUNT+index+1
|
||||
@ -713,16 +629,17 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0, IMPORT_FGO
|
||||
currentMesh.faces.append(f) # move the face onto the mesh
|
||||
|
||||
elif face_vert_count > 4: # NGons.
|
||||
# we need to map indicies to uv coords.
|
||||
# we need to map indices to uv coords.
|
||||
currentMeshRelativeIdxs= [currentUsedVertListSmoothGroup[i] for i in vIdxLs]
|
||||
|
||||
if fHasUV:
|
||||
vert2UvMapping=dict( [ (currentMeshRelativeIdxs[i],vtIdxLs[i]) for i in xrange(face_vert_count)] )
|
||||
|
||||
ngon_face_indicies= ngon(currentMesh, currentMeshRelativeIdxs)
|
||||
ngon_face_indices= BPyMesh.ngon(currentMesh, currentMeshRelativeIdxs)
|
||||
|
||||
|
||||
# At the moment scanfill always makes tri's but dont count on it
|
||||
for fillFace in ngon_face_indicies:
|
||||
for fillFace in ngon_face_indices:
|
||||
f= NMesh.Face([currentMesh.verts[currentMeshRelativeIdxs[i]] for i in fillFace])
|
||||
|
||||
if fHasUV:
|
||||
@ -739,7 +656,7 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0, IMPORT_FGO
|
||||
# Set fgon flag.
|
||||
if IMPORT_FGON:
|
||||
edgeUsers={}
|
||||
for fillFace in ngon_face_indicies:
|
||||
for fillFace in ngon_face_indices:
|
||||
for i in xrange(len(fillFace)): # Should always be 3
|
||||
i1= currentMeshRelativeIdxs[fillFace[i]]
|
||||
i2= currentMeshRelativeIdxs[fillFace[i-1]]
|
||||
@ -908,7 +825,7 @@ def load_obj_ui(file):
|
||||
('Create FGons', IMPORT_FGON, 'Import faces with more then 4 verts as fgons.'),\
|
||||
('Smooth Groups', IMPORT_SMOOTH_GROUPS, 'Only Share verts within smooth groups. (Warning, Hogs Memory)'),\
|
||||
('Split by Material', IMPORT_MTL_SPLIT, 'Import each material into a seperate mesh (Avoids >16 meterials per mesh problem)'),\
|
||||
('Relative Verts', IMPORT_RELATIVE_VERTS, 'Import non standard OBJs with relative vertex indicies, try if your mesh imports with scrambled faces.'),\
|
||||
('Relative Verts', IMPORT_RELATIVE_VERTS, 'Import non standard OBJs with relative vertex indices, try if your mesh imports with scrambled faces.'),\
|
||||
]
|
||||
|
||||
if not os:
|
||||
|
Loading…
Reference in New Issue
Block a user