Created
May 25, 2023 12:51
-
-
Save blender8r/3ea047af33381d0e41b8009115ccd0b8 to your computer and use it in GitHub Desktop.
Revisions
-
blender8r created this gist
May 25, 2023 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,233 @@ import bpy IMAGE = None TEXTURE_PATH = 'D:\\images\\textures\\hatch_1.jpg' for i in bpy.data.images: if i.filepath == TEXTURE_PATH: IMAGE = i if not IMAGE: IMAGE = bpy.data.images.load(TEXTURE_PATH) def add_group_controls(group, input_type, input_name, def_val, min_val=0.0, max_val=1.0): ctrl = group.inputs.new(input_type, input_name) ctrl.default_value = def_val if input_type == 'NodeSocketFloat' or input_type == 'NodeSocketFloatFactor': ctrl.min_value = min_val ctrl.max_value = max_val # based on TLousky's function posted in this thread # https://blender.stackexchange.com/questions/39127/how-to-put-together-a-driver-with-python/39129#39129 def add_driver(source, target, prop, dataPath, index = -1, negative = False, func = ''): if index != -1: d = source.driver_add(prop, index).driver else: d = source.driver_add(prop).driver v = d.variables.new() v.name = prop v.targets[0].id_type = 'MATERIAL' v.targets[0].id = target v.targets[0].data_path = dataPath d.expression = func + "(" + v.name + ")" if func else v.name d.expression = d.expression if not negative else "-1 * " + d.expression return d # create an ico sphere and set to smooth shade bpy.ops.mesh.primitive_ico_sphere_add() sphere = bpy.context.active_object for p in sphere.data.polygons: p.use_smooth = True # add subd modifier subd = sphere.modifiers.new('subsurf', type='SUBSURF') subd.levels = 3 # create new material mat_name = 'Ghibli Hatch Shader' mat = bpy.data.materials.new(mat_name) mat.use_nodes = True node_tree = mat.node_tree #nodes = node_tree.nodes links = node_tree.links sphere.data.materials.append(mat) # create control group group = bpy.data.node_groups.new(type='ShaderNodeTree', name='Ghibli Shader') nodes = group.nodes # add inputs with calls to our add input function add_group_controls(group, 'NodeSocketColor', 'Color A', (0.015, 0.125, 0.013, 1.0)) add_group_controls(group, 'NodeSocketColor', 'Color B', (0.481, 0.464, 0.153, 1.0)) add_group_controls(group, 'NodeSocketFloatFactor', 'Color A Clamp', 0.0) add_group_controls(group, 'NodeSocketFloatFactor', 'Color B Clamp', 0.7) add_group_controls(group, 'NodeSocketFloatFactor', 'Noise Strength', 0.75) add_group_controls(group, 'NodeSocketFloat', 'Noise Scale', 5.0, 0.0, 200.0) add_group_controls(group, 'NodeSocketFloatFactor', 'Noise Variation', 0.8) add_group_controls(group, 'NodeSocketFloatFactor', 'Noise Min', 0.0) add_group_controls(group, 'NodeSocketFloatFactor', 'Noise Max', 1.0) add_group_controls(group, 'NodeSocketFloatFactor', 'Noise Soft Min', 0.0) add_group_controls(group, 'NodeSocketFloatFactor', 'Color Soft Max', 0.9) add_group_controls(group, 'NodeSocketFloatFactor', 'Speckle Strength', 0.8) add_group_controls(group, 'NodeSocketFloat', 'Speckle Scale', 25.0, 0.0, 50.0) add_group_controls(group, 'NodeSocketFloatFactor', 'Shadow Blend', 1.0) add_group_controls(group, 'NodeSocketFloatFactor', 'Hatching Blend', 1.0) add_group_controls(group, 'NodeSocketVector', 'Hatching Scale', (8.0, 8.0, 8.0)) add_group_controls(group, 'NodeSocketFloatFactor', 'Hatching Falloff Min', 0.136) add_group_controls(group, 'NodeSocketFloatFactor', 'Hatching Falloff Max', 0.291) # create group inputs and outputs group.outputs.new('NodeSocketShader', 'Output1') output_node = group.nodes.new('NodeGroupOutput') input_node = group.nodes.new('NodeGroupInput') # assign the group to the main node tree group_node = node_tree.nodes.new('ShaderNodeGroup') group_node.node_tree = group ShaderNodeOutputMaterial_node = node_tree.nodes['Material Output'] links.new(group_node.outputs[0], ShaderNodeOutputMaterial_node.inputs[0]) # get main shader material output node node_mat_output = node_tree.nodes['Material Output'] # delete default bsdf node node_tree.nodes.remove(node_tree.nodes['Principled BSDF']) # create new nodes and set their values node_emission = nodes.new(type='ShaderNodeEmission') node_mix1 = nodes.new(type='ShaderNodeMixRGB') node_mix1.blend_type = 'MULTIPLY' node_mix1.inputs['Fac'].default_value = 1.0 node_mix1.label = 'Ink Effect Blend' node_mix2 = nodes.new(type='ShaderNodeMixRGB') node_mix2.blend_type = 'SOFT_LIGHT' node_mix2.inputs['Fac'].default_value = 0.75 node_mix2.label = 'Secondary Noise Strength' node_mix3 = nodes.new(type='ShaderNodeMixRGB') node_mix3.blend_type = 'SOFT_LIGHT' node_mix3.label = 'Hatching Effect Blend' node_mix4 = nodes.new(type='ShaderNodeMixRGB') node_mix4.blend_type = 'MIX' node_mix4.inputs['Fac'].default_value = 0.8 node_mix4.label = 'Speckle Effect Blend' node_color_ramp1 = nodes.new(type='ShaderNodeValToRGB') node_color_ramp1.color_ramp.elements[0].position = 0.0 node_color_ramp1.color_ramp.elements[0].color = (0.0373, 0.0752, 0.0305, 1.0) node_color_ramp1.color_ramp.elements[1].position = 0.7 node_color_ramp1.color_ramp.elements[1].color = (0.4351, 0.4297, 0.0953, 1.0) node_color_ramp1.label = 'Secondary Color Blend' node_color_ramp2 = nodes.new(type='ShaderNodeValToRGB') node_color_ramp2.color_ramp.elements[0].position = 0.15 node_color_ramp2.color_ramp.elements[1].position = 0.3 node_color_ramp2.label = 'Hatching Falloff' node_color_ramp3 = nodes.new(type='ShaderNodeValToRGB') node_color_ramp3.label = 'Voronoi Strength' node_color_ramp4 = nodes.new(type='ShaderNodeValToRGB') node_color_ramp4.color_ramp.elements[0].position = 0.5 node_color_ramp4.color_ramp.elements[1].position = 0.7 node_color_ramp4.label = 'Speckle Falloff' node_color_ramp5 = nodes.new(type='ShaderNodeValToRGB') node_color_ramp5.color_ramp.elements[0].position = 0.0 node_color_ramp5.color_ramp.elements[1].position = 0.9 node_color_ramp5.label = 'Voronoi Softness Variation' node_img_tex = nodes.new(type='ShaderNodeTexImage') node_img_tex.image = IMAGE node_img_tex.label = 'Hatching Texture Map' node_shader2RGB = nodes.new(type='ShaderNodeShaderToRGB') node_mapping = nodes.new(type='ShaderNodeMapping') node_mapping.inputs[3].default_value = (8.0, 8.0, 8.0) node_tex_coords = nodes.new(type='ShaderNodeTexCoord') node_diff_bsdf = nodes.new(type='ShaderNodeBsdfDiffuse') node_voronoi = nodes.new(type='ShaderNodeTexVoronoi') node_voronoi.feature = 'SMOOTH_F1' node_voronoi.inputs[2].default_value = 10.0 node_musgrave = nodes.new(type='ShaderNodeTexMusgrave') node_musgrave.inputs[2].default_value = 25.0 node_noise = nodes.new(type='ShaderNodeTexNoise') node_noise.inputs[2].default_value = 5.0 node_noise.inputs[4].default_value = 0.5 # link nodes together group.links.new(output_node.inputs['Output1'], node_emission.outputs['Emission']) group.links.new(node_emission.inputs['Color'], node_mix1.outputs['Color']) group.links.new(node_mix1.inputs['Color1'], node_color_ramp1.outputs['Color']) group.links.new(node_mix1.inputs['Color2'], node_color_ramp2.outputs['Color']) group.links.new(node_color_ramp1.inputs['Fac'], node_mix2.outputs['Color']) group.links.new(node_color_ramp2.inputs['Fac'], node_mix3.outputs['Color']) group.links.new(node_mix2.inputs['Color2'], node_mix4.outputs['Color']) group.links.new(node_mix4.inputs['Color2'], node_color_ramp4.outputs['Color']) group.links.new(node_color_ramp4.inputs['Fac'], node_musgrave.outputs['Fac']) group.links.new(node_mix4.inputs['Color1'], node_color_ramp3.outputs['Color']) group.links.new(node_color_ramp3.inputs['Fac'], node_voronoi.outputs['Color']) group.links.new(node_voronoi.inputs['Smoothness'], node_color_ramp5.outputs['Color']) group.links.new(node_color_ramp5.inputs['Fac'], node_noise.outputs['Color']) group.links.new(node_mix2.inputs['Color1'], node_shader2RGB.outputs['Color']) group.links.new(node_mix3.inputs['Color1'], node_shader2RGB.outputs['Color']) group.links.new(node_shader2RGB.inputs['Shader'], node_diff_bsdf.outputs['BSDF']) group.links.new(node_mix3.inputs['Color2'], node_img_tex.outputs['Color']) group.links.new(node_img_tex.inputs['Vector'], node_mapping.outputs['Vector']) group.links.new(node_mapping.inputs['Vector'], node_tex_coords.outputs['UV']) # link group controls to shader node inputs group.links.new(node_mix2.inputs['Fac'], input_node.outputs['Noise Strength']) group.links.new(node_noise.inputs['Scale'], input_node.outputs['Noise Variation']) group.links.new(node_voronoi.inputs['Scale'], input_node.outputs['Noise Scale']) group.links.new(node_mix4.inputs['Fac'], input_node.outputs['Speckle Strength']) group.links.new(node_musgrave.inputs['Scale'], input_node.outputs['Speckle Scale']) group.links.new(node_mix1.inputs['Fac'], input_node.outputs['Shadow Blend']) group.links.new(node_mix3.inputs['Fac'], input_node.outputs['Hatching Blend']) group.links.new(node_mapping.inputs['Scale'], input_node.outputs['Hatching Scale']) # add drivers for color ramps driver = add_driver(node_color_ramp1.color_ramp.elements[0], mat, 'position', 'node_tree.nodes["Group"].inputs["Color A Clamp"].default_value') driver = add_driver(node_color_ramp1.color_ramp.elements[1], mat, 'position', 'node_tree.nodes["Group"].inputs["Color B Clamp"].default_value') driver = add_driver(node_color_ramp3.color_ramp.elements[0], mat, 'position', 'node_tree.nodes["Group"].inputs["Noise Min"].default_value') driver = add_driver(node_color_ramp3.color_ramp.elements[1], mat, 'position', 'node_tree.nodes["Group"].inputs["Noise Max"].default_value') driver = add_driver(node_color_ramp5.color_ramp.elements[0], mat, 'position', 'node_tree.nodes["Group"].inputs["Noise Soft Min"].default_value') driver = add_driver(node_color_ramp5.color_ramp.elements[1], mat, 'position', 'node_tree.nodes["Group"].inputs["Noise Soft Max"].default_value') driver = add_driver(node_color_ramp2.color_ramp.elements[0], mat, 'position', 'node_tree.nodes["Group"].inputs["Hatching Falloff Min"].default_value') driver = add_driver(node_color_ramp2.color_ramp.elements[1], mat, 'position', 'node_tree.nodes["Group"].inputs["Hatching Falloff Max"].default_value') # add drivers for color ramp 1 colors per channel driver = add_driver(node_color_ramp1.color_ramp.elements[0], mat, 'color', 'node_tree.nodes["Group"].inputs["Color A"].default_value[0]', 0) driver = add_driver(node_color_ramp1.color_ramp.elements[0], mat, 'color', 'node_tree.nodes["Group"].inputs["Color A"].default_value[1]', 1) driver = add_driver(node_color_ramp1.color_ramp.elements[0], mat, 'color', 'node_tree.nodes["Group"].inputs["Color A"].default_value[2]', 2) driver = add_driver(node_color_ramp1.color_ramp.elements[0], mat, 'color', 'node_tree.nodes["Group"].inputs["Color A"].default_value[3]', 3) driver = add_driver(node_color_ramp1.color_ramp.elements[1], mat, 'color', 'node_tree.nodes["Group"].inputs["Color B"].default_value[0]', 0) driver = add_driver(node_color_ramp1.color_ramp.elements[1], mat, 'color', 'node_tree.nodes["Group"].inputs["Color B"].default_value[1]', 1) driver = add_driver(node_color_ramp1.color_ramp.elements[1], mat, 'color', 'node_tree.nodes["Group"].inputs["Color B"].default_value[2]', 2) driver = add_driver(node_color_ramp1.color_ramp.elements[1], mat, 'color', 'node_tree.nodes["Group"].inputs["Color B"].default_value[3]', 3)