Misc fixes and updates
authorAntonio Ospite <ospite@studenti.unina.it>
Fri, 14 Apr 2006 13:34:31 +0000 (15:34 +0200)
committerAntonio Ospite <ospite@studenti.unina.it>
Thu, 24 Sep 2009 11:24:15 +0000 (13:24 +0200)
 * Fix projection
 * Fix face color rendering and add a way to disable wireframe
 * Use a scene for the transformed object so we don't touch the
   original user data
 * Add a better visibility routine
 * A little better depth sorting
 * Add support for batch mode

Signed-off-by: Antonio Ospite <ospite@studenti.unina.it>
vrm.py

diff --git a/vrm.py b/vrm.py
index 871131e..00c8ed4 100755 (executable)
--- a/vrm.py
+++ b/vrm.py
@@ -84,14 +84,12 @@ class Projector:
         else:
             m2 = self._calcPerspectiveMatrix(fovy, aspect, near, far) 
         
-        m1 = Matrix()
-        mP = Matrix()
 
         # View transformation
-        cam = cameraObj.getInverseMatrix()
+        cam = Matrix(cameraObj.getInverseMatrix())
         cam.transpose() 
 
-        m1 = obMesh.getMatrix()
+        m1 = Matrix(obMesh.getMatrix())
         m1.transpose()
         
         mP = cam * m1
@@ -117,11 +115,11 @@ class Projector:
         mH = self.size[1]/2
         
         if p[3]<=0:
-            p[0] = int(p[0]*mW)+mW
-            p[1] = int(p[1]*mH)+mH
+            p[0] = round(p[0]*mW)+mW
+            p[1] = round(p[1]*mH)+mH
         else:
-            p[0] = int((p[0]/p[3])*mW)+mW
-            p[1] = int((p[1]/p[3])*mH)+mH
+            p[0] = round((p[0]/p[3])*mW)+mW
+            p[1] = round((p[1]/p[3])*mH)+mH
             
         # For now we want (0,0) in the top-left corner of the canvas
         # Mirror and translate along y
@@ -259,10 +257,11 @@ class SVGVectorWriter(VectorWriter):
 
         self._printHeader()
         
-        for obj in scene:
+        Objects = scene.getChildren()
+        for obj in Objects:
             self.file.write("<g>\n")
             
-            for face in obj.faces:
+            for face in obj.getData().faces:
                 self._printPolygon(face)
 
             self.file.write("</g>\n")
@@ -290,30 +289,33 @@ class SVGVectorWriter(VectorWriter):
 
     def _printPolygon(self, face):
         """Print our primitive, finally.
-
-        There is no color Handling for now, *FIX!*
         """
-
-        stroke_width=1
+        
+        wireframe = False
+        
+        stroke_width=0.5
         
         self.file.write("<polygon points=\"")
 
-        i = 0
         for v in face:
-            if i != 0:
-                self.file.write(", ")
-
-            i+=1
-            
-            self.file.write("%g, %g" % (v[0], v[1]))
+            self.file.write("%g,%g " % (v[0], v[1]))
         
-        color = [ int(c*255) for c in face.col]
-
+        self.file.seek(-1,1) # get rid of the last space
         self.file.write("\"\n")
+        
+        #take as face color the first vertex color
+        fcol = face.col[0]
+        color = [fcol.r, fcol.g, fcol.b]
+
+        stroke_col = [0, 0, 0]
+        if not wireframe:
+            stroke_col = color
+
         self.file.write("\tstyle=\"fill:rgb("+str(color[0])+","+str(color[1])+","+str(color[2])+");")
-        self.file.write(" stroke:rgb(0,0,0);")
+        self.file.write(" stroke:rgb("+str(stroke_col[0])+","+str(stroke_col[1])+","+str(stroke_col[2])+");")
         self.file.write(" stroke-width:"+str(stroke_width)+";\n")
-        self.file.write(" stroke-linecap:round;stroke-linejoin:round\"/>\n")
+        self.file.write(" stroke-linecap:round;stroke-linejoin:round")
+        self.file.write("\"/>\n")
 
 
 # ---------------------------------------------------------------------
