]> git.tdb.fi Git - libs/gl.git/commitdiff
Improve smoothing in blender exporter
authorMikko Rasa <tdb@tdb.fi>
Thu, 3 Feb 2011 21:23:12 +0000 (21:23 +0000)
committerMikko Rasa <tdb@tdb.fi>
Thu, 3 Feb 2011 21:23:12 +0000 (21:23 +0000)
Support exporting multiple sets of texture coordinates

blender/io_mesh_mspgl/__init__.py
blender/io_mesh_mspgl/export_mspgl.py
blender/io_mesh_mspgl/mesh.py

index 1445ff40fff814e11e9a0e156b89440634ebc75b..5ff3b4bc93e30cf635cb7d31e26bf87af2394df7 100644 (file)
@@ -13,10 +13,19 @@ class ExportMspGL(bpy.types.Operator, ExportHelper):
        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
index 6de38f8722935d884f45c4fbc441bca1e28926f7..e2082cb8d04770b1b4c510eaca90c4797114afcc 100644 (file)
@@ -71,10 +71,13 @@ class Exporter:
                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:
@@ -236,20 +239,30 @@ class Exporter:
                                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
@@ -264,23 +277,29 @@ class Exporter:
                        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
index 5af8578720d10bbe78759f995d72ab6912b79311..e3405f9f8e055490b71bf7a4323abcfc1475c752 100644 (file)
@@ -23,8 +23,7 @@ class Edge:
                        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:
@@ -41,10 +40,10 @@ class Vertex:
                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
@@ -64,7 +63,7 @@ class Face:
                self._mface = mf
                self.edges = []
                self.vertices = mf.vertices[:]
-               self.uv = None
+               self.uvs = []
                self.flag = False
                self.material = None
 
@@ -98,27 +97,34 @@ class Line:
                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]
@@ -127,8 +133,8 @@ class Mesh:
 
                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
 
@@ -164,13 +170,20 @@ class Mesh:
                        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]
@@ -180,7 +193,7 @@ class Mesh:
                        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)
 
@@ -204,7 +217,6 @@ class Mesh:
                                                        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
@@ -227,8 +239,8 @@ class Mesh:
        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
@@ -237,7 +249,6 @@ class Mesh:
                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
 
@@ -248,12 +259,12 @@ class Mesh:
 
                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
@@ -263,7 +274,15 @@ class Mesh:
                        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
@@ -272,26 +291,40 @@ class Mesh:
        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: