Skip to content

Instantly share code, notes, and snippets.

@wakarase
Last active March 31, 2023 11:53
Show Gist options
  • Save wakarase/315e365da4b8ca87144d7289abd27406 to your computer and use it in GitHub Desktop.
Save wakarase/315e365da4b8ca87144d7289abd27406 to your computer and use it in GitHub Desktop.
# Blender 質感・マテリアル設定実践テクニック
# ひび割れの作り方
# 3-06-01.blend 3-06-02.blend 3-06-03.blend
import bpy
class CrackType:
"""ひび割れの種類です。"""
NOISE = 1 # 大まかなひび割れ
VORONOI = 2 # 細かいひび割れ
MUSGRAVE = 3 # 不規則性の高いひび割れ
CRACK_TYPE = CrackType.VORONOI
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' # 自動生成したノードだというフラグです。
y_offset = -700
node.location = location[0], location[1] + y_offset
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])
# ひび割れのマテリアルを作っていきます。
texture_coordinate = create('TexCoord', (-1067, -151))
reroute = create('Reroute', (240, -86))
if CRACK_TYPE in [CrackType.NOISE, CrackType.VORONOI]:
# ひび割れに細かい変化をつけます。
# メインとしてノイズテクスチャを用いる場合、そのスケールの20倍が適切です。
noise_texture = create('TexNoise', (-882, -270), Scale=30)
# カラーミックスの係数を大きくするほど、ひび割れの細かい変化が強まります。
mix = create('Mix', (-714, -92), Factor=0.05)
mix.data_type = 'RGBA'
mix.blend_type = 'MIX'
link(Object=texture_coordinate, Vector=noise_texture)
link(Object=texture_coordinate, _6=mix)
link(Color=noise_texture, _7=mix)
if CRACK_TYPE == CrackType.NOISE:
# ひび割れの元になるテクスチャとしてノイズテクスチャを用いる場合です。
# スケールの値で模様の大きさを調整します。
noise_texture = create('TexNoise', (-471, -29), Scale=1.5)
color_ramp_1 = create('ValToRGB', (-298, -25))
color_ramp_2 = create('ValToRGB', (-16, -26))
# ノイズテクスチャの値0.5の等高線の辺りを強く出力します。
elements = color_ramp_1.color_ramp.elements
element = elements[0]
element.position = 0.0
element.color = 0, 0, 0, 1
element = elements[1]
element.position = 0.5
element.color = 1, 1, 1, 1
element = elements.new(position=1.0)
element.color = 0, 0, 0, 1
# 等高線から外れた値を捨てることで、ひびのような等高線が残ります。
elements = color_ramp_2.color_ramp.elements
element = elements[0]
element.position = 0.95 # 下げるほどひびの幅が広くなります。
link(_2=mix, Vector=noise_texture)
link(Fac=noise_texture, Fac_=color_ramp_1)
link(Color=color_ramp_1, Fac=color_ramp_2)
link(Color=color_ramp_2, Input=reroute)
if CRACK_TYPE == CrackType.VORONOI:
# ひび割れの元になるテクスチャとしてボロノイテクスチャを用いる場合です。
value = create('Value', (-707, -295))
voronoi_texture_1 = create('TexVoronoi', (-509, 130))
voronoi_texture_2 = create('TexVoronoi', (-512, -157))
difference = create('Mix', (-275, -27), Factor=1)
color_ramp = create('ValToRGB', (-62, 1))
# 2つのボロノイのスケールは等しい必要があるので、値ノードに一元化します。
if NOT_MODIFIED:
value.outputs[0].default_value = 10
else:
value.outputs[0].default_value = 20
# ボロノイF1スムーズはF1を滑らかにしたものですから、差をとると網目になります。
voronoi_texture_2.feature = 'SMOOTH_F1'
difference.data_type = 'RGBA'
difference.blend_type = 'DIFFERENCE'
elements = color_ramp.color_ramp.elements
element = elements[0]
element.position = 0.085
element = elements[1]
element.position = 0.250
link(_2=mix, Vector=voronoi_texture_1)
link(_2=mix, Vector=voronoi_texture_2)
link(Value=value, Scale=voronoi_texture_1)
link(Value=value, Scale=voronoi_texture_2)
link(Distance=voronoi_texture_1, _6=difference)
link(Distance=voronoi_texture_2, _7=difference)
link(_2=difference, Fac=color_ramp)
link(Color=color_ramp, Input=reroute)
if CRACK_TYPE == CrackType.MUSGRAVE:
# ひび割れの元になるテクスチャとしてマスグレイブテクスチャを用いる場合です。
musgrave_texture = create('TexMusgrave', (-256, -111), Scale=2, Detail=15, Dimension=0, Lacunarity=1.4, Gain=50)
color_ramp = create('ValToRGB', (-67, -111))
# 「畝のあるマルチフラクタル」を用います。
musgrave_texture.musgrave_type = 'RIDGED_MULTIFRACTAL'
# 正負を反転させ、血管のような谷を高い値として取り出します。
elements = color_ramp.color_ramp.elements
element = elements[0]
element.position = 0.0
element.color = 1, 1, 1, 1
element = elements[1]
element.position = 0.3
element.color = 0, 0, 0, 1
link(Object=texture_coordinate, Vector=musgrave_texture)
link(Fac=musgrave_texture, Fac_=color_ramp)
link(Color=color_ramp, Input=reroute)
# 凹んだ部分のアルベドを暗くしてひび割れを強調します。
# 第2の色を暗い灰色にするほど、凹み部分が暗くなります。
if NOT_MODIFIED:
# 青0x3888E2に灰色0xAAAAAAを乗算します。
multiply = create('Mix', (318, 283), _6=(0.040, 0.246, 0.761, 1.000), _7=(0.4, 0.4, 0.4, 1.0))
else:
multiply = create('Mix', (318, 283), _6=(0.250, 0.250, 0.250, 1.000), _7=(0.4, 0.4, 0.4, 1.0))
multiply.data_type = 'RGBA'
multiply.blend_type = 'MULTIPLY'
# 凹んでいない部分と凹んだ部分の粗さを設定します。ひびを粗くします。
map_range = create('MapRange', (310, 86), To_Min=0.2, To_Max=1.0)
# バンプで凹凸を追加します。
bump = create('Bump', (314, -171))
# 値の高い部分をひび割れにしたいので、反転をオンにします。
bump.invert = True
if NOT_MODIFIED:
principled_bsdf = create('BsdfPrincipled', (493, 345))
else:
principled_bsdf = create('BsdfPrincipled', (493, 345), Metallic=1)
link(Output=reroute, Factor=multiply)
link(Output=reroute, Value=map_range)
link(Output=reroute, Height=bump)
link(_2=multiply, Base_Color=principled_bsdf)
link(Result=map_range, Roughness=principled_bsdf)
link(Normal=bump, Normal_=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])
print('Done.')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment