Update for changes in Blender's API
[blender-addons.git] / archimesh / achm_tools.py
blob704f350e4f2d8911535de632099432528959846f
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 the
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
19 # <pep8 compliant>
21 # ----------------------------------------------------------
22 # support routines and general functions
23 # Author: Antonio Vazquez (antonioya)
25 # ----------------------------------------------------------
26 # noinspection PyUnresolvedReferences
27 import bpy
28 from os import path
31 # --------------------------------------------------------------------
32 # Get length Blender units
33 # --------------------------------------------------------------------
34 def get_blendunits(units):
35 if bpy.context.scene.unit_settings.system == "IMPERIAL":
36 return units * 0.3048
37 else:
38 return units
41 # --------------------------------------------------------------------
42 # Set normals
43 # True= faces to inside
44 # False= faces to outside
45 # --------------------------------------------------------------------
46 def set_normals(myobject, direction=False):
47 bpy.context.scene.objects.active = myobject
48 # go edit mode
49 bpy.ops.object.mode_set(mode='EDIT')
50 # select all faces
51 bpy.ops.mesh.select_all(action='SELECT')
52 # recalculate outside normals
53 bpy.ops.mesh.normals_make_consistent(inside=direction)
54 # go object mode again
55 bpy.ops.object.editmode_toggle()
58 # --------------------------------------------------------------------
59 # Remove doubles
60 # --------------------------------------------------------------------
61 def remove_doubles(myobject):
62 bpy.context.scene.objects.active = myobject
63 # go edit mode
64 bpy.ops.object.mode_set(mode='EDIT')
65 # select all faces
66 bpy.ops.mesh.select_all(action='SELECT')
67 # remove
68 bpy.ops.mesh.remove_doubles()
69 # go object mode again
70 bpy.ops.object.editmode_toggle()
73 # --------------------------------------------------------------------
74 # Set shade smooth
75 # --------------------------------------------------------------------
76 def set_smooth(myobject):
77 # deactivate others
78 for o in bpy.data.objects:
79 if o.select is True:
80 o.select = False
82 myobject.select = True
83 bpy.context.scene.objects.active = myobject
84 if bpy.context.scene.objects.active.name == myobject.name:
85 bpy.ops.object.shade_smooth()
88 # --------------------------------------------------------------------
89 # Add modifier (subdivision)
90 # --------------------------------------------------------------------
91 def set_modifier_subsurf(myobject):
92 bpy.context.scene.objects.active = myobject
93 if bpy.context.scene.objects.active.name == myobject.name:
94 bpy.ops.object.modifier_add(type='SUBSURF')
95 for mod in myobject.modifiers:
96 if mod.type == 'SUBSURF':
97 mod.levels = 2
100 # --------------------------------------------------------------------
101 # Add modifier (mirror)
102 # --------------------------------------------------------------------
103 def set_modifier_mirror(myobject, axis="Y"):
104 bpy.ops.object.select_all(False)
105 myobject.select = True
106 bpy.context.scene.objects.active = myobject
107 if bpy.context.scene.objects.active.name == myobject.name:
108 bpy.ops.object.modifier_add(type='MIRROR')
109 for mod in myobject.modifiers:
110 if mod.type == 'MIRROR':
111 if axis == "X":
112 mod.use_x = True
113 else:
114 mod.use_x = False
116 if axis == "Y":
117 mod.use_y = True
118 else:
119 mod.use_y = False
121 if axis == "Z":
122 mod.use_z = True
123 else:
124 mod.use_z = False
126 mod.use_clip = True
129 # --------------------------------------------------------------------
130 # Add modifier (array)
131 # --------------------------------------------------------------------
132 def set_modifier_array(myobject, axis, move, repeat, fix=False, fixmove=0, zmove=0):
133 bpy.ops.object.select_all(False)
134 myobject.select = True
135 bpy.context.scene.objects.active = myobject
136 if bpy.context.scene.objects.active.name == myobject.name:
137 bpy.ops.object.modifier_add(type='ARRAY')
138 for mod in myobject.modifiers:
139 if mod.type == 'ARRAY':
140 if mod.name == "Array":
141 mod.name = "Array_" + axis
142 mod.count = repeat
143 mod.use_constant_offset = fix
144 if axis == "X":
145 mod.relative_offset_displace[0] = move
146 mod.constant_offset_displace[0] = fixmove
147 mod.relative_offset_displace[1] = 0.0
148 mod.constant_offset_displace[1] = 0.0
149 mod.relative_offset_displace[2] = 0.0
150 mod.constant_offset_displace[2] = zmove
152 if axis == "Y":
153 mod.relative_offset_displace[0] = 0.0
154 mod.constant_offset_displace[0] = 0.0
155 mod.relative_offset_displace[1] = move
156 mod.constant_offset_displace[1] = fixmove
157 mod.relative_offset_displace[2] = 0.0
158 mod.constant_offset_displace[2] = 0.0
161 # --------------------------------------------------------------------
162 # Add modifier (curve)
163 # --------------------------------------------------------------------
164 def set_modifier_curve(myobject, mycurve):
165 bpy.context.scene.objects.active = myobject
166 if bpy.context.scene.objects.active.name == myobject.name:
167 bpy.ops.object.modifier_add(type='CURVE')
168 for mod in myobject.modifiers:
169 if mod.type == 'CURVE':
170 mod.deform_axis = 'POS_X'
171 mod.object = mycurve
174 # --------------------------------------------------------------------
175 # Add modifier (solidify)
176 # --------------------------------------------------------------------
177 def set_modifier_solidify(myobject, width):
178 bpy.context.scene.objects.active = myobject
179 if bpy.context.scene.objects.active.name == myobject.name:
180 bpy.ops.object.modifier_add(type='SOLIDIFY')
181 for mod in myobject.modifiers:
182 if mod.type == 'SOLIDIFY':
183 mod.thickness = width
184 mod.use_even_offset = True
185 mod.use_quality_normals = True
186 break
189 # --------------------------------------------------------------------
190 # Add modifier (boolean)
191 # --------------------------------------------------------------------
192 def set_modifier_boolean(myobject, bolobject):
193 bpy.context.scene.objects.active = myobject
194 if bpy.context.scene.objects.active.name == myobject.name:
195 bpy.ops.object.modifier_add(type='BOOLEAN')
196 mod = myobject.modifiers[len(myobject.modifiers) - 1]
197 mod.operation = 'DIFFERENCE'
198 mod.object = bolobject
201 # --------------------------------------------------------------------
202 # Set material to object
203 # --------------------------------------------------------------------
204 def set_material(myobject, mymaterial):
205 bpy.context.scene.objects.active = myobject
206 if bpy.context.scene.objects.active.name == myobject.name:
207 myobject.data.materials.append(mymaterial)
210 # --------------------------------------------------------------------
211 # Set material to selected faces
212 # --------------------------------------------------------------------
213 def set_material_faces(myobject, idx):
214 bpy.context.scene.objects.active = myobject
215 myobject.select = True
216 bpy.context.object.active_material_index = idx
217 if bpy.context.scene.objects.active.name == myobject.name:
218 bpy.ops.object.mode_set(mode='EDIT')
219 bpy.ops.object.material_slot_assign()
220 # Deselect
221 bpy.ops.mesh.select_all(action='DESELECT')
222 bpy.ops.object.mode_set(mode='OBJECT')
225 # --------------------------------------------------------------------
226 # Select faces
227 # --------------------------------------------------------------------
228 def select_faces(myobject, selface, clear):
229 myobject.select = True
230 bpy.context.scene.objects.active = myobject
231 if bpy.context.scene.objects.active.name == myobject.name:
232 # deselect everything
233 if clear:
234 bpy.ops.object.mode_set(mode='EDIT')
235 bpy.ops.mesh.select_all(action='DESELECT')
237 # reselect the originally selected face
238 bpy.ops.object.mode_set(mode='OBJECT')
239 myobject.data.polygons[selface].select = True
242 # --------------------------------------------------------------------
243 # Select vertices
244 # --------------------------------------------------------------------
245 def select_vertices(myobject, selvertices, clear=True):
246 myobject.select = True
247 bpy.context.scene.objects.active = myobject
248 if bpy.context.scene.objects.active.name == myobject.name:
249 # deselect everything
250 if clear:
251 bpy.ops.object.mode_set(mode='EDIT')
252 bpy.ops.mesh.select_all(action='DESELECT')
254 # Select Vertices
255 bpy.ops.object.mode_set(mode='EDIT', toggle=False)
256 sel_mode = bpy.context.tool_settings.mesh_select_mode
258 bpy.context.tool_settings.mesh_select_mode = [True, False, False]
259 bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
261 for i in selvertices:
262 myobject.data.vertices[i].select = True
264 bpy.ops.object.mode_set(mode='EDIT', toggle=False)
265 bpy.context.tool_settings.mesh_select_mode = sel_mode
266 bpy.ops.object.mode_set(mode='OBJECT')
269 # --------------------------------------------------------------------
270 # Mark Seam
271 # --------------------------------------------------------------------
272 def mark_seam(myobject):
273 # noinspection PyBroadException
274 try:
275 myobject.select = True
276 bpy.context.scene.objects.active = myobject
277 if bpy.context.scene.objects.active.name == myobject.name:
278 bpy.ops.object.mode_set(mode='EDIT', toggle=False)
279 bpy.ops.mesh.mark_seam()
280 bpy.ops.object.mode_set(mode='OBJECT')
281 except:
282 bpy.ops.object.mode_set(mode='OBJECT')
285 # --------------------------------------------------------------------
286 # Unwrap mesh
287 # --------------------------------------------------------------------
288 def unwrap_mesh(myobject, allfaces=True):
289 # noinspection PyBroadException
290 try:
291 myobject.select = True
292 bpy.context.scene.objects.active = myobject
293 if bpy.context.scene.objects.active.name == myobject.name:
294 # Unwrap
295 bpy.ops.object.mode_set(mode='EDIT', toggle=False)
296 if allfaces is True:
297 bpy.ops.mesh.select_all(action='DESELECT')
298 bpy.ops.mesh.select_all()
299 bpy.ops.uv.unwrap()
300 bpy.ops.object.mode_set(mode='OBJECT')
301 except:
302 bpy.ops.object.mode_set(mode='OBJECT')
305 # --------------------------------------------------------------------
306 # Get Node Index(multilanguage support)
307 # --------------------------------------------------------------------
308 def get_node_index(nodes, datatype):
309 idx = 0
310 for m in nodes:
311 if m.type == datatype:
312 return idx
313 idx += 1
315 # by default
316 return 1
319 # --------------------------------------------------------------------
320 # Create cycles diffuse material
321 # --------------------------------------------------------------------
322 def create_diffuse_material(matname, replace, r, g, b, rv=0.8, gv=0.8, bv=0.8, mix=0.1, twosides=False):
323 # Avoid duplicate materials
324 if replace is False:
325 matlist = bpy.data.materials
326 for m in matlist:
327 if m.name == matname:
328 return m
329 # Create material
330 mat = bpy.data.materials.new(matname)
331 mat.diffuse_color = (rv, gv, bv) # viewport color
332 mat.use_nodes = True
333 nodes = mat.node_tree.nodes
335 # support for multilanguage
336 node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')]
337 node.name = 'Diffuse BSDF'
338 node.label = 'Diffuse BSDF'
340 node.inputs[0].default_value = [r, g, b, 1]
341 node.location = 200, 320
343 node = nodes.new('ShaderNodeBsdfGlossy')
344 node.name = 'Glossy_0'
345 node.location = 200, 0
347 node = nodes.new('ShaderNodeMixShader')
348 node.name = 'Mix_0'
349 node.inputs[0].default_value = mix
350 node.location = 500, 160
352 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')]
353 node.location = 1100, 160
355 # Connect nodes
356 outn = nodes['Diffuse BSDF'].outputs[0]
357 inn = nodes['Mix_0'].inputs[1]
358 mat.node_tree.links.new(outn, inn)
360 outn = nodes['Glossy_0'].outputs[0]
361 inn = nodes['Mix_0'].inputs[2]
362 mat.node_tree.links.new(outn, inn)
364 if twosides is False:
365 outn = nodes['Mix_0'].outputs[0]
366 inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0]
367 mat.node_tree.links.new(outn, inn)
369 if twosides is True:
370 node = nodes.new('ShaderNodeNewGeometry')
371 node.name = 'Input_1'
372 node.location = -80, -70
374 node = nodes.new('ShaderNodeBsdfDiffuse')
375 node.name = 'Diffuse_1'
376 node.inputs[0].default_value = [0.30, 0.30, 0.30, 1]
377 node.location = 200, -280
379 node = nodes.new('ShaderNodeMixShader')
380 node.name = 'Mix_1'
381 node.inputs[0].default_value = mix
382 node.location = 800, -70
384 outn = nodes['Input_1'].outputs[6]
385 inn = nodes['Mix_1'].inputs[0]
386 mat.node_tree.links.new(outn, inn)
388 outn = nodes['Diffuse_1'].outputs[0]
389 inn = nodes['Mix_1'].inputs[2]
390 mat.node_tree.links.new(outn, inn)
392 outn = nodes['Mix_0'].outputs[0]
393 inn = nodes['Mix_1'].inputs[1]
394 mat.node_tree.links.new(outn, inn)
396 outn = nodes['Mix_1'].outputs[0]
397 inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0]
398 mat.node_tree.links.new(outn, inn)
400 return mat
403 # --------------------------------------------------------------------
404 # Create cycles translucent material
405 # --------------------------------------------------------------------
406 def create_translucent_material(matname, replace, r, g, b, rv=0.8, gv=0.8, bv=0.8, mix=0.1):
407 # Avoid duplicate materials
408 if replace is False:
409 matlist = bpy.data.materials
410 for m in matlist:
411 if m.name == matname:
412 return m
413 # Create material
414 mat = bpy.data.materials.new(matname)
415 mat.diffuse_color = (rv, gv, bv) # viewport color
416 mat.use_nodes = True
417 nodes = mat.node_tree.nodes
419 # support for multilanguage
420 node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')]
421 node.name = 'Diffuse BSDF'
422 node.label = 'Diffuse BSDF'
424 node.inputs[0].default_value = [r, g, b, 1]
425 node.location = 200, 320
427 node = nodes.new('ShaderNodeBsdfTranslucent')
428 node.name = 'Translucent_0'
429 node.location = 200, 0
431 node = nodes.new('ShaderNodeMixShader')
432 node.name = 'Mix_0'
433 node.inputs[0].default_value = mix
434 node.location = 500, 160
436 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')]
437 node.location = 1100, 160
439 # Connect nodes
440 outn = nodes['Diffuse BSDF'].outputs[0]
441 inn = nodes['Mix_0'].inputs[1]
442 mat.node_tree.links.new(outn, inn)
444 outn = nodes['Translucent_0'].outputs[0]
445 inn = nodes['Mix_0'].inputs[2]
446 mat.node_tree.links.new(outn, inn)
448 outn = nodes['Mix_0'].outputs[0]
449 inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0]
450 mat.node_tree.links.new(outn, inn)
452 return mat
455 # --------------------------------------------------------------------
456 # Create cycles glass material
457 # --------------------------------------------------------------------
458 def create_glass_material(matname, replace, rv=0.333, gv=0.342, bv=0.9):
459 # Avoid duplicate materials
460 if replace is False:
461 matlist = bpy.data.materials
462 for m in matlist:
463 if m.name == matname:
464 return m
465 # Create material
466 mat = bpy.data.materials.new(matname)
467 mat.use_nodes = True
468 mat.diffuse_color = (rv, gv, bv)
469 nodes = mat.node_tree.nodes
471 # support for multilanguage
472 node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')]
473 mat.node_tree.nodes.remove(node) # remove not used
475 node = nodes.new('ShaderNodeLightPath')
476 node.name = 'Light_0'
477 node.location = 10, 160
479 node = nodes.new('ShaderNodeBsdfRefraction')
480 node.name = 'Refraction_0'
481 node.inputs[2].default_value = 1 # IOR 1.0
482 node.location = 250, 400
484 node = nodes.new('ShaderNodeBsdfGlossy')
485 node.name = 'Glossy_0'
486 node.distribution = 'SHARP'
487 node.location = 250, 100
489 node = nodes.new('ShaderNodeBsdfTransparent')
490 node.name = 'Transparent_0'
491 node.location = 500, 10
493 node = nodes.new('ShaderNodeMixShader')
494 node.name = 'Mix_0'
495 node.inputs[0].default_value = 0.035
496 node.location = 500, 160
498 node = nodes.new('ShaderNodeMixShader')
499 node.name = 'Mix_1'
500 node.inputs[0].default_value = 0.1
501 node.location = 690, 290
503 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')]
504 node.location = 920, 290
506 # Connect nodes
507 outn = nodes['Light_0'].outputs[1]
508 inn = nodes['Mix_1'].inputs[0]
509 mat.node_tree.links.new(outn, inn)
511 outn = nodes['Refraction_0'].outputs[0]
512 inn = nodes['Mix_0'].inputs[1]
513 mat.node_tree.links.new(outn, inn)
515 outn = nodes['Glossy_0'].outputs[0]
516 inn = nodes['Mix_0'].inputs[2]
517 mat.node_tree.links.new(outn, inn)
519 outn = nodes['Mix_0'].outputs[0]
520 inn = nodes['Mix_1'].inputs[1]
521 mat.node_tree.links.new(outn, inn)
523 outn = nodes['Transparent_0'].outputs[0]
524 inn = nodes['Mix_1'].inputs[2]
525 mat.node_tree.links.new(outn, inn)
527 outn = nodes['Mix_1'].outputs[0]
528 inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0]
529 mat.node_tree.links.new(outn, inn)
531 return mat
534 # ---------------------------------------------
535 # Create cycles transparents material
536 # --------------------------------------------------------------------
537 def create_transparent_material(matname, replace, r=1, g=1, b=1, alpha=0):
538 # Avoid duplicate materials
539 if replace is False:
540 matlist = bpy.data.materials
541 for m in matlist:
542 if m.name == matname:
543 return m
544 # Create material
545 mat = bpy.data.materials.new(matname)
546 mat.use_nodes = True
547 mat.diffuse_color = (r, g, b)
548 nodes = mat.node_tree.nodes
550 # support for multilanguage
551 node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')]
552 mat.node_tree.nodes.remove(node) # remove not used
554 node = nodes.new('ShaderNodeBsdfTransparent')
555 node.name = 'Transparent_0'
556 node.location = 250, 160
557 node.inputs[0].default_value = [r, g, b, alpha]
559 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')]
560 node.location = 700, 160
562 # Connect nodes
563 outn = nodes['Transparent_0'].outputs[0]
564 inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0]
565 mat.node_tree.links.new(outn, inn)
567 return mat
570 # --------------------------------------------------------------------
571 # Create cycles glossy material
572 # --------------------------------------------------------------------
573 def create_glossy_material(matname, replace, r, g, b, rv=0.578, gv=0.555, bv=0.736, rvalue=0.2):
574 # Avoid duplicate materials
575 if replace is False:
576 matlist = bpy.data.materials
577 for m in matlist:
578 if m.name == matname:
579 return m
580 # Create material
581 mat = bpy.data.materials.new(matname)
582 mat.use_nodes = True
583 mat.diffuse_color = (rv, gv, bv)
584 nodes = mat.node_tree.nodes
586 # support for multilanguage
587 node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')]
588 mat.node_tree.nodes.remove(node) # remove not used
590 node = nodes.new('ShaderNodeBsdfGlossy')
591 node.name = 'Glossy_0'
592 node.inputs[0].default_value = [r, g, b, 1]
593 node.inputs[1].default_value = rvalue
594 node.location = 200, 160
596 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')]
597 node.location = 700, 160
599 # Connect nodes
600 outn = nodes['Glossy_0'].outputs[0]
601 inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0]
602 mat.node_tree.links.new(outn, inn)
604 return mat
607 # --------------------------------------------------------------------
608 # Create cycles emission material
609 # --------------------------------------------------------------------
610 def create_emission_material(matname, replace, r, g, b, energy):
611 # Avoid duplicate materials
612 if replace is False:
613 matlist = bpy.data.materials
614 for m in matlist:
615 if m.name == matname:
616 return m
617 # Create material
618 mat = bpy.data.materials.new(matname)
619 mat.use_nodes = True
620 nodes = mat.node_tree.nodes
622 # support for multilanguage
623 node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')]
624 mat.node_tree.nodes.remove(node) # remove not used
626 node = nodes.new('ShaderNodeEmission')
627 node.name = 'Emission_0'
628 node.inputs[0].default_value = [r, g, b, 1]
629 node.inputs[1].default_value = energy
630 node.location = 200, 160
632 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')]
633 node.location = 700, 160
635 # Connect nodes
636 outn = nodes['Emission_0'].outputs[0]
637 inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0]
638 mat.node_tree.links.new(outn, inn)
640 return mat
643 # --------------------------------------------------------------------
644 # Create cycles glass material
645 # --------------------------------------------------------------------
646 def create_old_glass_material(matname, replace, rv=0.352716, gv=0.760852, bv=0.9):
647 # Avoid duplicate materials
648 if replace is False:
649 matlist = bpy.data.materials
650 for m in matlist:
651 if m.name == matname:
652 return m
653 # Create material
654 mat = bpy.data.materials.new(matname)
655 mat.use_nodes = True
656 mat.diffuse_color = (rv, gv, bv)
657 nodes = mat.node_tree.nodes
659 # support for multilanguage
660 node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')]
661 mat.node_tree.nodes.remove(node) # remove not used
663 node = nodes.new('ShaderNodeLightPath')
664 node.name = 'Light_0'
665 node.location = 10, 160
667 node = nodes.new('ShaderNodeBsdfGlass')
668 node.name = 'Glass_0'
669 node.location = 250, 300
671 node = nodes.new('ShaderNodeBsdfTransparent')
672 node.name = 'Transparent_0'
673 node.location = 250, 0
675 node = nodes.new('ShaderNodeMixShader')
676 node.name = 'Mix_0'
677 node.inputs[0].default_value = 0.1
678 node.location = 500, 160
680 node = nodes.new('ShaderNodeMixShader')
681 node.name = 'Mix_1'
682 node.inputs[0].default_value = 0.1
683 node.location = 690, 290
685 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')]
686 node.location = 920, 290
688 # Connect nodes
689 outn = nodes['Light_0'].outputs[1]
690 inn = nodes['Mix_0'].inputs[0]
691 mat.node_tree.links.new(outn, inn)
693 outn = nodes['Light_0'].outputs[2]
694 inn = nodes['Mix_1'].inputs[0]
695 mat.node_tree.links.new(outn, inn)
697 outn = nodes['Glass_0'].outputs[0]
698 inn = nodes['Mix_0'].inputs[1]
699 mat.node_tree.links.new(outn, inn)
701 outn = nodes['Transparent_0'].outputs[0]
702 inn = nodes['Mix_0'].inputs[2]
703 mat.node_tree.links.new(outn, inn)
705 outn = nodes['Mix_0'].outputs[0]
706 inn = nodes['Mix_1'].inputs[1]
707 mat.node_tree.links.new(outn, inn)
709 outn = nodes['Mix_1'].outputs[0]
710 inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0]
711 mat.node_tree.links.new(outn, inn)
713 return mat
716 # --------------------------------------------------------------------
717 # Create cycles brick texture material
718 # --------------------------------------------------------------------
719 def create_brick_material(matname, replace, r, g, b, rv=0.8, gv=0.636, bv=0.315):
720 # Avoid duplicate materials
721 if replace is False:
722 matlist = bpy.data.materials
723 for m in matlist:
724 if m.name == matname:
725 return m
726 # Create material
727 mat = bpy.data.materials.new(matname)
728 mat.use_nodes = True
729 mat.diffuse_color = (rv, gv, bv)
730 nodes = mat.node_tree.nodes
732 # support for multilanguage
733 node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')]
734 node.name = 'Diffuse BSDF'
735 node.label = 'Diffuse BSDF'
737 node.inputs[0].default_value = [r, g, b, 1]
738 node.location = 500, 160
740 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')]
741 node.location = 700, 160
743 node = nodes.new('ShaderNodeTexBrick')
744 node.name = 'Brick_0'
745 node.inputs[3].default_value = [0.407, 0.411, 0.394, 1] # mortar color
746 node.inputs[4].default_value = 3 # scale
747 node.inputs[5].default_value = 0.001 # mortar
748 node.inputs[7].default_value = 0.60 # size_w
749 node.inputs[8].default_value = 0.30 # size_h
750 node.location = 300, 160
752 node = nodes.new('ShaderNodeRGB')
753 node.name = 'RGB_0'
754 node.outputs[0].default_value = [r, g, b, 1]
755 node.location = 70, 160
757 # Connect nodes
758 outn = nodes['RGB_0'].outputs['Color']
759 inn = nodes['Brick_0'].inputs['Color1']
760 mat.node_tree.links.new(outn, inn)
762 inn = nodes['Brick_0'].inputs['Color2']
763 mat.node_tree.links.new(outn, inn)
765 outn = nodes['Brick_0'].outputs['Color']
766 inn = nodes['Diffuse BSDF'].inputs['Color']
767 mat.node_tree.links.new(outn, inn)
769 return mat
772 # --------------------------------------------------------------------
773 # Create cycles fabric texture material
774 # --------------------------------------------------------------------
775 def create_fabric_material(matname, replace, r, g, b, rv=0.8, gv=0.636, bv=0.315):
776 # Avoid duplicate materials
777 if replace is False:
778 matlist = bpy.data.materials
779 for m in matlist:
780 if m.name == matname:
781 return m
782 # Create material
783 mat = bpy.data.materials.new(matname)
784 mat.use_nodes = True
785 mat.diffuse_color = (rv, gv, bv)
786 nodes = mat.node_tree.nodes
788 # support for multilanguage
789 node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')]
790 node.name = 'Diffuse BSDF'
791 node.label = 'Diffuse BSDF'
793 node.inputs[0].default_value = [r, g, b, 1]
794 node.location = 810, 270
796 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')]
797 node.location = 1210, 320
799 node = nodes.new('ShaderNodeTexCoord')
800 node.name = 'UVCoordinates'
801 node.location = 26, 395
803 node = nodes.new('ShaderNodeMapping')
804 node.name = 'UVMapping'
805 node.location = 266, 380
806 node.scale[0] = 1000
807 node.scale[1] = 1000
808 node.scale[2] = 1000
810 # ===========================================================================
811 # Image texture
812 # ===========================================================================
813 # Load image file.
815 realpath = path.join(path.dirname(__file__), "images", "fabric_diffuse.png")
816 print("Loading: " + realpath)
817 try:
818 img = bpy.data.images.load(realpath)
819 except:
820 raise NameError("Cannot load image %s" % realpath)
822 # Create image texture from image
823 ctex = bpy.data.textures.new('ColorTex', type='IMAGE')
824 ctex.image = img
826 node = nodes.new('ShaderNodeTexImage')
827 node.name = 'Image1'
828 node.image = ctex.image
829 node.location = 615, 350
831 node = nodes.new('ShaderNodeBsdfTransparent')
832 node.name = 'Transparent1'
833 node.location = 810, 395
834 node.inputs[0].default_value = [r, g, b, 1]
836 node = nodes.new('ShaderNodeAddShader')
837 node.name = 'Add1'
838 node.location = 1040, 356
840 # Connect nodes
841 outn = nodes['UVCoordinates'].outputs['UV']
842 inn = nodes['UVMapping'].inputs['Vector']
843 mat.node_tree.links.new(outn, inn)
845 outn = nodes['UVMapping'].outputs['Vector']
846 inn = nodes['Image1'].inputs['Vector']
847 mat.node_tree.links.new(outn, inn)
849 outn = nodes['Image1'].outputs['Color']
850 inn = nodes['Diffuse BSDF'].inputs['Color']
851 mat.node_tree.links.new(outn, inn)
853 outn = nodes['Transparent1'].outputs['BSDF']
854 inn = nodes['Add1'].inputs[0]
855 mat.node_tree.links.new(outn, inn)
857 outn = nodes['Diffuse BSDF'].outputs['BSDF']
858 inn = nodes['Add1'].inputs[1]
859 mat.node_tree.links.new(outn, inn)
861 outn = nodes['Add1'].outputs['Shader']
862 inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0]
863 mat.node_tree.links.new(outn, inn)
865 return mat
868 # --------------------------------------------------------------------
869 # Copy bin file
870 # --------------------------------------------------------------------
871 def copy_binfile(fromfile, tofile):
872 with open(fromfile, 'rb') as f1:
873 with open(tofile, 'wb') as f2:
874 while True:
875 mybytes = f1.read(1024)
876 if mybytes:
877 f2.write(mybytes)
878 else:
879 break
882 # --------------------------------------------------------------------
883 # Parent object (keep positions)
884 # --------------------------------------------------------------------
885 def parentobject(parentobj, childobj):
886 # noinspection PyBroadException
887 try:
888 bpy.ops.object.select_all(action='DESELECT')
889 bpy.context.scene.objects.active = parentobj
890 parentobj.select = True
891 childobj.select = True
892 bpy.ops.object.parent_set(type='OBJECT', keep_transform=False)
893 return True
894 except:
895 return False
898 # ------------------------------------------------------------------------------
899 # Create control box
901 # objName: Object name
902 # x: size x axis
903 # y: size y axis
904 # z: size z axis
905 # tube: True create a tube, False only sides
906 # ------------------------------------------------------------------------------
907 def create_control_box(objname, x, y, z, tube=True):
908 myvertex = [(-x / 2, 0, 0.0),
909 (-x / 2, y, 0.0),
910 (x / 2, y, 0.0),
911 (x / 2, 0, 0.0),
912 (-x / 2, 0, z),
913 (-x / 2, y, z),
914 (x / 2, y, z),
915 (x / 2, 0, z)]
917 if tube is True:
918 myfaces = [(0, 1, 2, 3), (0, 4, 5, 1), (1, 5, 6, 2), (3, 7, 4, 0), (2, 6, 7, 3), (5, 4, 7, 6)]
919 else:
920 myfaces = [(0, 4, 5, 1), (2, 6, 7, 3)]
922 mesh = bpy.data.meshes.new(objname)
923 myobject = bpy.data.objects.new(objname, mesh)
925 myobject.location = bpy.context.scene.cursor_location
926 bpy.context.scene.objects.link(myobject)
928 mesh.from_pydata(myvertex, [], myfaces)
929 mesh.update(calc_edges=True)
931 return myobject
934 # ------------------------------------------------------------------------------
935 # Remove all children objects
936 # ------------------------------------------------------------------------------
937 def remove_children(myobject):
938 # Remove children
939 for child in myobject.children:
940 # noinspection PyBroadException
941 try:
942 # noinspection PyBroadException
943 try:
944 # remove child relationship
945 for grandchild in child.children:
946 grandchild.parent = None
947 # remove modifiers
948 for mod in child.modifiers:
949 bpy.ops.object.modifier_remove(name=mod.name)
950 except:
951 pass
952 # clear child data
953 if child.type == 'MESH':
954 old = child.data
955 child.select = True
956 bpy.ops.object.delete()
957 bpy.data.meshes.remove(old)
958 if child.type == 'CURVE':
959 child.select = True
960 bpy.ops.object.delete()
961 except:
962 pass
965 # --------------------------------------------------------------------
966 # Get all parents
967 # --------------------------------------------------------------------
968 def get_allparents(myobj):
969 obj = myobj
970 mylist = []
971 while obj.parent is not None:
972 mylist.append(obj)
973 objp = obj.parent
974 obj = objp
976 mylist.append(obj)
978 return mylist
981 # --------------------------------------------------------------------
982 # Verify all faces are in vertice group to avoid Blander crash
984 # Review the faces array and remove any vertex out of the range
985 # this avoid any bug that can appear avoiding Blender crash
986 # --------------------------------------------------------------------
987 def check_mesh_errors(myvertices, myfaces):
988 vmax = len(myvertices)
990 f = 0
991 for face in myfaces:
992 for v in face:
993 if v < 0 or v > vmax:
994 print("Face=" + str(f) + "->removed vertex=" + str(v))
995 myfaces[f].remove(v)
996 f += 1
998 return myfaces