ついて雑多に書いています。いじることをやってきました。与える出力は適当な値を与えてきましたが、実際はもう少し真面目にやらなければなりません。いった事前計算された情報も書き込まれているからです。変えてみると良くわかります。球が前回と同じくレイマーチで作成した球、床や立方体はデフォルトのマテリアルを使用しています。スタンダードサーフェスシェーダを利用するとこのようにはならず、適切にライティングされます。サーフェスシェーダも最終的には頂点シェーダとフラグメントシェーダへと変換されているわけです。値を埋めてあげれば、適切にライティングの施された結果が得られると考えられます。そこで本エントリでは、ディファードレンダリングにおける、サーフェスシェーダに相当する最小限のフラグメントシェーダを示し、それぞれの処理がどういった意味を持っているのかを深掘りしてみたいと思います。フォワードレンダリングに関しては以下にまとめています。オブジェクトで、ライトがベイクされています。動いているものはライトプローブから影響を受けているのがわかると思います。ボタンを押下するとサーフェスシェーダを変換したコードを見ることが出来ます。このコードを頂点・フラグメントシェーダとして新しく作成したシェーダに貼り付ければ、サーフェスシェーダと同じ結果が得られます。いった様々なパスが含まれています。ディファードではこれらのパスは必要ないので消してしまいます。コードが長くなりますが、余分な箇所を省いて整形したコードを以下に示します。"Diffuse"}ここから自分の使わない機能を削っていって最適化していく方針で行くのが良いと思います。最適化するにしてもどこがどういった処理を行っているか把握することが必要だと思いますので、以下、いくつか概要を紹介したいと思います。使った分岐がたくさんあります。これは、スタンダードシェーダは汎用シェーダになっていて様々なケースに対応できるように書かれているのですが、それをオブジェクトやシーンの状態に従って分岐し、必要なメンバや処理を選択できるようにしているからです。等)が切り替えられます。***」のところで設定されているバリアントが確認できます。文があると思いますので、先に説明しておきます。ブロックに追加されています。これは組み込みで用意されているバリアントをまとめて設定してくれるショートカットにあたるのですが、本機能の明確な説明はドキュメント含めどこにも見当たりませんでした。必要なバリアントの設定がここでまとめて行われていると考えられます。最終段のパスになります。ような指定があったら分かりやすいのですが使いまわしているのでしょうか。このあたりは公開されている情報からだけでは分かりませんでした。文を書かない状態で試してみました。ライト関連のバリアントが消えています。つけるとオブジェクトやシーンの状態に応じて適切なキーワードを設定してくれるものであると考えられます。MRTs)を除外(exclude_renderes)する、という意味です。サポートしない環境でシェーダがコンパイルされないようになります。タイミングで入ったようです。ショートカットを使うといくつかのバリアントが自動で設定されてしまいます。いう形でスキップしたいバリアントを指定します。設定のフォグを使用したとしても不透明なオブジェクトには効かず、フォワードのパスで描画される半透明なオブジェクトにのみ影響します。フォグの処理は無駄となるため、ここではスキップしている、というわけです。されているのでスキップは必要ない気もします。シェーダの概要では具体的にシェーダの中で具体的に何が行われているのか見ていきます。先程のシェーダを見てもわかるようにかなりコードは長いです。結果を足し合わせ、それをエミッションバッファに格納する、ということを行っているに過ぎません。ベイク対象でない動的なライトは、このモデルの描画よりも後のレンダリングパスで計算を行います。記事でも少し触れました。いった計算はフォワードと同じようにモデル単位で計算されているわけです。渡ってくる構造体を見てみます。チェックを外したとき)にセットされます。昔はバリアントになっていたようですが今は(おそらくバリアント節約のために)セットされていません。されるようになっています。そのため、グラフィックデバッガからは確認できません。計算の分岐でも使われています。頂点シェーダ頂点シェーダを見ていきます。o;}最初は構造体を初期化し、位置や法線を通常通り詰めています。取ってこれるものです。計算してくれるものです。側が管理しているテクスチャの情報です。詳しい説明はこちらに載っていました。結果が格納されているようです。モードのときに計算されるようですが、コードを読むとフラグメントシェーダ側で利用されることはないように思えます(いまのところ不明、消しても問題ない?)。ない動的なオブジェクトの場合に入ります。定義されている)を呼んでアンビエントおよびライトプローブの強さを計算しています。マニュアル球面調和関数によるライティングは以下の記事が詳しいです。次元的な情報を持つキューブマップへと適用しているイメージです。(PRT)~PRTの基本。マイナビニュースここでは、それを頂点単位で行っている、というわけですね。フラグメントシェーダ次にフラグメントシェーダを見ていきます。サーフェスシェーダの呼び出しまずは前半です。値を出力する形で引数をとっています。サーフェスシェーダで記述した形そのままです。構造体に詰めている形になっています。複雑なことはしておらずシンプルです。必要な構造体に値を詰めるところです。ここではライトの情報が保存されます。次のような構造体です。これらのメンバは後の関数の中でセットされるので、特にここでは値がセットされたりはしません。関しても、後でまた初期化されるので単純に以下の形で良い気がします。応じていくつライトの情報が必要かを保存しておく構造体になっています。定義されているときが一番情報が必要なわけです。構造体は以下のようになっています。probeHDR[2];};頂点シェーダから渡ってきた値や組み込みの変数をセットします。宣言されているリフレクションプローブの組み込み変数をセットしています。対して処理されるので、ここでは必要ない気もしています(このブロックを外しても影響がなかったので...)。最後に構造体および出力用の変数ををライティングの関数に渡します。光の情報を書き出しています。圧縮される部分を挟んだ後、エミッションバッファへと書き出さます。代入しているだけです。これでようやく、全体の流れが追えました。既存のシェーダを改造するさて、長く険しい道程を経てシェーダの大まかな流れを理解したので、前回のレイマーチしたオブジェクトがこの計算を通るように改造してみます。レイマーチ部はすこし改造してしまっていますが、意味合いとしては、出力された位置・法線をポリゴンのそれらと置き換える、という感じです。長いですがほとんどコピペです。UNITY_OPAQUE_ALPHA(outDiffuse.a);}#endifそれでは結果を見てみましょう。左半分が通常のスタンダードサーフェスシェーダ、右がレイマーチしたものです。オブジェクトとなっています。エミッションバッファも見てみます。影響を受けているのがわかります。...が、このレイマーチしたオブジェクトはキューブをいじって球にしているのですが、何やらもとのキューブがうっすらと見えます。してしまった下側の球は、もとのポリゴンの形状をもとにライトマップを焼かれてしまっているのでどうしようもありません...。変わるだけでライティングには影響がないからです。でない上側の球にうっすらとキューブのライティングが現れているのは、球面調和関数によるライティングが頂点単位で行われていたからだと考えられます。キューブの法線の情報を使ってライティングの情報をデコードしていたので、それがここに現れているわけです。使ってレイマーチ後の位置・法線情報を使ってライティングをデコードしてみたいと思います。下記公式エントリを参考にします。...}頂点でやるよりも少し明るくなっていまが、きれいになりました。ものに関しても、ベイク時に周囲に影響は及ぼすものの自身はライトマップを使わずに球面調和関数によるライティングを使う、という考えでシェーダを書き直すことは出来ます。呼び出している関数の内部で結構分岐が多く、同様のライティングを再現するコードにまとめるのは少し面倒そうです。ときはなるべくもとのポリゴンの形状からかけ離れない形状にするのが吉だと思います(影も変形した形状ではベイクされないので)。おわりにスタンダードシェーダの内容を追いかけるのは、資料も少なく、推測しながら進めなければならない所も多々あり、非常に骨の折れる仕事でした...。はてなブログPro凹んでます。)スターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。