Unity シェーダーチュートリアル アルファとアルファテスト
シェーダー
前回、サーフェースシェーダーの基礎について書きましたが、
今回も基礎の引き続きでアルファ(透明)とアルファテストについて書いていきます。
アルファとアルファテストの違い
どちらもオブジェクトを透明にする為に使用しますが、以下のように使い分けをします。
◆ アルファ
ガラスのような、透明だけどそこにあるモノ。(透明で反射が出る)
幽霊のような、存在が希薄なモノ。(透明で反射が出ない)
半透明の表現ができる。
◆ アルファテスト
植物の葉のような、完全に無い部分をくり抜きたいモノ。
ジオメトリで表現するのが大変なのでテクスチャでくり抜く。
半透明の表現はなく、そこに有るか無いか。(くり抜かれた部分に反射は出ない)
アルファテスト
以下が基本的なアルファテストのシェーダーコードになります。
だいたいの意味は前回の記事を参照すれば分かると思います。
不透明シェーダーとの記述の違いを見ていきましょう。
閾値用のプロパティ
_Cutoff ("Cutoff", Range(0, 1)) = 0.5
Propaties のところに、_Cutoff という変数があります。
これは、テクスチャのアルファチャンネルに描かれた0~255の快調の中の、
どこをボーダーとしてくり抜くかを指定するプロパティになります。
簡単な例を示します。
まず、テクスチャのRGBチャンネルとアルファチャンネルに、
中心から外側に向かう四角形状のグラデーションが描かれているとします。
閾値のプロパティが0.5の場合、アルファチャンネルの128の階調がボーダーとなり、
255~128の階調に当たる中心が「有る部分」、127~0の快調に当たる外側が「無い部分」とされます。
分かりやすく説明するためにグラデーションを例にしましたが、
以下のようにボーダーのはっきりしたアルファチャンネルで、閾値を0.5にするのが普通です。
サーフェースシェーダーの設定
ただ閾値用のプロパティを宣言しただけでは、当然何の効果も成しません。
_Cutoff という変数名に役割があるわけでもありません。
「アルファテストの閾値として使用する」という設定が必要です。
それがサーフェースシェーダーのオプションとして記述してある alphatest:_Cutoff の部分です。
#pragma surface surf Standard fullforwardshadows alphatest:_Cutoff
このオプションを追加すると、アルファテストシェーダーとして働きます。
(当然ですが、_Cutoff という変数名である必要はないです)
そして、サーフェースシェーダー関数の o.Alpha にテクスチャのアルファチャンネルを接続すれば、
その形でくり抜きができます。
void surf (Input IN, inout SurfaceOutputStandard o) {
fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
o.Alpha = c.a;
}
上記コードではテクスチャに _Color を掛け合わせています。
アルベドに使用するRGBチャンネルとカラーとの掛け合わせは良くやりますが、
半透明の表現ができないアルファテストシェーダーにおいて、
アルファチャンネルにアルファを掛け合わせる必要性は特にない気がします。
私の場合は、以下の様にする事が多いです。
(やりたい事が明確になるので、後で見た時に混乱しない)
sampler2D _MainTex;
fixed3 _Color;
void surf (Input IN, inout SurfaceOutputStandard o) {
fixed4 mainTex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = mainTex.rgb * _Color;
o.Alpha = mainTex.a;
}
以下のコードも追加されています。これは両面を描画したい時の記述です。
Cull Off
Tagsの設定
少し前後しましたが、Tags の中を見てみましょう。
Tags {
"Queue" = "AlphaTest"
"RenderType" = "TransparentCutout"
}
ここは特に難しく考えずに、アルファテストシェーダーの通例として、
こう書いておけば概ね問題ないでしょう。
Fallbackの設定
最後にすべり止めシェーダーである、Fallback の設定です。
ここもアルファテストシェーダーの通例として以下のようにしておけば良いでしょう。
Fallback "Transparent/Cutout/Diffuse"
試しに、不透明シェーダーを Fallback に設定して見てください。
Fallback "Diffuse"
どちらも、球体に葉のアルファテストシェーダーを当てたものになりますが、
左奥が、Fallback に Transprent/Cutout/Diffuse を指定したシェーダー。
右手前が、Fallback に Diffuse を指定したシェーダーです。
前者は、アルファテストでくり抜かれた形に合わせて、正しく影が描画されているのに対し、
後者は、くり抜かれる前の球体の影が出てしまっています。
この様に、シェーダーに合わせて適切な Fallback を設定しないと、
影の描画がおかしな事になってしまいます。
影の描画を定義するシェーダーパス
ではなぜ、この様な事が起きてしまうのでしょうか?
それは、Shadow Caster と Shadow Collector という影の描画を定義する
シェーダーの記述が関係しています。
しかし、上記シェーダーコードを見ても、どこにもそのような記述は見当たりません。
そうです、書いていないのです。
書かない事によって Fallback のすべり止め効果が働き、
そちらに定義されている影の描画を利用します。
かいつまんで簡単に図解すると以下の様な感じです。
つまり、A と D のルートを通って描画しているわけです。
Transparent/Cutout/Diffuse の様な Unity のビルトインシェーダーには影の記述が含まれています。
Shadow Caster や Shadow Collector は、よほど特別なシェーダーを作りたい時以外は、
Fallback のビルトインシェーダーに任せてしまって、ほぼ問題ないと思います。
アルファ
以下が基本的なアルファのシェーダーコードになります。
サーフェースシェーダーの設定
以下のように、サーフェースシェーダーのオプションに alpha を追記すれば、
透明シェーダーとして働きます。
この場合、透明になっても反射が出るので、ガラスの様な表現に使用できます。
#pragma surface surf Standard fullforwardshadows alpha
幽霊のように、透明にして存在を消したい場合は(反射させたくない)、alpha:fade を使用します。
#pragma surface surf Standard fullforwardshadows alpha:fade
そして、サーフェースシェーダー関数の o.Alpha に _Color のアルファチャンネルをつなげれば、
不透明度を設定できるようになります。
テクスチャのアルファチャンネルとの掛け合わせも良いでしょう。
void surf (Input IN, inout SurfaceOutputStandard o) {
fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
o.Alpha = c.a
}
Tagsの設定
Tags の中を見てみましょう。
Tags {
"Queue" = "Transparent"
"RenderType" = "Transparent"
}
ここは特に難しく考えずに、透明シェーダーの通例として、
こう書いておけば概ね問題ないでしょう。
Fallbackの設定
Fallback の設定は、透明シェーダーの通例として以下のようにしておけば良いでしょう。
Fallback "Transparent/Diffuse"
透明シェーダーの影について
ビルトインシェーダーの Standard を Transparent 設定にして、
オブジェクトに割り当ててみましょう。すると、以下のようになります。
左奥が、今回作った透明シェーダーで、
右手前が、ビルトインシェーダーの Standard (Transparent) です。
Standard (Transparent) の方だけに、半透明の影が付いています。うらやましい。
Fallback に Transparent/Diffuse というビルトインシェーダーを適用したにもかかわらず、
影が付いてこないのは、Unityには半透明の影のサポートがないからです。
アルファテストの項で説明したとおり、影の描画には影用のシェーダー記述が必要です。
Standard シェーダーには半透明な影を描画するための、特別な記述が施されています。
つまり、Fallback に "Standard" と記述すれば、何と半透明の影が付いてくるのです。
ただし、以下の手順を踏む必要があります。
こうしないと、Fallback の影が半透明の設定になりません。
① マテリアルを一旦 Standard(Transparent) にする。
② 続けてカスタムの透明シェーダーに変更する
結局 Fallback はどうすれば?
前回、今回と、Fallback はすべり止め効果があるので
極力単純なシェーダーを指定しましょうと説明してきました。
Fallback "Diffuse" // 不透明シェーダー
Fallback "Transparent/Diffuse" // 透明シェーダー
Fallback "Transpaent/Cutout/Diffuse" // アルファテストシェーダー
しかし、明らかに古いハードウェアで実行する可能性がない場合や、
影レンダリングの重要項として捉える場合は、
用途に合わせて変えていった方が良いかもしれません。
おわりに
次回はアルファテストの項でも登場した、両面描画についてもう少し詳しく書いていきます。
[…] アルファとアルファテスト | Tsumiki Tech Times […]
[…] アルファとアルファテスト | Tsumiki Tech Times […]