# SPDX-License-Identifier: GPL-2.0-or-later # ---------------------------------------------------------- # support routines and general functions # Author: Antonio Vazquez (antonioya) # # ---------------------------------------------------------- # noinspection PyUnresolvedReferences import bpy from os import path # -------------------------------------------------------------------- # Get length Blender units # -------------------------------------------------------------------- def get_blendunits(units): if bpy.context.scene.unit_settings.system == "IMPERIAL": return units * 0.3048 else: return units # -------------------------------------------------------------------- # Set normals # True= faces to inside # False= faces to outside # -------------------------------------------------------------------- def set_normals(myobject, direction=False): bpy.context.view_layer.objects.active = myobject # go edit mode bpy.ops.object.mode_set(mode='EDIT') # select all faces bpy.ops.mesh.select_all(action='SELECT') # recalculate outside normals bpy.ops.mesh.normals_make_consistent(inside=direction) # go object mode again bpy.ops.object.editmode_toggle() # -------------------------------------------------------------------- # Remove doubles # -------------------------------------------------------------------- def remove_doubles(myobject): bpy.context.view_layer.objects.active = myobject # go edit mode bpy.ops.object.mode_set(mode='EDIT') # select all faces bpy.ops.mesh.select_all(action='SELECT') # remove bpy.ops.mesh.remove_doubles() # go object mode again bpy.ops.object.editmode_toggle() # -------------------------------------------------------------------- # Set shade smooth # -------------------------------------------------------------------- def set_smooth(myobject): # deactivate others for o in bpy.data.objects: if o.select_get() is True: o.select_set(False) myobject.select_set(True) bpy.context.view_layer.objects.active = myobject if bpy.context.view_layer.objects.active.name == myobject.name: bpy.ops.object.shade_smooth() # -------------------------------------------------------------------- # Add modifier (subdivision) # -------------------------------------------------------------------- def set_modifier_subsurf(myobject): bpy.context.view_layer.objects.active = myobject if bpy.context.view_layer.objects.active.name == myobject.name: bpy.ops.object.modifier_add(type='SUBSURF') for mod in myobject.modifiers: if mod.type == 'SUBSURF': mod.levels = 2 # -------------------------------------------------------------------- # Add modifier (mirror) # -------------------------------------------------------------------- def set_modifier_mirror(myobject, axis="Y"): bpy.ops.object.select_all(action='DESELECT') myobject.select_set(True) bpy.context.view_layer.objects.active = myobject if bpy.context.view_layer.objects.active.name == myobject.name: bpy.ops.object.modifier_add(type='MIRROR') for mod in myobject.modifiers: if mod.type == 'MIRROR': if axis == "X": mod.use_axis[0] = True else: mod.use__axis[0] = False if axis == "Y": mod.use_axis[1] = True else: mod.use_axis[1] = False if axis == "Z": mod.use_axis[2] = True else: mod.use_axis[2] = False mod.use_clip = True # -------------------------------------------------------------------- # Add modifier (array) # -------------------------------------------------------------------- def set_modifier_array(myobject, axis, move, repeat, fix=False, fixmove=0, zmove=0): bpy.ops.object.select_all(action='DESELECT') myobject.select_set(True) bpy.context.view_layer.objects.active = myobject if bpy.context.view_layer.objects.active.name == myobject.name: bpy.ops.object.modifier_add(type='ARRAY') for mod in myobject.modifiers: if mod.type == 'ARRAY': if mod.name == "Array": mod.name = "Array_" + axis mod.count = repeat mod.use_constant_offset = fix if axis == "X": mod.relative_offset_displace[0] = move mod.constant_offset_displace[0] = fixmove mod.relative_offset_displace[1] = 0.0 mod.constant_offset_displace[1] = 0.0 mod.relative_offset_displace[2] = 0.0 mod.constant_offset_displace[2] = zmove if axis == "Y": mod.relative_offset_displace[0] = 0.0 mod.constant_offset_displace[0] = 0.0 mod.relative_offset_displace[1] = move mod.constant_offset_displace[1] = fixmove mod.relative_offset_displace[2] = 0.0 mod.constant_offset_displace[2] = 0.0 # -------------------------------------------------------------------- # Add modifier (curve) # -------------------------------------------------------------------- def set_modifier_curve(myobject, mycurve): bpy.context.view_layer.objects.active = myobject if bpy.context.view_layer.objects.active.name == myobject.name: bpy.ops.object.modifier_add(type='CURVE') for mod in myobject.modifiers: if mod.type == 'CURVE': mod.deform_axis = 'POS_X' mod.object = mycurve # -------------------------------------------------------------------- # Add modifier (solidify) # -------------------------------------------------------------------- def set_modifier_solidify(myobject, width): bpy.context.view_layer.objects.active = myobject if bpy.context.view_layer.objects.active.name == myobject.name: bpy.ops.object.modifier_add(type='SOLIDIFY') for mod in myobject.modifiers: if mod.type == 'SOLIDIFY': mod.thickness = width mod.use_even_offset = True mod.use_quality_normals = True break # -------------------------------------------------------------------- # Add modifier (boolean) # -------------------------------------------------------------------- def set_modifier_boolean(myobject, bolobject): bpy.context.view_layer.objects.active = myobject if bpy.context.view_layer.objects.active.name == myobject.name: bpy.ops.object.modifier_add(type='BOOLEAN') mod = myobject.modifiers[len(myobject.modifiers) - 1] mod.operation = 'DIFFERENCE' mod.object = bolobject # -------------------------------------------------------------------- # Set material to object # -------------------------------------------------------------------- def set_material(myobject, mymaterial): bpy.context.view_layer.objects.active = myobject if bpy.context.view_layer.objects.active.name == myobject.name: myobject.data.materials.append(mymaterial) # -------------------------------------------------------------------- # Set material to selected faces # -------------------------------------------------------------------- def set_material_faces(myobject, idx): bpy.context.view_layer.objects.active = myobject myobject.select_set(True) bpy.context.object.active_material_index = idx if bpy.context.view_layer.objects.active.name == myobject.name: bpy.ops.object.mode_set(mode='EDIT') bpy.ops.object.material_slot_assign() # Deselect bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.object.mode_set(mode='OBJECT') # -------------------------------------------------------------------- # Select faces # -------------------------------------------------------------------- def select_faces(myobject, selface, clear): myobject.select_set(True) bpy.context.view_layer.objects.active = myobject if bpy.context.view_layer.objects.active.name == myobject.name: # deselect everything if clear: bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='DESELECT') # reselect the originally selected face bpy.ops.object.mode_set(mode='OBJECT') myobject.data.polygons[selface].select = True # -------------------------------------------------------------------- # Select vertices # -------------------------------------------------------------------- def select_vertices(myobject, selvertices, clear=True): myobject.select_set(True) bpy.context.view_layer.objects.active = myobject if bpy.context.view_layer.objects.active.name == myobject.name: # deselect everything if clear: bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='DESELECT') # Select Vertices bpy.ops.object.mode_set(mode='EDIT', toggle=False) sel_mode = bpy.context.tool_settings.mesh_select_mode bpy.context.tool_settings.mesh_select_mode = [True, False, False] bpy.ops.object.mode_set(mode='OBJECT', toggle=False) for i in selvertices: myobject.data.vertices[i].select = True bpy.ops.object.mode_set(mode='EDIT', toggle=False) bpy.context.tool_settings.mesh_select_mode = sel_mode bpy.ops.object.mode_set(mode='OBJECT') # -------------------------------------------------------------------- # Mark Seam # -------------------------------------------------------------------- def mark_seam(myobject): # noinspection PyBroadException try: myobject.select_set(True) bpy.context.view_layer.objects.active = myobject if bpy.context.view_layer.objects.active.name == myobject.name: bpy.ops.object.mode_set(mode='EDIT', toggle=False) bpy.ops.mesh.mark_seam() bpy.ops.object.mode_set(mode='OBJECT') except: bpy.ops.object.mode_set(mode='OBJECT') # -------------------------------------------------------------------- # Unwrap mesh # -------------------------------------------------------------------- def unwrap_mesh(myobject, allfaces=True): # noinspection PyBroadException try: myobject.select_set(True) bpy.context.view_layer.objects.active = myobject if bpy.context.view_layer.objects.active.name == myobject.name: # Unwrap bpy.ops.object.mode_set(mode='EDIT', toggle=False) if allfaces is True: bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.mesh.select_all() bpy.ops.uv.unwrap() bpy.ops.object.mode_set(mode='OBJECT') except: bpy.ops.object.mode_set(mode='OBJECT') # -------------------------------------------------------------------- # Get Node Index(multilanguage support) # -------------------------------------------------------------------- def get_node_index(nodes, datatype): idx = 0 for m in nodes: if m.type == datatype: return idx idx += 1 # by default return 1 # -------------------------------------------------------------------- # Create cycles diffuse material # -------------------------------------------------------------------- def create_diffuse_material(matname, replace, r, g, b, rv=0.8, gv=0.8, bv=0.8, mix=0.1, twosides=False): # Avoid duplicate materials if replace is False: matlist = bpy.data.materials for m in matlist: if m.name == matname: return m # Create material mat = bpy.data.materials.new(matname) mat.diffuse_color = (rv, gv, bv, 1.0) # viewport color mat.use_nodes = True nodes = mat.node_tree.nodes # support for multilanguage node = nodes.new('ShaderNodeBsdfDiffuse') node.name = 'Diffuse BSDF' node.inputs[0].default_value = [r, g, b, 1] node.location = 200, 320 node = nodes.new('ShaderNodeBsdfGlossy') node.name = 'Glossy_0' node.location = 200, 0 node = nodes.new('ShaderNodeMixShader') node.name = 'Mix_0' node.inputs[0].default_value = mix node.location = 500, 160 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')] node.location = 1100, 160 # Connect nodes outn = nodes['Diffuse BSDF'].outputs[0] inn = nodes['Mix_0'].inputs[1] mat.node_tree.links.new(outn, inn) outn = nodes['Glossy_0'].outputs[0] inn = nodes['Mix_0'].inputs[2] mat.node_tree.links.new(outn, inn) if twosides is False: outn = nodes['Mix_0'].outputs[0] inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0] mat.node_tree.links.new(outn, inn) if twosides is True: node = nodes.new('ShaderNodeNewGeometry') node.name = 'Input_1' node.location = -80, -70 node = nodes.new('ShaderNodeBsdfDiffuse') node.name = 'Diffuse_1' node.inputs[0].default_value = [0.30, 0.30, 0.30, 1] node.location = 200, -280 node = nodes.new('ShaderNodeMixShader') node.name = 'Mix_1' node.inputs[0].default_value = mix node.location = 800, -70 outn = nodes['Input_1'].outputs[6] inn = nodes['Mix_1'].inputs[0] mat.node_tree.links.new(outn, inn) outn = nodes['Diffuse_1'].outputs[0] inn = nodes['Mix_1'].inputs[2] mat.node_tree.links.new(outn, inn) outn = nodes['Mix_0'].outputs[0] inn = nodes['Mix_1'].inputs[1] mat.node_tree.links.new(outn, inn) outn = nodes['Mix_1'].outputs[0] inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0] mat.node_tree.links.new(outn, inn) return mat # -------------------------------------------------------------------- # Create cycles translucent material # -------------------------------------------------------------------- def create_translucent_material(matname, replace, r, g, b, rv=0.8, gv=0.8, bv=0.8, mix=0.1): # Avoid duplicate materials if replace is False: matlist = bpy.data.materials for m in matlist: if m.name == matname: return m # Create material mat = bpy.data.materials.new(matname) mat.diffuse_color = (rv, gv, bv, 1.0) # viewport color mat.use_nodes = True nodes = mat.node_tree.nodes # support for multilanguage node = nodes.new('ShaderNodeBsdfDiffuse') node.name = 'Diffuse BSDF' node.inputs[0].default_value = [r, g, b, 1] node.location = 200, 320 node = nodes.new('ShaderNodeBsdfTranslucent') node.name = 'Translucent_0' node.location = 200, 0 node = nodes.new('ShaderNodeMixShader') node.name = 'Mix_0' node.inputs[0].default_value = mix node.location = 500, 160 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')] node.location = 1100, 160 # Connect nodes outn = nodes['Diffuse BSDF'].outputs[0] inn = nodes['Mix_0'].inputs[1] mat.node_tree.links.new(outn, inn) outn = nodes['Translucent_0'].outputs[0] inn = nodes['Mix_0'].inputs[2] mat.node_tree.links.new(outn, inn) outn = nodes['Mix_0'].outputs[0] inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0] mat.node_tree.links.new(outn, inn) return mat # -------------------------------------------------------------------- # Create cycles glass material # -------------------------------------------------------------------- def create_glass_material(matname, replace, rv=0.333, gv=0.342, bv=0.9): # Avoid duplicate materials if replace is False: matlist = bpy.data.materials for m in matlist: if m.name == matname: return m # Create material mat = bpy.data.materials.new(matname) mat.use_nodes = True mat.diffuse_color = (rv, gv, bv, 1.0) nodes = mat.node_tree.nodes # support for multilanguage node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')] mat.node_tree.nodes.remove(node) # remove not used node = nodes.new('ShaderNodeLightPath') node.name = 'Light_0' node.location = 10, 160 node = nodes.new('ShaderNodeBsdfRefraction') node.name = 'Refraction_0' node.inputs[2].default_value = 1 # IOR 1.0 node.location = 250, 400 node = nodes.new('ShaderNodeBsdfGlossy') node.name = 'Glossy_0' node.distribution = 'SHARP' node.location = 250, 100 node = nodes.new('ShaderNodeBsdfTransparent') node.name = 'Transparent_0' node.location = 500, 10 node = nodes.new('ShaderNodeMixShader') node.name = 'Mix_0' node.inputs[0].default_value = 0.035 node.location = 500, 160 node = nodes.new('ShaderNodeMixShader') node.name = 'Mix_1' node.inputs[0].default_value = 0.1 node.location = 690, 290 node = nodes.new('ShaderNodeOutputMaterial') node.name = 'OUTPUT_MATERIAL' node.location = 920, 290 # Connect nodes outn = nodes['Light_0'].outputs[1] inn = nodes['Mix_1'].inputs[0] mat.node_tree.links.new(outn, inn) outn = nodes['Refraction_0'].outputs[0] inn = nodes['Mix_0'].inputs[1] mat.node_tree.links.new(outn, inn) outn = nodes['Glossy_0'].outputs[0] inn = nodes['Mix_0'].inputs[2] mat.node_tree.links.new(outn, inn) outn = nodes['Mix_0'].outputs[0] inn = nodes['Mix_1'].inputs[1] mat.node_tree.links.new(outn, inn) outn = nodes['Transparent_0'].outputs[0] inn = nodes['Mix_1'].inputs[2] mat.node_tree.links.new(outn, inn) outn = nodes['Mix_1'].outputs[0] inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0] mat.node_tree.links.new(outn, inn) return mat # --------------------------------------------- # Create cycles transparents material # -------------------------------------------------------------------- def create_transparent_material(matname, replace, r=1, g=1, b=1, alpha=0): # Avoid duplicate materials if replace is False: matlist = bpy.data.materials for m in matlist: if m.name == matname: return m # Create material mat = bpy.data.materials.new(matname) mat.use_nodes = True mat.diffuse_color = (r, g, b, 1.0) nodes = mat.node_tree.nodes # support for multilanguage node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')] mat.node_tree.nodes.remove(node) # remove not used node = nodes.new('ShaderNodeBsdfTransparent') node.name = 'Transparent_0' node.location = 250, 160 node.inputs[0].default_value = [r, g, b, alpha] node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')] node.location = 700, 160 # Connect nodes outn = nodes['Transparent_0'].outputs[0] inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0] mat.node_tree.links.new(outn, inn) return mat # -------------------------------------------------------------------- # Create cycles glossy material # -------------------------------------------------------------------- def create_glossy_material(matname, replace, r, g, b, rv=0.578, gv=0.555, bv=0.736, rvalue=0.2): # Avoid duplicate materials if replace is False: matlist = bpy.data.materials for m in matlist: if m.name == matname: return m # Create material mat = bpy.data.materials.new(matname) mat.use_nodes = True mat.diffuse_color = (rv, gv, bv, 1.0) nodes = mat.node_tree.nodes # support for multilanguage node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')] mat.node_tree.nodes.remove(node) # remove not used node = nodes.new('ShaderNodeBsdfGlossy') node.name = 'Glossy_0' node.inputs[0].default_value = [r, g, b, 1] node.inputs[1].default_value = rvalue node.location = 200, 160 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')] node.location = 700, 160 # Connect nodes outn = nodes['Glossy_0'].outputs[0] inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0] mat.node_tree.links.new(outn, inn) return mat # -------------------------------------------------------------------- # Create cycles emission material # -------------------------------------------------------------------- def create_emission_material(matname, replace, r, g, b, energy): # Avoid duplicate materials if replace is False: matlist = bpy.data.materials for m in matlist: if m.name == matname: return m # Create material mat = bpy.data.materials.new(matname) mat.use_nodes = True nodes = mat.node_tree.nodes # support for multilanguage node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')] mat.node_tree.nodes.remove(node) # remove not used node = nodes.new('ShaderNodeEmission') node.name = 'Emission_0' node.inputs[0].default_value = [r, g, b, 1] node.inputs[1].default_value = energy node.location = 200, 160 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')] node.location = 700, 160 # Connect nodes outn = nodes['Emission_0'].outputs[0] inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0] mat.node_tree.links.new(outn, inn) return mat # -------------------------------------------------------------------- # Create cycles glass material # -------------------------------------------------------------------- def create_old_glass_material(matname, replace, rv=0.352716, gv=0.760852, bv=0.9): # Avoid duplicate materials if replace is False: matlist = bpy.data.materials for m in matlist: if m.name == matname: return m # Create material mat = bpy.data.materials.new(matname) mat.use_nodes = True mat.diffuse_color = (rv, gv, bv, 1.0) nodes = mat.node_tree.nodes # support for multilanguage node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')] mat.node_tree.nodes.remove(node) # remove not used node = nodes.new('ShaderNodeLightPath') node.name = 'Light_0' node.location = 10, 160 node = nodes.new('ShaderNodeBsdfGlass') node.name = 'Glass_0' node.location = 250, 300 node = nodes.new('ShaderNodeBsdfTransparent') node.name = 'Transparent_0' node.location = 250, 0 node = nodes.new('ShaderNodeMixShader') node.name = 'Mix_0' node.inputs[0].default_value = 0.1 node.location = 500, 160 node = nodes.new('ShaderNodeMixShader') node.name = 'Mix_1' node.inputs[0].default_value = 0.1 node.location = 690, 290 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')] node.location = 920, 290 # Connect nodes outn = nodes['Light_0'].outputs[1] inn = nodes['Mix_0'].inputs[0] mat.node_tree.links.new(outn, inn) outn = nodes['Light_0'].outputs[2] inn = nodes['Mix_1'].inputs[0] mat.node_tree.links.new(outn, inn) outn = nodes['Glass_0'].outputs[0] inn = nodes['Mix_0'].inputs[1] mat.node_tree.links.new(outn, inn) outn = nodes['Transparent_0'].outputs[0] inn = nodes['Mix_0'].inputs[2] mat.node_tree.links.new(outn, inn) outn = nodes['Mix_0'].outputs[0] inn = nodes['Mix_1'].inputs[1] mat.node_tree.links.new(outn, inn) outn = nodes['Mix_1'].outputs[0] inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0] mat.node_tree.links.new(outn, inn) return mat # -------------------------------------------------------------------- # Create cycles brick texture material # -------------------------------------------------------------------- def create_brick_material(matname, replace, r, g, b, rv=0.8, gv=0.636, bv=0.315): # Avoid duplicate materials if replace is False: matlist = bpy.data.materials for m in matlist: if m.name == matname: return m # Create material mat = bpy.data.materials.new(matname) mat.use_nodes = True mat.diffuse_color = (rv, gv, bv, 1.0) nodes = mat.node_tree.nodes # support for multilanguage node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')] node.name = 'Diffuse BSDF' node.label = 'Diffuse BSDF' node.inputs[0].default_value = [r, g, b, 1] node.location = 500, 160 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')] node.location = 700, 160 node = nodes.new('ShaderNodeTexBrick') node.name = 'Brick_0' node.inputs[3].default_value = [0.407, 0.411, 0.394, 1] # mortar color node.inputs[4].default_value = 3 # scale node.inputs[5].default_value = 0.001 # mortar node.inputs[7].default_value = 0.60 # size_w node.inputs[8].default_value = 0.30 # size_h node.location = 300, 160 node = nodes.new('ShaderNodeRGB') node.name = 'RGB_0' node.outputs[0].default_value = [r, g, b, 1] node.location = 70, 160 # Connect nodes outn = nodes['RGB_0'].outputs['Color'] inn = nodes['Brick_0'].inputs['Color1'] mat.node_tree.links.new(outn, inn) inn = nodes['Brick_0'].inputs['Color2'] mat.node_tree.links.new(outn, inn) outn = nodes['Brick_0'].outputs['Color'] inn = nodes['Diffuse BSDF'].inputs['Color'] mat.node_tree.links.new(outn, inn) return mat # -------------------------------------------------------------------- # Create cycles fabric texture material # -------------------------------------------------------------------- def create_fabric_material(matname, replace, r, g, b, rv=0.8, gv=0.636, bv=0.315): # Avoid duplicate materials if replace is False: matlist = bpy.data.materials for m in matlist: if m.name == matname: return m # Create material mat = bpy.data.materials.new(matname) mat.use_nodes = True mat.diffuse_color = (rv, gv, bv, 1.0) nodes = mat.node_tree.nodes # support for multilanguage node = nodes.new('ShaderNodeBsdfDiffuse') node.name = 'Diffuse BSDF' node.inputs[0].default_value = [r, g, b, 1] node.location = 810, 270 node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')] node.location = 1210, 320 node = nodes.new('ShaderNodeTexCoord') node.name = 'UVCoordinates' node.location = 26, 395 node = nodes.new('ShaderNodeMapping') node.name = 'UVMapping' node.location = 266, 380 node.inputs['Scale'].default_value[0] = 1000 node.inputs['Scale'].default_value[1] = 1000 node.inputs['Scale'].default_value[2] = 1000 # =========================================================================== # Image texture # =========================================================================== # Load image file. realpath = path.join(path.dirname(__file__), "images", "fabric_diffuse.png") print("Loading: " + realpath) try: img = bpy.data.images.load(realpath) except: raise NameError("Cannot load image %s" % realpath) # Create image texture from image ctex = bpy.data.textures.new('ColorTex', type='IMAGE') ctex.image = img node = nodes.new('ShaderNodeTexImage') node.name = 'Image1' node.image = ctex.image node.location = 615, 350 node = nodes.new('ShaderNodeBsdfTransparent') node.name = 'Transparent1' node.location = 810, 395 node.inputs[0].default_value = [r, g, b, 1] node = nodes.new('ShaderNodeAddShader') node.name = 'Add1' node.location = 1040, 356 # Connect nodes outn = nodes['UVCoordinates'].outputs['UV'] inn = nodes['UVMapping'].inputs['Vector'] mat.node_tree.links.new(outn, inn) outn = nodes['UVMapping'].outputs['Vector'] inn = nodes['Image1'].inputs['Vector'] mat.node_tree.links.new(outn, inn) outn = nodes['Image1'].outputs['Color'] inn = nodes['Diffuse BSDF'].inputs['Color'] mat.node_tree.links.new(outn, inn) outn = nodes['Transparent1'].outputs['BSDF'] inn = nodes['Add1'].inputs[0] mat.node_tree.links.new(outn, inn) outn = nodes['Diffuse BSDF'].outputs['BSDF'] inn = nodes['Add1'].inputs[1] mat.node_tree.links.new(outn, inn) outn = nodes['Add1'].outputs['Shader'] inn = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')].inputs[0] mat.node_tree.links.new(outn, inn) return mat # -------------------------------------------------------------------- # Copy bin file # -------------------------------------------------------------------- def copy_binfile(fromfile, tofile): with open(fromfile, 'rb') as f1: with open(tofile, 'wb') as f2: while True: mybytes = f1.read(1024) if mybytes: f2.write(mybytes) else: break # -------------------------------------------------------------------- # Parent object (keep positions) # -------------------------------------------------------------------- def parentobject(parentobj, childobj): # noinspection PyBroadException try: bpy.ops.object.select_all(action='DESELECT') bpy.context.view_layer.objects.active = parentobj parentobj.select_set(True) childobj.select_set(True) bpy.ops.object.parent_set(type='OBJECT', keep_transform=False) return True except: return False # ------------------------------------------------------------------------------ # Create control box # # objName: Object name # x: size x axis # y: size y axis # z: size z axis # tube: True create a tube, False only sides # ------------------------------------------------------------------------------ def create_control_box(objname, x, y, z, tube=True): myvertex = [(-x / 2, 0, 0.0), (-x / 2, y, 0.0), (x / 2, y, 0.0), (x / 2, 0, 0.0), (-x / 2, 0, z), (-x / 2, y, z), (x / 2, y, z), (x / 2, 0, z)] if tube is True: 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)] else: myfaces = [(0, 4, 5, 1), (2, 6, 7, 3)] mesh = bpy.data.meshes.new(objname) myobject = bpy.data.objects.new(objname, mesh) myobject.location = bpy.context.scene.cursor.location bpy.context.collection.objects.link(myobject) mesh.from_pydata(myvertex, [], myfaces) mesh.update(calc_edges=True) return myobject # ------------------------------------------------------------------------------ # Remove all children objects # ------------------------------------------------------------------------------ def remove_children(myobject): # Remove children for child in myobject.children: # noinspection PyBroadException try: # noinspection PyBroadException try: # remove child relationship for grandchild in child.children: grandchild.parent = None # remove modifiers for mod in child.modifiers: bpy.ops.object.modifier_remove(name=mod.name) except: pass # clear child data if child.type == 'MESH': old = child.data child.select_set(True) bpy.ops.object.delete() bpy.data.meshes.remove(old) if child.type == 'CURVE': child.select_set(True) bpy.ops.object.delete() except: pass # -------------------------------------------------------------------- # Get all parents # -------------------------------------------------------------------- def get_allparents(myobj): obj = myobj mylist = [] while obj.parent is not None: mylist.append(obj) objp = obj.parent obj = objp mylist.append(obj) return mylist # -------------------------------------------------------------------- # Verify all faces are in vertice group to avoid Blander crash # # Review the faces array and remove any vertex out of the range # this avoid any bug that can appear avoiding Blender crash # -------------------------------------------------------------------- def check_mesh_errors(myvertices, myfaces): vmax = len(myvertices) f = 0 for face in myfaces: for v in face: if v < 0 or v > vmax: print("Face=" + str(f) + "->removed vertex=" + str(v)) myfaces[f].remove(v) f += 1 return myfaces