見出し画像

マテリアルを調べる

Material(マテリアル、素材)を使うと、メッシュの色づけするまでの方式を定義することができる。頂点カラーをつけたり、テクスチャを貼ったりするのも、マテリアルを経由して行われる。

たとえば、Vertex ColorモードでCubeオブジェクトの天面を青一色に塗る。

これをシェーダ(Shader、陰影処理)を使った描画へ切り替えても色は反映されない。

Shadingワーク・スペースにあるノード・グラフで、Vertex Colorを扱うノードを追加する必要がある。Vertex Colorノードの出力はColorプロパティで、頂点カラーそのものズバリの値が出力される。

シェーダは陰影処理と訳されるみたいだけど、各種パラメータを合成したり、パラメータを変更したりする工程を踏み、最終的にメッシュのサーフェス(Surface、表面)をどうするのかを決めているので、表面加工処理に近い気がする。

そのような訳で、ここではVertex Colorノードを次のノードへ繋いで加工し、最後にMaterial Outputノードへ繋ぐと、メッシュの表面へ色付けが決まる、みたいな解釈をしておく。

Material Outputノードに入力された結果が反映され、頂点カラーがついた。

途中にあるPrincipled BSDF(Bidirectional Scattering Distribution Function、双方向散乱分布関数)は、メッシュ表面に光を浴びたときに、どのようにして光を散乱させるのかを決める関数らしい。

BSDFのほか、反射率(Reflectance、リフレクタンス)を決めるBRDF、透過率(Transmittance、トランスミッタンス)を決めるBTDFがあり、メッシュ表面の特性を定める関数類はまとめてBxDFと呼ばれているみたいだ。

BxDFについては、次のサイトが詳しい。

memoRANDOM

なお、メッシュの表面加工処理が不要ならVertex Colorの出力を直接Material Outputへ繋いでも問題ないようだ。

ディズニーの原理モデル

Principled(プリンシプル、原則に基づいた)というのは、何の原則に基づいたものかがわからなかったので、引き続き調べることにする。

Blender公式マニュアルに「Principled (プリンシプル) BSDF」というページがあり、ディズニーの原理モデルにも基づいていることはわかったけれど、では具体的にどんな原則にしたがっているのかはわからなかった。

検索キーワードを工夫して少し調べてみると、「超雑訳 Physically Based Shading at Disney」というサイトを見つけることができた。そこからさらに遡って調べてみると、SIGGRAPH 2012でディスニーが発表した「Disney principled BRDF」という論文が元になっていることを突き止めることができた。

論文「Physically Based Shading at Disney」はディズニー・アニメーション・スタジオの公式サイトで見ることができる。

ディズニーの原則は、その論文の第5章 Disney “principled” BRDFの第1節 Principlesに記載されている(p.12)。

1. 物理的なパラメータより直感的なパラメータを使用する
2. パラメータ数はできるだけ減らす
3. パラメータ値の妥当な設定範囲は0~1にすること(正規化)
4. 必要性があるなら、パラメータ値が妥当な設定範囲を超えることも許されるべきである
5. すべてのパラメータの組み合わせは、可能な限り堅牢にし、かつ妥当性がなければならない
(Physically Based Shading at Disneyより引用、DeepL翻訳内容を元に意訳)

リアリスティックなパラメータ設定ではなく、アーティスティックなパラメータのほうを優先し、パラメータに妥当性を求める、というもののようだ。パラメータについては、プログラミングに通ずるところがあると思う。

ディズニーはPrincipled BSDFをさらに改良して、SIGGRAPH 2015で論文「Extending the Disney BRDF to a BSDF with Integrated Subsurface Scattering」を発表して、サブ・サーフェスの散乱(Scattering、スキャッタリング)を統合したとのことだった。

この辺りのシェーディング内部については、もはやアーティストの領域なので、どんなパラメータが並んでいるかを眺めるだけにしておく。

マテリアル・スロット

Blender Python上では、マテリアルがどのように管理されているのかを調べてみた。

オブジェクトの管理情報から探してみると、bpy.data.objects配下にmaterial_slotsプロパティを見つけることができた。

スロット内にあるデータの名前を表示させると"Material"となっているので、ここにメッシュ・オブジェクトへ割り当て可能なマテリアルの情報が格納されていることになる。

この管理方式は頂点グループなど、他の情報管理と同じ方式になっていて一貫性がある。

>>> bpy.data.objects["Cube"].material_slots[0].name
'Material'

マテリアルそのものの情報はメッシュ・データのほうに紐づいていた。これはアウトライナー画面で表示されている通りになっているようだ。

Blender Pythonからメッシュ・データに紐づいているマテリアルへアクセスするためには、materialsプロパティを参照すればいい。

>>> bpy.data.meshes["Cube"].materials[0].name
'Material'

データの管理方法と、データへのアクセス方法は、これでなんとなくわかった。イメージにすると次のようになる。

ただ、マテリアルには2つの大きな罠があった。

ひとつは、マテリアル・スロットは空のままでも定義することができる点。もうひとつはマテリアル・オブジェクトをメッシュ・オブジェクトにも紐づけることができる、という点だ。

