yumeの日記: Unity制作 メデューサ・ゲーム #5
●メデューサ・ゲーム
●Unityのバージョン
テキトーに最新版2020.1.4f1を使っていたが、長期サポートの対象はLTSバージョンである2019.4.9f1だから、ゲームをリリースするつもりならそっちのほうがよいらしい。
まだ要素も少ないので、一旦新しいプロジェクトをLTSバージョンで作り、そっちにインポートしておく。
って、引っ越したらすぐに2019.4.10f1が来たぞ……。でもマイナーバージョンアップは問題ないらしい。
--
●視界マスク
視界に入っているものは普通に描画し、視界外のものは描画処理を変えるやつを作りたい。
例えば、視界内は普通に表示して、視界外は真っ黒、とか任意のスプライトで覆うとかそういうの。
とは言ったものの、実際どうすればいいのか見当つかず。
Code Monkeyがまさにやりたいことを動画化してくれている。
しかし、スクリプト可能なレンダリングパイプラインを使う、と言っていきなりなんか見たことのないものをいじり始めた。
公式にもあるので、これも使える要素のはずなんだが、この概念が無い。
Code Monkeyではパッケージファイルもダウンロードできるらしいので、試しに登録してダウンロードしてみる。
インポートできたものの、いまいち使い方がわからない。めっちゃエラー出てるし。シーンも空なので実行しようがないな。
うーん、これは一旦止めよう。
--
wgld.org曰く、
・ステンシルバッファを使えば、あるモノのある部分を描画するかどうかを決められる
>結果として型抜きのような表現が可能になる
の前に、シェーダーについて調べておこう
samurai blog @sato曰く、
・Shaderは描画方法を記述したプログラム
・Unityではデフォルトで、Standard Shaderが実行されている
・Shaderはマテリアルの属性として選ぶ
・自作のShaderはCreate-shader で作る。種類がいろいろある
>試しにUnlit shaderを作れとある。 UnlitはLightの影響を受けないShaderらしい。
記事の続きでは、
・ShaderLabはUnityでShaderを記述する言語
>GLSLとかとは違うんだ
・コードをコピーしたら、真っ白なマテリアルが表示される。色を変えるとちゃんとかわる。
>なんかコード上にへんなゴミ(a____)があってエラーが出たが、コメントアウトしたらまぁ動いた。
うーんと、多分このサンプルコードでは、ただ色情報だけを持ってきておいて、フラグメントシェーダーにその色を返す。
頂点シェーダーでは、そのメッシュの頂点座標とかを入れて、
フラグメントシェーダーでは、拾っておいた色をすべてのピクセルに置いて実行している。
ということだと思う。シェーダーは全然理解できてないんだけどたぶん。
Sebastian Lagueが、視界のステンシルシェーダーについての動画を投稿している。
内容を追いかけると、だいたいこういう仕組みらしい:
・StencilMaskと、StencilObjectという二つのシェーダーを作る。
・StencilMaskは、Stencil{ Ref 1 }と書いてStencilメソッド?のRefを1にする。
・StencilObjectは、Ref 1のところだけ描画する
・オブジェクト用マテリアルと、視界領域用マテリアルを作り、それぞれにシェーダーをはめる。
・可視領域に「StencilMask」を、すべてのオブジェクトに「StencilObject」をあてる。
これで、視界領域のメッシュはマスクになり、オブジェクトは「通常は見えないが、マスクにかかったところだけは見える」ということになる。
とりあえずBackGroundだけにこのマテリアルを反映して、試してみよう。
なるほど。でも後々やりたいことを考えると、できたら逆にしたいな。「マスク」領域は「隠されて(マスクされ)」)、「でっかい板」がカメラの目の前にあって、その板がマスク領域だけ隠される。他のオブジェクトは普通に表示されるだけだが、板の後ろに隠れているところは見えない。そういう感じがいい。
もう一個調べよう
はるのゲーム開発メモ曰く、
・ベースとなるシェーダーを作り
・Write側とRead側に、それぞれ微妙に書き換えたシェーダーを渡す
・するとWrite側の範囲だけが描画される
このコードを見ると:
Write側は
Stencil{
ref 2
Comp always
Pass replace
}
Read側は
Stencil{
ref 2
Comp equal
Pass keep
}
公式曰く、
・Comp hogehogeのhogehogeが:
・always 常に表示
・Equal Refが等しいときだけ表示
・NotEqual Refが等しくないときだけ表示
他いろいろ。
ということは、現状は「Writeの範囲にある、WriteとRead両方を描画」ということになっているのを
「Writeの範囲外にある、Readのみを描画」にできるんじゃないか?
Write側を Comp Never
Read側を Comp NotEqualにすれば……。
だめか。これだけではだめで、
そのあとの
Pass replace
のあたりがミソだね。
Comp は「ref値とバッファ(現在値)を比較して、」
Comp equal は「ref値とバッファが等しいならステンシルテスト合格」
Pass は「ステンシルテストに合格した場合、バッファ値をどうするか」
Replace 「バッファをrefに置き換える」
この他に、
Fail なんてのものある。失敗時にバッファをどうするか
Fail replace なら「パステストに失敗した場合はバッファをrefに置き換える」
つまり……。
Write側:
//自分の領域はすべて描画せず、自分の領域すべてのバッファを2にする。
Stencil{
ref 2
Comp Never
Fail replace
}
Read側:
//バッファが2「ではない」領域全てで描画。
Stencil{
ref 2
Comp notequal
Pass keep
}
とすれば、ReadオブジェクトをWriteオブジェクトで隠すことができるんじゃないか。ではこれを可視領域とでっかい板に反映する。
えーと、可視領域は板より手前にないといけないから……。
・カメラ
・可視領域
・板
・その他の全部
という順にすればいいね。あと可視領域がプレイヤー本体とわずかな周囲を描画できるように、可視領域の深度に小さな球体(円形でいいんだけどないから)を置いて、そいつもWriteオブジェクトとする。
そうすっと……。うまくいくぞ!!
ってことは、例えばこのマテリアルをSpriteRendererに乗せることで、黒い板じゃなくて任意のスプライトでマスクできるかな。
うーん、さっき作ったShaderがSpriteを書くようにできてないみたいだ。
なので、新たなShaderを作って、Stencilの部分だけ追加する。
すると……。うまくいった!
Unity制作 メデューサ・ゲーム #5 More ログイン