@@ -390,7 +392,7 @@ class Renderer:
         Objects = scene.getChildren()
         
         # A structure to store the transformed scene
-        newscene = []
+        newscene = Scene.New("flat"+scene.name)
         
         for obj in Objects:
             
@@ -402,7 +404,8 @@ class Renderer:
             proj = Projector(cameraObj, obj, self.canvasSize)
 
             # Let's store the transformed data
-            transformed_mesh = NMesh.New(obj.name)
+            transformed_mesh = NMesh.New("flat"+obj.name)
+            transformed_mesh.hasVertexColours(1)
 
             # Store the materials
             materials = obj.getData().getMaterials()
@@ -412,26 +415,33 @@ class Renderer:
             for face in meshfaces:
 
                 # if the face is visible flatten it on the "picture plane"
-                if self._isFaceVisible(face, obj, cameraObj):
+                if self._isFaceVisible_old(face, obj, cameraObj):
                     
                     # Store transformed face
-                    transformed_face = []
+                    newface = NMesh.Face()
 
                     for vert in face:
 
                         p = proj.doProjection(vert.co)
 
-                        transformed_vert = NMesh.Vert(p[0], p[1], p[2])
-                        transformed_face.append(transformed_vert)
+                        tmp_vert = NMesh.Vert(p[0], p[1], p[2])
 
-                    newface = NMesh.Face(transformed_face)
+                        # Add the vert to the mesh
+                        transformed_mesh.verts.append(tmp_vert)
+                        
+                        newface.v.append(tmp_vert)
+                        
                     
                     # Per-face color calculation
                     # code taken mostly from the original vrm script
                     # TODO: understand the code and rewrite it clearly
-                    ambient = -250
-                    fakelight = [10, 10, 15]
-                    norm = face.normal
+                    ambient = -150
+                    
+                    fakelight = Object.Get("Lamp").loc
+                    if fakelight == None:
+                        fakelight = [1.0, 1.0, -0.3]
+
+                    norm = Vector(face.no)
                     vektori = (norm[0]*fakelight[0]+norm[1]*fakelight[1]+norm[2]*fakelight[2])
                     vduzine = fabs(sqrt(pow(norm[0],2)+pow(norm[1],2)+pow(norm[2],2))*sqrt(pow(fakelight[0],2)+pow(fakelight[1],2)+pow(fakelight[2],2)))
                     intensity = floor(ambient + 200*acos(vektori/vduzine))/200
@@ -439,21 +449,24 @@ class Renderer:
                         intensity = 0
 
                     if materials:
-                        newface.col = materials[face.mat].getRGBCol()
+                        tmp_col = materials[face.mat].getRGBCol()
                     else:
-                        newface.col = [0.5, 0.5, 0.5]
+                        tmp_col = [0.5, 0.5, 0.5]
                         
-                    newface.col = [ (c>0) and (c-intensity) for c in newface.col]
+                    tmp_col = [ (c>intensity) and int(round((c-intensity)*10)*25.5) for c in tmp_col ]
+
+                    vcol = NMesh.Col(tmp_col[0], tmp_col[1], tmp_col[2])
+                    newface.col = [vcol, vcol, vcol, 255]
                     
                     transformed_mesh.addFace(newface)
 
             # at the end of the loop on obj
             
-            #transformed_object = NMesh.PutRaw(transformed_mesh)
-            newscene.append(transformed_mesh)
+            transformed_obj = Object.New(obj.getType(), "flat"+obj.name)
+            transformed_obj.link(transformed_mesh)
+            transformed_obj.loc = obj.loc
+            newscene.link(transformed_obj)
 
-        # reverse the order (TODO: See how is the object order in NMesh)
-        #newscene.reverse()
         
         return newscene
 
@@ -462,7 +475,7 @@ class Renderer:
     # Private Methods
     #
 
