1 # SPDX-License-Identifier: GPL-2.0-or-later
5 # ----------------------------------------------------------
6 # support routines and general functions
7 # Author: Antonio Vazquez (antonioya)
9 # ----------------------------------------------------------
10 # noinspection PyUnresolvedReferences
15 # --------------------------------------------------------------------
16 # Get length Blender units
17 # --------------------------------------------------------------------
18 def get_blendunits(units
):
19 if bpy
.context
.scene
.unit_settings
.system
== "IMPERIAL":
25 # --------------------------------------------------------------------
27 # True= faces to inside
28 # False= faces to outside
29 # --------------------------------------------------------------------
30 def set_normals(myobject
, direction
=False):
31 bpy
.context
.view_layer
.objects
.active
= myobject
33 bpy
.ops
.object.mode_set(mode
='EDIT')
35 bpy
.ops
.mesh
.select_all(action
='SELECT')
36 # recalculate outside normals
37 bpy
.ops
.mesh
.normals_make_consistent(inside
=direction
)
38 # go object mode again
39 bpy
.ops
.object.editmode_toggle()
42 # --------------------------------------------------------------------
44 # --------------------------------------------------------------------
45 def remove_doubles(myobject
):
46 bpy
.context
.view_layer
.objects
.active
= myobject
48 bpy
.ops
.object.mode_set(mode
='EDIT')
50 bpy
.ops
.mesh
.select_all(action
='SELECT')
52 bpy
.ops
.mesh
.remove_doubles()
53 # go object mode again
54 bpy
.ops
.object.editmode_toggle()
57 # --------------------------------------------------------------------
59 # --------------------------------------------------------------------
60 def set_smooth(myobject
):
62 for o
in bpy
.data
.objects
:
63 if o
.select_get() is True:
66 myobject
.select_set(True)
67 bpy
.context
.view_layer
.objects
.active
= myobject
68 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
69 bpy
.ops
.object.shade_smooth()
72 # --------------------------------------------------------------------
73 # Add modifier (subdivision)
74 # --------------------------------------------------------------------
75 def set_modifier_subsurf(myobject
):
76 bpy
.context
.view_layer
.objects
.active
= myobject
77 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
78 bpy
.ops
.object.modifier_add(type='SUBSURF')
79 for mod
in myobject
.modifiers
:
80 if mod
.type == 'SUBSURF':
84 # --------------------------------------------------------------------
85 # Add modifier (mirror)
86 # --------------------------------------------------------------------
87 def set_modifier_mirror(myobject
, axis
="Y"):
88 bpy
.ops
.object.select_all(action
='DESELECT')
89 myobject
.select_set(True)
90 bpy
.context
.view_layer
.objects
.active
= myobject
91 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
92 bpy
.ops
.object.modifier_add(type='MIRROR')
93 for mod
in myobject
.modifiers
:
94 if mod
.type == 'MIRROR':
96 mod
.use_axis
[0] = True
98 mod
.use__axis
[0] = False
101 mod
.use_axis
[1] = True
103 mod
.use_axis
[1] = False
106 mod
.use_axis
[2] = True
108 mod
.use_axis
[2] = False
113 # --------------------------------------------------------------------
114 # Add modifier (array)
115 # --------------------------------------------------------------------
116 def set_modifier_array(myobject
, axis
, move
, repeat
, fix
=False, fixmove
=0, zmove
=0):
117 bpy
.ops
.object.select_all(action
='DESELECT')
118 myobject
.select_set(True)
119 bpy
.context
.view_layer
.objects
.active
= myobject
120 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
121 bpy
.ops
.object.modifier_add(type='ARRAY')
122 for mod
in myobject
.modifiers
:
123 if mod
.type == 'ARRAY':
124 if mod
.name
== "Array":
125 mod
.name
= "Array_" + axis
127 mod
.use_constant_offset
= fix
129 mod
.relative_offset_displace
[0] = move
130 mod
.constant_offset_displace
[0] = fixmove
131 mod
.relative_offset_displace
[1] = 0.0
132 mod
.constant_offset_displace
[1] = 0.0
133 mod
.relative_offset_displace
[2] = 0.0
134 mod
.constant_offset_displace
[2] = zmove
137 mod
.relative_offset_displace
[0] = 0.0
138 mod
.constant_offset_displace
[0] = 0.0
139 mod
.relative_offset_displace
[1] = move
140 mod
.constant_offset_displace
[1] = fixmove
141 mod
.relative_offset_displace
[2] = 0.0
142 mod
.constant_offset_displace
[2] = 0.0
145 # --------------------------------------------------------------------
146 # Add modifier (curve)
147 # --------------------------------------------------------------------
148 def set_modifier_curve(myobject
, mycurve
):
149 bpy
.context
.view_layer
.objects
.active
= myobject
150 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
151 bpy
.ops
.object.modifier_add(type='CURVE')
152 for mod
in myobject
.modifiers
:
153 if mod
.type == 'CURVE':
154 mod
.deform_axis
= 'POS_X'
158 # --------------------------------------------------------------------
159 # Add modifier (solidify)
160 # --------------------------------------------------------------------
161 def set_modifier_solidify(myobject
, width
):
162 bpy
.context
.view_layer
.objects
.active
= myobject
163 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
164 bpy
.ops
.object.modifier_add(type='SOLIDIFY')
165 for mod
in myobject
.modifiers
:
166 if mod
.type == 'SOLIDIFY':
167 mod
.thickness
= width
168 mod
.use_even_offset
= True
169 mod
.use_quality_normals
= True
173 # --------------------------------------------------------------------
174 # Add modifier (boolean)
175 # --------------------------------------------------------------------
176 def set_modifier_boolean(myobject
, bolobject
):
177 bpy
.context
.view_layer
.objects
.active
= myobject
178 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
179 bpy
.ops
.object.modifier_add(type='BOOLEAN')
180 mod
= myobject
.modifiers
[len(myobject
.modifiers
) - 1]
181 mod
.operation
= 'DIFFERENCE'
182 mod
.object = bolobject
185 # --------------------------------------------------------------------
186 # Set material to object
187 # --------------------------------------------------------------------
188 def set_material(myobject
, mymaterial
):
189 bpy
.context
.view_layer
.objects
.active
= myobject
190 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
191 myobject
.data
.materials
.append(mymaterial
)
194 # --------------------------------------------------------------------
195 # Set material to selected faces
196 # --------------------------------------------------------------------
197 def set_material_faces(myobject
, idx
):
198 bpy
.context
.view_layer
.objects
.active
= myobject
199 myobject
.select_set(True)
200 bpy
.context
.object.active_material_index
= idx
201 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
202 bpy
.ops
.object.mode_set(mode
='EDIT')
203 bpy
.ops
.object.material_slot_assign()
205 bpy
.ops
.mesh
.select_all(action
='DESELECT')
206 bpy
.ops
.object.mode_set(mode
='OBJECT')
209 # --------------------------------------------------------------------
211 # --------------------------------------------------------------------
212 def select_faces(myobject
, selface
, clear
):
213 myobject
.select_set(True)
214 bpy
.context
.view_layer
.objects
.active
= myobject
215 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
216 # deselect everything
218 bpy
.ops
.object.mode_set(mode
='EDIT')
219 bpy
.ops
.mesh
.select_all(action
='DESELECT')
221 # reselect the originally selected face
222 bpy
.ops
.object.mode_set(mode
='OBJECT')
223 myobject
.data
.polygons
[selface
].select
= True
226 # --------------------------------------------------------------------
228 # --------------------------------------------------------------------
229 def select_vertices(myobject
, selvertices
, clear
=True):
230 myobject
.select_set(True)
231 bpy
.context
.view_layer
.objects
.active
= myobject
232 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
233 # deselect everything
235 bpy
.ops
.object.mode_set(mode
='EDIT')
236 bpy
.ops
.mesh
.select_all(action
='DESELECT')
239 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
240 sel_mode
= bpy
.context
.tool_settings
.mesh_select_mode
242 bpy
.context
.tool_settings
.mesh_select_mode
= [True, False, False]
243 bpy
.ops
.object.mode_set(mode
='OBJECT', toggle
=False)
245 for i
in selvertices
:
246 myobject
.data
.vertices
[i
].select
= True
248 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
249 bpy
.context
.tool_settings
.mesh_select_mode
= sel_mode
250 bpy
.ops
.object.mode_set(mode
='OBJECT')
253 # --------------------------------------------------------------------
255 # --------------------------------------------------------------------
256 def mark_seam(myobject
):
257 # noinspection PyBroadException
259 myobject
.select_set(True)
260 bpy
.context
.view_layer
.objects
.active
= myobject
261 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
262 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
263 bpy
.ops
.mesh
.mark_seam()
264 bpy
.ops
.object.mode_set(mode
='OBJECT')
266 bpy
.ops
.object.mode_set(mode
='OBJECT')
269 # --------------------------------------------------------------------
271 # --------------------------------------------------------------------
272 def unwrap_mesh(myobject
, allfaces
=True):
273 # noinspection PyBroadException
275 myobject
.select_set(True)
276 bpy
.context
.view_layer
.objects
.active
= myobject
277 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
279 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
281 bpy
.ops
.mesh
.select_all(action
='DESELECT')
282 bpy
.ops
.mesh
.select_all()
284 bpy
.ops
.object.mode_set(mode
='OBJECT')
286 bpy
.ops
.object.mode_set(mode
='OBJECT')
289 # --------------------------------------------------------------------
290 # Get Node Index(multilanguage support)
291 # --------------------------------------------------------------------
292 def get_node_index(nodes
, datatype
):
295 if m
.type == datatype
:
303 # --------------------------------------------------------------------
304 # Create cycles diffuse material
305 # --------------------------------------------------------------------
306 def create_diffuse_material(matname
, replace
, r
, g
, b
, rv
=0.8, gv
=0.8, bv
=0.8, mix
=0.1, twosides
=False):
307 # Avoid duplicate materials
309 matlist
= bpy
.data
.materials
311 if m
.name
== matname
:
314 mat
= bpy
.data
.materials
.new(matname
)
315 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0) # viewport color
317 nodes
= mat
.node_tree
.nodes
319 # support for multilanguage
320 node
= nodes
.new('ShaderNodeBsdfDiffuse')
321 node
.name
= 'Diffuse BSDF'
322 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
323 node
.location
= 200, 320
325 node
= nodes
.new('ShaderNodeBsdfGlossy')
326 node
.name
= 'Glossy_0'
327 node
.location
= 200, 0
329 node
= nodes
.new('ShaderNodeMixShader')
331 node
.inputs
[0].default_value
= mix
332 node
.location
= 500, 160
334 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
335 node
.location
= 1100, 160
338 outn
= nodes
['Diffuse BSDF'].outputs
[0]
339 inn
= nodes
['Mix_0'].inputs
[1]
340 mat
.node_tree
.links
.new(outn
, inn
)
342 outn
= nodes
['Glossy_0'].outputs
[0]
343 inn
= nodes
['Mix_0'].inputs
[2]
344 mat
.node_tree
.links
.new(outn
, inn
)
346 if twosides
is False:
347 outn
= nodes
['Mix_0'].outputs
[0]
348 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
349 mat
.node_tree
.links
.new(outn
, inn
)
352 node
= nodes
.new('ShaderNodeNewGeometry')
353 node
.name
= 'Input_1'
354 node
.location
= -80, -70
356 node
= nodes
.new('ShaderNodeBsdfDiffuse')
357 node
.name
= 'Diffuse_1'
358 node
.inputs
[0].default_value
= [0.30, 0.30, 0.30, 1]
359 node
.location
= 200, -280
361 node
= nodes
.new('ShaderNodeMixShader')
363 node
.inputs
[0].default_value
= mix
364 node
.location
= 800, -70
366 outn
= nodes
['Input_1'].outputs
[6]
367 inn
= nodes
['Mix_1'].inputs
[0]
368 mat
.node_tree
.links
.new(outn
, inn
)
370 outn
= nodes
['Diffuse_1'].outputs
[0]
371 inn
= nodes
['Mix_1'].inputs
[2]
372 mat
.node_tree
.links
.new(outn
, inn
)
374 outn
= nodes
['Mix_0'].outputs
[0]
375 inn
= nodes
['Mix_1'].inputs
[1]
376 mat
.node_tree
.links
.new(outn
, inn
)
378 outn
= nodes
['Mix_1'].outputs
[0]
379 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
380 mat
.node_tree
.links
.new(outn
, inn
)
385 # --------------------------------------------------------------------
386 # Create cycles translucent material
387 # --------------------------------------------------------------------
388 def create_translucent_material(matname
, replace
, r
, g
, b
, rv
=0.8, gv
=0.8, bv
=0.8, mix
=0.1):
389 # Avoid duplicate materials
391 matlist
= bpy
.data
.materials
393 if m
.name
== matname
:
396 mat
= bpy
.data
.materials
.new(matname
)
397 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0) # viewport color
399 nodes
= mat
.node_tree
.nodes
401 # support for multilanguage
402 node
= nodes
.new('ShaderNodeBsdfDiffuse')
403 node
.name
= 'Diffuse BSDF'
404 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
405 node
.location
= 200, 320
407 node
= nodes
.new('ShaderNodeBsdfTranslucent')
408 node
.name
= 'Translucent_0'
409 node
.location
= 200, 0
411 node
= nodes
.new('ShaderNodeMixShader')
413 node
.inputs
[0].default_value
= mix
414 node
.location
= 500, 160
416 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
417 node
.location
= 1100, 160
420 outn
= nodes
['Diffuse BSDF'].outputs
[0]
421 inn
= nodes
['Mix_0'].inputs
[1]
422 mat
.node_tree
.links
.new(outn
, inn
)
424 outn
= nodes
['Translucent_0'].outputs
[0]
425 inn
= nodes
['Mix_0'].inputs
[2]
426 mat
.node_tree
.links
.new(outn
, inn
)
428 outn
= nodes
['Mix_0'].outputs
[0]
429 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
430 mat
.node_tree
.links
.new(outn
, inn
)
435 # --------------------------------------------------------------------
436 # Create cycles glass material
437 # --------------------------------------------------------------------
438 def create_glass_material(matname
, replace
, rv
=0.333, gv
=0.342, bv
=0.9):
439 # Avoid duplicate materials
441 matlist
= bpy
.data
.materials
443 if m
.name
== matname
:
446 mat
= bpy
.data
.materials
.new(matname
)
448 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0)
449 nodes
= mat
.node_tree
.nodes
451 # support for multilanguage
452 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
453 mat
.node_tree
.nodes
.remove(node
) # remove not used
455 node
= nodes
.new('ShaderNodeLightPath')
456 node
.name
= 'Light_0'
457 node
.location
= 10, 160
459 node
= nodes
.new('ShaderNodeBsdfRefraction')
460 node
.name
= 'Refraction_0'
461 node
.inputs
[2].default_value
= 1 # IOR 1.0
462 node
.location
= 250, 400
464 node
= nodes
.new('ShaderNodeBsdfGlossy')
465 node
.name
= 'Glossy_0'
466 node
.distribution
= 'SHARP'
467 node
.location
= 250, 100
469 node
= nodes
.new('ShaderNodeBsdfTransparent')
470 node
.name
= 'Transparent_0'
471 node
.location
= 500, 10
473 node
= nodes
.new('ShaderNodeMixShader')
475 node
.inputs
[0].default_value
= 0.035
476 node
.location
= 500, 160
478 node
= nodes
.new('ShaderNodeMixShader')
480 node
.inputs
[0].default_value
= 0.1
481 node
.location
= 690, 290
483 node
= nodes
.new('ShaderNodeOutputMaterial')
484 node
.name
= 'OUTPUT_MATERIAL'
485 node
.location
= 920, 290
488 outn
= nodes
['Light_0'].outputs
[1]
489 inn
= nodes
['Mix_1'].inputs
[0]
490 mat
.node_tree
.links
.new(outn
, inn
)
492 outn
= nodes
['Refraction_0'].outputs
[0]
493 inn
= nodes
['Mix_0'].inputs
[1]
494 mat
.node_tree
.links
.new(outn
, inn
)
496 outn
= nodes
['Glossy_0'].outputs
[0]
497 inn
= nodes
['Mix_0'].inputs
[2]
498 mat
.node_tree
.links
.new(outn
, inn
)
500 outn
= nodes
['Mix_0'].outputs
[0]
501 inn
= nodes
['Mix_1'].inputs
[1]
502 mat
.node_tree
.links
.new(outn
, inn
)
504 outn
= nodes
['Transparent_0'].outputs
[0]
505 inn
= nodes
['Mix_1'].inputs
[2]
506 mat
.node_tree
.links
.new(outn
, inn
)
508 outn
= nodes
['Mix_1'].outputs
[0]
509 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
510 mat
.node_tree
.links
.new(outn
, inn
)
515 # ---------------------------------------------
516 # Create cycles transparents material
517 # --------------------------------------------------------------------
518 def create_transparent_material(matname
, replace
, r
=1, g
=1, b
=1, alpha
=0):
519 # Avoid duplicate materials
521 matlist
= bpy
.data
.materials
523 if m
.name
== matname
:
526 mat
= bpy
.data
.materials
.new(matname
)
528 mat
.diffuse_color
= (r
, g
, b
, 1.0)
529 nodes
= mat
.node_tree
.nodes
531 # support for multilanguage
532 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
533 mat
.node_tree
.nodes
.remove(node
) # remove not used
535 node
= nodes
.new('ShaderNodeBsdfTransparent')
536 node
.name
= 'Transparent_0'
537 node
.location
= 250, 160
538 node
.inputs
[0].default_value
= [r
, g
, b
, alpha
]
540 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
541 node
.location
= 700, 160
544 outn
= nodes
['Transparent_0'].outputs
[0]
545 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
546 mat
.node_tree
.links
.new(outn
, inn
)
551 # --------------------------------------------------------------------
552 # Create cycles glossy material
553 # --------------------------------------------------------------------
554 def create_glossy_material(matname
, replace
, r
, g
, b
, rv
=0.578, gv
=0.555, bv
=0.736, rvalue
=0.2):
555 # Avoid duplicate materials
557 matlist
= bpy
.data
.materials
559 if m
.name
== matname
:
562 mat
= bpy
.data
.materials
.new(matname
)
564 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0)
565 nodes
= mat
.node_tree
.nodes
567 # support for multilanguage
568 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
569 mat
.node_tree
.nodes
.remove(node
) # remove not used
571 node
= nodes
.new('ShaderNodeBsdfGlossy')
572 node
.name
= 'Glossy_0'
573 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
574 node
.inputs
[1].default_value
= rvalue
575 node
.location
= 200, 160
577 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
578 node
.location
= 700, 160
581 outn
= nodes
['Glossy_0'].outputs
[0]
582 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
583 mat
.node_tree
.links
.new(outn
, inn
)
588 # --------------------------------------------------------------------
589 # Create cycles emission material
590 # --------------------------------------------------------------------
591 def create_emission_material(matname
, replace
, r
, g
, b
, energy
):
592 # Avoid duplicate materials
594 matlist
= bpy
.data
.materials
596 if m
.name
== matname
:
599 mat
= bpy
.data
.materials
.new(matname
)
601 nodes
= mat
.node_tree
.nodes
603 # support for multilanguage
604 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
605 mat
.node_tree
.nodes
.remove(node
) # remove not used
607 node
= nodes
.new('ShaderNodeEmission')
608 node
.name
= 'Emission_0'
609 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
610 node
.inputs
[1].default_value
= energy
611 node
.location
= 200, 160
613 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
614 node
.location
= 700, 160
617 outn
= nodes
['Emission_0'].outputs
[0]
618 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
619 mat
.node_tree
.links
.new(outn
, inn
)
624 # --------------------------------------------------------------------
625 # Create cycles glass material
626 # --------------------------------------------------------------------
627 def create_old_glass_material(matname
, replace
, rv
=0.352716, gv
=0.760852, bv
=0.9):
628 # Avoid duplicate materials
630 matlist
= bpy
.data
.materials
632 if m
.name
== matname
:
635 mat
= bpy
.data
.materials
.new(matname
)
637 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0)
638 nodes
= mat
.node_tree
.nodes
640 # support for multilanguage
641 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
642 mat
.node_tree
.nodes
.remove(node
) # remove not used
644 node
= nodes
.new('ShaderNodeLightPath')
645 node
.name
= 'Light_0'
646 node
.location
= 10, 160
648 node
= nodes
.new('ShaderNodeBsdfGlass')
649 node
.name
= 'Glass_0'
650 node
.location
= 250, 300
652 node
= nodes
.new('ShaderNodeBsdfTransparent')
653 node
.name
= 'Transparent_0'
654 node
.location
= 250, 0
656 node
= nodes
.new('ShaderNodeMixShader')
658 node
.inputs
[0].default_value
= 0.1
659 node
.location
= 500, 160
661 node
= nodes
.new('ShaderNodeMixShader')
663 node
.inputs
[0].default_value
= 0.1
664 node
.location
= 690, 290
666 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
667 node
.location
= 920, 290
670 outn
= nodes
['Light_0'].outputs
[1]
671 inn
= nodes
['Mix_0'].inputs
[0]
672 mat
.node_tree
.links
.new(outn
, inn
)
674 outn
= nodes
['Light_0'].outputs
[2]
675 inn
= nodes
['Mix_1'].inputs
[0]
676 mat
.node_tree
.links
.new(outn
, inn
)
678 outn
= nodes
['Glass_0'].outputs
[0]
679 inn
= nodes
['Mix_0'].inputs
[1]
680 mat
.node_tree
.links
.new(outn
, inn
)
682 outn
= nodes
['Transparent_0'].outputs
[0]
683 inn
= nodes
['Mix_0'].inputs
[2]
684 mat
.node_tree
.links
.new(outn
, inn
)
686 outn
= nodes
['Mix_0'].outputs
[0]
687 inn
= nodes
['Mix_1'].inputs
[1]
688 mat
.node_tree
.links
.new(outn
, inn
)
690 outn
= nodes
['Mix_1'].outputs
[0]
691 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
692 mat
.node_tree
.links
.new(outn
, inn
)
697 # --------------------------------------------------------------------
698 # Create cycles brick texture material
699 # --------------------------------------------------------------------
700 def create_brick_material(matname
, replace
, r
, g
, b
, rv
=0.8, gv
=0.636, bv
=0.315):
701 # Avoid duplicate materials
703 matlist
= bpy
.data
.materials
705 if m
.name
== matname
:
708 mat
= bpy
.data
.materials
.new(matname
)
710 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0)
711 nodes
= mat
.node_tree
.nodes
713 # support for multilanguage
714 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
715 node
.name
= 'Diffuse BSDF'
716 node
.label
= 'Diffuse BSDF'
718 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
719 node
.location
= 500, 160
721 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
722 node
.location
= 700, 160
724 node
= nodes
.new('ShaderNodeTexBrick')
725 node
.name
= 'Brick_0'
726 node
.inputs
[3].default_value
= [0.407, 0.411, 0.394, 1] # mortar color
727 node
.inputs
[4].default_value
= 3 # scale
728 node
.inputs
[5].default_value
= 0.001 # mortar
729 node
.inputs
[7].default_value
= 0.60 # size_w
730 node
.inputs
[8].default_value
= 0.30 # size_h
731 node
.location
= 300, 160
733 node
= nodes
.new('ShaderNodeRGB')
735 node
.outputs
[0].default_value
= [r
, g
, b
, 1]
736 node
.location
= 70, 160
739 outn
= nodes
['RGB_0'].outputs
['Color']
740 inn
= nodes
['Brick_0'].inputs
['Color1']
741 mat
.node_tree
.links
.new(outn
, inn
)
743 inn
= nodes
['Brick_0'].inputs
['Color2']
744 mat
.node_tree
.links
.new(outn
, inn
)
746 outn
= nodes
['Brick_0'].outputs
['Color']
747 inn
= nodes
['Diffuse BSDF'].inputs
['Color']
748 mat
.node_tree
.links
.new(outn
, inn
)
753 # --------------------------------------------------------------------
754 # Create cycles fabric texture material
755 # --------------------------------------------------------------------
756 def create_fabric_material(matname
, replace
, r
, g
, b
, rv
=0.8, gv
=0.636, bv
=0.315):
757 # Avoid duplicate materials
759 matlist
= bpy
.data
.materials
761 if m
.name
== matname
:
764 mat
= bpy
.data
.materials
.new(matname
)
766 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0)
767 nodes
= mat
.node_tree
.nodes
769 # support for multilanguage
770 node
= nodes
.new('ShaderNodeBsdfDiffuse')
771 node
.name
= 'Diffuse BSDF'
772 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
773 node
.location
= 810, 270
775 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
776 node
.location
= 1210, 320
778 node
= nodes
.new('ShaderNodeTexCoord')
779 node
.name
= 'UVCoordinates'
780 node
.location
= 26, 395
782 node
= nodes
.new('ShaderNodeMapping')
783 node
.name
= 'UVMapping'
784 node
.location
= 266, 380
785 node
.inputs
['Scale'].default_value
[0] = 1000
786 node
.inputs
['Scale'].default_value
[1] = 1000
787 node
.inputs
['Scale'].default_value
[2] = 1000
789 # ===========================================================================
791 # ===========================================================================
794 realpath
= path
.join(path
.dirname(__file__
), "images", "fabric_diffuse.png")
795 print("Loading: " + realpath
)
797 img
= bpy
.data
.images
.load(realpath
)
799 raise NameError("Cannot load image %s" % realpath
)
801 # Create image texture from image
802 ctex
= bpy
.data
.textures
.new('ColorTex', type='IMAGE')
805 node
= nodes
.new('ShaderNodeTexImage')
807 node
.image
= ctex
.image
808 node
.location
= 615, 350
810 node
= nodes
.new('ShaderNodeBsdfTransparent')
811 node
.name
= 'Transparent1'
812 node
.location
= 810, 395
813 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
815 node
= nodes
.new('ShaderNodeAddShader')
817 node
.location
= 1040, 356
820 outn
= nodes
['UVCoordinates'].outputs
['UV']
821 inn
= nodes
['UVMapping'].inputs
['Vector']
822 mat
.node_tree
.links
.new(outn
, inn
)
824 outn
= nodes
['UVMapping'].outputs
['Vector']
825 inn
= nodes
['Image1'].inputs
['Vector']
826 mat
.node_tree
.links
.new(outn
, inn
)
828 outn
= nodes
['Image1'].outputs
['Color']
829 inn
= nodes
['Diffuse BSDF'].inputs
['Color']
830 mat
.node_tree
.links
.new(outn
, inn
)
832 outn
= nodes
['Transparent1'].outputs
['BSDF']
833 inn
= nodes
['Add1'].inputs
[0]
834 mat
.node_tree
.links
.new(outn
, inn
)
836 outn
= nodes
['Diffuse BSDF'].outputs
['BSDF']
837 inn
= nodes
['Add1'].inputs
[1]
838 mat
.node_tree
.links
.new(outn
, inn
)
840 outn
= nodes
['Add1'].outputs
['Shader']
841 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
842 mat
.node_tree
.links
.new(outn
, inn
)
847 # --------------------------------------------------------------------
849 # --------------------------------------------------------------------
850 def copy_binfile(fromfile
, tofile
):
851 with
open(fromfile
, 'rb') as f1
:
852 with
open(tofile
, 'wb') as f2
:
854 mybytes
= f1
.read(1024)
861 # --------------------------------------------------------------------
862 # Parent object (keep positions)
863 # --------------------------------------------------------------------
864 def parentobject(parentobj
, childobj
):
865 # noinspection PyBroadException
867 bpy
.ops
.object.select_all(action
='DESELECT')
868 bpy
.context
.view_layer
.objects
.active
= parentobj
869 parentobj
.select_set(True)
870 childobj
.select_set(True)
871 bpy
.ops
.object.parent_set(type='OBJECT', keep_transform
=False)
877 # ------------------------------------------------------------------------------
880 # objName: Object name
884 # tube: True create a tube, False only sides
885 # ------------------------------------------------------------------------------
886 def create_control_box(objname
, x
, y
, z
, tube
=True):
887 myvertex
= [(-x
/ 2, 0, 0.0),
897 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)]
899 myfaces
= [(0, 4, 5, 1), (2, 6, 7, 3)]
901 mesh
= bpy
.data
.meshes
.new(objname
)
902 myobject
= bpy
.data
.objects
.new(objname
, mesh
)
904 myobject
.location
= bpy
.context
.scene
.cursor
.location
905 bpy
.context
.collection
.objects
.link(myobject
)
907 mesh
.from_pydata(myvertex
, [], myfaces
)
908 mesh
.update(calc_edges
=True)
913 # ------------------------------------------------------------------------------
914 # Remove all children objects
915 # ------------------------------------------------------------------------------
916 def remove_children(myobject
):
918 for child
in myobject
.children
:
919 # noinspection PyBroadException
921 # noinspection PyBroadException
923 # remove child relationship
924 for grandchild
in child
.children
:
925 grandchild
.parent
= None
927 for mod
in child
.modifiers
:
928 bpy
.ops
.object.modifier_remove(name
=mod
.name
)
932 if child
.type == 'MESH':
934 child
.select_set(True)
935 bpy
.ops
.object.delete()
936 bpy
.data
.meshes
.remove(old
)
937 if child
.type == 'CURVE':
938 child
.select_set(True)
939 bpy
.ops
.object.delete()
944 # --------------------------------------------------------------------
946 # --------------------------------------------------------------------
947 def get_allparents(myobj
):
950 while obj
.parent
is not None:
960 # --------------------------------------------------------------------
961 # Verify all faces are in vertice group to avoid Blander crash
963 # Review the faces array and remove any vertex out of the range
964 # this avoid any bug that can appear avoiding Blender crash
965 # --------------------------------------------------------------------
966 def check_mesh_errors(myvertices
, myfaces
):
967 vmax
= len(myvertices
)
972 if v
< 0 or v
> vmax
:
973 print("Face=" + str(f
) + "->removed vertex=" + str(v
))