2013年12月31日火曜日

Cyclesでボリュームマテリアルテスト その2

この記事を書いている間に2.69.8にマージされてボリュームシェーダーのノード構成が変わったので参考までにしてください


以前に内蔵レンダーでこういうのを作ったことがあって



要はサーフェスにマテリアルを貼っていない見えないオブジェクトの内側にライトを2個くらい置いて、ボリュームマテリアルに内側から光を当てている。Cyclesで同じことができないかと考えていたら2.7で実装されるらしいと聞いた。ボリュームマテリアルというのは、こういうオブジェクトの内側を点描するような、早く言えば雲とか煙を表現するのに向いている。現在のCyclesにはまだマテリアルをいじれる雲addonはなかった気がする。

Cyclesのシェーダーはもともとサーフェスに貼られたマテリアルを対象としているので内蔵レンダーにあるようなHaloやボリュームには向いてないと聞いているがどうやって実現しているのかかなり興味がある。

svn.blender.orgのDingtoリポジトリをビルドして試してみた。


どら焼きのようなICO球オブジェクトにポイントライトとエリアライトを1個ずつ置いた。色はライトそのものに薄い黄色と白を付けた。球のマテリアルノードはこれだけ。




一見すると星がきれいに表現されているように見えるが実はこれがただのノイズだったりするのだったw
密度を上げてみるとノイズが減って確かにきれいに見えるがボリューム全体がのっぺりしてしまう。オブジェクトの透明感と光のグラデーションの滑らかさは反比例するらしい。

等方性ボリュームのg値については soc-2013-dingto/intern/cycles/kernel/volume.h に以下のようなコメントがあるが:
レイ間に与えられたコサイン値は光子が軌道に沿って反射する確率密度を返す。引数gはそれが球状にどれくらい離れているかを決める。値が0のときデフューズのような形状になり、1のときは鋭い1本の光線のようになる。
このオブジェクトでいう光の減衰に影響するんじゃないかと思う

現在のところCPUレンダーのみ対応。機能セットは実験的にしておく。




