Implement proper View Frustum clipping
[vrm.git] / vrm.py
diff --git a/vrm.py b/vrm.py
index f4cfcbd..0338065 100755 (executable)
--- a/vrm.py
+++ b/vrm.py
@@ -119,9 +119,8 @@ class config:
     edges['COLOR'] = [0, 0, 0]
 
     output = dict()
     edges['COLOR'] = [0, 0, 0]
 
     output = dict()
-    output['FORMAT'] = 'PDF'
-    #output['ANIMATION'] = False
-    output['ANIMATION'] = True
+    output['FORMAT'] = 'SVG'
+    output['ANIMATION'] = False
     output['JOIN_OBJECTS'] = True
 
 
     output['JOIN_OBJECTS'] = True
 
 
@@ -593,7 +592,7 @@ class HSR:
 
     makeFaces = staticmethod(makeFaces)
 
 
     makeFaces = staticmethod(makeFaces)
 
-    def splitOn(Q, P):
+    def splitOn(Q, P, return_positive_faces=True, return_negative_faces=True):
         """Split P using the plane of Q.
         Logic taken from the knife.py python script
         """
         """Split P using the plane of Q.
         Logic taken from the knife.py python script
         """
@@ -691,16 +690,20 @@ class HSR:
 
         # If vertex are all on the same half-space, return
         #if len(posVertList) < 3:
 
         # If vertex are all on the same half-space, return
         #if len(posVertList) < 3:
-        #    print "Problem, we created a face with less that 3 verteices??"
+        #    print "Problem, we created a face with less that 3 vertices??"
         #    posVertList = []
         #if len(negVertList) < 3:
         #    posVertList = []
         #if len(negVertList) < 3:
-        #    print "Problem, we created a face with less that 3 verteices??"
+        #    print "Problem, we created a face with less that 3 vertices??"
         #    negVertList = []
 
         if len(posVertList) < 3 or len(negVertList) < 3:
         #    negVertList = []
 
         if len(posVertList) < 3 or len(negVertList) < 3:
-            print "RETURN NONE, SURE???"
+            #print "RETURN NONE, SURE???"
             return None
 
             return None
 
+        if not return_positive_faces:
+            posVertList = []
+        if not return_negative_faces:
+            negVertList = []
 
         newfaces = HSR.addNewFaces(posVertList, negVertList)
 
 
         newfaces = HSR.addNewFaces(posVertList, negVertList)
 
@@ -2097,7 +2100,7 @@ class Renderer:
         For now clip away only objects according to their center position.
         """
 
         For now clip away only objects according to their center position.
         """
 
-        cpos = self._getObjPosition(self.cameraObj)
+        cam_pos = self._getObjPosition(self.cameraObj)
         view_vect = self._cameraViewVector()
 
         near = self.cameraObj.data.clipStart
         view_vect = self._cameraViewVector()
 
         near = self.cameraObj.data.clipStart
@@ -2111,7 +2114,10 @@ class Renderer:
         for o in Objects:
             if o.getType() != 'Mesh': continue;
 
         for o in Objects:
             if o.getType() != 'Mesh': continue;
 
-            obj_vect = Vector(cpos) - self._getObjPosition(o)
+            # TODO: use the object bounding box (that is already in WorldSpace)
+            # bb = o.getBoundBox() and then: for point in bb: ...
+
+            obj_vect = Vector(cam_pos) - self._getObjPosition(o)
 
             d = obj_vect*view_vect
             theta = AngleBetweenVecs(obj_vect, view_vect)
 
             d = obj_vect*view_vect
             theta = AngleBetweenVecs(obj_vect, view_vect)
@@ -2402,6 +2408,70 @@ class Renderer:
         """Clip faces against the View Frustum.
         """
 
         """Clip faces against the View Frustum.
         """
 
+        # The Canonical View Volume, 8 vertices, and 6 faces,
+        # We consider its face normals pointing outside
+        
+        v1 = NMesh.Vert(1, 1, -1)
+        v2 = NMesh.Vert(1, -1, -1)
+        v3 = NMesh.Vert(-1, -1, -1)
+        v4 = NMesh.Vert(-1, 1, -1)
+        v5 = NMesh.Vert(1, 1, 1)
+        v6 = NMesh.Vert(1, -1, 1)
+        v7 = NMesh.Vert(-1, -1, 1)
+        v8 = NMesh.Vert(-1, 1, 1)
+
+        cvv = []
+        f1 = NMesh.Face([v1, v4, v3, v2])
+        cvv.append(f1)
+        f2 = NMesh.Face([v5, v6, v7, v8])
+        cvv.append(f2)
+        f3 = NMesh.Face([v1, v2, v6, v5])
+        cvv.append(f3)
+        f4 = NMesh.Face([v2, v3, v7, v6])
+        cvv.append(f4)
+        f5 = NMesh.Face([v3, v4, v8, v7])
+        cvv.append(f5)
+        f6 = NMesh.Face([v4, v1, v5, v8])
+        cvv.append(f6)
+
+        nmesh = NMesh.GetRaw(mesh.name)
+        clippedfaces = nmesh.faces[:]
+        facelist = clippedfaces[:]
+
+        for clipface in cvv:
+
+            clippedfaces = []
+            for f in facelist:
+                
+                newfaces = HSR.splitOn(clipface, f, return_positive_faces=False)
+
+                if not newfaces:
+                    # Check if the face is inside the view rectangle
+                    # TODO: Do this test before, it is more efficient
+                    points_outside = 0
+                    for v in f:
+                        if abs(v[0]) > 1-EPS or abs(v[1]) > 1-EPS:
+                            points_outside += 1
+
+                    if points_outside != len(f):
+                        clippedfaces.append(f)
+                else:
+                    for nf in newfaces:
+                        for v in nf:
+                            nmesh.verts.append(v)
+
+                        nf.mat = f.mat
+                        nf.sel = f.sel
+                        nf.col = [f.col[0]] * len(nf.v)
+
+                        clippedfaces.append(nf)
+
+            facelist = clippedfaces[:]
+
+        nmesh.faces = facelist
+        nmesh.update()
+        
+
     # HSR routines
     def __simpleDepthSort(self, mesh):
         """Sort faces by the furthest vertex.
     # HSR routines
     def __simpleDepthSort(self, mesh):
         """Sort faces by the furthest vertex.