X-Git-Url: https://git.ao2.it/vrm.git/blobdiff_plain/50d03fe3eb45bdc4a82144565911695a58e82f85..6522c892513097a6f9da53d64b5c38cf8d417c31:/vrm.py diff --git a/vrm.py b/vrm.py index f7382a7..5e2c128 100755 --- a/vrm.py +++ b/vrm.py @@ -8,7 +8,7 @@ Tooltip: 'Vector Rendering Method script' __author__ = "Antonio Ospite" __url__ = ["http://projects.blender.org/projects/vrm"] -__version__ = "0.3" +__version__ = "0.3.beta" __bpydoc__ = """\ Render the scene and save the result in vector format. @@ -42,8 +42,6 @@ __bpydoc__ = """\ # --------------------------------------------------------------------- # # Things TODO for a next release: -# - Use multiple lighting sources in color calculation, -# (this is part of the "shading refactor") and use light color! # - FIX the issue with negative scales in object tranformations! # - Use a better depth sorting algorithm # - Implement clipping of primitives and do handle object intersections. @@ -56,26 +54,39 @@ __bpydoc__ = """\ # - Consider SMIL for animation handling instead of ECMA Script? (Firefox do # not support SMIL for animations) # - Switch to the Mesh structure, should be considerably faster -# (partially done, but with Mesh we cannot sort faces, yet) +# (partially done, but with Mesh we cannot sort faces, yet) # - Implement Edge Styles (silhouettes, contours, etc.) (partially done). -# - Implement Shading Styles? (for now we use Flat Shading) (partially done). +# - Implement Shading Styles? (partially done, to make more flexible). # - Add Vector Writers other than SVG. +# - Check memory use!! +# - Support Indexed palettes!! (Useful for ILDA FILES, for example, +# see http://www.linux-laser.org/download/autotrace/ilda-output.patch) # # --------------------------------------------------------------------- # # Changelog: # -# vrm-0.3.py - 2006-05-19 -# * First release after code restucturing. -# Now the script offers a useful set of functionalities -# and it can render animations, too. +# vrm-0.3.py - ... +# * First release after code restucturing. +# Now the script offers a useful set of functionalities +# and it can render animations, too. +# * Optimization in Renderer.doEdgeStyle(), build a topology cache +# so to speed up the lookup of adjacent faces of an edge. +# Thanks ideasman42. +# * The SVG output is now SVG 1.0 valid. +# Checked with: http://jiggles.w3.org/svgvalidator/ValidatorURI.html +# * Progress indicator during HSR. # # --------------------------------------------------------------------- import Blender -from Blender import Scene, Object, Mesh, NMesh, Material, Lamp, Camera +from Blender import Scene, Object, Mesh, NMesh, Material, Lamp, Camera, Window from Blender.Mathutils import * from math import * +import sys, time + +# Constants +EPS = 10e-5 # Some global settings @@ -84,13 +95,17 @@ class config: polygons = dict() polygons['SHOW'] = True polygons['SHADING'] = 'TOON' + #polygons['HSR'] = 'PAINTER' # 'PAINTER' or 'NEWELL' + polygons['HSR'] = 'NEWELL' # Hidden to the user for now polygons['EXPANSION_TRICK'] = True + polygons['TOON_LEVELS'] = 2 + edges = dict() - edges['SHOW'] = True + edges['SHOW'] = False edges['SHOW_HIDDEN'] = False - edges['STYLE'] = 'SILHOUETTE' + edges['STYLE'] = 'MESH' # or SILHOUETTE edges['WIDTH'] = 2 edges['COLOR'] = [0, 0, 0] @@ -101,36 +116,68 @@ class config: +# Utility functions +def sign(x): + + if x < 0: + return -1 + elif x > 0: + return 1 + #else: + # return 0 + + # --------------------------------------------------------------------- # -## Utility Mesh class +## Mesh Utility class # # --------------------------------------------------------------------- class MeshUtils: - def getEdgeAdjacentFaces(edge, mesh): - """Get the faces adjacent to a given edge. - - There can be 0, 1 or more (usually 2) faces adjacent to an edge. - """ - adjface_list = [] - - for f in mesh.faces: - if (edge.v1 in f.v) and (edge.v2 in f.v): - adjface_list.append(f) - - return adjface_list + def buildEdgeFaceUsersCache(me): + ''' + Takes a mesh and returns a list aligned with the meshes edges. + Each item is a list of the faces that use the edge + would be the equiv for having ed.face_users as a property + + Taken from .blender/scripts/bpymodules/BPyMesh.py, + thanks to ideasman_42. + ''' + + def sorted_edge_indicies(ed): + i1= ed.v1.index + i2= ed.v2.index + if i1>i2: + i1,i2= i2,i1 + return i1, i2 + + + face_edges_dict= dict([(sorted_edge_indicies(ed), (ed.index, [])) for ed in me.edges]) + for f in me.faces: + fvi= [v.index for v in f.v]# face vert idx's + for i in xrange(len(f)): + i1= fvi[i] + i2= fvi[i-1] + + if i1>i2: + i1,i2= i2,i1 + + face_edges_dict[i1,i2][1].append(f) + + face_edges= [None] * len(me.edges) + for ed_index, ed_faces in face_edges_dict.itervalues(): + face_edges[ed_index]= ed_faces + + return face_edges - def isMeshEdge(e, mesh): + def isMeshEdge(adjacent_faces): """Mesh edge rule. - A mesh edge is visible if _any_ of its adjacent faces is selected. + A mesh edge is visible if _at_least_one_ of its adjacent faces is selected. Note: if the edge has no adjacent faces we want to show it as well, useful for "edge only" portion of objects. """ - adjacent_faces = MeshUtils.getEdgeAdjacentFaces(e, mesh) - if len(adjacent_faces) == 0: return True @@ -141,7 +188,7 @@ class MeshUtils: else: return False - def isSilhouetteEdge(e, mesh): + def isSilhouetteEdge(adjacent_faces): """Silhuette selection rule. An edge is a silhuette edge if it is shared by two faces with @@ -149,8 +196,6 @@ class MeshUtils: face. """ - adjacent_faces = MeshUtils.getEdgeAdjacentFaces(e, mesh) - if ((len(adjacent_faces) == 1 and adjacent_faces[0].sel == 1) or (len(adjacent_faces) == 2 and adjacent_faces[0].sel != adjacent_faces[1].sel) @@ -158,33 +203,52 @@ class MeshUtils: return True else: return False - - def toonShading(u): - levels = 2 + buildEdgeFaceUsersCache = staticmethod(buildEdgeFaceUsersCache) + isMeshEdge = staticmethod(isMeshEdge) + isSilhouetteEdge = staticmethod(isSilhouetteEdge) + + +# --------------------------------------------------------------------- +# +## Shading Utility class +# +# --------------------------------------------------------------------- +class ShadingUtils: + + shademap = None + + def toonShadingMapSetup(): + levels = config.polygons['TOON_LEVELS'] + texels = 2*levels - 1 - map = [0.0] + [(i)/float(texels-1) for i in range(1, texels-1) ] + [1.0] - + tmp_shademap = [0.0] + [(i)/float(texels-1) for i in xrange(1, texels-1) ] + [1.0] + + return tmp_shademap + + def toonShading(u): + + shademap = ShadingUtils.shademap + + if not shademap: + shademap = ShadingUtils.toonShadingMapSetup() + v = 1.0 - for i in range(0, len(map)-1): - pivot = (map[i]+map[i+1])/2.0 + for i in xrange(0, len(shademap)-1): + pivot = (shademap[i]+shademap[i+1])/2.0 j = int(u>pivot) - v = map[i+j] + v = shademap[i+j] - if v\n") - self.file.write("\n") - self.file.write("\n") + self.file.write("\n\n" % + self.file.write("\twidth=\"%d\" height=\"%d\">\n\n" % self.canvasSize) if self.animation: - self.file.write("""\n