Skip to content

Instantly share code, notes, and snippets.

@qubodup
Created March 27, 2018 15:21
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save qubodup/d3fc78f0aadb1df5581b76f4d556d25d to your computer and use it in GitHub Desktop.
Save qubodup/d3fc78f0aadb1df5581b76f4d556d25d to your computer and use it in GitHub Desktop.
Mirror of BI to Cycles Materials Converter for humane download option // https://blenderartists.org/forum/showthread.php?343575-BI-to-Cycles-Materials-Converter-(bug-fix-wip)
# convert_materials_to_cycles.py
#
# Copyright (C) 5-mar-2012, Silvio Falcinelli. Fixes by others.
#
# special thanks to user blenderartists.org cmomoney
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENCE BLOCK *****
bl_info = {
"name": "Convert Materials to Cycles",
"author": "Silvio Falcinelli",
"version": (0, 11),
"blender": (2, 68, 0),
"location": "Properties > Material > Convert to Cycles",
"description": "Convert non-nodes materials to Cycles",
"warning": "beta",
"wiki_url": 'http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/System/Convert_Materials_to_Cycles',
"category": "Materials"}
import bpy
import math
from math import log
from math import pow
from math import exp
import os.path
def AutoNodeOff():
mats = bpy.data.materials
for cmat in mats:
cmat.use_nodes = False
bpy.context.scene.render.engine = 'BLENDER_RENDER'
def BakingText(tex, mode):
print('________________________________________')
print('INFO start bake texture ' + tex.name)
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()
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:
sizeX = 600
sizeY = 600
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 mode == "ALPHA" and tex.texture.type == 'IMAGE':
img.filepath_raw = tex.texture.image.filepath + "_BAKING.jpg"
else:
img.filepath_raw = tex.texture.name + "_PTEXT.jpg"
sc.render.bake_type = 'ALPHA'
sc.render.use_bake_selected_to_active = True
sc.render.use_bake_clear = True
bpy.ops.object.bake_image()
img.save()
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)
bpy.data.materials.remove(tmat)
# print('INFO : end Bake ' + img.filepath_raw )
print('________________________________________')
def AutoNode(active=False):
sc = bpy.context.scene
if active:
mats = bpy.context.active_object.data.materials
else:
mats = bpy.data.materials
for cmat in mats:
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 = ''
shmix = ''
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])
sM = True
for tex in cmat.texture_slots:
if tex:
if tex.use:
if tex.use_map_alpha:
sM = False
if sc.EXTRACT_ALPHA:
if tex.texture.type == 'IMAGE' and tex.texture.use_alpha:
if not os.path.exists(bpy.path.abspath(tex.texture.image.filepath + "_BAKING.jpg")) or sc.EXTRACT_OW:
BakingText(tex, 'ALPHA')
else:
if not tex.texture.type == 'IMAGE':
if not os.path.exists(bpy.path.abspath(tex.texture.name + "_PTEXT.jpg")) or sc.EXTRACT_OW:
BakingText(tex, 'PTEXT')
cmat_is_transp = cmat.use_transparency and cmat.alpha < 1
if cmat_is_transp and cmat.raytrace_transparency.ior == 1 and not cmat.raytrace_mirror.use and sM:
if not shader.type == 'ShaderNodeBsdfTransparent':
print("INFO: Make TRANSPARENT shader node " + cmat.name)
TreeNodes.nodes.remove(shader)
shader = TreeNodes.nodes.new('ShaderNodeBsdfTransparent')
shader.location = 0, 470
links.new(shader.outputs[0], shout.inputs[0])
if not cmat.raytrace_mirror.use and not cmat_is_transp:
if not shader.type == 'ShaderNodeBsdfDiffuse':
print("INFO: Make DIFFUSE shader node" + 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':
print("INFO: Make GLASS shader node" + 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':
print("INFO: Make MIRROR shader node" + 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:
print("INFO: Mix EMISSION shader node" + 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:
print("INFO: Add EMISSION shader node" + 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 :
print("INFO: Add BSDF_TRANSLUCENT shader node" + 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
for tex in cmat.texture_slots:
sT = False
pText = ''
if tex:
if tex.use:
if tex.texture.type == 'IMAGE':
img = tex.texture.image
shtext = TreeNodes.nodes.new('ShaderNodeTexImage')
shtext.location = -200, 400
shtext.image = img
sT = True
if not tex.texture.type == 'IMAGE':
if sc.EXTRACT_PTEX:
print('INFO : Extract Procedural Texture ')
if not os.path.exists(bpy.path.abspath(tex.texture.name + "_PTEXT.jpg")) or sc.EXTRACT_OW:
BakingText(tex, 'PTEX')
img = bpy.data.images.load(tex.texture.name + "_PTEXT.jpg")
shtext = TreeNodes.nodes.new('ShaderNodeTexImage')
shtext.location = -200, 400
shtext.image = img
sT = True
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:
print("INFO: Mix EMISSION + Texture shader node " + 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:
print("INFO: Add Translucency + Texture shader node " + 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:
print("INFO: Mix Alpha + Texture shader node " + 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 = TreeNodes.nodes.new('ShaderNodeTexImage')
tMask.location = -200, 250
if tex.texture.type == 'IMAGE':
# if tex.texture.use_alpha:
# imask=bpy.data.images.load(img.filepath+"_BAKING.jpg")
# else:
imask = bpy.data.images.load(img.filepath)
else:
imask = bpy.data.images.load(img.name)
tMask.image = imask
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_Emission and not Add_Translucent:
links.new(Mix_Alpha.inputs[2], shader.outputs[0])
if Add_Emission and not Add_Translucent:
links.new(Mix_Alpha.inputs[2], Add_Emission.outputs[0])
if Add_Translucent:
links.new(Mix_Alpha.inputs[2], Add_Translucent.outputs[0])
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])
bpy.context.scene.render.engine = 'CYCLES'
class mllock(bpy.types.Operator):
bl_idname = "ml.lock"
bl_label = "Lock"
bl_description = "Lock/unlock this material against modification by conversions"
bl_register = True
bl_undo = True
@classmethod
def poll(cls, context):
return True
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(bpy.types.Operator):
bl_idname = "ml.refresh"
bl_label = "Convert All Materials"
bl_description = "Convert all materials in the scene from non-nodes to Cycles"
bl_register = True
bl_undo = True
@classmethod
def poll(cls, context):
return True
def execute(self, context):
AutoNode()
return {'FINISHED'}
class mlrefresh_active(bpy.types.Operator):
bl_idname = "ml.refresh_active"
bl_label = "Convert All Materials From Active Object"
bl_description = "Convert all materials from actice object from non-nodes to Cycles"
bl_register = True
bl_undo = True
@classmethod
def poll(cls, context):
return True
def execute(self, context):
AutoNode(True)
return {'FINISHED'}
class mlrestore(bpy.types.Operator):
bl_idname = "ml.restore"
bl_label = "Restore"
bl_description = "Restore"
bl_register = True
bl_undo = True
@classmethod
def poll(cls, context):
return True
def execute(self, context):
AutoNodeOff()
return {'FINISHED'}
from bpy.props import *
sc = bpy.types.Scene
sc.EXTRACT_ALPHA = BoolProperty(attr="EXTRACT_ALPHA", default=False)
sc.EXTRACT_PTEX = BoolProperty(attr="EXTRACT_PTEX", default=False)
sc.EXTRACT_OW = BoolProperty(attr="Overwrite", default=False, description="Extract textures again instead of re-using priorly extracted textures")
class OBJECT_PT_scenemassive(bpy.types.Panel):
bl_label = "Convert All Materials to Cycles"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "material"
def draw(self, context):
sc = context.scene
layout = self.layout
row = layout.row()
box = row.box()
box.operator("ml.refresh", text='Convert All to Cycles', icon='TEXTURE')
box.operator("ml.refresh_active", text='Convert Active to Cycles', icon='TEXTURE')
# box.prop(sc, "EXTRACT_ALPHA", text='Extract Alpha Textures (slow)')
# box.prop(sc, "EXTRACT_PTEX", text='Extract Procedural Textures (slow)')
# box.prop(sc, "EXTRACT_OW", text='Re-extract Textures')
row = layout.row()
row.operator("ml.restore", text='Back to Blender', icon='MATERIAL')
# Locking of nodes objects
try:
cmat = bpy.context.selected_objects[0].active_material
TreeNodes = cmat.node_tree # throws exception for non-nodes mats
locked = False
for n in TreeNodes.nodes: # throws exception if no node mat
if n.type == 'ShaderNodeOutputMaterial':
if n.label == 'Locked':
locked = True
break
row = layout.row()
row.label(text="Selected: " + cmat.name, icon=("LOCKED" if locked else "UNLOCKED"))
row.operator("ml.lock", text=("Unlock" if locked else "Lock"))
except:
pass
def register():
bpy.utils.register_module(__name__)
pass
def unregister():
bpy.utils.unregister_module(__name__)
pass
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment