Skip to content

Instantly share code, notes, and snippets.

@wakarase
Created March 28, 2023 08:01
Show Gist options
  • Save wakarase/34c23eb7c4b5fdd0f8c97fc30469f462 to your computer and use it in GitHub Desktop.
Save wakarase/34c23eb7c4b5fdd0f8c97fc30469f462 to your computer and use it in GitHub Desktop.
# Blender 質感・マテリアル設定実践テクニック
# 3-05-02.blend 錆びの作り方
import bpy
NOT_MODIFIED = False
object = bpy.data.objects['export3dcoat'] # シーンに配置済みのオブジェクト
slot = object.material_slots[0] # そのマテリアルスロット
material = slot.material # に設定されているマテリアル
node_tree = material.node_tree # のノードネットワーク
nodes = node_tree.nodes # にある各ノード
def delete():
"""過去に生成したノードを削除します。"""
for node in nodes:
if node.label.endswith(' del'):
nodes.remove(node)
delete()
def show():
"""既存のノードの情報を表示します。"""
for node in nodes:
s = 'node "{}" at {}'
s = s.format(node.name, list(node.location))
print(s, type(node))
show()
def format_key(key):
"""与えられた文字列を加工して必要なら整数にします。"""
if key.startswith('_'):
return int(key[1:]) # 先頭の下線で整数を表すことにします。
else:
key = key.rstrip('_') # 末尾の下線は無視することにします。
return key.replace('_', ' ') # 中間の下線で空白を表すことにします。
def create(name, location, **args):
"""新しくノードを作ってlocationに配置します。"""
if name in ['Reroute']:
node = nodes.new('Node' + name)
else:
node = nodes.new('ShaderNode' + name)
node.label = node.name + ' del' # 自動生成したノードだというフラグです。
x_offset = -2000
node.location = location[0] + x_offset, location[1]
for key, value in args.items():
node.inputs[format_key(key)].default_value = value
return node
def link(**args):
"""2つのノードを接続します。"""
(k_left, v_left), (k_right, v_right) = args.items()
k_left, k_right = format_key(k_left), format_key(k_right)
node_tree.links.new(v_right.inputs[k_right], v_left.outputs[k_left])
def create_uneven_color():
"""色ムラの設定を用意します。これだけでもマテリアルとして完結します。"""
texture_coordinate = create('TexCoord', (-1648, -90))
# 第1マスグレイブ。汚れの分布を定義します。
# 次元を増やして、汚れのぼやけ具合を調整できます。
musgrave_texture = create('TexMusgrave', (-1316, 289), Scale=2, Detail=15, Dimension=0.2, Lacunarity=1.4)
link(Object=texture_coordinate, Vector=musgrave_texture)
# +0.5が基本で、値を増やすほど汚れが広がります。
# さほど広くない錆びの範囲として+0.7にします。
if NOT_MODIFIED:
add = create('Math', (-1024, 182), _1=0.7)
else:
add = create('Math', (-1024, 182), _1=0.0)
link(Fac=musgrave_texture, Value=add)
reroute = create('Reroute', (-650, 110))
link(Value=add, Input=reroute)
# 汚れていない部分や汚れている部分に対応する色を定義します。
# 金属の腐食の複雑な色変化を表現するため、カラーミックスではなくカラーランプを使います。
color_ramp = create('ValToRGB', (-573, 441))
elements = color_ramp.color_ramp.elements
element = elements[0]
element.color = 0.560, 0.570, 0.580, 1.000 # 0xC5C7C8 錆びていない鉄。
element = elements[1]
element.color = 0.058, 0.013, 0.008, 1.000 # 0x441E16 錆びの進んだ暗い部分。
element = elements.new(position=0.5)
element.color = 0.413, 0.195, 0.061, 1.000 # 0xAC7A46 錆びはじめ部分。
link(Output=reroute, Fac=color_ramp)
# 第2マスグレイブ。覆い焼きの分布を定義します。
musgrave_texture = create('TexMusgrave', (-782, -82), Scale=2, Detail=15, Dimension=0, Lacunarity=1.5)
link(Object=texture_coordinate, Vector=musgrave_texture)
color_dudge = create('Mix', (-195, 440))
color_dudge.data_type = 'RGBA'
color_dudge.blend_type = 'DODGE'
link(Color=color_ramp, _6=color_dudge)
link(Fac=musgrave_texture, _7=color_dudge)
principled_bsdf = create('BsdfPrincipled', (7, 315))
link(_2=color_dudge, Base_Color=principled_bsdf)
# Material Outputノードがすでに配置されている前提で、それにつなげます。
material_outputs = []
for node in nodes:
if isinstance(node, bpy.types.ShaderNodeOutputMaterial):
material_outputs.append(node)
if len(material_outputs) != 1:
raise Exception('Number of Material Output nodes not 1.')
link(BSDF=principled_bsdf, Surface=material_outputs[0])
return texture_coordinate, add, reroute, color_dudge, principled_bsdf
def create_uneven_texture():
"""色ムラの分布に対し、粗さや凹凸などを追加します。「ドロドロ汚れの設定」などを担当します。"""
# まず色ムラを作ります。
texture_coordinate, add, reroute, color_dudge, principled_bsdf = create_uneven_color()
# 汚れの分布である第1マスグレイブを覆い焼きの係数として用い、汚れだけに色ムラをつけることができます。
# しかし、錆びた金属を表すには錆びてない部分もくすませたいので、同じ0.2にします。
map_range = create('MapRange', (-534, 717), To_Min=0.2, To_Max=0.2)
link(Output=reroute, Value=map_range)
link(Result=map_range, Factor=color_dudge)
# 粗さを調整します。
# 汚れていない部分の粗さを0.30、汚れ部分を1.00とし、錆び部分はツヤをなくします。
if NOT_MODIFIED:
map_range = create('MapRange', (-189, -5), To_Min=0.30, To_Max=1.00)
else:
map_range = create('MapRange', (-189, -5), To_Min=0.05, To_Max=1.00)
link(Output=reroute, Value_=map_range)
link(Result=map_range, Roughness=principled_bsdf)
# 汚れの凹凸を表現していきます。
# ノイズのスケールで凹凸模様の細かさを調整します。錆びなので細かくします。
noise_texture = create('TexNoise', (-708, -370), Scale=50)
bump = create('Bump', (-186, -271))
link(Object=texture_coordinate, Vector=noise_texture)
link(Fac=noise_texture, Height=bump)
link(Normal=bump, Normal_=principled_bsdf)
# 汚れていない部分のバンプを0.0、汚れ部分を0.5とします。
# 0.5を変えて錆び部分の凹凸の度合いを調整できます。
if NOT_MODIFIED:
map_range = create('MapRange', (-435, -131), To_Min=0.0, To_Max=0.5)
else:
map_range = create('MapRange', (-435, -131), To_Min=0.0, To_Max=0.2)
link(Output=reroute, Value_=map_range)
link(Result=map_range, Strength=bump)
return add, reroute, principled_bsdf
add, reroute, principled_bsdf = create_uneven_texture()
# 金属の質感を設定します。汚れのない部分がメタリック1です。
map_range = create('MapRange', (-190, 256), To_Min=1.0, To_Max=-0.1)
link(Output=reroute, Value=map_range)
link(Result=map_range, Metallic=principled_bsdf)
# アンビエントオクルージョンで凹んだ部分の錆びを表現していきます。
ambient_occlusion = create('AmbientOcclusion', (-1381, 53))
# 陰影を濃くします。レンダリングエンジンがEeveeならガンマ10、Cyclesならガンマ3にします。
if bpy.context.scene.render.engine == 'BLENDER_EEVEE':
gamma = 10
else:
if NOT_MODIFIED:
gamma = 3.0
else:
gamma = 1.5
gamma = create('Gamma', (-1198, -6), Gamma=gamma)
# 凹んだ部分を汚したいので白黒反転させます。
invert = create('Invert', (-1023, 15))
screen = create('Mix', (-842, 171), Factor=1)
screen.data_type = 'RGBA'
screen.blend_type = 'SCREEN'
link(Color=ambient_occlusion, Color_=gamma)
link(Color=gamma, Color_=invert)
link(Color=invert, _7=screen)
link(Value=add, _6=screen)
link(_2=screen, Input=reroute)
print('Done.')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment