1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # ----------------------------------------------------------
4 # support routines and general functions
5 # Author: Antonio Vazquez (antonioya)
7 # ----------------------------------------------------------
8 # noinspection PyUnresolvedReferences
13 # --------------------------------------------------------------------
14 # Get length Blender units
15 # --------------------------------------------------------------------
16 def get_blendunits(units
):
17 if bpy
.context
.scene
.unit_settings
.system
== "IMPERIAL":
23 # --------------------------------------------------------------------
25 # True= faces to inside
26 # False= faces to outside
27 # --------------------------------------------------------------------
28 def set_normals(myobject
, direction
=False):
29 bpy
.context
.view_layer
.objects
.active
= myobject
31 bpy
.ops
.object.mode_set(mode
='EDIT')
33 bpy
.ops
.mesh
.select_all(action
='SELECT')
34 # recalculate outside normals
35 bpy
.ops
.mesh
.normals_make_consistent(inside
=direction
)
36 # go object mode again
37 bpy
.ops
.object.editmode_toggle()
40 # --------------------------------------------------------------------
42 # --------------------------------------------------------------------
43 def remove_doubles(myobject
):
44 bpy
.context
.view_layer
.objects
.active
= myobject
46 bpy
.ops
.object.mode_set(mode
='EDIT')
48 bpy
.ops
.mesh
.select_all(action
='SELECT')
50 bpy
.ops
.mesh
.remove_doubles()
51 # go object mode again
52 bpy
.ops
.object.editmode_toggle()
55 # --------------------------------------------------------------------
57 # --------------------------------------------------------------------
58 def set_smooth(myobject
):
60 for o
in bpy
.data
.objects
:
61 if o
.select_get() is True:
64 myobject
.select_set(True)
65 bpy
.context
.view_layer
.objects
.active
= myobject
66 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
67 bpy
.ops
.object.shade_smooth()
70 # --------------------------------------------------------------------
71 # Add modifier (subdivision)
72 # --------------------------------------------------------------------
73 def set_modifier_subsurf(myobject
):
74 bpy
.context
.view_layer
.objects
.active
= myobject
75 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
76 bpy
.ops
.object.modifier_add(type='SUBSURF')
77 for mod
in myobject
.modifiers
:
78 if mod
.type == 'SUBSURF':
82 # --------------------------------------------------------------------
83 # Add modifier (mirror)
84 # --------------------------------------------------------------------
85 def set_modifier_mirror(myobject
, axis
="Y"):
86 bpy
.ops
.object.select_all(action
='DESELECT')
87 myobject
.select_set(True)
88 bpy
.context
.view_layer
.objects
.active
= myobject
89 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
90 bpy
.ops
.object.modifier_add(type='MIRROR')
91 for mod
in myobject
.modifiers
:
92 if mod
.type == 'MIRROR':
94 mod
.use_axis
[0] = True
96 mod
.use__axis
[0] = False
99 mod
.use_axis
[1] = True
101 mod
.use_axis
[1] = False
104 mod
.use_axis
[2] = True
106 mod
.use_axis
[2] = False
111 # --------------------------------------------------------------------
112 # Add modifier (array)
113 # --------------------------------------------------------------------
114 def set_modifier_array(myobject
, axis
, move
, repeat
, fix
=False, fixmove
=0, zmove
=0):
115 bpy
.ops
.object.select_all(action
='DESELECT')
116 myobject
.select_set(True)
117 bpy
.context
.view_layer
.objects
.active
= myobject
118 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
119 bpy
.ops
.object.modifier_add(type='ARRAY')
120 for mod
in myobject
.modifiers
:
121 if mod
.type == 'ARRAY':
122 if mod
.name
== "Array":
123 mod
.name
= "Array_" + axis
125 mod
.use_constant_offset
= fix
127 mod
.relative_offset_displace
[0] = move
128 mod
.constant_offset_displace
[0] = fixmove
129 mod
.relative_offset_displace
[1] = 0.0
130 mod
.constant_offset_displace
[1] = 0.0
131 mod
.relative_offset_displace
[2] = 0.0
132 mod
.constant_offset_displace
[2] = zmove
135 mod
.relative_offset_displace
[0] = 0.0
136 mod
.constant_offset_displace
[0] = 0.0
137 mod
.relative_offset_displace
[1] = move
138 mod
.constant_offset_displace
[1] = fixmove
139 mod
.relative_offset_displace
[2] = 0.0
140 mod
.constant_offset_displace
[2] = 0.0
143 # --------------------------------------------------------------------
144 # Add modifier (curve)
145 # --------------------------------------------------------------------
146 def set_modifier_curve(myobject
, mycurve
):
147 bpy
.context
.view_layer
.objects
.active
= myobject
148 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
149 bpy
.ops
.object.modifier_add(type='CURVE')
150 for mod
in myobject
.modifiers
:
151 if mod
.type == 'CURVE':
152 mod
.deform_axis
= 'POS_X'
156 # --------------------------------------------------------------------
157 # Add modifier (solidify)
158 # --------------------------------------------------------------------
159 def set_modifier_solidify(myobject
, width
):
160 bpy
.context
.view_layer
.objects
.active
= myobject
161 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
162 bpy
.ops
.object.modifier_add(type='SOLIDIFY')
163 for mod
in myobject
.modifiers
:
164 if mod
.type == 'SOLIDIFY':
165 mod
.thickness
= width
166 mod
.use_even_offset
= True
167 mod
.use_quality_normals
= True
171 # --------------------------------------------------------------------
172 # Add modifier (boolean)
173 # --------------------------------------------------------------------
174 def set_modifier_boolean(myobject
, bolobject
):
175 boolean_modifier
= myobject
.modifiers
.new("", 'BOOLEAN')
176 boolean_modifier
.operation
= 'DIFFERENCE'
177 boolean_modifier
.object = bolobject
180 # --------------------------------------------------------------------
181 # Set material to object
182 # --------------------------------------------------------------------
183 def set_material(myobject
, mymaterial
):
184 bpy
.context
.view_layer
.objects
.active
= myobject
185 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
186 myobject
.data
.materials
.append(mymaterial
)
189 # --------------------------------------------------------------------
190 # Set material to selected faces
191 # --------------------------------------------------------------------
192 def set_material_faces(myobject
, idx
):
193 bpy
.context
.view_layer
.objects
.active
= myobject
194 myobject
.select_set(True)
195 bpy
.context
.object.active_material_index
= idx
196 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
197 bpy
.ops
.object.mode_set(mode
='EDIT')
198 bpy
.ops
.object.material_slot_assign()
200 bpy
.ops
.mesh
.select_all(action
='DESELECT')
201 bpy
.ops
.object.mode_set(mode
='OBJECT')
204 # --------------------------------------------------------------------
206 # --------------------------------------------------------------------
207 def select_faces(myobject
, selface
, clear
):
208 myobject
.select_set(True)
209 bpy
.context
.view_layer
.objects
.active
= myobject
210 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
211 # deselect everything
213 bpy
.ops
.object.mode_set(mode
='EDIT')
214 bpy
.ops
.mesh
.select_all(action
='DESELECT')
216 # reselect the originally selected face
217 bpy
.ops
.object.mode_set(mode
='OBJECT')
218 myobject
.data
.polygons
[selface
].select
= True
221 # --------------------------------------------------------------------
223 # --------------------------------------------------------------------
224 def select_vertices(myobject
, selvertices
, clear
=True):
225 myobject
.select_set(True)
226 bpy
.context
.view_layer
.objects
.active
= myobject
227 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
228 # deselect everything
230 bpy
.ops
.object.mode_set(mode
='EDIT')
231 bpy
.ops
.mesh
.select_all(action
='DESELECT')
234 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
235 sel_mode
= bpy
.context
.tool_settings
.mesh_select_mode
237 bpy
.context
.tool_settings
.mesh_select_mode
= [True, False, False]
238 bpy
.ops
.object.mode_set(mode
='OBJECT', toggle
=False)
240 for i
in selvertices
:
241 myobject
.data
.vertices
[i
].select
= True
243 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
244 bpy
.context
.tool_settings
.mesh_select_mode
= sel_mode
245 bpy
.ops
.object.mode_set(mode
='OBJECT')
248 # --------------------------------------------------------------------
250 # --------------------------------------------------------------------
251 def mark_seam(myobject
):
252 # noinspection PyBroadException
254 myobject
.select_set(True)
255 bpy
.context
.view_layer
.objects
.active
= myobject
256 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
257 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
258 bpy
.ops
.mesh
.mark_seam()
259 bpy
.ops
.object.mode_set(mode
='OBJECT')
261 bpy
.ops
.object.mode_set(mode
='OBJECT')
264 # --------------------------------------------------------------------
266 # --------------------------------------------------------------------
267 def unwrap_mesh(myobject
, allfaces
=True):
268 # noinspection PyBroadException
270 myobject
.select_set(True)
271 bpy
.context
.view_layer
.objects
.active
= myobject
272 if bpy
.context
.view_layer
.objects
.active
.name
== myobject
.name
:
274 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
276 bpy
.ops
.mesh
.select_all(action
='DESELECT')
277 bpy
.ops
.mesh
.select_all()
279 bpy
.ops
.object.mode_set(mode
='OBJECT')
281 bpy
.ops
.object.mode_set(mode
='OBJECT')
284 # --------------------------------------------------------------------
285 # Get Node Index(multilanguage support)
286 # --------------------------------------------------------------------
287 def get_node_index(nodes
, datatype
):
290 if m
.type == datatype
:
298 # --------------------------------------------------------------------
299 # Create cycles diffuse material
300 # --------------------------------------------------------------------
301 def create_diffuse_material(matname
, replace
, r
, g
, b
, rv
=0.8, gv
=0.8, bv
=0.8, mix
=0.1, twosides
=False):
302 # Avoid duplicate materials
304 matlist
= bpy
.data
.materials
306 if m
.name
== matname
:
309 mat
= bpy
.data
.materials
.new(matname
)
310 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0) # viewport color
312 nodes
= mat
.node_tree
.nodes
314 # support for multilanguage
315 node
= nodes
.new('ShaderNodeBsdfDiffuse')
316 node
.name
= 'Diffuse BSDF'
317 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
318 node
.location
= 200, 320
320 node
= nodes
.new('ShaderNodeBsdfGlossy')
321 node
.name
= 'Glossy_0'
322 node
.location
= 200, 0
324 node
= nodes
.new('ShaderNodeMixShader')
326 node
.inputs
[0].default_value
= mix
327 node
.location
= 500, 160
329 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
330 node
.location
= 1100, 160
333 outn
= nodes
['Diffuse BSDF'].outputs
[0]
334 inn
= nodes
['Mix_0'].inputs
[1]
335 mat
.node_tree
.links
.new(outn
, inn
)
337 outn
= nodes
['Glossy_0'].outputs
[0]
338 inn
= nodes
['Mix_0'].inputs
[2]
339 mat
.node_tree
.links
.new(outn
, inn
)
341 if twosides
is False:
342 outn
= nodes
['Mix_0'].outputs
[0]
343 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
344 mat
.node_tree
.links
.new(outn
, inn
)
347 node
= nodes
.new('ShaderNodeNewGeometry')
348 node
.name
= 'Input_1'
349 node
.location
= -80, -70
351 node
= nodes
.new('ShaderNodeBsdfDiffuse')
352 node
.name
= 'Diffuse_1'
353 node
.inputs
[0].default_value
= [0.30, 0.30, 0.30, 1]
354 node
.location
= 200, -280
356 node
= nodes
.new('ShaderNodeMixShader')
358 node
.inputs
[0].default_value
= mix
359 node
.location
= 800, -70
361 outn
= nodes
['Input_1'].outputs
[6]
362 inn
= nodes
['Mix_1'].inputs
[0]
363 mat
.node_tree
.links
.new(outn
, inn
)
365 outn
= nodes
['Diffuse_1'].outputs
[0]
366 inn
= nodes
['Mix_1'].inputs
[2]
367 mat
.node_tree
.links
.new(outn
, inn
)
369 outn
= nodes
['Mix_0'].outputs
[0]
370 inn
= nodes
['Mix_1'].inputs
[1]
371 mat
.node_tree
.links
.new(outn
, inn
)
373 outn
= nodes
['Mix_1'].outputs
[0]
374 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
375 mat
.node_tree
.links
.new(outn
, inn
)
380 # --------------------------------------------------------------------
381 # Create cycles translucent material
382 # --------------------------------------------------------------------
383 def create_translucent_material(matname
, replace
, r
, g
, b
, rv
=0.8, gv
=0.8, bv
=0.8, mix
=0.1):
384 # Avoid duplicate materials
386 matlist
= bpy
.data
.materials
388 if m
.name
== matname
:
391 mat
= bpy
.data
.materials
.new(matname
)
392 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0) # viewport color
394 nodes
= mat
.node_tree
.nodes
396 # support for multilanguage
397 node
= nodes
.new('ShaderNodeBsdfDiffuse')
398 node
.name
= 'Diffuse BSDF'
399 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
400 node
.location
= 200, 320
402 node
= nodes
.new('ShaderNodeBsdfTranslucent')
403 node
.name
= 'Translucent_0'
404 node
.location
= 200, 0
406 node
= nodes
.new('ShaderNodeMixShader')
408 node
.inputs
[0].default_value
= mix
409 node
.location
= 500, 160
411 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
412 node
.location
= 1100, 160
415 outn
= nodes
['Diffuse BSDF'].outputs
[0]
416 inn
= nodes
['Mix_0'].inputs
[1]
417 mat
.node_tree
.links
.new(outn
, inn
)
419 outn
= nodes
['Translucent_0'].outputs
[0]
420 inn
= nodes
['Mix_0'].inputs
[2]
421 mat
.node_tree
.links
.new(outn
, inn
)
423 outn
= nodes
['Mix_0'].outputs
[0]
424 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
425 mat
.node_tree
.links
.new(outn
, inn
)
430 # --------------------------------------------------------------------
431 # Create cycles glass material
432 # --------------------------------------------------------------------
433 def create_glass_material(matname
, replace
, rv
=0.333, gv
=0.342, bv
=0.9):
434 # Avoid duplicate materials
436 matlist
= bpy
.data
.materials
438 if m
.name
== matname
:
441 mat
= bpy
.data
.materials
.new(matname
)
443 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0)
444 nodes
= mat
.node_tree
.nodes
446 # support for multilanguage
447 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
448 mat
.node_tree
.nodes
.remove(node
) # remove not used
450 node
= nodes
.new('ShaderNodeLightPath')
451 node
.name
= 'Light_0'
452 node
.location
= 10, 160
454 node
= nodes
.new('ShaderNodeBsdfRefraction')
455 node
.name
= 'Refraction_0'
456 node
.inputs
[2].default_value
= 1 # IOR 1.0
457 node
.location
= 250, 400
459 node
= nodes
.new('ShaderNodeBsdfGlossy')
460 node
.name
= 'Glossy_0'
461 node
.distribution
= 'SHARP'
462 node
.location
= 250, 100
464 node
= nodes
.new('ShaderNodeBsdfTransparent')
465 node
.name
= 'Transparent_0'
466 node
.location
= 500, 10
468 node
= nodes
.new('ShaderNodeMixShader')
470 node
.inputs
[0].default_value
= 0.035
471 node
.location
= 500, 160
473 node
= nodes
.new('ShaderNodeMixShader')
475 node
.inputs
[0].default_value
= 0.1
476 node
.location
= 690, 290
478 node
= nodes
.new('ShaderNodeOutputMaterial')
479 node
.name
= 'OUTPUT_MATERIAL'
480 node
.location
= 920, 290
483 outn
= nodes
['Light_0'].outputs
[1]
484 inn
= nodes
['Mix_1'].inputs
[0]
485 mat
.node_tree
.links
.new(outn
, inn
)
487 outn
= nodes
['Refraction_0'].outputs
[0]
488 inn
= nodes
['Mix_0'].inputs
[1]
489 mat
.node_tree
.links
.new(outn
, inn
)
491 outn
= nodes
['Glossy_0'].outputs
[0]
492 inn
= nodes
['Mix_0'].inputs
[2]
493 mat
.node_tree
.links
.new(outn
, inn
)
495 outn
= nodes
['Mix_0'].outputs
[0]
496 inn
= nodes
['Mix_1'].inputs
[1]
497 mat
.node_tree
.links
.new(outn
, inn
)
499 outn
= nodes
['Transparent_0'].outputs
[0]
500 inn
= nodes
['Mix_1'].inputs
[2]
501 mat
.node_tree
.links
.new(outn
, inn
)
503 outn
= nodes
['Mix_1'].outputs
[0]
504 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
505 mat
.node_tree
.links
.new(outn
, inn
)
510 # ---------------------------------------------
511 # Create cycles transparents material
512 # --------------------------------------------------------------------
513 def create_transparent_material(matname
, replace
, r
=1, g
=1, b
=1, alpha
=0):
514 # Avoid duplicate materials
516 matlist
= bpy
.data
.materials
518 if m
.name
== matname
:
521 mat
= bpy
.data
.materials
.new(matname
)
523 mat
.diffuse_color
= (r
, g
, b
, 1.0)
524 nodes
= mat
.node_tree
.nodes
526 # support for multilanguage
527 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
528 mat
.node_tree
.nodes
.remove(node
) # remove not used
530 node
= nodes
.new('ShaderNodeBsdfTransparent')
531 node
.name
= 'Transparent_0'
532 node
.location
= 250, 160
533 node
.inputs
[0].default_value
= [r
, g
, b
, alpha
]
535 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
536 node
.location
= 700, 160
539 outn
= nodes
['Transparent_0'].outputs
[0]
540 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
541 mat
.node_tree
.links
.new(outn
, inn
)
546 # --------------------------------------------------------------------
547 # Create cycles glossy material
548 # --------------------------------------------------------------------
549 def create_glossy_material(matname
, replace
, r
, g
, b
, rv
=0.578, gv
=0.555, bv
=0.736, rvalue
=0.2):
550 # Avoid duplicate materials
552 matlist
= bpy
.data
.materials
554 if m
.name
== matname
:
557 mat
= bpy
.data
.materials
.new(matname
)
559 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0)
560 nodes
= mat
.node_tree
.nodes
562 # support for multilanguage
563 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
564 mat
.node_tree
.nodes
.remove(node
) # remove not used
566 node
= nodes
.new('ShaderNodeBsdfGlossy')
567 node
.name
= 'Glossy_0'
568 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
569 node
.inputs
[1].default_value
= rvalue
570 node
.location
= 200, 160
572 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
573 node
.location
= 700, 160
576 outn
= nodes
['Glossy_0'].outputs
[0]
577 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
578 mat
.node_tree
.links
.new(outn
, inn
)
583 # --------------------------------------------------------------------
584 # Create cycles emission material
585 # --------------------------------------------------------------------
586 def create_emission_material(matname
, replace
, r
, g
, b
, energy
):
587 # Avoid duplicate materials
589 matlist
= bpy
.data
.materials
591 if m
.name
== matname
:
594 mat
= bpy
.data
.materials
.new(matname
)
596 nodes
= mat
.node_tree
.nodes
598 # support for multilanguage
599 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
600 mat
.node_tree
.nodes
.remove(node
) # remove not used
602 node
= nodes
.new('ShaderNodeEmission')
603 node
.name
= 'Emission_0'
604 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
605 node
.inputs
[1].default_value
= energy
606 node
.location
= 200, 160
608 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
609 node
.location
= 700, 160
612 outn
= nodes
['Emission_0'].outputs
[0]
613 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
614 mat
.node_tree
.links
.new(outn
, inn
)
619 # --------------------------------------------------------------------
620 # Create cycles glass material
621 # --------------------------------------------------------------------
622 def create_old_glass_material(matname
, replace
, rv
=0.352716, gv
=0.760852, bv
=0.9):
623 # Avoid duplicate materials
625 matlist
= bpy
.data
.materials
627 if m
.name
== matname
:
630 mat
= bpy
.data
.materials
.new(matname
)
632 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0)
633 nodes
= mat
.node_tree
.nodes
635 # support for multilanguage
636 node
= nodes
[get_node_index(nodes
, 'BSDF_DIFFUSE')]
637 mat
.node_tree
.nodes
.remove(node
) # remove not used
639 node
= nodes
.new('ShaderNodeLightPath')
640 node
.name
= 'Light_0'
641 node
.location
= 10, 160
643 node
= nodes
.new('ShaderNodeBsdfGlass')
644 node
.name
= 'Glass_0'
645 node
.location
= 250, 300
647 node
= nodes
.new('ShaderNodeBsdfTransparent')
648 node
.name
= 'Transparent_0'
649 node
.location
= 250, 0
651 node
= nodes
.new('ShaderNodeMixShader')
653 node
.inputs
[0].default_value
= 0.1
654 node
.location
= 500, 160
656 node
= nodes
.new('ShaderNodeMixShader')
658 node
.inputs
[0].default_value
= 0.1
659 node
.location
= 690, 290
661 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
662 node
.location
= 920, 290
665 outn
= nodes
['Light_0'].outputs
[1]
666 inn
= nodes
['Mix_0'].inputs
[0]
667 mat
.node_tree
.links
.new(outn
, inn
)
669 outn
= nodes
['Light_0'].outputs
[2]
670 inn
= nodes
['Mix_1'].inputs
[0]
671 mat
.node_tree
.links
.new(outn
, inn
)
673 outn
= nodes
['Glass_0'].outputs
[0]
674 inn
= nodes
['Mix_0'].inputs
[1]
675 mat
.node_tree
.links
.new(outn
, inn
)
677 outn
= nodes
['Transparent_0'].outputs
[0]
678 inn
= nodes
['Mix_0'].inputs
[2]
679 mat
.node_tree
.links
.new(outn
, inn
)
681 outn
= nodes
['Mix_0'].outputs
[0]
682 inn
= nodes
['Mix_1'].inputs
[1]
683 mat
.node_tree
.links
.new(outn
, inn
)
685 outn
= nodes
['Mix_1'].outputs
[0]
686 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
687 mat
.node_tree
.links
.new(outn
, inn
)
692 # --------------------------------------------------------------------
693 # Create cycles brick texture material
694 # --------------------------------------------------------------------
695 def create_brick_material(matname
, replace
, r
, g
, b
, rv
=0.8, gv
=0.636, bv
=0.315):
696 # Avoid duplicate materials
698 matlist
= bpy
.data
.materials
700 if m
.name
== matname
:
703 mat
= bpy
.data
.materials
.new(matname
)
705 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0)
706 nodes
= mat
.node_tree
.nodes
708 # support for multilanguage
709 principled_node
= nodes
[get_node_index(nodes
, 'BSDF_PRINCIPLED')]
711 principled_node
.inputs
[0].default_value
= [r
, g
, b
, 1]
712 principled_node
.location
= 500, 160
714 output_node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
715 output_node
.location
= 700, 160
717 brick_node
= nodes
.new('ShaderNodeTexBrick')
718 brick_node
.name
= 'Brick_0'
719 brick_node
.inputs
[3].default_value
= [0.407, 0.411, 0.394, 1] # mortar color
720 brick_node
.inputs
[4].default_value
= 3 # scale
721 brick_node
.inputs
[5].default_value
= 0.001 # mortar
722 brick_node
.inputs
[7].default_value
= 0.60 # size_w
723 brick_node
.inputs
[8].default_value
= 0.30 # size_h
724 brick_node
.location
= 300, 160
726 rgb_node
= nodes
.new('ShaderNodeRGB')
727 rgb_node
.name
= 'RGB_0'
728 rgb_node
.outputs
[0].default_value
= [r
, g
, b
, 1]
729 rgb_node
.location
= 70, 160
732 outn
= rgb_node
.outputs
['Color']
733 inn
= brick_node
.inputs
['Color1']
734 mat
.node_tree
.links
.new(outn
, inn
)
736 inn
= brick_node
.inputs
['Color2']
737 mat
.node_tree
.links
.new(outn
, inn
)
739 outn
= brick_node
.outputs
['Color']
740 inn
= principled_node
.inputs
['Base Color']
741 mat
.node_tree
.links
.new(outn
, inn
)
746 # --------------------------------------------------------------------
747 # Create cycles fabric texture material
748 # --------------------------------------------------------------------
749 def create_fabric_material(matname
, replace
, r
, g
, b
, rv
=0.8, gv
=0.636, bv
=0.315):
750 # Avoid duplicate materials
752 matlist
= bpy
.data
.materials
754 if m
.name
== matname
:
757 mat
= bpy
.data
.materials
.new(matname
)
759 mat
.diffuse_color
= (rv
, gv
, bv
, 1.0)
760 nodes
= mat
.node_tree
.nodes
762 # support for multilanguage
763 node
= nodes
.new('ShaderNodeBsdfDiffuse')
764 node
.name
= 'Diffuse BSDF'
765 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
766 node
.location
= 810, 270
768 node
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')]
769 node
.location
= 1210, 320
771 node
= nodes
.new('ShaderNodeTexCoord')
772 node
.name
= 'UVCoordinates'
773 node
.location
= 26, 395
775 node
= nodes
.new('ShaderNodeMapping')
776 node
.name
= 'UVMapping'
777 node
.location
= 266, 380
778 node
.inputs
['Scale'].default_value
[0] = 1000
779 node
.inputs
['Scale'].default_value
[1] = 1000
780 node
.inputs
['Scale'].default_value
[2] = 1000
782 # ===========================================================================
784 # ===========================================================================
787 realpath
= path
.join(path
.dirname(__file__
), "images", "fabric_diffuse.png")
788 print("Loading: " + realpath
)
790 img
= bpy
.data
.images
.load(realpath
)
792 raise NameError("Cannot load image %s" % realpath
)
794 # Create image texture from image
795 ctex
= bpy
.data
.textures
.new('ColorTex', type='IMAGE')
798 node
= nodes
.new('ShaderNodeTexImage')
800 node
.image
= ctex
.image
801 node
.location
= 615, 350
803 node
= nodes
.new('ShaderNodeBsdfTransparent')
804 node
.name
= 'Transparent1'
805 node
.location
= 810, 395
806 node
.inputs
[0].default_value
= [r
, g
, b
, 1]
808 node
= nodes
.new('ShaderNodeAddShader')
810 node
.location
= 1040, 356
813 outn
= nodes
['UVCoordinates'].outputs
['UV']
814 inn
= nodes
['UVMapping'].inputs
['Vector']
815 mat
.node_tree
.links
.new(outn
, inn
)
817 outn
= nodes
['UVMapping'].outputs
['Vector']
818 inn
= nodes
['Image1'].inputs
['Vector']
819 mat
.node_tree
.links
.new(outn
, inn
)
821 outn
= nodes
['Image1'].outputs
['Color']
822 inn
= nodes
['Diffuse BSDF'].inputs
['Color']
823 mat
.node_tree
.links
.new(outn
, inn
)
825 outn
= nodes
['Transparent1'].outputs
['BSDF']
826 inn
= nodes
['Add1'].inputs
[0]
827 mat
.node_tree
.links
.new(outn
, inn
)
829 outn
= nodes
['Diffuse BSDF'].outputs
['BSDF']
830 inn
= nodes
['Add1'].inputs
[1]
831 mat
.node_tree
.links
.new(outn
, inn
)
833 outn
= nodes
['Add1'].outputs
['Shader']
834 inn
= nodes
[get_node_index(nodes
, 'OUTPUT_MATERIAL')].inputs
[0]
835 mat
.node_tree
.links
.new(outn
, inn
)
840 # --------------------------------------------------------------------
842 # --------------------------------------------------------------------
843 def copy_binfile(fromfile
, tofile
):
844 with
open(fromfile
, 'rb') as f1
:
845 with
open(tofile
, 'wb') as f2
:
847 mybytes
= f1
.read(1024)
854 # --------------------------------------------------------------------
855 # Parent object (keep positions)
856 # --------------------------------------------------------------------
857 def parentobject(parentobj
, childobj
):
858 # noinspection PyBroadException
860 bpy
.ops
.object.select_all(action
='DESELECT')
861 bpy
.context
.view_layer
.objects
.active
= parentobj
862 parentobj
.select_set(True)
863 childobj
.select_set(True)
864 bpy
.ops
.object.parent_set(type='OBJECT', keep_transform
=False)
870 # ------------------------------------------------------------------------------
873 # objName: Object name
877 # tube: True create a tube, False only sides
878 # ------------------------------------------------------------------------------
879 def create_control_box(objname
, x
, y
, z
, tube
=True):
880 myvertex
= [(-x
/ 2, 0, 0.0),
890 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)]
892 myfaces
= [(0, 4, 5, 1), (2, 6, 7, 3)]
894 mesh
= bpy
.data
.meshes
.new(objname
)
895 myobject
= bpy
.data
.objects
.new(objname
, mesh
)
897 myobject
.location
= bpy
.context
.scene
.cursor
.location
898 bpy
.context
.collection
.objects
.link(myobject
)
900 mesh
.from_pydata(myvertex
, [], myfaces
)
901 mesh
.update(calc_edges
=True)
906 # ------------------------------------------------------------------------------
907 # Remove all children objects
908 # ------------------------------------------------------------------------------
909 def remove_children(myobject
):
911 for child
in myobject
.children
:
912 # noinspection PyBroadException
914 # noinspection PyBroadException
916 # remove child relationship
917 for grandchild
in child
.children
:
918 grandchild
.parent
= None
920 for mod
in child
.modifiers
:
921 bpy
.ops
.object.modifier_remove(name
=mod
.name
)
925 if child
.type == 'MESH':
927 child
.select_set(True)
928 bpy
.ops
.object.delete()
929 bpy
.data
.meshes
.remove(old
)
930 if child
.type == 'CURVE':
931 child
.select_set(True)
932 bpy
.ops
.object.delete()
937 # --------------------------------------------------------------------
939 # --------------------------------------------------------------------
940 def get_allparents(myobj
):
943 while obj
.parent
is not None:
953 # --------------------------------------------------------------------
954 # Verify all faces are in vertice group to avoid Blander crash
956 # Review the faces array and remove any vertex out of the range
957 # this avoid any bug that can appear avoiding Blender crash
958 # --------------------------------------------------------------------
959 def check_mesh_errors(myvertices
, myfaces
):
960 vmax
= len(myvertices
)
965 if v
< 0 or v
> vmax
:
966 print("Face=" + str(f
) + "->removed vertex=" + str(v
))