optimize_cache = bpy.props.BoolProperty(name="Optimize cache", description="Optimize element order for vertex cache", default=True)
cache_size = bpy.props.IntProperty(name="Cache size", description="Simulated vertex cache size used in optimization", default=64, min=8, max=1024)
export_lines = bpy.props.BoolProperty(name="Export lines", description="Export edges without faces as lines", default=False)
+ export_uv = bpy.props.EnumProperty(name="Export UV", description="Export UV coordinates", default="UNIT0",
+ items=(("NONE", "None", "No UV coordinates are exported"),
+ ("UNIT0", "Unit 0", "UV coordinates for unit 0 are exported"),
+ ("ALL", "All", "All UV coordinates are exported")))
tbn_vecs = bpy.props.BoolProperty(name="TBN vectors", description="Compute tangent and binormal vectors for vertices", default=False)
+ tbn_uvtex = bpy.props.StringProperty(name="TBN UV layer", description="UV layer to use as basis for TBN vectors", default="")
compound = bpy.props.BoolProperty(name="Compound", description="Combine all selected objects into one for exporting", default=False)
object = bpy.props.BoolProperty(name="Object", description="Export an object instead of a mesh", default=False)
material_tex = bpy.props.BoolProperty(name="Material texture", description="Generate a texture based on material colors", default=False)
+ smoothing = bpy.props.EnumProperty(name="Smoothing", description="Smoothing method to use", default="MSPGL",
+ items=(("NONE", "None", "No smoothing"),
+ ("BLENDER", "Blender", "Use Blender's vertex normals"),
+ ("MSPGL", "MspGL", "Compute vertex normals internally")))
def execute(self, context):
from . import export_mspgl
self.optimize_cache = False
self.cache_size = 64
self.export_lines = True
+ self.export_uv = "UNIT0"
self.tbn_vecs = False
+ self.tbn_uvtex = ""
self.compound = False
self.object = False
self.material_tex = False
+ self.smoothing = "MSPGL"
def stripify(self, mesh, progress = None):
for f in mesh.faces:
mesh.splice(Mesh(bmesh))
progress.set_task("Smoothing", 0.05, 0.35)
- mesh.split_smooth()
+ if self.smoothing=="NONE":
+ mesh.flatten_faces()
+ mesh.split_smooth(progress)
- mesh.compute_normals()
+ if self.smoothing!="BLENDER":
+ mesh.compute_normals()
if self.material_tex:
mesh.generate_material_uv()
- if mesh.has_uv:
- progress.set_task("Splitting UVs", 0.35, 0.65)
- mesh.split_uv()
+ texunits = []
+ if mesh.uv_textures and self.export_uv!="NONE":
+ if self.export_uv=="UNIT0":
+ texunits = [0]
+ else:
+ texunits = list(range(len(mesh.uv_textures)))
+
+ for i in texunits:
+ progress.set_task("Splitting UVs", 0.35+0.3*i/len(texunits), 0.35+0.3*(i+1)/len(texunits))
+ mesh.split_uv(i, progress)
mesh.compute_uv()
if self.tbn_vecs:
- mesh.compute_tbn()
+ mesh.compute_tbn(self.tbn_uvtex)
strips = []
loose = mesh.faces
out_file.begin("mesh")
fmt = "NORMAL3"
- if mesh.has_uv:
+ if texunits:
fmt += "_TEXCOORD2"
+ for i in texunits[1:]:
+ fmt += "_TEXCOORD2%d"%i
if self.tbn_vecs:
fmt += "_ATTRIB33_ATTRIB34"
fmt += "_VERTEX3"
out_file.begin("vertices", fmt)
normal = None
- uv = None
+ uvs = [None]*len(mesh.uv_textures)
tan = None
bino = None
for v in mesh.vertices:
if v.normal!=normal:
out_file.write("normal3", *v.normal)
normal = v.normal
- if v.uv!=uv:
- out_file.write("texcoord2", *v.uv)
- uv = v.uv
+ for i in texunits:
+ if v.uvs[i]!=uvs[i]:
+ if i==0:
+ out_file.write("texcoord2", *v.uvs[i])
+ else:
+ out_file.write("multitexcoord2", i, *v.uvs[i])
+ uvs[i] = v.uvs[i]
if v.tan!=tan:
out_file.write("attrib3", 3, *v.tan)
tan = v.tan
return
d = self.faces[0].normal.dot(self.faces[1].normal)
- if (d>limit and self.faces[0].use_smooth and self.faces[1].use_smooth) or d>0.999:
- self.smooth = True
+ self.smooth = ((d>limit and self.faces[0].use_smooth and self.faces[1].use_smooth) or d>0.99995)
def other_face(self, f):
if f.index==self.faces[0].index:
if mv.__class__==Vertex:
self._mvert = mv._mvert
self.normal = mv.normal
- self.uv = mv.uv
+ self.uvs = mv.uvs[:]
else:
self._mvert = mv
- self.uv = None
+ self.uvs = []
self.flag = False
self.faces = []
self.tan = None
self._mface = mf
self.edges = []
self.vertices = mf.vertices[:]
- self.uv = None
+ self.uvs = []
self.flag = False
self.material = None
self.flag = False
+def uvtex_unit_number(uvtex):
+ dot = uvtex.name.find('.')
+ if dot!=-1 and uvtex.name[dot+1:dot+5]=="unit" and uvtex.name[dot+5:].isdigit():
+ return int(uvtex.name[dot+5])
+ else:
+ return 1000
+
class Mesh:
def __init__(self, m):
self._mesh = m
- self.vertices = [Vertex(v) for v in m.vertices]
- self.faces = [Face(f) for f in m.faces]
- self.materials = m.materials[:]
- self.has_uv = False
- uvtex = None
- if m.uv_textures:
- uvtex = self.uv_textures[0]
- self.has_uv = True
+ self.vertices = [Vertex(v) for v in self.vertices]
+ self.faces = [Face(f) for f in self.faces]
+
+ self.materials = self.materials[:]
+
+ self.uv_textures = [u for u in self.uv_textures if not u.name.endswith(".hidden")]
+ self.uv_textures.sort(key=uvtex_unit_number)
for f in self.faces:
f.vertices = [self.vertices[i] for i in f.vertices]
- if uvtex:
- f.uv = uvtex.data[f.index].uv
for v in f.vertices:
v.faces.append(f)
+ for u in self.uv_textures:
+ r = u.data[f.index].uv_raw;
+ f.uvs.append([(r[i], r[i+1]) for i in range(0, 8, 2)])
- self.edges = dict([(e.key, Edge(e)) for e in m.edges])
+ self.edges = dict([(e.key, Edge(e)) for e in self.edges])
for f in self.faces:
for k in f.edge_keys:
e = self.edges[k]
self.lines = [Line(e) for e in self.edges.values() if not e.faces]
- if m.use_auto_smooth:
- smooth_limit = math.cos(m.auto_smooth_angle*math.pi/180)
+ if self.use_auto_smooth:
+ smooth_limit = math.cos(self.auto_smooth_angle*math.pi/180)
else:
smooth_limit = -1
self.edges[e.key] = e
self.lines += other.lines
-
+
+ def flatten_faces(self):
+ for f in self.faces:
+ f.use_smooth = False
+
+ for e in self.edges.values():
+ e.check_smooth(1)
+
def generate_material_uv(self):
for f in self.faces:
f.uv = ([(f.material_index+0.5)/len(self.materials), 0.5],)*len(f.vertices)
self.has_uv = True
- def split_vertices(self, find_group_func, progress = None):
+ def split_vertices(self, find_group_func, progress, *args):
groups = []
for i in range(len(self.vertices)):
v = self.vertices[i]
vg = []
for f in v.faces:
if not f.flag:
- vg.append(find_group_func(v, f))
+ vg.append(find_group_func(v, f, *args))
groups.append(vg)
continue
if e.other_face(f) not in g and len(e.faces)>=2:
- k = e.faces.index(f)
e.faces.remove(f)
e = Edge(e)
f.edges[j] = e
def split_smooth(self, progress = None):
self.split_vertices(self.find_smooth_group, progress)
- def split_uv(self, progress = None):
- self.split_vertices(self.find_uv_group, progress)
+ def split_uv(self, index, progress = None):
+ self.split_vertices(self.find_uv_group, progress, index)
def find_smooth_group(self, vertex, face):
face.flag = True
for f in queue:
for e in f.edges:
other = e.other_face(f)
- #if not other or other.index not in face_indices:
if other not in vertex.faces:
continue
return queue
- def find_uv_group(self, vertex, face):
- uv = face.uv[face.vertices.index(vertex)]
+ def find_uv_group(self, vertex, face, index):
+ uv = face.uvs[index][face.vertices.index(vertex)]
face.flag = True
group = [face]
for f in vertex.faces:
- if not f.flag and f.uv[f.vertices.index(vertex)]==uv:
+ if not f.flag and f.uvs[index][f.vertices.index(vertex)]==uv:
f.flag = True
group.append(f)
return group
if v.faces:
v.normal = mathutils.Vector()
for f in v.faces:
- v.normal += f.normal
+ fv = f.pivot_vertices(v)
+ edge1 = fv[1].co-fv[0].co
+ edge2 = fv[-1].co-fv[0].co
+ weight = 1
+ if len(f.get_edge(fv[0], fv[1]).faces)==1:
+ weight += 1
+ if len(f.get_edge(fv[0], fv[-1]).faces)==1:
+ weight += 1
+ v.normal += f.normal*edge1.angle(edge2)*weight
v.normal.normalize()
else:
# XXX Should use edges to compute normal
def compute_uv(self):
for v in self.vertices:
if v.faces:
- v.uv = v.faces[0].uv[v.faces[0].vertices.index(v)]
+ f = v.faces[0]
+ i = f.vertices.index(v)
+ v.uvs = [u[i] for u in f.uvs]
+
+ def compute_tbn(self, uvtex):
+ if not self.uv_textures:
+ return
+
+ uvtex_names = [u.name for u in self.uv_textures]
+ if uvtex in uvtex_names:
+ uvtex_index = uvtex_names.index(uvtex)
+ else:
+ uvtex_index = 0
- def compute_tbn(self):
for v in self.vertices:
v.tan = mathutils.Vector()
v.bino = mathutils.Vector()
for f in v.faces:
- fv = f.pivot_vertices(False, v)
- v1 = fv[1]
- v2 = fv[-1]
- du1 = v1.uv[0]-v.uv[0]
- du2 = v2.uv[0]-v.uv[0]
- dv1 = v1.uv[1]-v.uv[1]
- dv2 = v2.uv[1]-v.uv[1]
- div = du1*dv2-du2*dv1
+ fv = f.pivot_vertices(v)
+ uv0 = fv[0].uvs[uvtex_index]
+ uv1 = fv[1].uvs[uvtex_index]
+ uv2 = fv[-1].uvs[uvtex_index]
+ du1 = uv1[0]-uv0[0]
+ du2 = uv2[0]-uv0[0]
+ dv1 = uv1[1]-uv0[1]
+ dv2 = uv2[1]-uv0[1]
edge1 = fv[1].co-fv[0].co
edge2 = fv[-1].co-fv[0].co
+ div = (du1*dv2-du2*dv1)
if div:
- v.tan += (edge1*dv2-edge2*dv1)/div
- v.bino += (edge2*du1-edge1*du2)/div
+ mul = edge1.angle(edge2)/div
+ v.tan += (edge1*dv2-edge2*dv1)*mul
+ v.bino += (edge2*du1-edge1*du2)*mul
+
if v.tan.length:
v.tan.normalize()
if v.bino.length: