6 Tooltip: 'Vector Rendering Method Export Script 0.3'
9 # ---------------------------------------------------------------------
10 # Copyright (c) 2006 Antonio Ospite
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 2 of the License, or
15 # (at your option) any later version.
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 # ---------------------------------------------------------------------
28 # NOTE: I do not know who is the original author of 'vrm'.
29 # The present code is almost entirely rewritten from scratch,
30 # but if I have to give credits to anyone, please let me know,
31 # so I can update the copyright.
33 # ---------------------------------------------------------------------
36 # Thanks to Emilio Aguirre for S2flender from which I took inspirations :)
37 # Thanks to Anthony C. D'Agostino for the backface.py script
39 # ---------------------------------------------------------------------
42 from Blender import Scene, Object, NMesh, Lamp, Camera
43 from Blender.Mathutils import *
47 # ---------------------------------------------------------------------
49 ## Projections classes
51 # ---------------------------------------------------------------------
55 print "New projection"
57 class PerspectiveProjection(Projection):
59 Projection.__init__(self)
63 print "do a perspective projection!!"
65 def Perspective(fovy, aspect, near, far):
66 top = near * tan(fovy * pi / 360.0)
70 x = (2.0 * near) / (right-left)
71 y = (2.0 * near) / (top-bottom)
72 a = (right+left) / (right-left)
73 b = (top+bottom) / (top - bottom)
74 c = - ((far+near) / (far-near))
75 d = - ((2*far*near)/(far-near))
76 return Matrix([x,0.0,a,0.0],[0.0,y,b,0.0],[0.0,0.0,c,d],[0.0,0.0,-1.0,0.0])
78 def flatten_new(v, cameraObj, canvasSize, obMesh):
80 cam = cameraObj.getInverseMatrix()
83 # Changing the view mode
84 cmra = cameraObj.getData()
88 #m2 = Ortho(fovy,float(w*ax)/float(h*ay),cmra.clipStart, cmra.clipEnd,17) #cmra.scale)
93 #frustum = _Frustum(cam,m2)
98 fovy = atan(0.5/(float(canvasSize[0])/float(canvasSize[1]))/(cmra.lens/32))
101 m2 = Perspective(fovy,float(canvasSize[0])/float(canvasSize[1]),cmra.clipStart, cmra.clipEnd)
103 m1 = obMesh.matrixWorld #mat
108 #Transform the vertices to global coordinates
109 p = mP*Vector([v.co[0],v.co[1],v.co[2],1.0])
111 #p = m1*Vector([v.co[0],v.co[1],v.co[2],1.0])
112 #t2.append([p[0],p[1],p[2]])
118 p[0] = int(p[0]*mW)+mW
119 p[1] = int(p[1]*mH)+mH
121 p[0] = int((p[0]/p[3])*mW)+mW
122 p[1] = int((p[1]/p[3])*mH)+mH
124 # Mirror and translate along y
126 p[1] += canvasSize[1]
132 # distance from camera Z'
133 def Distance(PX,PY,PZ):
135 dist = sqrt(PX*PX+PY*PY+PZ*PZ)
138 def RotatePoint(PX,PY,PZ,AngleX,AngleY,AngleZ):
142 NewY = (PY * cos(AngleX))-(PZ * sin(AngleX))
143 NewZ = (PZ * cos(AngleX))+(PY * sin(AngleX))
147 NewZ = (PZ * cos(AngleY))-(PX * sin(AngleY))
148 NewX = (PX * cos(AngleY))+(PZ * sin(AngleY))
152 NewX = (PX * cos(AngleZ))-(PY * sin(AngleZ))
153 NewY = (PY * cos(AngleZ))+(PX * sin(AngleZ))
154 NewPoint.append(NewX)
155 NewPoint.append(NewY)
156 NewPoint.append(NewZ)
159 def flatten(vertx, verty, vertz, cameraObj, canvasSize):
161 camera = cameraObj.getData()
162 Lens = camera.getLens() # The Camera lens
164 xres = canvasSize[0] # X res for output
165 yres = canvasSize[1] # Y res for output
168 fov = atan(ratio * 16.0 / Lens) # Get fov stuff
170 dist = xres/2*tan(fov) # Calculate dist from pinhole camera to image plane
177 #----------------------------
178 # calculate x'=dist*x/z & y'=dist*x/z
179 #----------------------------
180 screenxy[0]=int(xres/2.0+4*x*dist/z)
181 screenxy[1]=int(yres/2.0+4*y*dist/z)
184 ## Backface culling routine
187 def isFaceVisible(face, obj, cameraObj):
189 Determine if the face is visible from the current camera.
197 a = RotatePoint(a[0], a[1], a[2], obj.RotX, obj.RotY, obj.RotZ)
198 a[0] += obj.LocX - cameraObj.LocX
199 a[1] += obj.LocY - cameraObj.LocY
200 a[2] += obj.LocZ - cameraObj.LocZ
205 b = RotatePoint(b[0], b[1], b[2], obj.RotX, obj.RotY, obj.RotZ)
206 b[0] += obj.LocX - cameraObj.LocX
207 b[1] += obj.LocY - cameraObj.LocY
208 b[2] += obj.LocZ - cameraObj.LocZ
210 c.append(face[numvert-1][0])
211 c.append(face[numvert-1][1])
212 c.append(face[numvert-1][2])
213 c = RotatePoint(c[0], c[1], c[2], obj.RotX, obj.RotY, obj.RotZ)
214 c[0] += obj.LocX - cameraObj.LocX
215 c[1] += obj.LocY - cameraObj.LocY
216 c[2] += obj.LocZ - cameraObj.LocZ
219 norm[0] = (b[1] - a[1])*(c[2] - a[2]) - (c[1] - a[1])*(b[2] - a[2])
220 norm[1] = -((b[0] - a[0])*(c[2] - a[2]) - (c[0] - a[0])*(b[2] - a[2]))
221 norm[2] = (b[0] - a[0])*(c[1] - a[1]) - (c[0] - a[0])*(b[1] - a[1])
223 d = norm[0]*a[0] + norm[1]*a[1] + norm[2]*a[2]
227 # ---------------------------------------------------------------------
229 ## Mesh representation class
231 # ---------------------------------------------------------------------
233 # TODO: a class to represent the needed properties of a 2D vector image
236 # ---------------------------------------------------------------------
238 ## Vector Drawing Classes
240 # ---------------------------------------------------------------------
246 A class for printing output in a vectorial format.
248 Given a 2D representation of the 3D scene the class is responsible to
249 write it is a vector format.
251 Every subclasses of VectorWriter must have at last the following public
253 - printCanvas(mesh) --- where mesh is as specified before.
256 def __init__(self, fileName, canvasSize):
257 """Open the file named #fileName# and set the canvas size."""
259 self.file = open(fileName, "w")
260 print "Outputting to: ", fileName
262 self.canvasSize = canvasSize
268 def printCanvas(mesh):
284 class SVGVectorWriter(VectorWriter):
285 """A concrete class for writing SVG output.
287 The class does not support animations, yet.
291 def __init__(self, file, canvasSize):
292 """Simply call the parent Contructor."""
293 VectorWriter.__init__(self, file, canvasSize)
299 def printCanvas(self, mesh):
300 """Convert the mesh representation to SVG."""
306 self._printPolygon(face)
314 def _printHeader(self):
315 """Print SVG header."""
317 self.file.write("<?xml version=\"1.0\"?>\n")
318 self.file.write("<svg version=\"1.2\"\n")
319 self.file.write("\txmlns=\"http://www.w3.org/2000/svg\"\n")
320 self.file.write("\twidth=\"%d\" height=\"%d\" streamable=\"true\">\n\n" %
323 def _printFooter(self):
324 """Print the SVG footer."""
326 self.file.write("\n</svg>\n")
329 def _printPolygon(self, face):
330 """Print our primitive, finally.
332 There is no color Handling for now, *FIX!*
338 self.file.write("<polygon points=\"")
341 if face.index(v)!= 0:
342 self.file.write(", ")
344 self.file.write(`v[0]` + ", " + `v[1]`)
346 self.file.write("\"\n")
347 self.file.write("\tstyle=\"fill:rgb("+str(intensity)+","+str(intensity)+","+str(intensity)+");")
348 self.file.write(" stroke:rgb(0,0,0);")
349 self.file.write(" stroke-width:"+str(stroke_width)+"\"/>\n")
352 # ---------------------------------------------------------------------
356 # ---------------------------------------------------------------------
359 """Render a scene viewed from a given camera.
361 This class is responsible of the rendering process, hence transormation
362 and projection of the ojects in the scene are invoked by the renderer.
364 The user can optionally provide a specific camera for the rendering, see
365 the #doRendering# method for more informations.
369 """Set the canvas size to a defaulr value.
371 The only instance attribute here is the canvas size, which can be
372 queryed to the renderer by other entities.
374 self.canvasSize = (0.0, 0.0)
380 def getCanvasSize(self):
381 """Return the current canvas size read from Blender rendering context"""
382 return self.canvasSize
384 def doRendering(self, scene, cameraObj=None):
385 """Control the rendering process.
387 Here we control the entire rendering process invoking the operation
388 needed to transforma project the 3D scene in two dimensions.
391 scene --- the Blender Scene to render
392 cameraObj --- the camera object to use for the viewing processing
395 if cameraObj == None:
396 cameraObj = scene.getCurrentCamera()
398 # TODO: given the camera get the Wold-to-camera transform and the
401 context = scene.getRenderingContext()
402 self.canvasSize = (context.imageSizeX(), context.imageSizeY())
404 Objects = scene.getChildren()
406 # A mesh to store the transformed geometrical structure
411 if (obj.getType() != "Mesh"):
412 print "Type:", obj.getType(), "\tSorry, only mesh Object supported!"
415 OBJmesh = obj.getData() # Get the mesh data for the object
416 meshfaces = OBJmesh.faces # The number of faces in the object
418 transformed_object = []
420 for face in meshfaces:
422 # TODO: per face color calculation
423 # TODO: add/sorting in Z' direction (per face??)
425 # if the face is visible flatten it on the "picture plane"
426 if isFaceVisible(face, obj, cameraObj):
428 # Store transformed face
429 transformed_face = []
435 p1 = flatten_new(vert, cameraObj, self.canvasSize,
437 transformed_face.append(p1)
441 vertxyz = RotatePoint(vertxyz[0], vertxyz[1], vertxyz[2],
442 cameraObj.RotX, cameraObj.RotY, cameraObj.RotZ)
443 #-cameraObj.RotX, -cameraObj.RotY, -cameraObj.RotZ)
446 # original setting for translate
447 vertxyz[0] -= (obj.LocX - cameraObj.LocX)
448 vertxyz[1] -= (obj.LocY - cameraObj.LocY)
449 vertxyz[2] -= (obj.LocZ - cameraObj.LocZ)
453 vertxyz = RotatePoint(vertxyz[0], vertxyz[1], vertxyz[2], obj.RotX, obj.RotY, obj.RotZ)
457 p1 = flatten(vertxyz[0], vertxyz[1], vertxyz[2],
458 cameraObj, self.canvasSize)
460 transformed_face.append(p1)
462 # just some fake lighting...
464 transformed_object.append(transformed_face)
466 # at the end of the loop on obj
467 mesh.append(transformed_object)
474 def _removehiddenFaces(obj):
477 def _testClipping(face):
481 # ---------------------------------------------------------------------
485 # ---------------------------------------------------------------------
488 scene = Scene.GetCurrent()
489 renderer = Renderer()
491 projectedMesh = renderer.doRendering(scene)
492 canvasSize = renderer.getCanvasSize()
494 # hackish sorting of faces according to the max z value of a vertex
495 for o in projectedMesh:
496 o.sort(lambda f1, f2:
497 cmp(sum([v[2] for v in f1])/len(f1), sum([v[2] for v in f2])/len(f2)))
500 writer = SVGVectorWriter("proba.svg", canvasSize)
501 writer.printCanvas(projectedMesh)