1
# ***** BEGIN GPL LICENSE BLOCK *****
3
# This program is free software; you can redistribute it and/or
4
# modify it under the terms of the GNU General Public License
5
# as published by the Free Software Foundation; either version 2
6
# of the License, or (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See th
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software Foundation,
15
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
# object_render_wire.py liero, meta-androcto,
18
# Yorik van Havre, Alejandro Sierra, Howard Trickey
19
# ***** END GPL LICENCE BLOCK *****
22
"name": "Render Wireframe",
23
"author": "Community",
24
"description": " WireRender & WireSoild modes",
27
"location": "Object > Render Wireframe",
29
'wiki_url': 'http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts',
30
'tracker_url': 'https://projects.blender.org/tracker/index.php?'\
31
'func=detail&aid=26997',
36
cube_faces = [ [0,3,2,1], [5,6,7,4], [0,1,5,4],
37
[7,6,2,3], [2,6,5,1], [0,4,7,3] ]
38
cube_normals = [ mathutils.Vector((0,0,-1)),
39
mathutils.Vector((0,0,1)),
40
mathutils.Vector((0,-1,0)),
41
mathutils.Vector((0,1,0)),
42
mathutils.Vector((1,0,0)),
43
mathutils.Vector((-1,0,0)) ]
45
def create_cube(me, v, d):
49
coords=[ [x-d,y-d,z-d], [x+d,y-d,z-d], [x+d,y+d,z-d], [x-d,y+d,z-d],
50
[x-d,y-d,z+d], [x+d,y-d,z+d], [x+d,y+d,z+d], [x-d,y+d,z+d] ]
53
me.vertices[-1].co = mathutils.Vector(coord)
55
def norm_dot(e, k, fnorm, me):
56
v = me.vertices[e[1]].co - me.vertices[e[0]].co
62
def fill_cube_face(me, index, f):
63
return [index + cube_faces[f][i] for i in range(4)]
65
# Coords of jth point of face f in cube instance i
66
def cube_face_v(me, f, i, j):
67
return me.vertices[i + cube_faces[f][j]].co
69
def cube_face_center(me, f, i):
70
return 0.5 * (cube_face_v(me, f, i, 0) + \
71
cube_face_v(me, f, i, 2))
73
# Return distance between points on two faces when
74
# each point is projected onto the plane that goes through
75
# the face center and is perpendicular to the line
76
# through the face centers.
77
def projected_dist(me, i1, i2, f1, f2, j1, j2):
78
f1center = cube_face_center(me, f1, i1)
79
f2center = cube_face_center(me, f2, i2)
80
axis_norm = (f2center - f1center).normalized()
81
v1 = cube_face_v(me, f1, i1, j1)
82
v2 = cube_face_v(me, f2, i2, j2)
83
v1proj = v1 - (axis_norm * (v1 - f1center)) * axis_norm
84
v2proj = v2 - (axis_norm * (v2 - f2center)) * axis_norm
85
return (v2proj - v1proj).length
87
def skin_edges(me, i1, i2, f1, f2):
88
# Connect verts starting at i1 forming cube face f1
89
# to those starting at i2 forming cube face f2.
90
# Need to find best alignment to avoid a twist.
94
x = projected_dist(me, i1, i2, f1, f2, 0, i)
95
if x < shortest_length:
101
fdata = [i1 + cube_faces[f1][i],
102
i2 + cube_faces[f2][j],
103
i2 + cube_faces[f2][(j + 1) % 4],
104
i1 + cube_faces[f1][(i - 1) % 4]]
106
fdata = [fdata[3]] + fdata[0:3]
112
# Return map: v -> list of length len(node_normals) where
113
# each element of the list is either None (no assignment)
114
# or ((v0, v1), 0 or 1) giving an edge and direction that face is assigned to.
115
def find_assignment(me, edges, vert_edges, node_normals):
116
nf = len(node_normals)
120
fds = [(f, norm_dot(e, k, node_normals[f], me)) for f in range(nf)]
121
feasible[(e, k)] = [fd for fd in fds if fd[1] > 0.01]
123
for v, ves in vert_edges.items():
124
assignment[v] = best_assignment(ves, feasible, nf)
127
def best_assignment(ves, feasible, nf):
128
apartial = [ None ] * nf
129
return best_assign_help(ves, feasible, apartial, 0.0)[0]
131
def best_assign_help(ves, feasible, apartial, sumpartial):
133
return (apartial, sumpartial)
141
if apartial[f] is None:
144
# sum up d**2 to penalize smaller d's more
145
sp = sumpartial + d*d
146
(a, s) = best_assign_help(vesrest, feasible, ap, sp)
151
return (besta, bestsum)
153
# not feasible to assign e0, k0; try to assign rest
154
return best_assign_help(vesrest, feasible, apartial, sumpartial)
156
def assigned_face(e, assignment):
159
for j, ee in enumerate(a):
164
def create_wired_mesh(me2, me, thick):
168
if be.select and not be.hide:
169
e = (be.key[0], be.key[1])
172
if e[k] not in vert_edges:
173
vert_edges[e[k]] = []
174
vert_edges[e[k]].append((e, k))
176
assignment = find_assignment(me, edges, vert_edges, cube_normals)
178
# Create the geometry
181
vpos = me.vertices[v]
182
index = len(me2.vertices)
183
# We need to associate each node with the new geometry
185
# Geometry for the nodes, each one a cube
186
create_cube(me2, vpos, thick)
188
# Skin using the new geometry
190
for k, f in assignment.items():
192
for i in range(len(cube_faces)):
194
cfaces.extend(fill_cube_face(me2, n_idx[k], i))
197
# only skin between edges in forward direction
198
# to avoid making doubles
200
# but first make sure other end actually assigned
201
i2 = assigned_face(((v0, v1), 0), assignment)
203
cfaces.extend(fill_cube_face(me2, n_idx[k], i))
205
i2 = assigned_face(((v0, v1), 1), assignment)
207
cfaces.extend(skin_edges(me2, n_idx[v0], n_idx[v1], i, i2))
209
# assignment failed for this edge
210
cfaces.extend(fill_cube_face(me2, n_idx[k], i))
212
# adding faces to the mesh
213
me2.tessfaces.add(len(cfaces) // 4)
214
me2.tessfaces.foreach_set("vertices_raw", cfaces)
215
me2.update(calc_edges=True)
217
# panel containing tools
218
def wire_add(mallas):
220
bpy.ops.object.select_all(action='DESELECT')
221
bpy.context.scene.objects.active = mallas[0]
222
for o in mallas: o.select = True
223
bpy.ops.object.duplicate()
224
obj, sce = bpy.context.object, bpy.context.scene
225
for mod in obj.modifiers: obj.modifiers.remove(mod)
226
bpy.ops.object.join()
227
bpy.ops.object.mode_set(mode='EDIT')
228
bpy.ops.mesh.select_all(action='SELECT')
229
bpy.ops.mesh.delete(type='ONLY_FACE')
230
bpy.ops.object.mode_set()
231
bpy.ops.object.convert(target='CURVE')
232
if 'wire_object' in sce.objects.keys():
233
sce.objects.get('wire_object').data = obj.data
234
sce.objects.get('wire_object').matrix_world = mallas[0].matrix_world
235
sce.objects.unlink(obj)
237
obj.name = 'wire_object'
238
obj.data.resolution_u = 1
239
obj.data.bevel_depth = 0.005
240
obj.data.fill_mode = 'FULL'
241
obj.data.materials.append(bpy.data.materials.get('mat_wireobj'))
245
class VIEW3D_PT_tools_SolidifyWireframe(bpy.types.Panel):
246
bl_space_type = 'VIEW_3D'
247
bl_region_type = 'TOOLS'
248
bl_context = "mesh_edit"
249
bl_label = "Solidify Wireframe"
251
def draw(self, context):
252
active_obj = context.active_object
254
col = layout.column(align=True)
255
col.operator("mesh.solidify_wireframe", text="Solidify")
256
col.prop(context.scene, "swThickness")
257
col.prop(context.scene, "swSelectNew")
259
# a class for your operator
260
class SolidifyWireframe(bpy.types.Operator):
261
'''Turns the selected edges of a mesh into solid objects'''
262
bl_idname = "mesh.solidify_wireframe"
263
bl_label = "Solidify Wireframe"
264
bl_options = {'REGISTER', 'UNDO'}
266
def invoke(self, context, event):
267
return self.execute(context)
270
def poll(cls, context):
271
ob = context.active_object
272
return ob and ob.type == 'MESH'
274
def execute(self, context):
275
# Get the active object
276
ob_act = context.active_object
277
# getting current edit mode
278
currMode = ob_act.mode
279
# switching to object mode
280
bpy.ops.object.mode_set(mode='OBJECT')
281
bpy.ops.object.select_all(action='DESELECT')
285
newmesh = bpy.data.meshes.new(mymesh.name + " wire")
286
obj = bpy.data.objects.new(newmesh.name,newmesh)
287
obj.location = ob_act.location
288
obj.rotation_euler = ob_act.rotation_euler
289
obj.scale = ob_act.scale
290
context.scene.objects.link(obj)
291
create_wired_mesh(newmesh, mymesh, context.scene.swThickness)
293
# restoring original editmode if needed
294
if context.scene.swSelectNew:
296
context.scene.objects.active = obj
298
bpy.ops.object.mode_set(mode=currMode)
300
# returning after everything is done
303
class WireMaterials(bpy.types.Operator):
304
bl_idname = 'scene.wire_render'
305
bl_label = 'Create Materials'
306
bl_description = 'Set Up Materials for a Wire Render'
307
bl_options = {'REGISTER', 'UNDO'}
309
def execute(self, context):
310
wm = bpy.context.window_manager
311
scn = bpy.context.scene
313
if 'mat_clay' not in bpy.data.materials:
314
mat = bpy.data.materials.new('mat_clay')
315
mat.specular_intensity = 0
316
else: mat = bpy.data.materials.get('mat_clay')
317
mat.diffuse_color = wm.col_clay
318
mat.use_shadeless = wm.shadeless_mat
320
if 'mat_wire' not in bpy.data.materials:
321
mat = bpy.data.materials.new('mat_wire')
322
mat.specular_intensity = 0
323
mat.use_transparency = True
326
else: mat = bpy.data.materials.get('mat_wire')
327
mat.diffuse_color = wm.col_wire
328
mat.use_shadeless = wm.shadeless_mat
330
try: bpy.ops.object.mode_set()
333
if wm.selected_meshes: objetos = bpy.context.selected_objects
334
else: objetos = bpy.data.objects
336
mallas = [o for o in objetos if o.type == 'MESH' and o.is_visible(scn)]
339
scn.objects.active = obj
340
print ('procesando >', obj.name)
341
obj.show_wire = wm.wire_view
342
for mat in obj.material_slots:
343
bpy.ops.object.material_slot_remove()
344
obj.data.materials.append(bpy.data.materials.get('mat_wire'))
345
obj.data.materials.append(bpy.data.materials.get('mat_clay'))
346
obj.material_slots.data.active_material_index = 1
347
bpy.ops.object.editmode_toggle()
348
bpy.ops.mesh.select_all(action='SELECT')
349
bpy.ops.object.material_slot_assign()
350
bpy.ops.object.mode_set()
353
if 'mat_wireobj' not in bpy.data.materials:
354
mat = bpy.data.materials.new('mat_wireobj')
355
mat.specular_intensity = 0
356
else: mat = bpy.data.materials.get('mat_wireobj')
357
mat.diffuse_color = wm.col_wire
358
mat.use_shadeless = wm.shadeless_mat
363
class PanelWMat(bpy.types.Panel):
364
bl_label = 'Setup Wire Render'
365
bl_space_type = 'VIEW_3D'
366
bl_region_type = 'TOOLS'
368
def draw(self, context):
369
wm = bpy.context.window_manager
370
active_obj = context.active_object
373
column = layout.column(align=True)
374
column.prop(wm, 'col_clay')
375
column.prop(wm, 'col_wire')
376
column = layout.column(align=True)
377
column.prop(wm, 'selected_meshes')
378
column.prop(wm, 'shadeless_mat')
379
column.prop(wm, 'wire_view')
380
column.prop(wm, 'wire_object')
382
column.operator('scene.wire_render')
383
column.label(text='- - - - - - - - - - - - - - - - - - - - - -')
384
col = layout.column(align=True)
385
column.label(text='Solid WireFrame')
386
layout.operator("mesh.solidify_wireframe", text="Create Mesh Object")
387
col.prop(context.scene, "swThickness")
388
col.prop(context.scene, "swSelectNew")
389
bpy.types.WindowManager.selected_meshes = bpy.props.BoolProperty(name='Selected Meshes', default=False, description='Apply materials to Selected Meshes / All Visible Meshes')
390
bpy.types.WindowManager.shadeless_mat = bpy.props.BoolProperty(name='Shadeless', default=False, description='Generate Shadeless Materials')
391
bpy.types.WindowManager.col_clay = bpy.props.FloatVectorProperty(name='', description='Clay Color', default=(1.0, 0.9, 0.8), min=0, max=1, step=1, precision=3, subtype='COLOR_GAMMA', size=3)
392
bpy.types.WindowManager.col_wire = bpy.props.FloatVectorProperty(name='', description='Wire Color', default=(0.1 ,0.0 ,0.0), min=0, max=1, step=1, precision=3, subtype='COLOR_GAMMA', size=3)
393
bpy.types.WindowManager.wire_view = bpy.props.BoolProperty(name='Viewport Wires', default=False, description='Overlay wires display over solid in Viewports')
394
bpy.types.WindowManager.wire_object = bpy.props.BoolProperty(name='Create Curve Object', default=False, description='Very slow! - Add a Wire Object to scene to be able to render wires in Cycles')
395
bpy.types.Scene.swThickness = bpy.props.FloatProperty(name="Thickness", description="Thickness of the skinned edges", default=0.01)
396
bpy.types.Scene.swSelectNew = bpy.props.BoolProperty(name="Select wire", description="If checked, the wire object will be selected after creation", default=True)
398
# Register the operator
399
def solidifyWireframe_menu_func(self, context):
400
self.layout.operator(SolidifyWireframe.bl_idname, text="Solidify Wireframe", icon='PLUGIN')
402
# Add "Solidify Wireframe" menu to the "Mesh" menu.
404
bpy.utils.register_class(WireMaterials)
405
bpy.utils.register_class(PanelWMat)
406
bpy.utils.register_module(__name__)
407
bpy.types.Scene.swThickness = bpy.props.FloatProperty(name="Thickness",
408
description="Thickness of the skinned edges",
410
bpy.types.Scene.swSelectNew = bpy.props.BoolProperty(name="Select wire",
411
description="If checked, the wire object will be selected after creation",
413
bpy.types.VIEW3D_MT_edit_mesh_edges.append(solidifyWireframe_menu_func)
415
# Remove "Solidify Wireframe" menu entry from the "Mesh" menu.
417
bpy.utils.unregister_class(WireMaterials)
418
bpy.utils.unregister_class(PanelWMat)
419
bpy.utils.unregister_module(__name__)
420
del bpy.types.Scene.swThickness
421
bpy.types.VIEW3D_MT_edit_mesh_edges.remove(solidifyWireframe_menu_func)
423
if __name__ == "__main__":