空のスロット

マテリアル・スロットは、マテリアルを格納するための器になったいる。ここにマテリアル・オブジェクトが格納される。

マテリアル画面から+ボタンを押していくと、どんどんと空のスロットが追加されていくのを確認することができる。

マテリアル・スロットは器に過ぎないので、同じマテリアルを複数のスロットへ紐づけることもできる。ただ、Blenderにとっては同じマテリアル・オブジェクトを複数のマテリアル・スロットへ紐づけることは好ましくないようだ。

同一のマテリアル・オブジェクトを複数のマテリアル・スロットへ紐づけた場合、マテリアル名の横に数字が表示される。この数字は選択しているマテリアル・オブジェクトがいくつのマテリアル・スロットへ紐づけられているかを示している。

オブジェクト・モードに切り替えて、この数字をクリックすると、重複しているマテリアル・オブジェクトのコピーが自動作成され、正しい状態になる。

メッシュ・オブジェクトへの紐づけ

マテリアル・オブジェクトはメッシュ・データのみならず、メッシュ・オブジェクトへ紐づけることもできる。

マテリアル名の右側に見慣れたアイコンが見つけられるけれど、このドロップ・ダウン・リストを開くと、「Object」「Data」というリストが表示される。これは言うまでもなく、メッシュ・オブジェクトとメッシュ・データのことを指している。

ドロップ・ダウン・リストをメッシュ・オブジェクトへ切り替えると、マテリアル・スロット自体が切り替わる。

メッシュ・オブジェクトのマテリアル・スロットは、メッシュ・データへ紐づいているマテリアル・スロットとは別管理されているようで、マテリアル・スロットを切り替えると空になる。

マテリアル・スロットを追加し、マテリアル・オブジェクトを追加して割り当てると、アウトレイヤー上でもメッシュ・オブジェクト配下に紐づけられることが確認できた。

リンク

マテリアルがメッシュ・オブジェクトへ紐づくのか、あるいはメッシュ・データへ紐づくのかを決めているのが、マテリアル・スロットのlinkプロパティだった。

インタラクティブ・コンソールで次のスクリプトを叩くと、マテリアル・スロットへ割り当てられるマテリアル・オブジェクトが切り替わるのを確認することができた。

>>> bpy.data.objects["Cube"].material_slots[0].link = "DATA"
>>> bpy.data.objects["Cube"].material_slots[0].material.name
'Material'

>>> bpy.data.objects["Cube"].material_slots[0].link = "OBJECT"
>>> bpy.data.objects["Cube"].material_slots[0].material.name
'Material.001'

リンク先を切り替えれば、マテリアル・オブジェクトをメッシュ・オブジェクトに紐づけるか、メッシュ・データに紐づけるかを設定できることはわかった。しかし、メッシュ・オブジェクトにはmaterialsプロパティは存在しない。

試しにマテリアル・スロットのモードをメッシュ・オブジェクトに切り替えて、マテリアル・オブジェクトの名前を表示させてみると、やはりメッシュ・オブジェクト経由のマテリアルを表示することができない。

マテリアル・スロットのリンク先がメッシュ・オブジェクトに切り替わった場合、マテリアル・スロットに並ぶマテリアル・オブジェクトの一覧も更新されるので、メッシュ・オブジェクトに紐づけられているマテリアル・スロットは、メッシュ・データに紐づけられているマテリアル・スロットとは、別のメモリ・アドレスを参照していることは、容易に推測できる。

さらに調べてみると、bpy.data.objects["Cube"]のmaterial_slotsプロパティの参照先がダイレクトに変わっていることがわかる。

>>> bpy.data.objects["Cube"].material_slots[0].link
'OBJECT'

>>> id(bpy.data.objects["Cube"].material_slots)
2392344273808

>>> bpy.data.objects["Cube"].material_slots[0].link
'DATA'

>>> id(bpy.data.objects["Cube"].material_slots)
2392344273760

ところが、このメッシュ・オブジェクト用のマテリアル・スロットの大元がどこにあるのか、すぐにはわかりそうにはない。どこかにマテリアル・スロットのコレクションが存在しているだろうとは思うけれど、それらしいAPIが見つけられなかった。

フェイス・グループ

エディット・モードに切り替えると、マテリアルにフェイスを割り当てることができるようになる。割り当てる仕組みは頂点グループに似ているので、ここでは便宜的にフェイス・グループと呼ぶことにする。

マテリアルに指定されたフェイス・グループごとに表面加工処理が行われるので、たとえば、Cubeオブジェクトの天面を別のマテリアルに割り当てると、天面は新しく割り当てたマテリアルでの描画に切り替わる。

冒頭で頂点カラーを使って青く塗ったCubeオブジェクトの天面を別のマテリアルに割り当てると、天面だけ色がすっぽりと抜ける。

フェイス・グループもまた、選択状態をコントロールすることができるので、フェイス・グループに定義されるすべての頂点を使った頂点グループがあるなら、別管理しないで済むかもしれない。

この記事が気に入ったらサポートをしてみませんか?