-    def _isFaceVisible(self, face, obj, cameraObj):
+    def _isFaceVisible_old(self, face, obj, cameraObj):
         """Determine if the face is visible from the current camera.
 
         The following code is taken basicly from the original vrm script.
@@ -508,13 +521,40 @@ class Renderer:
         c[1] += obj.LocY - camera.LocY
         c[2] += obj.LocZ - camera.LocZ
 
-        norm = Vector([0,0,0])
+        norm = [0, 0, 0]
         norm[0] = (b[1] - a[1])*(c[2] - a[2]) - (c[1] - a[1])*(b[2] - a[2])
         norm[1] = -((b[0] - a[0])*(c[2] - a[2]) - (c[0] - a[0])*(b[2] - a[2]))
         norm[2] = (b[0] - a[0])*(c[1] - a[1]) - (c[0] - a[0])*(b[1] - a[1])
 
         d = norm[0]*a[0] + norm[1]*a[1] + norm[2]*a[2]
-        # d = DotVecs(norm, Vector(a))
+        #d = DotVecs(Vector(norm), Vector(a))
+
+        return (d<0)
+    
+    def _isFaceVisible(self, face, obj, cameraObj):
+        """Determine if the face is visible from the current camera.
+
+        The following code is taken basicly from the original vrm script.
+        """
+
+        camera = cameraObj
+
+        numvert = len(face)
+
+        # backface culling
+
+        # translate and rotate according to the object matrix
+        # and then translate according to the camera position
+        m = obj.getMatrix()
+        m.transpose()
+        
+        a = m*Vector(face[0]) - Vector(cameraObj.loc)
+        b = m*Vector(face[1]) - Vector(cameraObj.loc)
+        c = m*Vector(face[numvert-1]) - Vector(cameraObj.loc)
+
+        norm = m*Vector(face.no)
+
+        d = DotVecs(norm, a)
 
         return (d<0)
 
@@ -529,10 +569,24 @@ class Renderer:
 # ---------------------------------------------------------------------
 
 
-# hackish sorting of faces according to the max z value of a vertex
-def zSorting(scene):
-    for o in scene:
-        o.faces.sort(lambda f1, f2:
+# FIXME: really hackish code, just to test if the other parts work
+def depthSorting(scene):
+
+    cameraObj = Scene.GetCurrent().getCurrentCamera()
+    Objects = scene.getChildren()
+
+    Objects.sort(lambda obj1, obj2: 
+            cmp(Vector(Vector(cameraObj.loc) - Vector(obj1.loc)).length,
+                Vector(Vector(cameraObj.loc) - Vector(obj2.loc)).length
+                )
+            )
+    
+    # hackish sorting of faces according to the max z value of a vertex
+    for o in Objects:
+
+        mesh = o.data
+        mesh.faces.sort(
+            lambda f1, f2:
                 # Sort faces according to the min z coordinate in a face
                 #cmp(min([v[2] for v in f1]), min([v[2] for v in f2])))
 
@@ -541,30 +595,37 @@ def zSorting(scene):
                 
                 # Sort faces according to the avg z coordinate in a face
                 #cmp(sum([v[2] for v in f1])/len(f1), sum([v[2] for v in f2])/len(f2)))
-        o.faces.reverse()
+        mesh.faces.reverse()
+        mesh.update()
+        
+    # update the scene
+    for o in scene.getChildren():
+        scene.unlink(o)
+    for o in Objects:
+        scene.link(o)
     
-from Blender import sys
 def vectorize(filename):
 
     print "Filename: %s" % filename
-    print
-    filename = filename.replace('/', sys.sep)
-    print filename
-    print
     
-    scene   = Scene.GetCurrent()
+    scene = Scene.GetCurrent()
     renderer = Renderer()
 
     flatScene = renderer.doRendering(scene)
     canvasSize = renderer.getCanvasSize()
 
-    zSorting(flatScene)
+    depthSorting(flatScene)
 
     writer = SVGVectorWriter(filename, canvasSize)
     writer.printCanvas(flatScene)
-    
-try:
-    Blender.Window.FileSelector (vectorize, 'Save SVG', "proba.svg")
-except:
-    vectorize("proba.svg")
+
+    Blender.Scene.unlink(flatScene)
+    del flatScene
+
+# Here the main
+if __name__ == "__main__":
+    try:
+        Blender.Window.FileSelector (vectorize, 'Save SVG', "proba.svg")
+    except:
+        vectorize("proba.svg")