* Implement Edge coloring
* Fix some values in the config class
* Apply the color model to objects, FLAT or TOON?
* Add edge color picker to the GUI
Signed-off-by: Antonio Ospite <ospite@studenti.unina.it>
# - Implement clipping of primitives and do handle object intersections.
# (for now only clipping for whole objects is supported).
# - Implement Edge Styles (silhouettes, contours, etc.) (partially done).
# - Implement clipping of primitives and do handle object intersections.
# (for now only clipping for whole objects is supported).
# - Implement Edge Styles (silhouettes, contours, etc.) (partially done).
-# - Implement Edge coloring
# - Use multiple lighting sources in color calculation
# - Implement Shading Styles? (for now we use Flat Shading).
# - Use a data structure other than Mesh to represent the 2D image?
# - Use multiple lighting sources in color calculation
# - Implement Shading Styles? (for now we use Flat Shading).
# - Use a data structure other than Mesh to represent the 2D image?
class config:
polygons = dict()
class config:
polygons = dict()
- polygons['FILL'] = True
- polygons['STYLE'] = None
+ polygons['SHOW'] = True
+ polygons['SHADING'] = 'TOON'
# Hidden to the user for now
polygons['EXPANSION_TRICK'] = True
edges = dict()
edges['SHOW'] = True
edges['SHOW_HIDDEN'] = False
# Hidden to the user for now
polygons['EXPANSION_TRICK'] = True
edges = dict()
edges['SHOW'] = True
edges['SHOW_HIDDEN'] = False
- edges['STYLE'] = 'silhouette'
+ edges['STYLE'] = 'SILHOUETTE'
+ edges['COLOR'] = [0, 0, 0]
output = dict()
output['FORMAT'] = 'SVG'
output['ANIMATION'] = False
output = dict()
output['FORMAT'] = 'SVG'
output['ANIMATION'] = False
- output['MERGED_OBJECTS'] = True
+ output['JOIN_OBJECTS'] = True
- def isVisibleEdge(e, mesh):
- """Normal edge selection rule.
+ def isMeshEdge(e, mesh):
+ """Mesh edge rule.
- An edge is visible if _any_ of its adjacent faces is selected.
+ A mesh edge is visible if _any_ 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.
"""
Note: if the edge has no adjacent faces we want to show it as well,
useful for "edge only" portion of objects.
"""
getEdgeAdjacentFaces = staticmethod(getEdgeAdjacentFaces)
getEdgeAdjacentFaces = staticmethod(getEdgeAdjacentFaces)
- isVisibleEdge = staticmethod(isVisibleEdge)
+ isMeshEdge = staticmethod(isMeshEdge)
isSilhouetteEdge = staticmethod(isSilhouetteEdge)
toonShading = staticmethod(toonShading)
isSilhouetteEdge = staticmethod(isSilhouetteEdge)
toonShading = staticmethod(toonShading)
self.file.write("\n</svg>\n")
self.file.write("\n</svg>\n")
- def _printPolygons(self, mesh):
+ def _printPolygons(self, mesh):
"""Print the selected (visible) polygons.
"""
"""Print the selected (visible) polygons.
"""
else:
color = [255, 255, 255, 255]
else:
color = [255, 255, 255, 255]
+ # Convert the color to the #RRGGBB form
+ str_col = "#%02X%02X%02X" % (color[0], color[1], color[2])
+
# use the stroke property to alleviate the "adjacent edges" problem,
# we simulate polygon expansion using borders,
# see http://www.antigrain.com/svg/index.html for more info
# use the stroke property to alleviate the "adjacent edges" problem,
# we simulate polygon expansion using borders,
# see http://www.antigrain.com/svg/index.html for more info
- # Convert the color to the #RRGGBB form
- str_col = "#%02X%02X%02X" % (color[0], color[1], color[2])
-
# Handle transparent polygons
opacity_string = ""
if color[3] != 255:
# Handle transparent polygons
opacity_string = ""
if color[3] != 255:
"""Print the wireframe using mesh edges.
"""
"""Print the wireframe using mesh edges.
"""
- stroke_width=EDGES_WIDTH
- stroke_col = [0, 0, 0]
+ stroke_width = config.edges['WIDTH']
+ stroke_col = config.edges['COLOR']
#
# ---------------------------------------------------------------------
#
# ---------------------------------------------------------------------
-# A dictionary to collect all the different edge styles and their edge
-# selection criteria
-edgeSelectionStyles = {
- 'normal': MeshUtils.isVisibleEdge,
- 'silhouette': MeshUtils.isSilhouetteEdge
- }
+# A dictionary to collect different shading style methods
+shadingStyles = dict()
+shadingStyles['FLAT'] = None
+shadingStyles['TOON'] = None
+
+# A dictionary to collect different edge style methods
+edgeStyles = dict()
+edgeStyles['MESH'] = MeshUtils.isMeshEdge
+edgeStyles['SILHOUETTE'] = MeshUtils.isSilhouetteEdge
# A dictionary to collect the supported output formats
# A dictionary to collect the supported output formats
-outputWriters = {
- 'SVG': SVGVectorWriter,
- }
+outputWriters = dict()
+outputWriters['SVG'] = SVGVectorWriter
"""
context = self._SCENE.getRenderingContext()
"""
context = self._SCENE.getRenderingContext()
- currentFrame = context.currentFrame()
+ origCurrentFrame = context.currentFrame()
# Handle the animation case
if not animation:
# Handle the animation case
if not animation:
- startFrame = currentFrame
+ startFrame = origCurrentFrame
endFrame = startFrame
outputWriter.open()
else:
endFrame = startFrame
outputWriter.open()
else:
# Use some temporary workspace, a full copy of the scene
inputScene = self._SCENE.copy(2)
# Use some temporary workspace, a full copy of the scene
inputScene = self._SCENE.copy(2)
try:
renderedScene = self.doRenderScene(inputScene)
try:
renderedScene = self.doRenderScene(inputScene)
+ except :
+ print "There was an error! Aborting."
+ import traceback
+ print traceback.print_exc()
+
self._SCENE.makeCurrent()
Scene.unlink(inputScene)
del inputScene
self._SCENE.makeCurrent()
Scene.unlink(inputScene)
del inputScene
outputWriter.printCanvas(renderedScene,
outputWriter.printCanvas(renderedScene,
- doPrintPolygons = config.polygons['FILL'],
+ doPrintPolygons = config.polygons['SHOW'],
doPrintEdges = config.edges['SHOW'],
showHiddenEdges = config.edges['SHOW_HIDDEN'])
doPrintEdges = config.edges['SHOW'],
showHiddenEdges = config.edges['SHOW_HIDDEN'])
# clear the rendered scene
self._SCENE.makeCurrent()
Scene.unlink(renderedScene)
# clear the rendered scene
self._SCENE.makeCurrent()
Scene.unlink(renderedScene)
outputWriter.close()
print "Done!"
outputWriter.close()
print "Done!"
- context.currentFrame(currentFrame)
+ context.currentFrame(origCurrentFrame)
def doRenderScene(self, workScene):
def doRenderScene(self, workScene):
self._doSceneClipping(workScene)
self._doSceneClipping(workScene)
-
- # XXX: Joining objects does not work in batch mode!!
- # Do not touch the following if, please :)
-
- global OPTIMIZE_FOR_SPACE
- if Blender.mode == 'background':
- print "\nWARNING! Joining objects not supported in background mode!\n"
- OPTIMIZE_FOR_SPACE = False
-
- if OPTIMIZE_FOR_SPACE:
+ if config.output['JOIN_OBJECTS']:
self._joinMeshObjectsInScene(workScene)
self._joinMeshObjectsInScene(workScene)
self._doSceneDepthSorting(workScene)
# Per object activities
self._doSceneDepthSorting(workScene)
# Per object activities
print "Rendering: ", obj.getName()
print "Rendering: ", obj.getName()
+ mesh = obj.getData(mesh=1)
self._doModelToWorldCoordinates(mesh, obj.matrix)
self._doObjectDepthSorting(mesh)
self._doModelToWorldCoordinates(mesh, obj.matrix)
self._doObjectDepthSorting(mesh)
- # We use both Mesh and NMesh because for depth sorting we change
- # face order and Mesh class don't let us to do that.
- mesh.update()
- mesh = obj.getData(mesh=1)
-
self._doBackFaceCulling(mesh)
self._doColorAndLighting(mesh)
self._doBackFaceCulling(mesh)
self._doColorAndLighting(mesh)
- self._doEdgesStyle(mesh, edgeSelectionStyles[EDGE_STYLE])
+ self._doEdgesStyle(mesh, edgeStyles[config.edges['STYLE']])
self._doProjection(mesh, self.proj)
self._doProjection(mesh, self.proj)
me.recalcNormals()
me.update()
me.recalcNormals()
me.update()
def _doSceneClipping(self, scene):
"""Clip objects against the View Frustum.
def _doSceneClipping(self, scene):
"""Clip objects against the View Frustum.
"""Merge all the Mesh Objects in a scene into a single Mesh Object.
"""
"""Merge all the Mesh Objects in a scene into a single Mesh Object.
"""
+ if Blender.mode == 'background':
+ print "\nWARNING! Joining objects not supported in background mode!\n"
+ return
+
oList = [o for o in scene.getChildren() if o.getType()=='Mesh']
# FIXME: Object.join() do not work if the list contains 1 object
if len(oList) == 1:
return
oList = [o for o in scene.getChildren() if o.getType()=='Mesh']
# FIXME: Object.join() do not work if the list contains 1 object
if len(oList) == 1:
return
+ mesh = Mesh.New('BigOne')
bigObj = Object.New('Mesh', 'BigOne')
bigObj.link(mesh)
bigObj = Object.New('Mesh', 'BigOne')
bigObj.link(mesh)
+
+ try:
+ bigObj.join(oList)
+ except RuntimeError:
+ print "Can't Join Objects"
+ scene.unlink(bigObj)
+ return
+ except TypeError:
+ print "Objects Type error?"
+
for o in oList:
scene.unlink(o)
for o in oList:
scene.unlink(o)
The faces in the object are sorted following the distance of the
vertices from the camera position.
"""
The faces in the object are sorted following the distance of the
vertices from the camera position.
"""
+ if len(mesh.faces) == 0:
+ return
+
c = self._getObjPosition(self.cameraObj)
# hackish sorting of faces
c = self._getObjPosition(self.cameraObj)
# hackish sorting of faces
cmp(sum([(Vector(v.co)-Vector(c)).length for v in f1])/len(f1),
sum([(Vector(v.co)-Vector(c)).length for v in f2])/len(f2)))
cmp(sum([(Vector(v.co)-Vector(c)).length for v in f1])/len(f1),
sum([(Vector(v.co)-Vector(c)).length for v in f2])/len(f2)))
- mesh.faces.sort(by_max_vert_dist)
- mesh.faces.reverse()
+
+ # FIXME: using NMesh to sort faces. We should avoid that!
+ nmesh = NMesh.GetRaw(mesh.name)
+ nmesh.faces.sort(by_max_vert_dist)
+ nmesh.faces.reverse()
+
+ mesh.faces.delete(1, range(0, len(mesh.faces)))
+
+ for i,f in enumerate(nmesh.faces):
+ fv = [v.index for v in f.v]
+ mesh.faces.extend(fv)
+ mesh.faces[i].mat = f.mat
+
def _doBackFaceCulling(self, mesh):
"""Simple Backface Culling routine.
def _doBackFaceCulling(self, mesh):
"""Simple Backface Culling routine.
if self._isFaceVisible(f):
f.sel = 1
if self._isFaceVisible(f):
f.sel = 1
- # Is this the correct way to propagate the face selection info to the
- # vertices belonging to a face ??
- # TODO: Using the Mesh module this should come for free. Right?
- #Mesh.Mode(Mesh.SelectModes['VERTEX'])
- #for f in mesh.faces:
- # if not f.sel:
- # for v in f: v.sel = 0;
-
- #for f in mesh.faces:
- # if f.sel:
- # for v in f: v.sel = 1;
-
def _doColorAndLighting(self, mesh):
def _doColorAndLighting(self, mesh):
- """Apply an Illumination model to the object.
+ """Apply an Illumination ans shading model to the object.
- The Illumination model used is the Phong one, it may be inefficient,
+ The model used is the Phong one, it may be inefficient,
but I'm just learning about rendering and starting from Phong seemed
the most natural way.
"""
but I'm just learning about rendering and starting from Phong seemed
the most natural way.
"""
L = Vector(light_pos).normalize()
L = Vector(light_pos).normalize()
- V = (Vector(camPos) - Vector(f.v[0].co)).normalize()
+ V = (Vector(camPos) - Vector(f.cent)).normalize()
N = Vector(f.no).normalize()
R = 2 * (N*L) * N - L
# TODO: Attenuation factor (not used for now)
N = Vector(f.no).normalize()
R = 2 * (N*L) * N - L
# TODO: Attenuation factor (not used for now)
- a0 = 1; a1 = 0.0; a2 = 0.0
+ a0 = 1.0; a1 = 0.0; a2 = 1.0
d = (Vector(f.v[0].co) - Vector(light_pos)).length
d = (Vector(f.v[0].co) - Vector(light_pos)).length
- fd = min(1, 1.0/(a0 + a1*d + a2*d*d))
+ fd = min(1, 1.0/(a0 + a1*d + a2*(d*d)))
# Ambient component
Ia = 1.0
# Ambient component
Ia = 1.0
# Diffuse component (add light.col for kd)
kd = mat.getRef() * Vector(mat.getRGBCol())
Ip = light.getEnergy()
# Diffuse component (add light.col for kd)
kd = mat.getRef() * Vector(mat.getRGBCol())
Ip = light.getEnergy()
- #Idiff = Ip * kd * int(N*L > 0.5)
- Idiff = Ip * kd * MeshUtils.toonShading(N*L)
+
+ if config.polygons['SHADING'] == 'FLAT':
+ Idiff = Ip * kd * (N*L)
+ elif config.polygons['SHADING'] == 'TOON':
+ Idiff = Ip * kd * MeshUtils.toonShading(N*L)
# Specular component
ks = mat.getSpec() * Vector(mat.getSpecCol())
# Specular component
ks = mat.getSpec() * Vector(mat.getSpecCol())
# Emissive component
ki = Vector([mat.getEmit()]*3)
# Emissive component
ki = Vector([mat.getEmit()]*3)
- I = ki + Iamb + Idiff + Ispec
+ I = ki + Iamb + (Idiff + Ispec)
# Set Alpha component
I = list(I)
I.append(mat.getAlpha())
# Set Alpha component
I = list(I)
I.append(mat.getAlpha())
- # Toon shading
- #I = [MeshUtils.toonShading(c) for c in I]
-
# Clamp I values between 0 and 1
I = [ min(c, 1) for c in I]
I = [ max(0, c) for c in I]
# Clamp I values between 0 and 1
I = [ min(c, 1) for c in I]
I = [ max(0, c) for c in I]
+
+ # Convert to a value between 0 and 255
tmp_col = [ int(c * 255.0) for c in I]
for c in f.col:
tmp_col = [ int(c * 255.0) for c in I]
for c in f.col:
GUI.evtAnimToggle = 1
# Join Objects toggle button
GUI.evtAnimToggle = 1
# Join Objects toggle button
- GUI.joinObjsToggle = Draw.Create(config.output['MERGED_OBJECTS'])
+ GUI.joinObjsToggle = Draw.Create(config.output['JOIN_OBJECTS'])
GUI.evtJoinObjsToggle = 2
# Render filled polygons
GUI.evtJoinObjsToggle = 2
# Render filled polygons
- GUI.polygonsToggle = Draw.Create(config.polygons['FILL'])
+ GUI.polygonsToggle = Draw.Create(config.polygons['SHOW'])
+
+ # Shading Style menu
+ shading_style = config.polygons['SHADING']
+ default_value = shadingStyles.keys().index(shading_style)+1
+ GUI.shadingStyleMenu = Draw.Create(default_value)
+ GUI.evtShadingStyleMenu = 21
GUI.evtPolygonsToggle = 3
# We hide the config.polygons['EXPANSION_TRICK'], for now
GUI.evtPolygonsToggle = 3
# We hide the config.polygons['EXPANSION_TRICK'], for now
# Edge Style menu
edge_style = config.edges['STYLE']
# Edge Style menu
edge_style = config.edges['STYLE']
- default_value = edgeSelectionStyles.keys().index(edge_style)+1
+ default_value = edgeStyles.keys().index(edge_style)+1
GUI.edgeStyleMenu = Draw.Create(default_value)
GUI.evtEdgeStyleMenu = 6
GUI.edgeStyleMenu = Draw.Create(default_value)
GUI.evtEdgeStyleMenu = 6
GUI.edgeWidthSlider = Draw.Create(config.edges['WIDTH'])
GUI.evtEdgeWidthSlider = 7
GUI.edgeWidthSlider = Draw.Create(config.edges['WIDTH'])
GUI.evtEdgeWidthSlider = 7
+ # Edge Color Picker
+ c = config.edges['COLOR']
+ GUI.edgeColorPicker = Draw.Create(c[0]/255.0, c[1]/255.0, c[2]/255.0)
+ GUI.evtEdgeColorPicker = 71
+
# Render Button
GUI.evtRenderButton = 8
# Render Button
GUI.evtRenderButton = 8
200, 285, 160, 18, GUI.polygonsToggle.val,
"Render filled polygons")
200, 285, 160, 18, GUI.polygonsToggle.val,
"Render filled polygons")
+ if GUI.polygonsToggle.val == 1:
+
+ # Polygon Shading Style
+ shadingStyleMenuStruct = "Shading Style %t"
+ for t in shadingStyles.keys():
+ shadingStyleMenuStruct = shadingStyleMenuStruct + "|%s" % t.lower()
+ GUI.shadingStyleMenu = Draw.Menu(shadingStyleMenuStruct, GUI.evtShadingStyleMenu,
+ 200, 260, 160, 18, GUI.shadingStyleMenu.val,
+ "Choose the shading style")
+
+
# Render Edges
GUI.showEdgesToggle = Draw.Toggle("Show Edges", GUI.evtShowEdgesToggle,
# Render Edges
GUI.showEdgesToggle = Draw.Toggle("Show Edges", GUI.evtShowEdgesToggle,
- 200, 260, 160, 18, GUI.showEdgesToggle.val,
+ 200, 235, 160, 18, GUI.showEdgesToggle.val,
"Render polygon edges")
if GUI.showEdgesToggle.val == 1:
# Edge Style
edgeStyleMenuStruct = "Edge Style %t"
"Render polygon edges")
if GUI.showEdgesToggle.val == 1:
# Edge Style
edgeStyleMenuStruct = "Edge Style %t"
- for t in edgeSelectionStyles.keys():
- edgeStyleMenuStruct = edgeStyleMenuStruct + "|%s" % t
+ for t in edgeStyles.keys():
+ edgeStyleMenuStruct = edgeStyleMenuStruct + "|%s" % t.lower()
GUI.edgeStyleMenu = Draw.Menu(edgeStyleMenuStruct, GUI.evtEdgeStyleMenu,
GUI.edgeStyleMenu = Draw.Menu(edgeStyleMenuStruct, GUI.evtEdgeStyleMenu,
- 200, 235, 160, 18, GUI.edgeStyleMenu.val,
+ 200, 210, 160, 18, GUI.edgeStyleMenu.val,
"Choose the edge style")
# Edge size
GUI.edgeWidthSlider = Draw.Slider("Width: ", GUI.evtEdgeWidthSlider,
"Choose the edge style")
# Edge size
GUI.edgeWidthSlider = Draw.Slider("Width: ", GUI.evtEdgeWidthSlider,
- 200, 210, 160, 18, GUI.edgeWidthSlider.val,
+ 200, 185, 140, 18, GUI.edgeWidthSlider.val,
0.0, 10.0, 0, "Change Edge Width")
0.0, 10.0, 0, "Change Edge Width")
+ # Edge Color
+ GUI.edgeColorPicker = Draw.ColorPicker(GUI.evtEdgeColorPicker,
+ 342, 185, 18, 18, GUI.edgeColorPicker.val, "Choose Edge Color")
+
# Show Hidden Edges
GUI.showHiddenEdgesToggle = Draw.Toggle("Show Hidden Edges",
GUI.evtShowHiddenEdgesToggle,
# Show Hidden Edges
GUI.showHiddenEdgesToggle = Draw.Toggle("Show Hidden Edges",
GUI.evtShowHiddenEdgesToggle,
- 200, 185, 160, 18, GUI.showHiddenEdgesToggle.val,
+ 200, 160, 160, 18, GUI.showHiddenEdgesToggle.val,
"Render hidden edges as dashed lines")
glRasterPos2i(10, 160)
"Render hidden edges as dashed lines")
glRasterPos2i(10, 160)
config.outpur['ANIMATION'] = bool(GUI.animToggle.val)
elif evt == GUI.evtJoinObjsToggle:
config.outpur['ANIMATION'] = bool(GUI.animToggle.val)
elif evt == GUI.evtJoinObjsToggle:
- config.output['MERGED_OBJECTS'] = bool(GUI.joinObjsToggle.val)
+ config.output['JOIN_OBJECTS'] = bool(GUI.joinObjsToggle.val)
elif evt == GUI.evtPolygonsToggle:
elif evt == GUI.evtPolygonsToggle:
- config.polygons['FILL'] = bool(GUI.polygonsToggle.val)
+ config.polygons['SHOW'] = bool(GUI.polygonsToggle.val)
+
+ elif evt == GUI.evtShadingStyleMenu:
+ i = GUI.shadingStyleMenu.val - 1
+ config.polygons['SHADING'] = shadingStyles.keys()[i]
elif evt == GUI.evtShowEdgesToggle:
config.edges['SHOW'] = bool(GUI.showEdgesToggle.val)
elif evt == GUI.evtShowEdgesToggle:
config.edges['SHOW'] = bool(GUI.showEdgesToggle.val)
elif evt == GUI.evtEdgeStyleMenu:
i = GUI.edgeStyleMenu.val - 1
elif evt == GUI.evtEdgeStyleMenu:
i = GUI.edgeStyleMenu.val - 1
- config.edges['STYLE'] = edgeSelectionStyles.keys()[i]
+ config.edges['STYLE'] = edgeStyles.keys()[i]
elif evt == GUI.evtEdgeWidthSlider:
config.edges['WIDTH'] = float(GUI.edgeWidthSlider.val)
elif evt == GUI.evtEdgeWidthSlider:
config.edges['WIDTH'] = float(GUI.edgeWidthSlider.val)
+ elif evt == GUI.evtEdgeColorPicker:
+ config.edges['COLOR'] = [int(c*255.0) for c in GUI.edgeColorPicker.val]
+
elif evt == GUI.evtRenderButton:
label = "Save %s" % config.output['FORMAT']
# Show the File Selector
elif evt == GUI.evtRenderButton:
label = "Save %s" % config.output['FORMAT']
# Show the File Selector
def conf_debug():
from pprint import pprint
def conf_debug():
from pprint import pprint
+ print "\nConfig"
+ pprint(config.output)
+ pprint(config.polygons)
+ pprint(config.edges)
_init = staticmethod(_init)
draw = staticmethod(draw)
_init = staticmethod(_init)
draw = staticmethod(draw)