1 # SPDX-FileCopyrightText: 2016-2023 Blender Foundation
3 # 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 boolean_modifier
= myobject
.modifiers
.new("", 'BOOLEAN')
178 boolean_modifier
.operation
= 'DIFFERENCE'
179 boolean_modifier
.object = bolobject
182 # --------------------------------------------------------------------
183 # Set material to object
184 # --------------------------------------------------------------------
185 def set_material(myobject
, mymaterial
):
186 bpy
.context
.view_layer
.objects
.active
= myobject
187 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
188 myobject
.data
.materials
.append(mymaterial
)
191 # --------------------------------------------------------------------
192 # Set material to selected faces
193 # --------------------------------------------------------------------
194 def set_material_faces(myobject
, idx
):
195 bpy
.context
.view_layer
.objects
.active
= myobject
196 myobject
.select_set(True)
197 bpy
.context
.object.active_material_index
= idx
198 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
199 bpy
.ops
.object.mode_set(mode
='EDIT')
200 bpy
.ops
.object.material_slot_assign()
202 bpy
.ops
.mesh
.select_all(action
='DESELECT')
203 bpy
.ops
.object.mode_set(mode
='OBJECT')
206 # --------------------------------------------------------------------
208 # --------------------------------------------------------------------
209 def select_faces(myobject
, selface
, clear
):
210 myobject
.select_set(True)
211 bpy
.context
.view_layer
.objects
.active
= myobject
212 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
213 # deselect everything
215 bpy
.ops
.object.mode_set(mode
='EDIT')
216 bpy
.ops
.mesh
.select_all(action
='DESELECT')
218 # reselect the originally selected face
219 bpy
.ops
.object.mode_set(mode
='OBJECT')
220 myobject
.data
.polygons
[selface
].select
= True
223 # --------------------------------------------------------------------
225 # --------------------------------------------------------------------
226 def select_vertices(myobject
, selvertices
, clear
=True):
227 myobject
.select_set(True)
228 bpy
.context
.view_layer
.objects
.active
= myobject
229 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
230 # deselect everything
232 bpy
.ops
.object.mode_set(mode
='EDIT')
233 bpy
.ops
.mesh
.select_all(action
='DESELECT')
236 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
237 sel_mode
= bpy
.context
.tool_settings
.mesh_select_mode
239 bpy
.context
.tool_settings
.mesh_select_mode
= [True, False, False]
240 bpy
.ops
.object.mode_set(mode
='OBJECT', toggle
=False)
242 for i
in selvertices
:
243 myobject
.data
.vertices
[i
].select
= True
245 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
246 bpy
.context
.tool_settings
.mesh_select_mode
= sel_mode
247 bpy
.ops
.object.mode_set(mode
='OBJECT')
250 # --------------------------------------------------------------------
252 # --------------------------------------------------------------------
253 def mark_seam(myobject
):
254 # noinspection PyBroadException
256 myobject
.select_set(True)
257 bpy
.context
.view_layer
.objects
.active
= myobject
258 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
259 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
260 bpy
.ops
.mesh
.mark_seam()
261 bpy
.ops
.object.mode_set(mode
='OBJECT')
263 bpy
.ops
.object.mode_set(mode
='OBJECT')
266 # --------------------------------------------------------------------
268 # --------------------------------------------------------------------
269 def unwrap_mesh(myobject
, allfaces
=True):
270 # noinspection PyBroadException
272 myobject
.select_set(True)
273 bpy
.context
.view_layer
.objects
.active
= myobject
274 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
276 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
278 bpy
.ops
.mesh
.select_all(action
='DESELECT')
279 bpy
.ops
.mesh
.select_all()
281 bpy
.ops
.object.mode_set(mode
='OBJECT')
283 bpy
.ops
.object.mode_set(mode
='OBJECT')
286 # --------------------------------------------------------------------
287 # Get Node Index(multilanguage support)
288 # --------------------------------------------------------------------
289 def get_node_index(nodes
, datatype
):
292 if m
.type == datatype
:
300 # --------------------------------------------------------------------
301 # Create cycles diffuse material
302 # --------------------------------------------------------------------
303 def create_diffuse_material(matname
, replace
, r
, g
, b
, rv
=0.8, gv
=0.8, bv
=0.8, mix
=0.1, twosides
=False):
304 # Avoid duplicate materials
306 matlist
= bpy
.data
.materials
308 if m
.name
== matname
:
311 mat
= bpy
.data
.materials
.new(matname
)
312 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0) # viewport color
314 nodes
= mat
.node_tree
.nodes
316 # support for multilanguage
317 node
= nodes
.new('ShaderNodeBsdfDiffuse')
318 node
.name
= 'Diffuse BSDF'
319 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
320 node
.location
= 200, 320
322 node
= nodes
.new('ShaderNodeBsdfGlossy')
323 node
.name
= 'Glossy_0'
324 node
.location
= 200, 0
326 node
= nodes
.new('ShaderNodeMixShader')
328 node
.inputs
[0].default_value
= mix
329 node
.location
= 500, 160
331 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
332 node
.location
= 1100, 160
335 outn
= nodes
['Diffuse BSDF'].outputs
[0]
336 inn
= nodes
['Mix_0'].inputs
[1]
337 mat
.node_tree
.links
.new(outn
, inn
)
339 outn
= nodes
['Glossy_0'].outputs
[0]
340 inn
= nodes
['Mix_0'].inputs
[2]
341 mat
.node_tree
.links
.new(outn
, inn
)
343 if twosides
is False:
344 outn
= nodes
['Mix_0'].outputs
[0]
345 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
346 mat
.node_tree
.links
.new(outn
, inn
)
349 node
= nodes
.new('ShaderNodeNewGeometry')
350 node
.name
= 'Input_1'
351 node
.location
= -80, -70
353 node
= nodes
.new('ShaderNodeBsdfDiffuse')
354 node
.name
= 'Diffuse_1'
355 node
.inputs
[0].default_value
= [0.30, 0.30, 0.30, 1]
356 node
.location
= 200, -280
358 node
= nodes
.new('ShaderNodeMixShader')
360 node
.inputs
[0].default_value
= mix
361 node
.location
= 800, -70
363 outn
= nodes
['Input_1'].outputs
[6]
364 inn
= nodes
['Mix_1'].inputs
[0]
365 mat
.node_tree
.links
.new(outn
, inn
)
367 outn
= nodes
['Diffuse_1'].outputs
[0]
368 inn
= nodes
['Mix_1'].inputs
[2]
369 mat
.node_tree
.links
.new(outn
, inn
)
371 outn
= nodes
['Mix_0'].outputs
[0]
372 inn
= nodes
['Mix_1'].inputs
[1]
373 mat
.node_tree
.links
.new(outn
, inn
)
375 outn
= nodes
['Mix_1'].outputs
[0]
376 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
377 mat
.node_tree
.links
.new(outn
, inn
)
382 # --------------------------------------------------------------------
383 # Create cycles translucent material
384 # --------------------------------------------------------------------
385 def create_translucent_material(matname
, replace
, r
, g
, b
, rv
=0.8, gv
=0.8, bv
=0.8, mix
=0.1):
386 # Avoid duplicate materials
388 matlist
= bpy
.data
.materials
390 if m
.name
== matname
:
393 mat
= bpy
.data
.materials
.new(matname
)
394 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0) # viewport color
396 nodes
= mat
.node_tree
.nodes
398 # support for multilanguage
399 node
= nodes
.new('ShaderNodeBsdfDiffuse')
400 node
.name
= 'Diffuse BSDF'
401 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
402 node
.location
= 200, 320
404 node
= nodes
.new('ShaderNodeBsdfTranslucent')
405 node
.name
= 'Translucent_0'
406 node
.location
= 200, 0
408 node
= nodes
.new('ShaderNodeMixShader')
410 node
.inputs
[0].default_value
= mix
411 node
.location
= 500, 160
413 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
414 node
.location
= 1100, 160
417 outn
= nodes
['Diffuse BSDF'].outputs
[0]
418 inn
= nodes
['Mix_0'].inputs
[1]
419 mat
.node_tree
.links
.new(outn
, inn
)
421 outn
= nodes
['Translucent_0'].outputs
[0]
422 inn
= nodes
['Mix_0'].inputs
[2]
423 mat
.node_tree
.links
.new(outn
, inn
)
425 outn
= nodes
['Mix_0'].outputs
[0]
426 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
427 mat
.node_tree
.links
.new(outn
, inn
)
432 # --------------------------------------------------------------------
433 # Create cycles glass material
434 # --------------------------------------------------------------------
435 def create_glass_material(matname
, replace
, rv
=0.333, gv
=0.342, bv
=0.9):
436 # Avoid duplicate materials
438 matlist
= bpy
.data
.materials
440 if m
.name
== matname
:
443 mat
= bpy
.data
.materials
.new(matname
)
445 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0)
446 nodes
= mat
.node_tree
.nodes
448 # support for multilanguage
449 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
450 mat
.node_tree
.nodes
.remove(node
) # remove not used
452 node
= nodes
.new('ShaderNodeLightPath')
453 node
.name
= 'Light_0'
454 node
.location
= 10, 160
456 node
= nodes
.new('ShaderNodeBsdfRefraction')
457 node
.name
= 'Refraction_0'
458 node
.inputs
[2].default_value
= 1 # IOR 1.0
459 node
.location
= 250, 400
461 node
= nodes
.new('ShaderNodeBsdfGlossy')
462 node
.name
= 'Glossy_0'
463 node
.location
= 250, 100
465 node
= nodes
.new('ShaderNodeBsdfTransparent')
466 node
.name
= 'Transparent_0'
467 node
.location
= 500, 10
469 node
= nodes
.new('ShaderNodeMixShader')
471 node
.inputs
[0].default_value
= 0.035
472 node
.location
= 500, 160
474 node
= nodes
.new('ShaderNodeMixShader')
476 node
.inputs
[0].default_value
= 0.1
477 node
.location
= 690, 290
479 node
= nodes
.new('ShaderNodeOutputMaterial')
480 node
.name
= 'OUTPUT_MATERIAL'
481 node
.location
= 920, 290
484 outn
= nodes
['Light_0'].outputs
[1]
485 inn
= nodes
['Mix_1'].inputs
[0]
486 mat
.node_tree
.links
.new(outn
, inn
)
488 outn
= nodes
['Refraction_0'].outputs
[0]
489 inn
= nodes
['Mix_0'].inputs
[1]
490 mat
.node_tree
.links
.new(outn
, inn
)
492 outn
= nodes
['Glossy_0'].outputs
[0]
493 inn
= nodes
['Mix_0'].inputs
[2]
494 mat
.node_tree
.links
.new(outn
, inn
)
496 outn
= nodes
['Mix_0'].outputs
[0]
497 inn
= nodes
['Mix_1'].inputs
[1]
498 mat
.node_tree
.links
.new(outn
, inn
)
500 outn
= nodes
['Transparent_0'].outputs
[0]
501 inn
= nodes
['Mix_1'].inputs
[2]
502 mat
.node_tree
.links
.new(outn
, inn
)
504 outn
= nodes
['Mix_1'].outputs
[0]
505 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
506 mat
.node_tree
.links
.new(outn
, inn
)
511 # ---------------------------------------------
512 # Create cycles transparents material
513 # --------------------------------------------------------------------
514 def create_transparent_material(matname
, replace
, r
=1, g
=1, b
=1, alpha
=0):
515 # Avoid duplicate materials
517 matlist
= bpy
.data
.materials
519 if m
.name
== matname
:
522 mat
= bpy
.data
.materials
.new(matname
)
524 mat
.diffuse_color
= (r
, g
, b
, 1.0)
525 nodes
= mat
.node_tree
.nodes
527 # support for multilanguage
528 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
529 mat
.node_tree
.nodes
.remove(node
) # remove not used
531 node
= nodes
.new('ShaderNodeBsdfTransparent')
532 node
.name
= 'Transparent_0'
533 node
.location
= 250, 160
534 node
.inputs
[0].default_value
= [r
, g
, b
, alpha
]
536 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
537 node
.location
= 700, 160
540 outn
= nodes
['Transparent_0'].outputs
[0]
541 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
542 mat
.node_tree
.links
.new(outn
, inn
)
547 # --------------------------------------------------------------------
548 # Create cycles glossy material
549 # --------------------------------------------------------------------
550 def create_glossy_material(matname
, replace
, r
, g
, b
, rv
=0.578, gv
=0.555, bv
=0.736, rvalue
=0.2):
551 # Avoid duplicate materials
553 matlist
= bpy
.data
.materials
555 if m
.name
== matname
:
558 mat
= bpy
.data
.materials
.new(matname
)
560 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0)
561 nodes
= mat
.node_tree
.nodes
563 # support for multilanguage
564 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
565 mat
.node_tree
.nodes
.remove(node
) # remove not used
567 node
= nodes
.new('ShaderNodeBsdfGlossy')
568 node
.name
= 'Glossy_0'
569 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
570 node
.inputs
[1].default_value
= rvalue
571 node
.location
= 200, 160
573 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
574 node
.location
= 700, 160
577 outn
= nodes
['Glossy_0'].outputs
[0]
578 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
579 mat
.node_tree
.links
.new(outn
, inn
)
584 # --------------------------------------------------------------------
585 # Create cycles emission material
586 # --------------------------------------------------------------------
587 def create_emission_material(matname
, replace
, r
, g
, b
, energy
):
588 # Avoid duplicate materials
590 matlist
= bpy
.data
.materials
592 if m
.name
== matname
:
595 mat
= bpy
.data
.materials
.new(matname
)
597 nodes
= mat
.node_tree
.nodes
599 # support for multilanguage
600 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
601 mat
.node_tree
.nodes
.remove(node
) # remove not used
603 node
= nodes
.new('ShaderNodeEmission')
604 node
.name
= 'Emission_0'
605 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
606 node
.inputs
[1].default_value
= energy
607 node
.location
= 200, 160
609 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
610 node
.location
= 700, 160
613 outn
= nodes
['Emission_0'].outputs
[0]
614 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
615 mat
.node_tree
.links
.new(outn
, inn
)
620 # --------------------------------------------------------------------
621 # Create cycles glass material
622 # --------------------------------------------------------------------
623 def create_old_glass_material(matname
, replace
, rv
=0.352716, gv
=0.760852, bv
=0.9):
624 # Avoid duplicate materials
626 matlist
= bpy
.data
.materials
628 if m
.name
== matname
:
631 mat
= bpy
.data
.materials
.new(matname
)
633 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0)
634 nodes
= mat
.node_tree
.nodes
636 # support for multilanguage
637 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
638 mat
.node_tree
.nodes
.remove(node
) # remove not used
640 node
= nodes
.new('ShaderNodeLightPath')
641 node
.name
= 'Light_0'
642 node
.location
= 10, 160
644 node
= nodes
.new('ShaderNodeBsdfGlass')
645 node
.name
= 'Glass_0'
646 node
.location
= 250, 300
648 node
= nodes
.new('ShaderNodeBsdfTransparent')
649 node
.name
= 'Transparent_0'
650 node
.location
= 250, 0
652 node
= nodes
.new('ShaderNodeMixShader')
654 node
.inputs
[0].default_value
= 0.1
655 node
.location
= 500, 160
657 node
= nodes
.new('ShaderNodeMixShader')
659 node
.inputs
[0].default_value
= 0.1
660 node
.location
= 690, 290
662 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
663 node
.location
= 920, 290
666 outn
= nodes
['Light_0'].outputs
[1]
667 inn
= nodes
['Mix_0'].inputs
[0]
668 mat
.node_tree
.links
.new(outn
, inn
)
670 outn
= nodes
['Light_0'].outputs
[2]
671 inn
= nodes
['Mix_1'].inputs
[0]
672 mat
.node_tree
.links
.new(outn
, inn
)
674 outn
= nodes
['Glass_0'].outputs
[0]
675 inn
= nodes
['Mix_0'].inputs
[1]
676 mat
.node_tree
.links
.new(outn
, inn
)
678 outn
= nodes
['Transparent_0'].outputs
[0]
679 inn
= nodes
['Mix_0'].inputs
[2]
680 mat
.node_tree
.links
.new(outn
, inn
)
682 outn
= nodes
['Mix_0'].outputs
[0]
683 inn
= nodes
['Mix_1'].inputs
[1]
684 mat
.node_tree
.links
.new(outn
, inn
)
686 outn
= nodes
['Mix_1'].outputs
[0]
687 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
688 mat
.node_tree
.links
.new(outn
, inn
)
693 # --------------------------------------------------------------------
694 # Create cycles brick texture material
695 # --------------------------------------------------------------------
696 def create_brick_material(matname
, replace
, r
, g
, b
, rv
=0.8, gv
=0.636, bv
=0.315):
697 # Avoid duplicate materials
699 matlist
= bpy
.data
.materials
701 if m
.name
== matname
:
704 mat
= bpy
.data
.materials
.new(matname
)
706 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0)
707 nodes
= mat
.node_tree
.nodes
709 # support for multilanguage
710 principled_node
= nodes
[get_node_index(nodes
, 'BSDF_PRINCIPLED')]
712 principled_node
.inputs
[0].default_value
= [r
, g
, b
, 1]
713 principled_node
.location
= 500, 160
715 output_node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
716 output_node
.location
= 700, 160
718 brick_node
= nodes
.new('ShaderNodeTexBrick')
719 brick_node
.name
= 'Brick_0'
720 brick_node
.inputs
[3].default_value
= [0.407, 0.411, 0.394, 1] # mortar color
721 brick_node
.inputs
[4].default_value
= 3 # scale
722 brick_node
.inputs
[5].default_value
= 0.001 # mortar
723 brick_node
.inputs
[7].default_value
= 0.60 # size_w
724 brick_node
.inputs
[8].default_value
= 0.30 # size_h
725 brick_node
.location
= 300, 160
727 rgb_node
= nodes
.new('ShaderNodeRGB')
728 rgb_node
.name
= 'RGB_0'
729 rgb_node
.outputs
[0].default_value
= [r
, g
, b
, 1]
730 rgb_node
.location
= 70, 160
733 outn
= rgb_node
.outputs
['Color']
734 inn
= brick_node
.inputs
['Color1']
735 mat
.node_tree
.links
.new(outn
, inn
)
737 inn
= brick_node
.inputs
['Color2']
738 mat
.node_tree
.links
.new(outn
, inn
)
740 outn
= brick_node
.outputs
['Color']
741 inn
= principled_node
.inputs
['Base Color']
742 mat
.node_tree
.links
.new(outn
, inn
)
747 # --------------------------------------------------------------------
748 # Create cycles fabric texture material
749 # --------------------------------------------------------------------
750 def create_fabric_material(matname
, replace
, r
, g
, b
, rv
=0.8, gv
=0.636, bv
=0.315):
751 # Avoid duplicate materials
753 matlist
= bpy
.data
.materials
755 if m
.name
== matname
:
758 mat
= bpy
.data
.materials
.new(matname
)
760 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0)
761 nodes
= mat
.node_tree
.nodes
763 # support for multilanguage
764 node
= nodes
.new('ShaderNodeBsdfDiffuse')
765 node
.name
= 'Diffuse BSDF'
766 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
767 node
.location
= 810, 270
769 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
770 node
.location
= 1210, 320
772 node
= nodes
.new('ShaderNodeTexCoord')
773 node
.name
= 'UVCoordinates'
774 node
.location
= 26, 395
776 node
= nodes
.new('ShaderNodeMapping')
777 node
.name
= 'UVMapping'
778 node
.location
= 266, 380
779 node
.inputs
['Scale'].default_value
[0] = 1000
780 node
.inputs
['Scale'].default_value
[1] = 1000
781 node
.inputs
['Scale'].default_value
[2] = 1000
783 # ===========================================================================
785 # ===========================================================================
788 realpath
= path
.join(path
.dirname(__file__
), "images", "fabric_diffuse.png")
789 print("Loading: " + realpath
)
791 img
= bpy
.data
.images
.load(realpath
)
793 raise NameError("Cannot load image %s" % realpath
)
795 # Create image texture from image
796 ctex
= bpy
.data
.textures
.new('ColorTex', type='IMAGE')
799 node
= nodes
.new('ShaderNodeTexImage')
801 node
.image
= ctex
.image
802 node
.location
= 615, 350
804 node
= nodes
.new('ShaderNodeBsdfTransparent')
805 node
.name
= 'Transparent1'
806 node
.location
= 810, 395
807 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
809 node
= nodes
.new('ShaderNodeAddShader')
811 node
.location
= 1040, 356
814 outn
= nodes
['UVCoordinates'].outputs
['UV']
815 inn
= nodes
['UVMapping'].inputs
['Vector']
816 mat
.node_tree
.links
.new(outn
, inn
)
818 outn
= nodes
['UVMapping'].outputs
['Vector']
819 inn
= nodes
['Image1'].inputs
['Vector']
820 mat
.node_tree
.links
.new(outn
, inn
)
822 outn
= nodes
['Image1'].outputs
['Color']
823 inn
= nodes
['Diffuse BSDF'].inputs
['Color']
824 mat
.node_tree
.links
.new(outn
, inn
)
826 outn
= nodes
['Transparent1'].outputs
['BSDF']
827 inn
= nodes
['Add1'].inputs
[0]
828 mat
.node_tree
.links
.new(outn
, inn
)
830 outn
= nodes
['Diffuse BSDF'].outputs
['BSDF']
831 inn
= nodes
['Add1'].inputs
[1]
832 mat
.node_tree
.links
.new(outn
, inn
)
834 outn
= nodes
['Add1'].outputs
['Shader']
835 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
836 mat
.node_tree
.links
.new(outn
, inn
)
841 # --------------------------------------------------------------------
843 # --------------------------------------------------------------------
844 def copy_binfile(fromfile
, tofile
):
845 with
open(fromfile
, 'rb') as f1
:
846 with
open(tofile
, 'wb') as f2
:
848 mybytes
= f1
.read(1024)
855 # --------------------------------------------------------------------
856 # Parent object (keep positions)
857 # --------------------------------------------------------------------
858 def parentobject(parentobj
, childobj
):
859 # noinspection PyBroadException
861 bpy
.ops
.object.select_all(action
='DESELECT')
862 bpy
.context
.view_layer
.objects
.active
= parentobj
863 parentobj
.select_set(True)
864 childobj
.select_set(True)
865 bpy
.ops
.object.parent_set(type='OBJECT', keep_transform
=False)
871 # ------------------------------------------------------------------------------
874 # objName: Object name
878 # tube: True create a tube, False only sides
879 # ------------------------------------------------------------------------------
880 def create_control_box(objname
, x
, y
, z
, tube
=True):
881 myvertex
= [(-x
/ 2, 0, 0.0),
891 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)]
893 myfaces
= [(0, 4, 5, 1), (2, 6, 7, 3)]
895 mesh
= bpy
.data
.meshes
.new(objname
)
896 myobject
= bpy
.data
.objects
.new(objname
, mesh
)
898 myobject
.location
= bpy
.context
.scene
.cursor
.location
899 bpy
.context
.collection
.objects
.link(myobject
)
901 mesh
.from_pydata(myvertex
, [], myfaces
)
902 mesh
.update(calc_edges
=True)
907 # ------------------------------------------------------------------------------
908 # Remove all children objects
909 # ------------------------------------------------------------------------------
910 def remove_children(myobject
):
912 for child
in myobject
.children
:
913 # noinspection PyBroadException
915 # noinspection PyBroadException
917 # remove child relationship
918 for grandchild
in child
.children
:
919 grandchild
.parent
= None
921 for mod
in child
.modifiers
:
922 bpy
.ops
.object.modifier_remove(name
=mod
.name
)
926 if child
.type == 'MESH':
928 child
.select_set(True)
929 bpy
.ops
.object.delete()
930 bpy
.data
.meshes
.remove(old
)
931 if child
.type == 'CURVE':
932 child
.select_set(True)
933 bpy
.ops
.object.delete()
938 # --------------------------------------------------------------------
940 # --------------------------------------------------------------------
941 def get_allparents(myobj
):
944 while obj
.parent
is not None:
954 # --------------------------------------------------------------------
955 # Verify all faces are in vertice group to avoid Blander crash
957 # Review the faces array and remove any vertex out of the range
958 # this avoid any bug that can appear avoiding Blender crash
959 # --------------------------------------------------------------------
960 def check_mesh_errors(myvertices
, myfaces
):
961 vmax
= len(myvertices
)
966 if v
< 0 or v
> vmax
:
967 print("Face=" + str(f
) + "->removed vertex=" + str(v
))