Vector Displacement Mapブラシの使い方と作り方
Vector Displacement Map ブラシとは
次の動画を見れば、10秒で理解できると思います。 ドローブラシをドラッグする距離と方向で、スカルプトする形状の大きさと方向が決まります。ドラッグ中に [Esc] キーを押すとキャンセルできます。
Vector Displacement Map とは
メッシュの頂点を移動して、スタンプのように決まった形状を作るための仕組みです。 ハイポリメッシュに対して、スカルプトモードのドローブラシをVector Displacement Map の設定にして使います。
Vector Displacement Map の仕組みは簡単です。 次の図のように平面状のメッシュを変形させた時の、頂点の移動方向と移動量をベクトルで表した値をテクスチャ画像として保存して、ブラシに登録してメッシュを変形させます。
法線マップと同じように画像ファイルに保存しますが、法線ベクトルが長さ1で、面の表を向いているのに対して、Vector Displacement Map では、色々な長さで、方向も3軸それぞれで正負の値が必要となります。
各軸が 8bit の精度では不足するため、普通の画像形式ではなく色を浮動小数点数で扱うことができる OpenEXR という画像形式で保存します。 ここでは16ビットの半精度浮動小数点数を使っていますが、VDMブラシとしては十分な精度が得られます。
VDMブラシ用アドオン
VDMブラシの使い方と作り方の詳しい手順は下で説明しますが、長くて覚えてられないのでアドオンを作りました。
VDMブラシ用のテクスチャ画像6種とアドオンをまとめたものを公開します。 こちらからダウンロード (VDMSetup-0.2.zip) できます。
アドオン VDMSetup.py のソースです。
import bpy import os from bpy.props import StringProperty, BoolProperty from bpy.types import Operator from bpy_extras.io_utils import ImportHelper # 2023-03-17 bl_info = { "name": "Setup VDM brush", "author": "Jun Mizutani", "version": (0, 2), "blender": (3, 5, 0), "location": "3D View", "description": "Change brush settings between Draw Brush and VDM brush", "warning": "", "category": "Sculpt" } # update checkbox def vdm_update_callback(self, context): scene = context.scene brush = bpy.data.brushes["SculptDraw"] if (scene.prop_vdm == True): brush.stroke_method = 'ANCHORED' brush.curve_preset = 'CONSTANT' brush.texture_slot.map_mode = 'AREA_PLANE' brush.use_color_as_displacement = True else: brush.stroke_method = 'SPACE' brush.curve_preset = 'SMOOTH' brush.texture_slot.map_mode = 'TILED' brush.use_color_as_displacement = False brush.texture_slot.texture = None # VDM Panel class VDM_PT_Panel(bpy.types.Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'Tool' bl_label = 'VDM' # draw checkbox only in sculpt mode @classmethod def poll(cls, context): if context.mode == "SCULPT": if context.tool_settings.sculpt.brush.name == 'SculptDraw': return True return False def draw(self, context): scene = context.scene layout = self.layout layout.prop(scene, "prop_vdm", text="VDM Brush") layout.operator(VDM_OT_Button.bl_idname,text="Load VDM Image") layout.operator(VDM_OT_MakeButton.bl_idname,text="VDM Shader") # [Load VDM Brush] Button class VDM_OT_Button(bpy.types.Operator): bl_idname = "vdm.load" bl_label = "Load VDM" def execute(self, context): bpy.ops.vdm.open_filebrowser('INVOKE_DEFAULT') return{'FINISHED'} # [VDM Shader] Button class VDM_OT_MakeButton(bpy.types.Operator): bl_idname = "vdm.material" bl_label = "VDM Shader" def execute(self, context): # material material = bpy.data.materials.new(name="VDM_material") material.use_nodes = True node_tree = material.node_tree node_tree.nodes.remove(node_tree.nodes.get('Principled BSDF')) material_output = node_tree.nodes.get('Material Output') # add nodes tex_coord = node_tree.nodes.new('ShaderNodeTexCoord') multadd = node_tree.nodes.new('ShaderNodeVectorMath') subtract = node_tree.nodes.new('ShaderNodeVectorMath') teximage = node_tree.nodes.new('ShaderNodeTexImage') multadd.inputs[1].default_value = (2.0, 2.0, 0) multadd.inputs[2].default_value = (-1.0, -1.0, 0) # operation subtract.operation = 'SUBTRACT' multadd.operation = 'MULTIPLY_ADD' # location tex_coord.location = (00, 200) multadd.location = (200, 200) subtract.location = (400, 200) material_output.location = (600, 200) teximage.location = (400, 50) # links links = node_tree.links links.new(tex_coord.outputs[2], multadd.inputs[0]) links.new(tex_coord.outputs[3], subtract.inputs[0]) links.new(multadd.outputs[0], subtract.inputs[1]) links.new(subtract.outputs[0],material_output.inputs[0]) # make teximage active node_tree.nodes.active = teximage return{'FINISHED'} # Filebrowser class OT_VDMOpenFilebrowser(Operator, ImportHelper): bl_idname = "vdm.open_filebrowser" bl_label = "Load VDM Image" filter_glob: StringProperty( default='*.exr', options={'HIDDEN'} ) def execute(self, context): path = self.filepath dir, filename = os.path.split(path) new_texture = bpy.data.textures.new(filename, type='IMAGE') new_texture.image = bpy.data.images.load(filepath=path) return {'FINISHED'} def init_props(): scene = bpy.types.Scene scene.prop_vdm = BoolProperty( name="vdm", description="Enable VDM Brush", default=False, update=vdm_update_callback ) def clear_props(): scene = bpy.types.Scene del scene.prop_vdm def register(): bpy.utils.register_class(VDM_OT_Button) bpy.utils.register_class(VDM_OT_MakeButton) bpy.utils.register_class(VDM_PT_Panel) bpy.utils.register_class(OT_VDMOpenFilebrowser) init_props() def unregister(): clear_props() bpy.utils.unregister_class(VDM_PT_Panel) bpy.utils.unregister_class(VDM_OT_Button) bpy.utils.unregister_class(VDM_OT_MakeButton) bpy.utils.unregister_class(OT_VDMOpenFilebrowser) if __name__ == "__main__": register()
アドオンのインストール
「install」をクリックして、ファイルブラウザから保存した VDMSetup.py を選択します。 「vdm」で検索して「Setup VDM Brush」にチェックを入れます。
アドオンの場所
インストールしたアドオンは、スカルプトモードでドローブラシを選択したときだけプロパティのアクティブツールタブの下の方とサイドバーの「Tool」タブにパネルが現れます。 このパネルは移動できるため、必要に応じて上の方の使いやすい位置に移動してください。
Load VDM Image
ファイルブラウザが開きます。 拡張子が「exr」のOpenEXR形式のファイルをVDMブラシとして選択します。 連続して画像を読み込んでも、別々のテクスチャとして読み込まれるため、VDMブラシのテクスチャ画像をクリックすることで選択できるようになります。
VDM Brush
チェックボックスをチェックして、テクスチャ画像をクリックして、使用するVDMブラシを選択します。 スカルプト対象のオブジェクト上でマウスを左ドラッグすると、サイズと方向を変更できます。
VDM Shader
Vector Displacement Mapを作成するためのシェーダノードを作成します。 変形後のメッシュをVDM用のテクスチャとしてマテリアルに出力するシェーダノードです。 そのマテリアルをテクスチャ画像にベイクして VDM用の画像を作成します。 「blendファイルで配布してアペンドで使う」のは面倒なので、Python スクリプトでシェーダノードを作っています。 ベイクの前に画像ファイルはイメージエディタで作成しておく必要があります。
VDMブラシの使い方
これ以降は上記のアドオンを使用しないで、VDMブラシを使う場合の手順です。
スカルプト用のメッシュを用意する
デフォルトキューブにVDMブラシでスカルプトすることにします。 メッシュを十分細かくするため、編集モードにします。
辺 (Edge) から Subdivide を選択します。
今回は10分割を2回行いました。
以上で、スカルプトの対象とする約9万頂点のオブジェクトができました。
ドローブラシをVDMブラシとして設定する
スカルプトモードでドローブラシを選択して、プロパティエディタからアクティブツールを選択します。 テクスチャの項目で、「New」をクリックします。
「New」をクリックした後で現れるアイコンをクリックするとテクスチャタブに切り替わります。
OpenEXR形式のファイルを読み込み
Image で「Open」をクリックして画像を読み込みます。
VDMブラシで使う画像は拡張子が「exr」のOpenEXR形式のファイルになります。 ここで使っている「VDM_Test.exr」の作り方は、後半で説明します。
画像を読み込んだら、「Alpha」 と 「Clamp」のチェックを外します。
タブからアクティブツールを選択して、マッピング を「Area Plane (エリア平面)」を選択し、Vector Displacement (ベクトルディスプレイスメント) をチェックします。 ストロークは「Anchored (アンカー)」、Falloff(減衰) は 「Constant (一定)」 を選びます。
以上でVDMブラシの準備は終了です。
VDMブラシで描画
最初の動画のように、ドローブラシをドラッグする距離と方向で、スカルプトする形状の大きさと方向が決まります。位置を修正する場合には、ドラッグ中に [Esc] キーを押すと描画をキャンセルできるので、再度描画します。
ブラシの「強さ」は 1.0 で使いますが、小さくすると薄くなります。 またコントロールキーを押しながらマウスをドラッグすると凹凸が逆になります。 Falloff(減衰)をスムーズなどに変更すると境界が目立たなくなります。 マスクを使うとマスクの強さによって変形量が変わります。
スカルプト対象のメッシュの密度が充分でないと、VDMブラシで描画しても元の形状が再現できない場合があります。 Vector Displacement Mapの解像度より、描画対象のメッシュの密度が重要です。
ドローブラシへ戻す
ドローブラシを VDM ブラシに切り替える方法を説明しましたが、反対にドローブラシに戻す方法も書いておきます。 まず赤枠の[X]をクリックして、テクスチャの割当を解除します。
「Vector Displacement」のチェックを外して、ストローク方法を「Space」に戻します。
最後にフォールオフを「Smooth」に戻すと普通のドローブラシへ戻ります。
複数のVDMブラシを切り替えて使う
ここまでは、1つの VDM ブラシを設定して使いましたが、VDM ブラシを使う場合は複数の形状、例えば、目、耳、鼻、口などのブラシを切り替えて使いたい場合もあると思います。 ここまでの説明のように VDM の画像ファイルを読み込んでブラシに設定して描画して、次のブラシを設定して描画して、、、では面倒です。
イメージエディタに画像ファイルを連続して読み込んで、VDM ブラシでテクスチャを切り替えて使うことができます。
イメージエディタに読み込んでフェイクユーザを設定する
画像ファイルをフェイクユーザを設定すると、保存して再度開いた場合に削除されることがなくなります。 ファイル/外部データ/リソースの自動パック (File/External Data/Automatically Pack resources) をチェックすると blend ファイルに残すこともできます。
テクスチャにVDM用画像を登録
プロパティのテクスチャタブでテクスチャと画像ファイルを関連付けます。
テクスチャを登録して名前をつける
読み込んだ画像ファイルをテクスチャに設定してテクスチャ名をつけます。
VDMブラシにテクスチャを設定
テクスチャのドロップダウンで指定したテクスチャをブラシに設定できます。
ブラシのテクスチャを選択
テクスチャの画像をクリックしてもテクスチャを選択できます。 こちらの方法が楽です。
VDMブラシを使う
ブラシをドラッグ開始した位置が中心となって、移動する距離と方向で、スカルプトする形状の大きさと方向が決まります。
VDMブラシを作る
Vector Displacement Mapの仕組み
- Z座標が0でXY座標が±1の範囲の平面のメッシュを用意する。
- そのメッシュのUVマップを割り当てる。平面やグリッドには最初からUVが割当てられているため、特に準備する必要はない。
- スカルプトで必要な形状を作成するが、リメッシュを行うとUV座標が崩れるためリメッシュは行わないこと。
- 変形後のメッシュの頂点座標とUV座標を±1に変換したものの差を求めると、XY平面の移動量が求められる。
- XY平面の移動量と変形後の頂点のZ座標を組み合わせて、マテリアルとして出力される色をテクスチャ画像にベイクすると Vector Displacement Map が得られる。
VDM ブラシの形状を作成
VDM ブラシの形状をスカルプトするための平面を用意します。Z座標が0でXY座標が±1の範囲の平面のメッシュですが、Blenderを起動して立方体を削除して、平面(Plane)を追加するだけです。
VDM ブラシが生成する形状を平面のメッシュをスカルプトして作りますが、メッシュを十分に細かくしておきます。
編集モードで、辺(Edge)メニューからサブディバイドを選択します。 ここでは 10回を2度行いました。 ポリゴン数が多くても最終的なVDM ブラシには影響しません。
大きく変形するとポリゴンが伸び過ぎたりするため、ワイヤーフレーム表示にすると確認しやすくなります。
Vector Displacement Map作成用のシェーダノードの設定
Vector Displacement Mapを作成するためのシェーダノードを設定しますが、3種類だけなので簡単です。
まず、シェーダエディターを表示して、「New」をクリックします。
「Material Output」を残し、「Principled BSDF」を選択して、[X] か [Delete] キーで削除します。
Add メニューから「Input / Texture Coordinate」、「Converter / Vector Math」を2つ、「Texture / Image Texture」ノードを追加します。
「Vector Math」ノードの「Add」のドロップダウンリストから「Multiply Add」を選択します。右側の「Add」は「Subtract」に変更します。
テクスチャ座標の「UV」を「Multiply Add」に接続して、XとY成分を2倍して1を減算します。 これで、UV座標とメッシュ平面上の座標が一致します。Z成分は0になるようにします。 テクスチャ座標の「Object」から「Multiply Add」の出力の Vector を減算(Subtract) すると 「Vector Displacement」が求められます。これをマテリアル出力に接続するだけです。 ベイクの出力用のテクスチャをアクティブにするため、Image Texture ノードを選択しておきます。
画像エディタで「New」を押してベイク結果の書き込み先のテクスチャ画像を作成します。
ここでは「VDM_test」をいう名前にして、256 x 256 の画像を生成します。メッシュの解像度が120程度なので、128 x 128 ピクセルでも十分ですが、400KB程度の画像なので 1辺 256ピクセルの画像としています。
ベイクするために、レンダーエンジンは「Cycles」にします。
デノイズは不要なのでチェックを外します。
ベイクタイプは「Emit (放射)」にして、ビュー元は「Above Surface (表面の上)」に設定します。
メッシュをスカルプトします。 高さマップではないので、曲がった形状でも大丈夫です。 ただし、メッシュが引き伸ばされる場合でもリメッシュは使えません。 元の平面のUV座標と形が変化したメッシュ頂点の対応が崩れてしまうためです。
変形が大きいと「スライドリラックス」ブラシを使ったり、編集モードで頂点を移動したりしてメッシュの形状を整える必要があります。
オブジェクトモードで、「Bake (ベイク)」を押すと、画像が生成されます。頂点が移動したところに色が付きますが、各軸のマイナス方向の移動は黒のままです。
VDMブラシ用の画像を保存します。
保管する画像のフォーマットは「OpenEXR」とします。 色は「RGB」、色深度は「Float(Half)」とします。 16ビットの半精度浮動小数点数ですが、ベクトルマップとしての数値の精度は十分です。
描画時の歪み
もし、VDMブラシで描画する場合に歪みが生ずる場合は、VDMブラシの画素の要素が 0.0 から 1.0 にクリップされた状態の可能性があります。 平面上の移動ベクトルも正方向のみとなるのでVDMブラシの形が歪むことになります。
通常の画像ファイルと異なって、VDMブラシの色要素は浮動小数点数で格納されるため、負の値や1.0以上の値となる可能性があります。 Vector Displacement Map では負の値が格納されているのが普通です。
OpenEXRファイルの画素の値を確認する方法
VDMブラシの画素の要素が 0.0 から 1.0 にクリップされているかどうかは、OpenEXRの画像ファイルを調べるとわかります。
OpenEXR の画素の値は、例えばGIMP で確認する事ができます。 メニューの「Windows / Dockable Dialogs / Pointer」(「ウィンドウ/ドッキング可能なダイアログ / ピクセル情報」) をクリックして、ピクセルの色情報を表示できるようにします。
画像中のピクセルの位置によって、負の値や1より大きい値が確認できるはずです。
Blender 2.8 - 4.3 の使い方 [目次]
- (01) インストールと日本語化
- (02) 画面構成とモード
- (03) オブジェクトモード
- (04) 球と円柱でモデリング
- (05) スカルプトモード
- (06) 編集モード
- (07) リトポロジー
- (08) Python スクリプト
- (09) マテリアル (1)
- (10) マテリアル (2)
- (11) マテリアル (3)
- (12) アーマチュア(ボーン)
- (13) Rigifyによるリギング
- (14) パーティクルヘア
- (15) グリースペンシル
- (16) ジオメトリーノード (1)
- (17) ジオメトリーノード (2)
- (18) カメラ
- (19) ジオメトリーノード (3)
- (20) 新ヘアシステム Hair Curves
- (21) ヘアカーブの進化
- (22) Vector Displacement Mapブラシ
- (23) アセットライブラリ
- (24) シミュレーションゾーン
- (25) ボーンコレクションとRigify