Last active
March 31, 2023 11:53
-
-
Save wakarase/315e365da4b8ca87144d7289abd27406 to your computer and use it in GitHub Desktop.
This file contains 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 characters
# 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