diff options
author | meta-androcto <meta.androcto1@gmail.com> | 2016-08-05 02:27:33 +0300 |
---|---|---|
committer | meta-androcto <meta.androcto1@gmail.com> | 2016-08-05 02:27:33 +0300 |
commit | 3854131d083b01dfd9fd08a24de12e632820b866 (patch) | |
tree | 108b1399bdb2d44e940e8dbac4b7e8ad8fcd6940 /materials_utils/materials_cycles_converter.py | |
parent | 6ee6d9e44aefc6eb1e7cdbf3e8b1e62392f2df6a (diff) |
update materias utils & conversion re: T48642
Diffstat (limited to 'materials_utils/materials_cycles_converter.py')
-rw-r--r-- | materials_utils/materials_cycles_converter.py | 683 |
1 files changed, 683 insertions, 0 deletions
diff --git a/materials_utils/materials_cycles_converter.py b/materials_utils/materials_cycles_converter.py new file mode 100644 index 00000000..600de7e2 --- /dev/null +++ b/materials_utils/materials_cycles_converter.py @@ -0,0 +1,683 @@ +# gpl: author Silvio Falcinelli. Fixes by angavrilov and others. +# special thanks to user blenderartists.org cmomoney +# -*- coding: utf-8 -*- + +import bpy +import os +from os import path as os_path +from bpy.types import Operator +from bpy.props import ( + BoolProperty, + EnumProperty, + ) +from .warning_messages_utils import ( + warning_messages, + c_is_cycles_addon_enabled, + c_data_has_materials, + collect_report, + ) + +# ----------------------------------------------------------------------------- +# Globals # + +# switch for operator's function called after AutoNodeInitiate +CHECK_AUTONODE = False + +# set the node color for baked textures (default greenish) +NODE_COLOR = (0.32, 0.75, 0.32) + +# ----------------------------------------------------------------------------- +# Functions # + + +def AutoNodeSwitch(renderer="CYCLES", switch="OFF", operator=None): + mats = bpy.data.materials + use_nodes = (True if switch in ("ON") else False) + warn_message = ('BI_SW_NODES_ON' if switch in ("ON") else + 'BI_SW_NODES_OFF') + warn_message_2 = ('CYC_SW_NODES_ON' if switch in ("ON") else + 'CYC_SW_NODES_OFF') + for cmat in mats: + cmat.use_nodes = use_nodes + renders = ('CYCLES' if renderer and renderer == "CYCLES" else + 'BLENDER_RENDER') + bpy.context.scene.render.engine = renders + if operator: + warning_messages(operator, (warn_message_2 if renders in ('CYCLES') else + warn_message)) + + +def SetFakeUserTex(): + images = bpy.data.images + for image in images: + has_user = getattr(image, "users", -1) + image_name = getattr(image, "name", "NONAME") + + if has_user == 0: + image.use_fake_user = True + collect_report("INFO: Set fake user for unused image: " + image_name) + + +def BakingText(tex, mode, tex_type=None): + collect_report("INFO: start bake texture named: " + tex.name) + saved_img_path = None + bpy.ops.object.mode_set(mode='OBJECT') + sc = bpy.context.scene + tmat = '' + img = '' + Robj = bpy.context.active_object + for n in bpy.data.materials: + if n.name == 'TMP_BAKING': + tmat = n + if not tmat: + tmat = bpy.data.materials.new('TMP_BAKING') + tmat.name = "TMP_BAKING" + + bpy.ops.mesh.primitive_plane_add() + tm = bpy.context.active_object + tm.name = "TMP_BAKING" + tm.data.name = "TMP_BAKING" + bpy.ops.object.select_pattern(extend=False, pattern="TMP_BAKING", + case_sensitive=False) + sc.objects.active = tm + bpy.context.scene.render.engine = 'BLENDER_RENDER' + tm.data.materials.append(tmat) + if len(tmat.texture_slots.items()) == 0: + tmat.texture_slots.add() + tmat.texture_slots[0].texture_coords = 'UV' + tmat.texture_slots[0].use_map_alpha = True + tmat.texture_slots[0].texture = tex.texture + tmat.texture_slots[0].use_map_alpha = True + tmat.texture_slots[0].use_map_color_diffuse = False + tmat.use_transparency = True + tmat.alpha = 0 + tmat.use_nodes = False + tmat.diffuse_color = 1, 1, 1 + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.uv.unwrap() + + # clean up temporary baking images if any + for n in bpy.data.images: + if n.name == 'TMP_BAKING': + n.user_clear() + bpy.data.images.remove(n) + + if mode == "ALPHA" and tex.texture.type == 'IMAGE': + sizeX = tex.texture.image.size[0] + sizeY = tex.texture.image.size[1] + else: + bake_size = (int(sc.mat_specials.img_bake_size) if + sc.mat_specials.img_bake_size else 1024) + sizeX = bake_size + sizeY = bake_size + + bpy.ops.image.new(name="TMP_BAKING", width=sizeX, height=sizeY, + color=(0.0, 0.0, 0.0, 1.0), alpha=True, float=False) + bpy.data.screens['UV Editing'].areas[1].spaces[0].image = bpy.data.images["TMP_BAKING"] + sc.render.engine = 'BLENDER_RENDER' + img = bpy.data.images["TMP_BAKING"] + img = bpy.data.images.get("TMP_BAKING") + img.file_format = ("JPEG" if not mode == "ALPHA" else "PNG") + + paths = bpy.path.abspath(sc.mat_specials.conv_path) + tex_name = getattr(getattr(tex.texture, "image", None), "name", None) + texture_name = (tex_name.rpartition(".")[0] if tex_name else tex.texture.name) + new_tex_name = "baked" + name_append = ("_BAKING" if mode == "ALPHA" and + tex.texture.type == 'IMAGE' else "_PTEXT") + new_appendix = (".jpg" if not mode == "ALPHA" else ".png") + + if name_append in texture_name: + new_tex_name = texture_name + elif tex_type: + new_tex_name = tex_type + name_append + else: + new_tex_name = texture_name + name_append + + img.filepath_raw = paths + new_tex_name + new_appendix + saved_img_path = img.filepath_raw + + sc.render.bake_type = 'ALPHA' + sc.render.use_bake_selected_to_active = True + sc.render.use_bake_clear = True + + # try to bake if it fails give report + try: + bpy.ops.object.bake_image() + img.save() + except: + # no return value so the image loading is skipped + saved_img_path = None + collect_report("ERROR: Baking could not be completed. " + "Check System Console for info") + + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.delete() + bpy.ops.object.select_pattern(extend=False, pattern=Robj.name, case_sensitive=False) + sc.objects.active = Robj + img.user_clear() + bpy.data.images.remove(img) + + if tmat.users == 0: + bpy.data.materials.remove(tmat) + + if saved_img_path: + collect_report("________________________________________") + return saved_img_path + + +def AutoNodeInitiate(active=False, operator=None): + # Checks with bpy.ops.material.check_converter_path + # if it's possible to write in the output path + # if it passes procedes with calling AutoNode + + # if CheckImagePath(operator): + check_path = bpy.ops.material.check_converter_path() + + global CHECK_AUTONODE + + if 'FINISHED' in check_path: + sc = bpy.context.scene + CHECK_AUTONODE = True + collect_report("________________________________________", True, False) + AutoNode(active, operator) + if sc.mat_specials.SET_FAKE_USER: + SetFakeUserTex() + collect_report("Conversion finished !", False, True) + else: + warning_messages(operator, 'DIR_PATH_CONVERT') + + +def AutoNode(active=False, operator=None): + global CHECK_AUTONODE + sc = bpy.context.scene + if active: + # fix for empty slots by angavrilov + mats = [slot.material for slot in bpy.context.active_object.material_slots if + slot.material] + else: + mats = bpy.data.materials + + # No Materials for the chosen action - abort + if not mats: + CHECK_AUTONODE = False + if operator: + if active: + act_obj = bpy.context.active_object + warning_messages(operator, 'CONV_NO_OBJ_MAT', act_obj.name) + else: + warning_messages(operator, 'CONV_NO_SC_MAT') + return + + for cmat in mats: + # check for empty material (it will fall through the first check) + test_empty = getattr(cmat, "name", None) + if test_empty is None: + collect_report("An empty material was hit, skipping") + continue + + cmat.use_nodes = True + TreeNodes = cmat.node_tree + links = TreeNodes.links + + # Don't alter nodes of locked materials + locked = False + for n in TreeNodes.nodes: + if n.type == 'ShaderNodeOutputMaterial': + if n.label == 'Locked': + locked = True + break + + if not locked: + # Convert this material from non-nodes to Cycles nodes + shader = '' + shtsl = '' + Add_Emission = '' + Add_Translucent = '' + Mix_Alpha = '' + sT = False + + for n in TreeNodes.nodes: + TreeNodes.nodes.remove(n) + + # Starting point is diffuse BSDF and output material + shader = TreeNodes.nodes.new('ShaderNodeBsdfDiffuse') + shader.location = 0, 470 + shout = TreeNodes.nodes.new('ShaderNodeOutputMaterial') + shout.location = 200, 400 + links.new(shader.outputs[0], shout.inputs[0]) + + cmat_is_transp = cmat.use_transparency and cmat.alpha < 1 + + if not cmat.raytrace_mirror.use and not cmat_is_transp: + if not shader.type == 'ShaderNodeBsdfDiffuse': + collect_report("INFO: Make DIFFUSE shader node for: " + cmat.name) + TreeNodes.nodes.remove(shader) + shader = TreeNodes.nodes.new('ShaderNodeBsdfDiffuse') + shader.location = 0, 470 + links.new(shader.outputs[0], shout.inputs[0]) + + if cmat.raytrace_mirror.use and cmat.raytrace_mirror.reflect_factor > 0.001 and cmat_is_transp: + if not shader.type == 'ShaderNodeBsdfGlass': + collect_report("INFO: Make GLASS shader node for: " + cmat.name) + TreeNodes.nodes.remove(shader) + shader = TreeNodes.nodes.new('ShaderNodeBsdfGlass') + shader.location = 0, 470 + links.new(shader.outputs[0], shout.inputs[0]) + + if cmat.raytrace_mirror.use and not cmat_is_transp and cmat.raytrace_mirror.reflect_factor > 0.001: + if not shader.type == 'ShaderNodeBsdfGlossy': + collect_report("INFO: Make MIRROR shader node for: " + cmat.name) + TreeNodes.nodes.remove(shader) + shader = TreeNodes.nodes.new('ShaderNodeBsdfGlossy') + shader.location = 0, 520 + links.new(shader.outputs[0], shout.inputs[0]) + + if cmat.emit > 0.001: + if (not shader.type == 'ShaderNodeEmission' and not + cmat.raytrace_mirror.reflect_factor > 0.001 and not cmat_is_transp): + + collect_report("INFO: Mix EMISSION shader node for: " + cmat.name) + TreeNodes.nodes.remove(shader) + shader = TreeNodes.nodes.new('ShaderNodeEmission') + shader.location = 0, 450 + links.new(shader.outputs[0], shout.inputs[0]) + else: + if not Add_Emission: + collect_report("INFO: Add EMISSION shader node for: " + cmat.name) + shout.location = 550, 330 + Add_Emission = TreeNodes.nodes.new('ShaderNodeAddShader') + Add_Emission.location = 370, 490 + + shem = TreeNodes.nodes.new('ShaderNodeEmission') + shem.location = 180, 380 + + links.new(Add_Emission.outputs[0], shout.inputs[0]) + links.new(shem.outputs[0], Add_Emission.inputs[1]) + links.new(shader.outputs[0], Add_Emission.inputs[0]) + + shem.inputs['Color'].default_value = (cmat.diffuse_color.r, + cmat.diffuse_color.g, + cmat.diffuse_color.b, 1) + shem.inputs['Strength'].default_value = cmat.emit + + if cmat.translucency > 0.001: + collect_report("INFO: Add BSDF_TRANSLUCENT shader node for: " + cmat.name) + shout.location = 770, 330 + Add_Translucent = TreeNodes.nodes.new('ShaderNodeAddShader') + Add_Translucent.location = 580, 490 + + shtsl = TreeNodes.nodes.new('ShaderNodeBsdfTranslucent') + shtsl.location = 400, 350 + + links.new(Add_Translucent.outputs[0], shout.inputs[0]) + links.new(shtsl.outputs[0], Add_Translucent.inputs[1]) + + if Add_Emission: + links.new(Add_Emission.outputs[0], Add_Translucent.inputs[0]) + pass + else: + links.new(shader.outputs[0], Add_Translucent.inputs[0]) + pass + shtsl.inputs['Color'].default_value = (cmat.translucency, + cmat.translucency, + cmat.translucency, 1) + + shader.inputs['Color'].default_value = (cmat.diffuse_color.r, + cmat.diffuse_color.g, + cmat.diffuse_color.b, 1) + + if shader.type == 'ShaderNodeBsdfDiffuse': + shader.inputs['Roughness'].default_value = cmat.specular_intensity + + if shader.type == 'ShaderNodeBsdfGlossy': + shader.inputs['Roughness'].default_value = 1 - cmat.raytrace_mirror.gloss_factor + + if shader.type == 'ShaderNodeBsdfGlass': + shader.inputs['Roughness'].default_value = 1 - cmat.raytrace_mirror.gloss_factor + shader.inputs['IOR'].default_value = cmat.raytrace_transparency.ior + + if shader.type == 'ShaderNodeEmission': + shader.inputs['Strength'].default_value = cmat.emit + + # texture frame check and tex count (if bigger than 1 add frame) + frame_check, tex_count, node_frame = False, 0, None + + for tex in cmat.texture_slots: + if tex: + tex_count += 1 + if not frame_check: + frame_check = True + if tex_count > 1: + break + + if frame_check: + if tex_count > 1: + node_frame = TreeNodes.nodes.new('NodeFrame') + node_frame.name = 'Converter Textures' + node_frame.label = 'Converter Textures' + + # count the number of texture nodes created + # for spreading a bit the texture nodes + row_node, col_node = -1, False + sM = True + baked_path = None + + for tex in cmat.texture_slots: + sT = False + tex_use = getattr(tex, "use", None) + if tex_use: + row_node = (row_node + 1 if not col_node else row_node) + col_node = not col_node + tex_node_loc = -(200 + (row_node * 150)), (400 if col_node else 650) + ma_alpha = getattr(tex, "use_map_alpha", None) + sM = (False if ma_alpha else True) + + if tex.texture.type == 'IMAGE': + if sc.mat_specials.EXTRACT_ALPHA and tex.texture.use_alpha: + if (not + os_path.exists(bpy.path.abspath(tex.texture.image.filepath + "_BAKING.png")) or + sc.mat_specials.EXTRACT_OW): + baked_path = BakingText(tex, 'ALPHA') + try: + if baked_path: + img = bpy.data.images.load(baked_path) + collect_report("INFO: Loading Baked texture path:") + collect_report(baked_path) + else: + img = tex.texture.image + + img_name = (img.name if hasattr(img, "name") else "NO NAME") + shtext = TreeNodes.nodes.new('ShaderNodeTexImage') + shtext.location = tex_node_loc + shtext.image = img + shtext.name = img_name + shtext.label = "Image " + img_name + if baked_path: + shtext.use_custom_color = True + shtext.color = NODE_COLOR + collect_report("INFO: Creating Image Node for image: " + img_name) + if node_frame: + shtext.parent = node_frame + sT = True + except: + collect_report("ERROR: A problem occured with loading an image for {} " + "(possibly missing)".format(tex.texture.name)) + else: + if sc.mat_specials.EXTRACT_PTEX or (sc.mat_specials.EXTRACT_ALPHA and ma_alpha): + if (not os_path.exists(bpy.path.abspath(tex.texture.name + "_PTEXT.jpg")) or + sc.mat_specials.EXTRACT_OW): + tex_type = tex.texture.type.lower() + collect_report("Attempting to Extract Procedural Texture type: " + tex_type) + baked_path = BakingText(tex, 'PTEX', tex_type) + + if baked_path: + try: + img = bpy.data.images.load(baked_path) + collect_report("Loading Baked texture path:") + collect_report(baked_path) + img_name = (img.name if hasattr(img, "name") else "NO NAME") + shtext = TreeNodes.nodes.new('ShaderNodeTexImage') + shtext.location = tex_node_loc + shtext.image = img + shtext.name = img_name + shtext.label = "Baked Image " + img_name + shtext.use_custom_color = True + shtext.color = NODE_COLOR + collect_report("Creating Image Node for baked image: " + img_name) + if node_frame: + shtext.parent = node_frame + sT = True + except: + collect_report("ERROR: Failure to load baked image: " + img_name) + else: + collect_report("ERROR: Failure during baking, no images loaded") + + if cmat_is_transp and cmat.raytrace_transparency.ior == 1 and not cmat.raytrace_mirror.use and sM: + if not shader.type == 'ShaderNodeBsdfTransparent': + collect_report("INFO: Make TRANSPARENT shader node for: " + cmat.name) + TreeNodes.nodes.remove(shader) + shader = TreeNodes.nodes.new('ShaderNodeBsdfTransparent') + shader.location = 0, 470 + links.new(shader.outputs[0], shout.inputs[0]) + + shader.inputs['Color'].default_value = (cmat.diffuse_color.r, + cmat.diffuse_color.g, + cmat.diffuse_color.b, 1) + + if sT: + if tex.use_map_color_diffuse: + links.new(shtext.outputs[0], shader.inputs[0]) + + if tex.use_map_emit: + if not Add_Emission: + collect_report("INFO: Mix EMISSION + Texture shader node for: " + cmat.name) + intensity = 0.5 + (tex.emit_factor / 2) + + shout.location = 550, 330 + Add_Emission = TreeNodes.nodes.new('ShaderNodeAddShader') + Add_Emission.name = "Add_Emission" + Add_Emission.location = 370, 490 + + shem = TreeNodes.nodes.new('ShaderNodeEmission') + shem.location = 180, 380 + + links.new(Add_Emission.outputs[0], shout.inputs[0]) + links.new(shem.outputs[0], Add_Emission.inputs[1]) + links.new(shader.outputs[0], Add_Emission.inputs[0]) + + shem.inputs['Color'].default_value = (cmat.diffuse_color.r, + cmat.diffuse_color.g, + cmat.diffuse_color.b, 1) + shem.inputs['Strength'].default_value = intensity * 2 + + links.new(shtext.outputs[0], shem.inputs[0]) + + if tex.use_map_mirror: + links.new(shader.inputs[0], shtext.outputs[0]) + + if tex.use_map_translucency: + if not Add_Translucent: + collect_report("INFO: Add Translucency + Texture shader node for: " + cmat.name) + + intensity = 0.5 + (tex.emit_factor / 2) + shout.location = 550, 330 + Add_Translucent = TreeNodes.nodes.new('ShaderNodeAddShader') + Add_Translucent.name = "Add_Translucent" + Add_Translucent.location = 370, 290 + + shtsl = TreeNodes.nodes.new('ShaderNodeBsdfTranslucent') + shtsl.location = 180, 240 + + links.new(shtsl.outputs[0], Add_Translucent.inputs[1]) + + if Add_Emission: + links.new(Add_Translucent.outputs[0], shout.inputs[0]) + links.new(Add_Emission.outputs[0], Add_Translucent.inputs[0]) + pass + else: + links.new(Add_Translucent.outputs[0], shout.inputs[0]) + links.new(shader.outputs[0], Add_Translucent.inputs[0]) + + links.new(shtext.outputs[0], shtsl.inputs[0]) + + if tex.use_map_alpha: + if not Mix_Alpha: + collect_report("INFO: Mix Alpha + Texture shader node for: " + cmat.name) + + shout.location = 750, 330 + Mix_Alpha = TreeNodes.nodes.new('ShaderNodeMixShader') + Mix_Alpha.name = "Add_Alpha" + Mix_Alpha.location = 570, 290 + sMask = TreeNodes.nodes.new('ShaderNodeBsdfTransparent') + sMask.location = 250, 180 + tMask, imask = None, None + + # search if the texture node already exists, if not create + nodes = getattr(cmat.node_tree, "nodes", None) + img_name = getattr(img, "name", "NO NAME") + for node in nodes: + if type(node) == bpy.types.ShaderNodeTexImage: + node_name = getattr(node, "name") + if img_name in node_name: + tMask = node + collect_report("INFO: Using existing Texture Node for Mask: " + node_name) + break + + if tMask is None: + tMask = TreeNodes.nodes.new('ShaderNodeTexImage') + + if node_frame: + tMask.parent = node_frame + tex_node_loc = -(200 + ((row_node + 1) * 150)), (650 if col_node else 400) + tMask.location = tex_node_loc + + try: + file_path = getattr(img, "filepath", None) + if file_path: + imask = bpy.data.images.load(file_path) + else: + imask = bpy.data.images.get(img_name) + collect_report("INFO: Attempting to load image for Mask: " + img_name) + except: + collect_report("ERROR: Failure to load image for Mask: " + img_name) + + if imask: + tMask.image = imask + + if tMask: + links.new(Mix_Alpha.inputs[0], tMask.outputs[1]) + links.new(shout.inputs[0], Mix_Alpha.outputs[0]) + links.new(sMask.outputs[0], Mix_Alpha.inputs[1]) + + if not Add_Translucent: + if Add_Emission: + links.new(Mix_Alpha.inputs[2], Add_Emission.outputs[0]) + else: + links.new(Mix_Alpha.inputs[2], shader.outputs[0]) + else: + links.new(Mix_Alpha.inputs[2], Add_Translucent.outputs[0]) + else: + collect_report("ERROR: Mix Alpha could not be created " + "(mask image could not be loaded)") + + if tex.use_map_normal: + t = TreeNodes.nodes.new('ShaderNodeRGBToBW') + t.location = -0, 300 + links.new(t.outputs[0], shout.inputs[2]) + links.new(shtext.outputs[0], t.inputs[0]) + else: + collect_report("No textures in the Scene, no Image Nodes to add") + + bpy.context.scene.render.engine = 'CYCLES' + + +# ----------------------------------------------------------------------------- +# Operator Classes # + +class mllock(Operator): + bl_idname = "ml.lock" + bl_label = "Lock" + bl_description = "Lock/unlock this material against modification by conversions" + bl_options = {'REGISTER', 'UNDO'} + + @classmethod + def poll(cls, context): + return (c_is_cycles_addon_enabled() and c_data_has_materials()) + + def execute(self, context): + cmat = bpy.context.selected_objects[0].active_material + TreeNodes = cmat.node_tree + for n in TreeNodes.nodes: + if n.type == 'ShaderNodeOutputMaterial': + if n.label == 'Locked': + n.label = '' + else: + n.label = 'Locked' + return {'FINISHED'} + + +class mlrefresh(Operator): + bl_idname = "ml.refresh" + bl_label = "Convert All Materials" + bl_description = "Convert All Materials in the scene from non-nodes to Cycles" + bl_options = {'REGISTER', 'UNDO'} + + @classmethod + def poll(cls, context): + return (c_is_cycles_addon_enabled() and c_data_has_materials()) + + def execute(self, context): + AutoNodeInitiate(False, self) + + if CHECK_AUTONODE is True: + bpy.ops.object.editmode_toggle() + bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0.001) + bpy.ops.object.editmode_toggle() + + return {'FINISHED'} + + +class mlrefresh_active(Operator): + bl_idname = "ml.refresh_active" + bl_label = "Convert All Materials From Active Object" + bl_description = "Convert all Active Object's Materials from non-nodes to Cycles" + bl_options = {'REGISTER', 'UNDO'} + + @classmethod + def poll(cls, context): + return (c_is_cycles_addon_enabled() and c_data_has_materials() and + context.active_object is not None) + + def execute(self, context): + AutoNodeInitiate(True, self) + if CHECK_AUTONODE is True: + bpy.ops.object.editmode_toggle() + bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0.001) + bpy.ops.object.editmode_toggle() + return {'FINISHED'} + + +class mlrestore(Operator): + bl_idname = "ml.restore" + bl_label = "Switch Between Renderers" + bl_description = ("Switch between Renderers \n" + "(Doesn't create new nor converts existing materials)") + bl_options = {'REGISTER', 'UNDO'} + + switcher = BoolProperty( + name="Use Nodes", + description="When restoring, switch Use Nodes On/Off", + default=True + ) + renderer = EnumProperty( + name="Renderer", + description="Choose Cycles or Blender Internal", + items=(('CYCLES', "Cycles", "Switch to Cycles"), + ('BI', "Blender Internal", "Switch to Blender Internal")), + default='CYCLES', + ) + + @classmethod + def poll(cls, context): + return c_is_cycles_addon_enabled() + + def execute(self, context): + if self.switcher: + AutoNodeSwitch(self.renderer, "ON", self) + else: + AutoNodeSwitch(self.renderer, "OFF", self) + return {'FINISHED'} + + +def register(): + bpy.utils.register_module(__name__) + pass + + +def unregister(): + bpy.utils.unregister_module(__name__) + pass + +if __name__ == "__main__": + register() |