Blender Cycles memo( http://cycles.wiki.fc2.com/ )
の翻訳によると、Cyclesのボリュームシェーダは、オブジェクト内を光が通過する際の作用を表現している。ボリューム内を通過する光は任意の点で分散するか吸収するかまたは放射される、とある。ガラスや光沢と組み合わせると氷のようになる、と書いてある。



グラスBSDFを足してみると若干滑らかになる。グラデーションを滑らかにする方法はほかにもあるかもしれない。無論コンポジットでごまかすこともできるのだが、アニメーションした場合フレーム間で微妙なズレが生じ絵の動きによってはチラつきが目立ってしまう。コンポジットは1枚の静止画のレンダー後にレタッチをするのと同じことなので補助的な編集ツールにすぎないと考えている。オブジェクトレベルで高い精度があればいくら動かしても劣化せずに使える。

銀河系



銀河系を作ってみたのだがかなり悩んだ。中心にあるどら焼き型の光はボリューム。外側の渦巻きの4色の点々はパーティクル。赤いガス星雲はボリュームにボロノイを貼っているが最初は綺麗にガスっぽい感じが出てたのにいじりすぎて元に戻せなくなってしまった。以下はガス星雲のマテリアルノード。


霧も光もオブジェクト内にある点の存在は、すべて等方性ボリュームの密度の値で行われる。なのでオブジェクト内の座標(あえてジオメトリの位置として呼称している?)にボロノイやウェーブテクスチャを食わせてスポンジのような効果を作り出すこともできる。千切れ雲とかちぎりこんにゃくの集合みたいな形状も可能らしいのだが、その場合はいずれかのノードのディスプレイス値を使うらしいということしか分からなかった。たぶんマテリアル出力にあるディスプレイスだと思うがやり方がわからない。それが理由でガス星雲の部分はオブジェクトの表面にぺったりと貼り付けたようになっている。

将来修正されるであろう不具合。同じレイヤー上に2つ以上のボリュームオブジェクトがあるとアルファ透過してくれない。同じボリュームマテリアルを貼ったオブジェクト同士は重なった部分がきれいに表現できない。今回はレイヤーを分けてコンポジットで重ねた。同じオブジェクトに複数のマテリアルを重ねられない。

2つ以上のボリュームマテリアルを混ぜて使いたい場合はノードエディタ上で2系統作りミックスか追加シェーダーで合成してやればよい(なかなかうまく混ぜられないが)。

透過させるにはカラーの出ているノードからアルファ値を密度に食わせてやればよい。

散光星雲


レンダー所要時間:46時間37分
(4コア3.6GHz 8Gメモリ CPUレンダリング500サンプル)

冒頭にある散光星雲を作ってみたのだがレンダーにかなり時間かかっちまって、たぶん実装がまだpythonコードだからだと思うがいろいろと調整が必要だということを感じた。レンダータブにある2つのアルゴリズムはそれぞれ特性が違っていて所要時間も違う。実はサンプリング1000と2000も試したのだが開始から2日目くらいでフリーズして諦めて500に戻した。GPUレンダならよくあることだが今回はOSカーネル自体が固まったのでメモリを食い尽くしてしまったのかもしれん。サンプル数を上げていくとスムーズな点の減衰になることは分かった。

ガス部分のマテリアルノード

星雲は単にディスプレイスで凸凹させているので実際にはボリュームが減衰しているわけではない。真ん中にライト代わりの凸凹オブジェクトを埋め込んでいるのでこういう光になっている。
等方性ボリュームを2つにしたのは、上は周辺の赤い部分の色、下は中心に若干赤紫を足したかったためだが、両方をバランスよく出すのは難しかった。この値では外側の赤が強い。ボロノイにノイズテクスチャを食わせているのはblenderartistのスレでこういう使い方をしているのを見て真似してみたのだがどういう原理で機能しているのかは分からない(そもそももっさりとしたCPUレンダーなので値をちまちま変更して変化を見るという検証ができない)。

点の密度が外側に向かって緩やかに減衰していくのを期待しているのだが、思ったようなグラデーションが出ていない。つまり減衰にはサインカーブが使われているはずなのだが内蔵レンダーのボリュームマテリアルで表現されるような減衰が行われていない。
ボリュームマテリアルは霧や雲ジェネレータのような元になるものなのでこういう感じにぷっつり切れてしまうというのは機能的に美しくない。

等方性ボリュームの密度入力にサイン値を与えてみているのだが密度が厳密に何を指すのかわかってないので意味がなかったかもしれない。むしろレンダータブのボリュームセクション内にある「密度係数」を下げるほうが効果があった。係数は乗数らしい。ワールドの点の減衰が綺麗なのはこの値を直接使っているからではないかと思う。むしろ裾野が緩やかに伸びるアークタンジェントのようなカーブが欲しかった。

2つのアルゴリズム

レンダータブにはInhomogeneous(不均一)にRay marchingとWoodcockのアルゴリズムがあるが簡単に言うと:

Ray Marching:レイ上を一定距離のステップでオブジェクトに進み、交点を探索してその点の色を計算するもの。オブジェクトの複雑さと面積に比例して計算量が増加する。割と古くから使われている光子マッピングの手法。光線の上を一歩ずつ歩測する様子からこの名前になっているらしい。

Woodcock:ボリューム中を通過するレイ上の最初の点を探しだす。このときの点の散布は透過率と等しくなる。2点間の透過率は点の間のパスの衝突の平均値になる。Ray Marchingの代替手段として考案されたもので比較的計算が早い。

ということらしい。Ray MarchingはOpenGLなどのCGプログラマがロジックを説明している日本語のページがいくつかあるが、いずれにしてもCG学会で発表される論文レベルの知識が必要なので方程式を見てもなんのことやらだった。


ハンガリーブダペスト情報経済大学の論文(PDF): http://sirkan.iit.bme.hu/~szirmay/woodcock1.pdf


この論文ではWoodcockの利点を解説している。抜粋すると、Ray Marchingのアルゴリズムはボクセルの配列が大きい場合や吸光係数の平均値が小さい場合に大量のボクセル配列を要求する。つまりメモリを消費する。
Woodcockレイトレースは吸光係数(光がある媒体に入射したときどれくらい光を吸収するかを表す定数)が最大値でパスの長さが無制限なサンプリングができ、最大距離でサンプリングしたレイの改善、最大確率の点の使用と不使用の選択などを提供する、また解像度に依存しない自由なパスのサンプリングを提供する、とのことだ。

欠点もいくつかあるらしいのだがいまいち理解できなくて申し訳ない。