# -*- coding: utf-8 -*- import bpy import math from mathutils import Vector from bpy.types import Operator from .warning_messages_utils import ( warning_messages, c_is_cycles_addon_enabled, c_data_has_materials, collect_report, ) # ----------------------------------------------------------------------------- # Globals nodesDictionary = None NODE_FRAME = 'NodeFrame' BI_MATERIAL_NODE = 'ShaderNodeMaterial' BI_OUTPUT_NODE = 'ShaderNodeOutput' TEXTURE_IMAGE_NODE = 'ShaderNodeTexImage' OUTPUT_NODE = 'ShaderNodeOutputMaterial' RGB_MIX_NODE = 'ShaderNodeMixRGB' MAPPING_NODE = 'ShaderNodeMapping' NORMAL_MAP_NODE = 'ShaderNodeNormalMap' SHADER_MIX_NODE = 'ShaderNodeMixShader' SHADER_ADD_NODE = 'ShaderNodeAddShader' COORD_NODE = 'ShaderNodeTexCoord' RGB_TO_BW_NODE = 'ShaderNodeRGBToBW' BSDF_DIFFUSE_NODE = 'ShaderNodeBsdfDiffuse' BSDF_EMISSION_NODE = 'ShaderNodeEmission' BSDF_TRANSPARENT_NODE = 'ShaderNodeBsdfTransparent' BSDF_GLOSSY_NODE = 'ShaderNodeBsdfGlossy' BSDF_GLASS_NODE = 'ShaderNodeBsdfGlass' textureNodeSizeX = 150 textureNodeSizeY = 350 # ----------------------------------------------------------------------------- # Functions def makeTextureNodeDict(cmat): global nodesDictionary nodesDictionary = {} textures = {textureSlot.texture for textureSlot in cmat.texture_slots if textureSlot} for tex in textures: texNode = None if tex.type == 'IMAGE': texNode = makeNodeUsingImage1(cmat, tex) if texNode: nodesDictionary[tex] = texNode return nodesDictionary def getTexNodeDic(texture): return nodesDictionary.get(texture) def clearNodes(TreeNodes): TreeNodes.nodes.clear() def clearCycleMaterial(cmat): TreeNodes = cmat.node_tree clearNodes(TreeNodes) def copyMapping(textureSlot, textureMapping): textureMapping.scale.x = textureSlot.scale.x textureMapping.scale.y = textureSlot.scale.y textureMapping.scale.z = textureSlot.scale.z def addRGBMixNode(TreeNodes, textureSlot, mixRgbNode, prevTexNode, newTexNode, nodeType, textureIdx): try: links = TreeNodes.links mixRgbNode.name = '{} Mix {:d}'.format(nodeType, textureIdx) mixRgbNode.blend_type = textureSlot.blend_type mixRgbNode.inputs['Fac'].default_value = textureSlot.diffuse_color_factor links.new(prevTexNode.outputs['Color'], mixRgbNode.inputs['Color2']) links.new(newTexNode.outputs['Color'], mixRgbNode.inputs['Color1']) except: collect_report("ERROR: Failure to find link with a Mix node") def makeBiNodes(cmat): # Create Blender Internal Material Nodes TreeNodes = cmat.node_tree links = TreeNodes.links BIFrame = TreeNodes.nodes.new(NODE_FRAME) BIFrame.name = 'BI Frame' BIFrame.label = 'BI Material' biShaderNodeMaterial = TreeNodes.nodes.new(BI_MATERIAL_NODE) biShaderNodeMaterial.parent = BIFrame biShaderNodeMaterial.name = 'BI Material' biShaderNodeMaterial.material = cmat biShaderNodeMaterial.location = 0, 600 biShaderNodeOutput = TreeNodes.nodes.new(BI_OUTPUT_NODE) biShaderNodeOutput.parent = BIFrame biShaderNodeOutput.name = 'BI Output' biShaderNodeOutput.location = 200, 600 try: links.new(biShaderNodeMaterial.outputs['Color'], biShaderNodeOutput.inputs['Color']) links.new(biShaderNodeMaterial.outputs['Alpha'], biShaderNodeOutput.inputs['Alpha']) except: collect_report("ERROR: Failure to find links with the BI Shader Material") def placeNode(node, posX, posY, deltaX, deltaY, countX, countY): nodeX = posX - (deltaX * countX) nodeY = posY - (deltaY * countY) node.location = nodeX, nodeY def makeImageTextureNode(TreeNodes, img): texNode = TreeNodes.nodes.new(TEXTURE_IMAGE_NODE) texNode.image = img return texNode def makeNodeUsingImage1(cmat, texture): TreeNodes = cmat.node_tree img = texture.image texNode = makeImageTextureNode(TreeNodes, img) return texNode def makeMainShader(TreeNodes): mainShader = TreeNodes.nodes.new(BSDF_DIFFUSE_NODE) mainShader.name = 'Diffuse BSDF' mainShader.location = 0, 0 return mainShader def makeEmissionShader(TreeNodes): mainShader = TreeNodes.nodes.new(BSDF_EMISSION_NODE) mainShader.name = 'Emmission' mainShader.location = 0, 0 return mainShader def makeMaterialOutput(TreeNodes): shout = TreeNodes.nodes.new(OUTPUT_NODE) shout.location = 200, 0 return shout def replaceNode(oldNode, newNode): newNode.location = oldNode.location try: for link in oldNode.outputs['BSDF'].links: link.new(newNode.outputs['BSDF'], link.to_socket) for link in oldNode.inputs['Color'].links: link.new(newNode.inputs['Color'], link.from_socket) for link in oldNode.inputs['Normal'].links: link.new(newNode.inputs['Normal'], link.from_socket) except: collect_report("ERROR: Failure to replace node") def BIToCycleTexCoord(links, textureSlot, texCoordNode, textureMappingNode): # Texture Coordinates linkOutput = None if textureSlot.texture_coords in {'TANGENT', 'STRESS', 'STRAND'}: linkOutput = None elif textureSlot.texture_coords == 'REFLECTION': linkOutput = 'Reflection' elif textureSlot.texture_coords == 'NORMAL': linkOutput = 'Normal' elif textureSlot.texture_coords == 'WINDOW': linkOutput = 'Window' elif textureSlot.texture_coords == 'UV': linkOutput = 'UV' elif textureSlot.texture_coords == 'ORCO': linkOutput = 'Generated' elif textureSlot.texture_coords == 'OBJECT': linkOutput = 'Object' elif textureSlot.texture_coords == 'GLOBAL': linkOutput = 'Camera' if linkOutput: links.new(texCoordNode.outputs[linkOutput], textureMappingNode.inputs['Vector']) def createDiffuseNodes(cmat, texCoordNode, mainShader, materialOutput): TreeNodes = cmat.node_tree links = TreeNodes.links texCount = len([node for node in TreeNodes.nodes if node.type == 'MAPPING']) currPosY = -textureNodeSizeY * texCount textureSlots = [textureSlot for textureSlot in cmat.texture_slots if (textureSlot and textureSlot.use_map_color_diffuse)] texCount = len(textureSlots) texNode = None latestNode = None groupName = 'Diffuse' if any(textureSlots): diffuseFrame = TreeNodes.nodes.new(NODE_FRAME) diffuseFrame.name = '{} Frame'.format(groupName) diffuseFrame.label = '{}'.format(groupName) for textureIdx, textureSlot in enumerate(textureSlots): texNode = getTexNodeDic(textureSlot.texture) if texNode: tex_node_name = getattr(texNode.image, "name", "") collect_report("INFO: Generating {} Nodes for: ".format(groupName) + tex_node_name) texNode.parent = diffuseFrame placeNode(texNode, -500 - ((texCount - 1) * 200), currPosY, textureNodeSizeX, textureNodeSizeY, 0, textureIdx) # Add mapping node textureMapping = TreeNodes.nodes.new(MAPPING_NODE) textureMapping.parent = diffuseFrame renameNode(textureMapping, '{} Mapping'.format(groupName), texCount, textureIdx) textureMapping.location = texNode.location + Vector((-400, 0)) copyMapping(textureSlot, textureMapping) # Texture Coordinates BIToCycleTexCoord(links, textureSlot, texCoordNode, textureMapping) # Place the texture node renameNode(texNode, '{} Texture'.format(groupName), texCount, textureIdx) links.new(textureMapping.outputs['Vector'], texNode.inputs['Vector']) # Add multiply node colorMult = TreeNodes.nodes.new(RGB_MIX_NODE) colorMult.parent = diffuseFrame renameNode(colorMult, 'Color Mult', texCount, textureIdx) colorMult.blend_type = 'MIX' colorMult.inputs['Fac'].default_value = 1 colorMult.inputs['Color1'].default_value = (1, 1, 1, 1) colorMult.location = texNode.location + Vector((200, 0)) links.new(texNode.outputs['Color'], colorMult.inputs['Color2']) texNode = colorMult if textureSlot.use and textureIdx == 0: latestNode = texNode if textureSlot.use and textureIdx > 0: try: # Create a node to mix multiple texture nodes mixRgbNode = TreeNodes.nodes.new(RGB_MIX_NODE) mixRgbNode.parent = diffuseFrame addRGBMixNode(TreeNodes, textureSlot, mixRgbNode, texNode, latestNode, '{}'.format(groupName), textureIdx) mixRgbNode.location = Vector( (max(texNode.location.x, latestNode.location.x), (texNode.location.y + latestNode.location.y) / 2)) + Vector((200, 0) ) latestNode = mixRgbNode except: continue if latestNode: links.new(latestNode.outputs['Color'], mainShader.inputs['Color']) # Y Position next texture node currPosY = currPosY - (textureNodeSizeY * (texCount)) # BI Material to Cycles - Alpha Transparency textureSlots = [textureSlot for textureSlot in cmat.texture_slots if (textureSlot and textureSlot.use_map_alpha)] texCount = len(textureSlots) texNode = None latestNode = None for textureIdx, textureSlot in enumerate(textureSlots): texNode = getTexNodeDic(textureSlot.texture) if texNode: tex_node_name = getattr(texNode.image, "name", "") collect_report("INFO: Generating Transparency Nodes for: " + tex_node_name) if textureSlot.use and textureIdx == 0: latestNode = texNode if textureSlot.use and textureIdx > 0: try: # Create a node to mix multiple texture nodes mixAlphaNode = TreeNodes.nodes.new(RGB_MIX_NODE) mixAlphaNode.name = 'Alpha Mix {:d}'.format(textureIdx) mixAlphaNode.blend_type = textureSlot.blend_type mixAlphaNode.inputs['Fac'].default_value = textureSlot.diffuse_color_factor placeNode(mixAlphaNode, -200 - ((texCount - textureIdx - 1) * 200), 400 - 240, textureNodeSizeX, textureNodeSizeY, 0, 0) links.new(texNode.outputs['Alpha'], mixAlphaNode.inputs['Color2']) links.new(latestNode.outputs['Alpha'], mixAlphaNode.inputs['Color1']) latestNode = mixAlphaNode except: continue if latestNode: alphaMixShader = TreeNodes.nodes.get('Alpha Mix Shader') if alphaMixShader: if latestNode.type == 'TEX_IMAGE': outputLink = 'Alpha' else: outputLink = 'Color' links.new(latestNode.outputs[outputLink], alphaMixShader.inputs['Fac']) def createNormalNodes(cmat, texCoordNode, mainShader, materialOutput): TreeNodes = cmat.node_tree links = TreeNodes.links texCount = len([node for node in TreeNodes.nodes if node.type == 'MAPPING']) currPosY = -textureNodeSizeY * texCount textureSlots = [textureSlot for textureSlot in cmat.texture_slots if (textureSlot and textureSlot.use_map_normal)] texCount = len(textureSlots) texNode = None latestNode = None groupName = 'Normal' if any(textureSlots): normalFrame = TreeNodes.nodes.new(NODE_FRAME) normalFrame.name = '{} Frame'.format(groupName) normalFrame.label = '{}'.format(groupName) for textureIdx, textureSlot in enumerate(textureSlots): texNode = getTexNodeDic(textureSlot.texture) if texNode: tex_node_name = getattr(texNode.image, "name", "") collect_report("INFO: Generating Normal Nodes for: " + tex_node_name) texNode.parent = normalFrame placeNode(texNode, -500 - ((texCount) * 200), currPosY, textureNodeSizeX, textureNodeSizeY, 0, textureIdx) # Add mapping node normalMapping = TreeNodes.nodes.new(MAPPING_NODE) normalMapping.parent = normalFrame renameNode(normalMapping, '{} Mapping'.format(groupName), texCount, textureIdx) normalMapping.location = texNode.location + Vector((-400, 0)) copyMapping(textureSlot, normalMapping) # Texture Coordinates BIToCycleTexCoord(links, textureSlot, texCoordNode, normalMapping) # Place the texture node renameNode(texNode, '{} Texture'.format(groupName), texCount, textureIdx) texNode.color_space = 'NONE' links.new(normalMapping.outputs['Vector'], texNode.inputs['Vector']) # Add multiply node normalMult = TreeNodes.nodes.new(RGB_MIX_NODE) normalMult.parent = normalFrame renameNode(normalMult, 'Normal Mult', texCount, textureIdx) normalMult.blend_type = 'MIX' normalMult.inputs['Fac'].default_value = 1 normalMult.inputs['Color1'].default_value = (.5, .5, 1, 1) normalMult.location = texNode.location + Vector((200, 0)) links.new(texNode.outputs['Color'], normalMult.inputs['Color2']) texNode = normalMult if textureSlot.use and textureIdx == 0: latestNode = texNode if textureSlot.use and textureIdx > 0: try: # Create a node to mix multiple texture nodes mixRgbNode = TreeNodes.nodes.new(RGB_MIX_NODE) mixRgbNode.parent = normalFrame addRGBMixNode(TreeNodes, textureSlot, mixRgbNode, texNode, latestNode, '{}'.format(groupName), textureIdx) mixRgbNode.location = Vector( (max(texNode.location.x, latestNode.location.x), (texNode.location.y + latestNode.location.y) / 2)) + Vector((200, 0) ) latestNode = mixRgbNode except: continue if latestNode: normalMapNode = TreeNodes.nodes.new(NORMAL_MAP_NODE) normalMapNode.parent = normalFrame normalMapNode.location = latestNode.location + Vector((200, 0)) links.new(latestNode.outputs['Color'], normalMapNode.inputs['Color']) links.new(normalMapNode.outputs['Normal'], mainShader.inputs['Normal']) def createSpecularNodes(cmat, texCoordNode, mainShader, mainDiffuse, materialOutput): TreeNodes = cmat.node_tree links = TreeNodes.links texCount = len([node for node in TreeNodes.nodes if node.type == 'MAPPING']) currPosY = -textureNodeSizeY * texCount textureSlots = [textureSlot for textureSlot in cmat.texture_slots if (textureSlot and textureSlot.use_map_color_spec)] texCount = len(textureSlots) texNode = None latestNode = None groupName = 'Specular' if any(textureSlots): specularFrame = TreeNodes.nodes.new(NODE_FRAME) specularFrame.name = '{} Frame'.format(groupName) specularFrame.label = '{}'.format(groupName) for textureIdx, textureSlot in enumerate(textureSlots): texNode = getTexNodeDic(textureSlot.texture) if texNode: tex_node_name = getattr(texNode.image, "name", "") collect_report("INFO: Generating {} Nodes for: ".format(groupName) + tex_node_name) texNode.parent = specularFrame placeNode(texNode, -500 - ((texCount) * 200), currPosY, textureNodeSizeX, textureNodeSizeY, 0, textureIdx) # Add mapping node specularMapping = TreeNodes.nodes.new(MAPPING_NODE) specularMapping.parent = specularFrame renameNode(specularMapping, '{} Mapping'.format(groupName), texCount, textureIdx) specularMapping.location = texNode.location + Vector((-400, 0)) copyMapping(textureSlot, specularMapping) # Texture Coordinates BIToCycleTexCoord(links, textureSlot, texCoordNode, specularMapping) # Place the texture node renameNode(texNode, '{} Texture'.format(groupName), texCount, textureIdx) links.new(specularMapping.outputs['Vector'], texNode.inputs['Vector']) # Add multiply node specularMult = TreeNodes.nodes.new(RGB_MIX_NODE) specularMult.parent = specularFrame renameNode(specularMult, 'Specular Mult', texCount, textureIdx) specularMult.blend_type = 'MULTIPLY' specularMult.inputs['Fac'].default_value = 1 specularMult.inputs['Color1'].default_value = (1, 1, 1, 1) specularMult.location = texNode.location + Vector((200, 0)) links.new(texNode.outputs['Color'], specularMult.inputs['Color2']) texNode = specularMult if textureSlot.use and textureIdx == 0: latestNode = texNode if textureSlot.use and textureIdx > 0: try: # Create a node to mix multiple texture nodes mixRgbNode = TreeNodes.nodes.new(RGB_MIX_NODE) mixRgbNode.parent = specularFrame addRGBMixNode(TreeNodes, textureSlot, mixRgbNode, texNode, latestNode, '{}'.format(groupName), textureIdx) mixRgbNode.location = Vector( (max(texNode.location.x, latestNode.location.x), (texNode.location.y + latestNode.location.y) / 2)) + Vector((200, 0) ) latestNode = mixRgbNode except: continue if latestNode: try: glossShader = TreeNodes.nodes.new(BSDF_GLOSSY_NODE) RGBToBW = TreeNodes.nodes.new(RGB_TO_BW_NODE) RGBToBW.location = Vector((0, latestNode.location.y)) + Vector((0, 0)) glossShader.location = Vector((0, latestNode.location.y)) + Vector((0, -80)) links.new(latestNode.outputs['Color'], glossShader.inputs['Color']) links.new(latestNode.outputs['Color'], RGBToBW.inputs['Color']) outputNode = TreeNodes.nodes.get('Material Output') spec_mixer_1 = TreeNodes.nodes.new(SHADER_MIX_NODE) spec_mixer_1.location = outputNode.location spec_mixer_2 = TreeNodes.nodes.new(SHADER_MIX_NODE) spec_mixer_2.inputs['Fac'].default_value = .4 spec_mixer_2.location = outputNode.location + Vector((180, 0)) links.new(spec_mixer_1.outputs['Shader'], spec_mixer_2.inputs[2]) links.new(spec_mixer_2.outputs['Shader'], outputNode.inputs['Surface']) links.new(RGBToBW.outputs['Val'], spec_mixer_1.inputs['Fac']) links.new(glossShader.outputs['BSDF'], spec_mixer_1.inputs[2]) outputNode.location += Vector((360, 0)) normalMapNode = TreeNodes.nodes.get('Normal Map') links.new(normalMapNode.outputs['Normal'], glossShader.inputs['Normal']) if mainDiffuse.type == 'BSDF_DIFFUSE': outputLink = 'BSDF' else: outputLink = 'Shader' links.new(mainDiffuse.outputs[outputLink], spec_mixer_1.inputs[1]) links.new(mainDiffuse.outputs[outputLink], spec_mixer_2.inputs[1]) except: return def createEmissionNodes(cmat, texCoordNode, mainShader, materialOutput): TreeNodes = cmat.node_tree links = TreeNodes.links texCount = len([node for node in TreeNodes.nodes if node.type == 'MAPPING']) currPosY = -textureNodeSizeY * texCount textureSlots = [textureSlot for textureSlot in cmat.texture_slots if (textureSlot and textureSlot.use_map_emit)] texCount = len(textureSlots) texNode = None latestNode = None groupName = 'Emission' if any(textureSlots): emissionFrame = TreeNodes.nodes.new(NODE_FRAME) emissionFrame.name = '{} Frame'.format(groupName) emissionFrame.label = '{}'.format(groupName) for textureIdx, textureSlot in enumerate(textureSlots): texNode = getTexNodeDic(textureSlot.texture) if texNode: tex_node_name = getattr(texNode.image, "name", "") collect_report("INFO: Generating {} Nodes for: ".format(groupName) + tex_node_name) texNode.parent = emissionFrame placeNode(texNode, -500 - ((texCount) * 200), currPosY, textureNodeSizeX, textureNodeSizeY, 0, textureIdx) # Add mapping node emissionMapping = TreeNodes.nodes.new(MAPPING_NODE) emissionMapping.parent = emissionFrame renameNode(emissionMapping, '{} Mapping'.format(groupName), texCount, textureIdx) emissionMapping.location = texNode.location + Vector((-400, 0)) copyMapping(textureSlot, emissionMapping) # Texture Coordinates BIToCycleTexCoord(links, textureSlot, texCoordNode, emissionMapping) # Place the texture node renameNode(texNode, '{} Texture'.format(groupName), texCount, textureIdx) texNode.color_space = 'NONE' links.new(emissionMapping.outputs['Vector'], texNode.inputs['Vector']) # Add multiply node emissionMult = TreeNodes.nodes.new(RGB_MIX_NODE) emissionMult.parent = emissionFrame renameNode(emissionMult, 'Emission Mult', texCount, textureIdx) emissionMult.blend_type = 'MIX' emissionMult.inputs['Fac'].default_value = 1 emissionMult.inputs['Color1'].default_value = (0, 0, 0, 1) emissionMult.location = texNode.location + Vector((200, 0)) links.new(texNode.outputs['Color'], emissionMult.inputs['Color2']) texNode = emissionMult if textureSlot.use and textureIdx == 0: latestNode = texNode if textureSlot.use and textureIdx > 0: try: # Create a node to mix multiple texture nodes mixRgbNode = TreeNodes.nodes.new(RGB_MIX_NODE) mixRgbNode.parent = emissionFrame addRGBMixNode(TreeNodes, textureSlot, mixRgbNode, texNode, latestNode, '{}'.format(groupName), textureIdx) mixRgbNode.location = Vector( (max(texNode.location.x, latestNode.location.x), (texNode.location.y + latestNode.location.y) / 2)) + Vector((200, 0) ) latestNode = mixRgbNode except: continue if latestNode: try: emissionNode = TreeNodes.nodes.new(BSDF_EMISSION_NODE) emissionNode.inputs['Strength'].default_value = 1 addShaderNode = TreeNodes.nodes.new(SHADER_ADD_NODE) addShaderNode.location = materialOutput.location + Vector((0, -100)) xPos = mainShader.location.x yPos = latestNode.location.y emissionNode.location = Vector((xPos, yPos)) materialOutput.location += Vector((400, 0)) node = materialOutput.inputs[0].links[0].from_node node.location += Vector((400, 0)) links.new(latestNode.outputs['Color'], emissionNode.inputs['Color']) links.new(emissionNode.outputs['Emission'], addShaderNode.inputs[1]) links.new(mainShader.outputs['BSDF'], addShaderNode.inputs[0]) links.new(addShaderNode.outputs['Shader'], node.inputs[2]) except: return def renameNode(node, baseName, nodesCount, nodeIndex): if nodesCount == 1: node.name = baseName else: node.name = '{} {:d}'.format(baseName, nodeIndex + 1) def hasAlphaTex(cmat): tex_is_transp = False for textureSlot in cmat.texture_slots: if textureSlot: if textureSlot.use: if textureSlot.use_map_alpha: tex_is_transp = tex_is_transp or True return tex_is_transp def AutoNode(active=False, operator=None): collect_report("________________________________________", True, False) collect_report("START CYCLES CONVERSION") if active: materials = [mat for obj in bpy.context.selected_objects if obj.type == 'MESH' for mat in obj.data.materials] else: materials = bpy.data.materials # No Materials for the chosen action - abort if not materials: if operator: if active: warning_messages(operator, 'CONV_NO_SEL_MAT', override=True) else: warning_messages(operator, 'CONV_NO_SC_MAT', override=True) return for cmat in materials: # check for empty material (it will fall through the first check) test_empty = getattr(cmat, "name", None) if test_empty is None: collect_report("INFO: An empty material was hit, skipping") continue else: cmat.use_nodes = True clearCycleMaterial(cmat) makeBiNodes(cmat) makeCyclesFromBI(cmat) collect_report("Conversion finished !", False, True) bpy.context.scene.render.engine = 'CYCLES' def makeCyclesFromBI(cmat): mat_name = getattr(cmat, "name", "NO NAME") collect_report("Converting Material: " + mat_name) global nodesDictionary TreeNodes = cmat.node_tree links = TreeNodes.links # Convert this material from non-nodes to Cycles nodes mainShader = None mainDiffuse = None Mix_Alpha = None tex_is_transp = hasAlphaTex(cmat) cmat_use_transp = cmat.use_transparency and cmat.alpha < 1 cmat_trans_method = cmat.transparency_method cmat_ior = cmat.raytrace_transparency.ior cmat_transp_z = cmat_use_transp and cmat_trans_method == 'Z_TRANSPARENCY' cmat_transp_ray = cmat_use_transp and cmat_trans_method == 'RAYTRACE' and cmat_ior == 1 cmat_mirror = cmat.raytrace_mirror.use cmat_mirror_fac = cmat.raytrace_mirror.reflect_factor # Material Shaders # Diffuse nodes # -------------------------------------- # Make Diffuse and Output nodes mainShader = makeMainShader(TreeNodes) mainShader.inputs['Roughness'].default_value = math.sqrt(max(cmat.specular_intensity, 0.0)) mainDiffuse = mainShader materialOutput = makeMaterialOutput(TreeNodes) links.new(mainShader.outputs['BSDF'], materialOutput.inputs['Surface']) texCoordNode = TreeNodes.nodes.new(COORD_NODE) texCoordNode.name = 'Texture Coordinate' # Material Transparent if not cmat_mirror and cmat_use_transp and tex_is_transp and (cmat_transp_z or cmat_transp_ray): collect_report("INFO: Make TRANSPARENT material nodes: " + cmat.name) Mix_Alpha = TreeNodes.nodes.new(SHADER_MIX_NODE) Mix_Alpha.name = 'Alpha Mix Shader' Mix_Alpha.location = materialOutput.location materialOutput.location += Vector((180, 0)) Mix_Alpha.inputs['Fac'].default_value = cmat.alpha transparentShader = TreeNodes.nodes.new(BSDF_TRANSPARENT_NODE) transparentShader.location = mainShader.location mainShader.location += Vector((0, -100)) links.new(transparentShader.outputs['BSDF'], Mix_Alpha.inputs[1]) links.new(mainShader.outputs['BSDF'], Mix_Alpha.inputs[2]) links.new(Mix_Alpha.outputs['Shader'], materialOutput.inputs['Surface']) mainDiffuse = Mix_Alpha if cmat_mirror and cmat_mirror_fac > 0.001: if cmat_use_transp: # Material Glass collect_report("INFO: Make GLASS shader node: " + cmat.name) newShader = TreeNodes.nodes.new(BSDF_GLASS_NODE) shader = newShader replaceNode(shader, newShader) TreeNodes.nodes.remove(shader) else: # Material Mirror collect_report("INFO: Make MIRROR shader node: " + cmat.name) newShader = TreeNodes.nodes.new(BSDF_GLOSSY_NODE) shader = newShader replaceNode(shader, newShader) TreeNodes.nodes.remove(shader) nodesDictionary = makeTextureNodeDict(cmat) # -------------------------------------- # Texture nodes # BI Material to Cycles - Diffuse Textures createDiffuseNodes(cmat, texCoordNode, mainShader, materialOutput) # BI Material to Cycles - Normal map createNormalNodes(cmat, texCoordNode, mainShader, materialOutput) # BI Material to Cycles - Specular map createSpecularNodes(cmat, texCoordNode, mainShader, mainDiffuse, materialOutput) # BI Material to Cycles - Emission map createEmissionNodes(cmat, texCoordNode, mainShader, materialOutput) # Texture coordinates # list all nodes connected to outputs mappingNodes = [link.to_node for output in texCoordNode.outputs for link in output.links] mappingNodesCount = len(mappingNodes) if mappingNodes: xList = [node.location.x for node in mappingNodes] yList = [node.location.y for node in mappingNodes] minPosX = min(xList) - 400 avgPosY = sum(yList) / mappingNodesCount texCoordNode.location = Vector((minPosX, avgPosY)) # ----------------------------------------------------------------------------- # Operator Classes class material_convert_all(Operator): bl_idname = "xps_tools.convert_to_cycles_all" bl_label = "Convert All Materials" bl_description = ("Convert All Materials to BI and Cycles Nodes\n" "Needs saving the .blend file first") bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): return (bpy.data.filepath != "" and c_is_cycles_addon_enabled() and c_data_has_materials()) def execute(self, context): AutoNode(False, self) return {'FINISHED'} class material_convert_selected(Operator): bl_idname = "xps_tools.convert_to_cycles_selected" bl_label = "Convert All Materials From Selected Objects" bl_description = ("Convert All Materials on Selected Objects to BI and Cycles Nodes\n" "Needs saving the .blend file first") bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): return (bpy.data.filepath != "" and c_data_has_materials() and c_is_cycles_addon_enabled() and bool(next((obj for obj in context.selected_objects if obj.type == 'MESH'), None)) ) def execute(self, context): AutoNode(True, self) return {'FINISHED'} def register(): bpy.utils.register_module(__name__) pass def unregister(): bpy.utils.unregister_module(__name__) pass if __name__ == "__main__": register()