← back to Handbag Authentication
handbag_data/github_datasets/amazon-berkeley-objects/render/utils/material.py
572 lines
import bpy
from typing import Tuple
from utils.node import set_socket_value_range, arrange_nodes, create_frame_node, clean_nodes
def create_texture_node(node_tree: bpy.types.NodeTree, path: str, is_color_data: bool) -> bpy.types.Node:
# Instantiate a new texture image node
texture_node = node_tree.nodes.new(type='ShaderNodeTexImage')
# Open an image and set it to the node
texture_node.image = bpy.data.images.load(path)
# Set other parameters
texture_node.image.colorspace_settings.is_data = False if is_color_data else True
# Return the node
return texture_node
def set_principled_node(principled_node: bpy.types.Node,
base_color: Tuple[float, float, float, float] = (0.6, 0.6, 0.6, 1.0),
subsurface: float = 0.0,
subsurface_color: Tuple[float, float, float, float] = (0.8, 0.8, 0.8, 1.0),
subsurface_radius: Tuple[float, float, float] = (1.0, 0.2, 0.1),
metallic: float = 0.0,
specular: float = 0.5,
specular_tint: float = 0.0,
roughness: float = 0.5,
anisotropic: float = 0.0,
anisotropic_rotation: float = 0.0,
sheen: float = 0.0,
sheen_tint: float = 0.5,
clearcoat: float = 0.0,
clearcoat_roughness: float = 0.03,
ior: float = 1.45,
transmission: float = 0.0,
transmission_roughness: float = 0.0) -> None:
principled_node.inputs['Base Color'].default_value = base_color
principled_node.inputs['Subsurface'].default_value = subsurface
principled_node.inputs['Subsurface Color'].default_value = subsurface_color
principled_node.inputs['Subsurface Radius'].default_value = subsurface_radius
principled_node.inputs['Metallic'].default_value = metallic
principled_node.inputs['Specular'].default_value = specular
principled_node.inputs['Specular Tint'].default_value = specular_tint
principled_node.inputs['Roughness'].default_value = roughness
principled_node.inputs['Anisotropic'].default_value = anisotropic
principled_node.inputs['Anisotropic Rotation'].default_value = anisotropic_rotation
principled_node.inputs['Sheen'].default_value = sheen
principled_node.inputs['Sheen Tint'].default_value = sheen_tint
principled_node.inputs['Clearcoat'].default_value = clearcoat
principled_node.inputs['Clearcoat Roughness'].default_value = clearcoat_roughness
principled_node.inputs['IOR'].default_value = ior
principled_node.inputs['Transmission'].default_value = transmission
principled_node.inputs['Transmission Roughness'].default_value = transmission_roughness
def build_pbr_nodes(node_tree: bpy.types.NodeTree,
base_color: Tuple[float, float, float, float] = (0.6, 0.6, 0.6, 1.0),
metallic: float = 0.0,
specular: float = 0.5,
roughness: float = 0.5,
sheen: float = 0.0) -> None:
output_node = node_tree.nodes.new(type='ShaderNodeOutputMaterial')
principled_node = node_tree.nodes.new(type='ShaderNodeBsdfPrincipled')
node_tree.links.new(principled_node.outputs['BSDF'], output_node.inputs['Surface'])
set_principled_node(principled_node=principled_node,
base_color=base_color,
metallic=metallic,
specular=specular,
roughness=roughness,
sheen=sheen)
arrange_nodes(node_tree)
def build_checker_board_nodes(node_tree: bpy.types.NodeTree, size: float) -> None:
output_node = node_tree.nodes.new(type='ShaderNodeOutputMaterial')
principled_node = node_tree.nodes.new(type='ShaderNodeBsdfPrincipled')
checker_texture_node = node_tree.nodes.new(type='ShaderNodeTexChecker')
set_principled_node(principled_node=principled_node)
checker_texture_node.inputs['Scale'].default_value = size
node_tree.links.new(checker_texture_node.outputs['Color'], principled_node.inputs['Base Color'])
node_tree.links.new(principled_node.outputs['BSDF'], output_node.inputs['Surface'])
arrange_nodes(node_tree)
def build_matcap_nodes(node_tree: bpy.types.NodeTree, image_path: str) -> None:
tex_coord_node = node_tree.nodes.new(type='ShaderNodeTexCoord')
vector_transform_node = node_tree.nodes.new(type='ShaderNodeVectorTransform')
mapping_node = node_tree.nodes.new(type='ShaderNodeMapping')
texture_image_node = create_texture_node(node_tree, image_path, True)
emmission_node = node_tree.nodes.new(type='ShaderNodeEmission')
output_node = node_tree.nodes.new(type='ShaderNodeOutputMaterial')
create_frame_node(node_tree, (tex_coord_node, vector_transform_node, mapping_node),
name="MatCap UV",
label="MatCap UV")
vector_transform_node.vector_type = "VECTOR"
vector_transform_node.convert_from = "OBJECT"
vector_transform_node.convert_to = "CAMERA"
mapping_node.vector_type = "TEXTURE"
if bpy.app.version >= (2, 81, 0):
mapping_node.inputs["Location"].default_value = (1.0, 1.0, 0.0)
mapping_node.inputs["Scale"].default_value = (2.0, 2.0, 1.0)
else:
mapping_node.translation = (1.0, 1.0, 0.0)
mapping_node.scale = (2.0, 2.0, 1.0)
node_tree.links.new(tex_coord_node.outputs['Normal'], vector_transform_node.inputs['Vector'])
node_tree.links.new(vector_transform_node.outputs['Vector'], mapping_node.inputs['Vector'])
node_tree.links.new(mapping_node.outputs['Vector'], texture_image_node.inputs['Vector'])
node_tree.links.new(texture_image_node.outputs['Color'], emmission_node.inputs['Color'])
node_tree.links.new(emmission_node.outputs['Emission'], output_node.inputs['Surface'])
arrange_nodes(node_tree)
def build_pbr_textured_nodes(
node_tree: bpy.types.NodeTree,
color_texture_path: str = "",
metallic_texture_path: str = "",
roughness_texture_path: str = "",
normal_texture_path: str = "",
displacement_texture_path: str = "",
ambient_occlusion_texture_path: str = "",
scale: Tuple[float, float, float] = (1.0, 1.0, 1.0)) -> None:
output_node = node_tree.nodes.new(type='ShaderNodeOutputMaterial')
principled_node = node_tree.nodes.new(type='ShaderNodeBsdfPrincipled')
node_tree.links.new(principled_node.outputs['BSDF'], output_node.inputs['Surface'])
coord_node = node_tree.nodes.new(type='ShaderNodeTexCoord')
mapping_node = node_tree.nodes.new(type='ShaderNodeMapping')
mapping_node.vector_type = 'TEXTURE'
mapping_node.scale = scale
node_tree.links.new(coord_node.outputs['UV'], mapping_node.inputs['Vector'])
if color_texture_path != "":
texture_node = create_texture_node(node_tree, color_texture_path, True)
node_tree.links.new(mapping_node.outputs['Vector'], texture_node.inputs['Vector'])
if ambient_occlusion_texture_path != "":
ao_texture_node = create_texture_node(node_tree, ambient_occlusion_texture_path, False)
node_tree.links.new(mapping_node.outputs['Vector'], ao_texture_node.inputs['Vector'])
mix_node = node_tree.nodes.new(type='ShaderNodeMixRGB')
mix_node.blend_type = 'MULTIPLY'
node_tree.links.new(texture_node.outputs['Color'], mix_node.inputs['Color1'])
node_tree.links.new(ao_texture_node.outputs['Color'], mix_node.inputs['Color2'])
node_tree.links.new(mix_node.outputs['Color'], principled_node.inputs['Base Color'])
else:
node_tree.links.new(texture_node.outputs['Color'], principled_node.inputs['Base Color'])
if metallic_texture_path != "":
texture_node = create_texture_node(node_tree, metallic_texture_path, False)
node_tree.links.new(mapping_node.outputs['Vector'], texture_node.inputs['Vector'])
node_tree.links.new(texture_node.outputs['Color'], principled_node.inputs['Metallic'])
if roughness_texture_path != "":
texture_node = create_texture_node(node_tree, roughness_texture_path, False)
node_tree.links.new(mapping_node.outputs['Vector'], texture_node.inputs['Vector'])
node_tree.links.new(texture_node.outputs['Color'], principled_node.inputs['Roughness'])
if normal_texture_path != "":
texture_node = create_texture_node(node_tree, normal_texture_path, False)
node_tree.links.new(mapping_node.outputs['Vector'], texture_node.inputs['Vector'])
normal_map_node = node_tree.nodes.new(type='ShaderNodeNormalMap')
node_tree.links.new(texture_node.outputs['Color'], normal_map_node.inputs['Color'])
node_tree.links.new(normal_map_node.outputs['Normal'], principled_node.inputs['Normal'])
if displacement_texture_path != "":
texture_node = create_texture_node(node_tree, displacement_texture_path, False)
node_tree.links.new(mapping_node.outputs['Vector'], texture_node.inputs['Vector'])
node_tree.links.new(texture_node.outputs['Color'], output_node.inputs['Displacement'])
arrange_nodes(node_tree)
def add_parametric_color_ramp() -> bpy.types.NodeGroup:
group = bpy.data.node_groups.new(type="ShaderNodeTree", name="Parametric Color Ramp")
# Input
input_node = group.nodes.new(type="NodeGroupInput")
group.inputs.new("NodeSocketFloatFactor", "Fac")
group.inputs.new("NodeSocketColor", "Color1")
group.inputs.new("NodeSocketColor", "Color2")
group.inputs.new("NodeSocketFloatFactor", "Pos1")
group.inputs.new("NodeSocketFloatFactor", "Pos2")
set_socket_value_range(group.inputs["Fac"], default_value=0.5)
set_socket_value_range(group.inputs["Pos1"], default_value=0.0)
set_socket_value_range(group.inputs["Pos2"], default_value=1.0)
# Math
denominator_subtract_node = group.nodes.new(type="ShaderNodeMath")
denominator_subtract_node.operation = "SUBTRACT"
denominator_subtract_node.use_clamp = True
numerator_subtract_node = group.nodes.new(type="ShaderNodeMath")
numerator_subtract_node.operation = "SUBTRACT"
numerator_subtract_node.use_clamp = True
divide_node = group.nodes.new(type="ShaderNodeMath")
divide_node.operation = "DIVIDE"
divide_node.use_clamp = True
group.links.new(input_node.outputs["Pos2"], denominator_subtract_node.inputs[0])
group.links.new(input_node.outputs["Fac"], denominator_subtract_node.inputs[1])
group.links.new(input_node.outputs["Pos2"], numerator_subtract_node.inputs[0])
group.links.new(input_node.outputs["Pos1"], numerator_subtract_node.inputs[1])
group.links.new(denominator_subtract_node.outputs["Value"], divide_node.inputs[0])
group.links.new(numerator_subtract_node.outputs["Value"], divide_node.inputs[1])
# Mixing
mix_node = group.nodes.new(type="ShaderNodeMixRGB")
group.links.new(divide_node.outputs["Value"], mix_node.inputs["Fac"])
group.links.new(input_node.outputs["Color2"], mix_node.inputs[1])
group.links.new(input_node.outputs["Color1"], mix_node.inputs[2])
# Output
output_node = group.nodes.new(type="NodeGroupOutput")
group.outputs.new("NodeSocketColor", "Color")
group.links.new(mix_node.outputs["Color"], output_node.inputs["Color"])
# Return
arrange_nodes(group)
return group
def create_parametric_color_ramp_node(node_tree: bpy.types.NodeTree) -> bpy.types.Node:
color_ramp_node_group: bpy.types.NodeGroup
if "Parametric Color Ramp" in bpy.data.node_groups:
color_ramp_node_group = bpy.data.node_groups["Parametric Color Ramp"]
else:
color_ramp_node_group = add_parametric_color_ramp()
node = node_tree.nodes.new(type='ShaderNodeGroup')
node.name = "Parametric Color Ramp"
node.node_tree = color_ramp_node_group
return node
def add_tri_parametric_color_ramp() -> bpy.types.NodeGroup:
group = bpy.data.node_groups.new(type="ShaderNodeTree", name="Tri Parametric Color Ramp")
# Input
input_node = group.nodes.new(type="NodeGroupInput")
group.inputs.new("NodeSocketFloatFactor", "Fac")
group.inputs.new("NodeSocketColor", "Color1")
group.inputs.new("NodeSocketColor", "Color2")
group.inputs.new("NodeSocketColor", "Color3")
group.inputs.new("NodeSocketFloatFactor", "Pos1")
group.inputs.new("NodeSocketFloatFactor", "Pos2")
group.inputs.new("NodeSocketFloatFactor", "Pos3")
set_socket_value_range(group.inputs["Fac"], default_value=0.5)
set_socket_value_range(group.inputs["Pos1"], default_value=0.25)
set_socket_value_range(group.inputs["Pos2"], default_value=0.50)
set_socket_value_range(group.inputs["Pos3"], default_value=0.75)
# Nested color ramp
nested_color_ramp_node = create_parametric_color_ramp_node(group)
group.links.new(input_node.outputs["Color1"], nested_color_ramp_node.inputs["Color1"])
group.links.new(input_node.outputs["Color2"], nested_color_ramp_node.inputs["Color2"])
group.links.new(input_node.outputs["Pos1"], nested_color_ramp_node.inputs["Pos1"])
group.links.new(input_node.outputs["Pos2"], nested_color_ramp_node.inputs["Pos2"])
group.links.new(input_node.outputs["Fac"], nested_color_ramp_node.inputs["Fac"])
# Math
denominator_subtract_node = group.nodes.new(type="ShaderNodeMath")
denominator_subtract_node.operation = "SUBTRACT"
denominator_subtract_node.use_clamp = True
numerator_subtract_node = group.nodes.new(type="ShaderNodeMath")
numerator_subtract_node.operation = "SUBTRACT"
numerator_subtract_node.use_clamp = True
divide_node = group.nodes.new(type="ShaderNodeMath")
divide_node.operation = "DIVIDE"
divide_node.use_clamp = True
group.links.new(input_node.outputs["Pos3"], denominator_subtract_node.inputs[0])
group.links.new(input_node.outputs["Fac"], denominator_subtract_node.inputs[1])
group.links.new(input_node.outputs["Pos3"], numerator_subtract_node.inputs[0])
group.links.new(input_node.outputs["Pos2"], numerator_subtract_node.inputs[1])
group.links.new(denominator_subtract_node.outputs["Value"], divide_node.inputs[0])
group.links.new(numerator_subtract_node.outputs["Value"], divide_node.inputs[1])
# Mixing
mix_node = group.nodes.new(type="ShaderNodeMixRGB")
group.links.new(divide_node.outputs["Value"], mix_node.inputs["Fac"])
group.links.new(input_node.outputs["Color3"], mix_node.inputs[1])
group.links.new(nested_color_ramp_node.outputs["Color"], mix_node.inputs[2])
# Output
output_node = group.nodes.new(type="NodeGroupOutput")
group.outputs.new("NodeSocketColor", "Color")
group.links.new(mix_node.outputs["Color"], output_node.inputs["Color"])
# Return
arrange_nodes(group)
return group
def create_tri_parametric_color_ramp_node(node_tree: bpy.types.NodeTree) -> bpy.types.Node:
tri_color_ramp_node_group: bpy.types.NodeGroup
if "Tri Parametric Color Ramp" in bpy.data.node_groups:
tri_color_ramp_node_group = bpy.data.node_groups["Tri Parametric Color Ramp"]
else:
tri_color_ramp_node_group = add_tri_parametric_color_ramp()
node = node_tree.nodes.new(type='ShaderNodeGroup')
node.name = "Tri Parametric Color Ramp"
node.node_tree = tri_color_ramp_node_group
return node
def add_peeling_paint_metal_node_group() -> bpy.types.NodeGroup:
group = bpy.data.node_groups.new(type="ShaderNodeTree", name="Peeling Paint Metal")
input_node = group.nodes.new(type="NodeGroupInput")
group.inputs.new("NodeSocketColor", "Paint Color")
group.inputs.new("NodeSocketFloatFactor", "Paint Roughness")
group.inputs.new("NodeSocketColor", "Metal Color")
group.inputs.new("NodeSocketFloatFactor", "Metal Roughness")
group.inputs.new("NodeSocketFloat", "Scale")
group.inputs.new("NodeSocketFloat", "Detail")
group.inputs.new("NodeSocketFloat", "Distortion")
group.inputs.new("NodeSocketFloatFactor", "Threshold")
group.inputs.new("NodeSocketFloat", "Peel Intense")
group.inputs["Paint Color"].default_value = (0.152, 0.524, 0.067, 1.000)
group.inputs["Metal Color"].default_value = (0.062, 0.015, 0.011, 1.000)
set_socket_value_range(group.inputs["Paint Roughness"], default_value=0.05)
set_socket_value_range(group.inputs["Metal Roughness"], default_value=0.50)
set_socket_value_range(group.inputs["Scale"], default_value=4.5, min_value=0.0, max_value=1000.0)
set_socket_value_range(group.inputs["Detail"], default_value=8.0, min_value=0.0, max_value=16.0)
set_socket_value_range(group.inputs["Distortion"], default_value=0.5, min_value=0.0, max_value=1000.0)
set_socket_value_range(group.inputs["Threshold"], default_value=0.42)
set_socket_value_range(group.inputs["Peel Intense"], default_value=0.2, min_value=0.0, max_value=1.0)
tex_coord_node = group.nodes.new(type="ShaderNodeTexCoord")
mapping_node = group.nodes.new(type="ShaderNodeMapping")
group.links.new(tex_coord_node.outputs["Object"], mapping_node.inputs["Vector"])
# Peeling region segmentation
peeling_noise_node = group.nodes.new(type="ShaderNodeTexNoise")
group.links.new(mapping_node.outputs["Vector"], peeling_noise_node.inputs["Vector"])
group.links.new(input_node.outputs["Scale"], peeling_noise_node.inputs["Scale"])
group.links.new(input_node.outputs["Detail"], peeling_noise_node.inputs["Detail"])
group.links.new(input_node.outputs["Distortion"], peeling_noise_node.inputs["Distortion"])
peeling_threshold_node = create_parametric_color_ramp_node(group)
peeling_threshold_node.inputs["Color1"].default_value = (0.0, 0.0, 0.0, 1.0)
peeling_threshold_node.inputs["Color2"].default_value = (1.0, 1.0, 1.0, 1.0)
# Base color
epsilon_subtract_node = group.nodes.new(type="ShaderNodeMath")
epsilon_subtract_node.operation = "SUBTRACT"
epsilon_subtract_node.inputs[1].default_value = 0.001
group.links.new(input_node.outputs["Threshold"], epsilon_subtract_node.inputs[0])
group.links.new(peeling_noise_node.outputs["Fac"], peeling_threshold_node.inputs["Fac"])
group.links.new(epsilon_subtract_node.outputs["Value"], peeling_threshold_node.inputs["Pos1"])
group.links.new(input_node.outputs["Threshold"], peeling_threshold_node.inputs["Pos2"])
color_mix_node = group.nodes.new(type="ShaderNodeMixRGB")
group.links.new(peeling_threshold_node.outputs["Color"], color_mix_node.inputs["Fac"])
group.links.new(input_node.outputs["Metal Color"], color_mix_node.inputs[1])
group.links.new(input_node.outputs["Paint Color"], color_mix_node.inputs[2])
# Ambient occulusion
epsilon_add_node = group.nodes.new(type="ShaderNodeMath")
epsilon_add_node.operation = "ADD"
epsilon_add_node.inputs[1].default_value = 0.010
group.links.new(input_node.outputs["Threshold"], epsilon_add_node.inputs[0])
fallout_subtract_node = group.nodes.new(type="ShaderNodeMath")
fallout_subtract_node.operation = "SUBTRACT"
fallout_subtract_node.inputs[1].default_value = 0.060
group.links.new(input_node.outputs["Threshold"], fallout_subtract_node.inputs[0])
ao_node = create_tri_parametric_color_ramp_node(group)
ao_node.inputs["Color1"].default_value = (1.0, 1.0, 1.0, 1.0)
ao_node.inputs["Color2"].default_value = (0.0, 0.0, 0.0, 1.0)
ao_node.inputs["Color3"].default_value = (1.0, 1.0, 1.0, 1.0)
group.links.new(peeling_noise_node.outputs["Fac"], ao_node.inputs["Fac"])
group.links.new(fallout_subtract_node.outputs["Value"], ao_node.inputs["Pos1"])
group.links.new(input_node.outputs["Threshold"], ao_node.inputs["Pos2"])
group.links.new(epsilon_add_node.outputs["Value"], ao_node.inputs["Pos3"])
ao_mix_node = group.nodes.new(type="ShaderNodeMixRGB")
ao_mix_node.blend_type = "MULTIPLY"
ao_mix_node.inputs["Fac"].default_value = 1.0
group.links.new(color_mix_node.outputs["Color"], ao_mix_node.inputs[1])
group.links.new(ao_node.outputs["Color"], ao_mix_node.inputs[2])
create_frame_node(group, nodes=(epsilon_add_node, fallout_subtract_node, ao_node), name="AO", label="AO")
# Metallic
metallic_node = group.nodes.new(type="ShaderNodeMixRGB")
metallic_node.inputs["Color1"].default_value = (1.0, 1.0, 1.0, 1.0)
metallic_node.inputs["Color2"].default_value = (0.0, 0.0, 0.0, 1.0)
group.links.new(peeling_threshold_node.outputs["Color"], metallic_node.inputs["Fac"])
# Roughness
roughness_node = group.nodes.new(type="ShaderNodeMixRGB")
group.links.new(input_node.outputs["Metal Roughness"], roughness_node.inputs["Color1"])
group.links.new(input_node.outputs["Paint Roughness"], roughness_node.inputs["Color2"])
group.links.new(peeling_threshold_node.outputs["Color"], roughness_node.inputs["Fac"])
# Bump
height_node = create_tri_parametric_color_ramp_node(group)
height_node.inputs["Color1"].default_value = (0.0, 0.0, 0.0, 1.0)
height_node.inputs["Color2"].default_value = (1.0, 1.0, 1.0, 1.0)
height_node.inputs["Color3"].default_value = (0.5, 0.5, 0.5, 1.0)
height_peak_add_node = group.nodes.new(type="ShaderNodeMath")
height_peak_add_node.operation = "MULTIPLY_ADD"
height_peak_add_node.inputs[1].default_value = 0.025
height_peak_add_node.label = "Height Peak Add"
height_tail_add_node = group.nodes.new(type="ShaderNodeMath")
height_tail_add_node.operation = "MULTIPLY_ADD"
height_tail_add_node.inputs[1].default_value = 0.100
height_tail_add_node.label = "Height Tail Add"
group.links.new(input_node.outputs["Threshold"], height_peak_add_node.inputs[2])
group.links.new(input_node.outputs["Peel Intense"], height_peak_add_node.inputs[0])
group.links.new(height_peak_add_node.outputs["Value"], height_tail_add_node.inputs[2])
group.links.new(input_node.outputs["Peel Intense"], height_tail_add_node.inputs[0])
group.links.new(peeling_noise_node.outputs["Fac"], height_node.inputs["Fac"])
group.links.new(input_node.outputs["Threshold"], height_node.inputs["Pos1"])
group.links.new(height_peak_add_node.outputs["Value"], height_node.inputs["Pos2"])
group.links.new(height_tail_add_node.outputs["Value"], height_node.inputs["Pos3"])
bump_node = group.nodes.new(type="ShaderNodeBump")
group.links.new(height_node.outputs["Color"], bump_node.inputs["Height"])
create_frame_node(group,
nodes=(height_node, height_peak_add_node, height_tail_add_node, bump_node),
name="Bump",
label="Bump")
# Output
output_node = group.nodes.new("NodeGroupOutput")
group.outputs.new("NodeSocketColor", "Color")
group.outputs.new("NodeSocketFloatFactor", "Metallic")
group.outputs.new("NodeSocketFloatFactor", "Roughness")
group.outputs.new("NodeSocketVectorDirection", "Bump")
group.links.new(ao_mix_node.outputs["Color"], output_node.inputs["Color"])
group.links.new(metallic_node.outputs["Color"], output_node.inputs["Metallic"])
group.links.new(roughness_node.outputs["Color"], output_node.inputs["Roughness"])
group.links.new(bump_node.outputs["Normal"], output_node.inputs["Bump"])
arrange_nodes(group)
return group
def create_peeling_paint_metal_node_group(node_tree: bpy.types.NodeTree) -> bpy.types.Node:
peeling_paint_metal_node_group: bpy.types.NodeGroup
if "Peeling Paint Metal" in bpy.data.node_groups:
peeling_paint_metal_node_group = bpy.data.node_groups["Peeling Paint Metal"]
else:
peeling_paint_metal_node_group = add_peeling_paint_metal_node_group()
node = node_tree.nodes.new(type='ShaderNodeGroup')
node.name = "Peeling Paint Metal"
node.node_tree = peeling_paint_metal_node_group
return node
def build_peeling_paint_metal_nodes(node_tree: bpy.types.NodeTree) -> None:
output_node = node_tree.nodes.new(type='ShaderNodeOutputMaterial')
principled_node = node_tree.nodes.new(type='ShaderNodeBsdfPrincipled')
peeling_paint_metal_node = create_peeling_paint_metal_node_group(node_tree)
node_tree.links.new(peeling_paint_metal_node.outputs['Color'], principled_node.inputs['Base Color'])
node_tree.links.new(peeling_paint_metal_node.outputs['Metallic'], principled_node.inputs['Metallic'])
node_tree.links.new(peeling_paint_metal_node.outputs['Roughness'], principled_node.inputs['Roughness'])
node_tree.links.new(peeling_paint_metal_node.outputs['Bump'], principled_node.inputs['Normal'])
node_tree.links.new(principled_node.outputs['BSDF'], output_node.inputs['Surface'])
arrange_nodes(node_tree)
def build_emission_nodes(node_tree: bpy.types.NodeTree,
color: Tuple[float, float, float] = (0.0, 0.0, 0.0),
strength: float = 1.0) -> None:
'''
https://docs.blender.org/api/current/bpy.types.ShaderNodeEmission.html
'''
output_node = node_tree.nodes.new(type='ShaderNodeOutputMaterial')
emission_node = node_tree.nodes.new(type='ShaderNodeEmission')
emission_node.inputs["Color"].default_value = color + (1.0, )
emission_node.inputs["Strength"].default_value = strength
node_tree.links.new(emission_node.outputs['Emission'], output_node.inputs['Surface'])
arrange_nodes(node_tree)
def add_material(name: str = "Material",
use_nodes: bool = False,
make_node_tree_empty: bool = False) -> bpy.types.Material:
'''
https://docs.blender.org/api/current/bpy.types.BlendDataMaterials.html
https://docs.blender.org/api/current/bpy.types.Material.html
'''
# TODO: Check whether the name is already used or not
material = bpy.data.materials.new(name)
material.use_nodes = use_nodes
if use_nodes and make_node_tree_empty:
clean_nodes(material.node_tree.nodes)
return material