【UnityShader】リムライティング #8
前回の成果
ドラゴンが氷っぽくなった。
今回やること
ドラゴンをリムライティングっぽくします!
前回とやることはほぼ同じそうですね。
ちなみにリムライティングとは、
このように、モデルの後方からライトが当たっている状態を再現することです。
ではやっていきましょう!
ソースコード
Shader "Custom/rimlighting" { SubShader { Tags { "RenderType" = "Opaque"} LOD 200 CGPROGRAM #pragma surface surf Standard #pragma target 3.0 struct Input { float3 worldNormal; float3 viewDir; }; void surf(Input IN, inout SurfaceOutputStandard o) { fixed4 baseColor = fixed4(0.05f,0.1f,0,1.0f); fixed4 rimColor = fixed4(0.5f,0.7f,0.5f,1.0f); o.Albedo = baseColor; float rim = 1 - saturate(dot(IN.viewDir,IN.worldNormal)); o.Emission = rimColor * pow(rim, 2); } ENDCG } FallBack "Diffuse" }
ソースコードも前回とほぼ同じですね。
異なっている部分は
float rim = 1 - saturate(dot(IN.viewDir,IN.worldNormal)); o.Emission = rimColor * pow(rim, 2);
この部分と
Tags { "RenderType" = "Opaque"}
この部分です。
Emissonってなんだっけ、と忘れてしまった方
、発行度合いのことです。
詳しくはこちらをどうぞ。
saturate??pow??
まずは、この2つのキーワードについて説明していきたいと思います。
saturate
引数に持たせた数字を0〜1の間に収める関数です。
int a = -10; int b = 2; float c = 0.5f; // 0が返ってくる saturate(a); // 1が返ってくる saturate(b); // 0.5が返ってくる saturate(c);
pow
// xのy乗返す
pow(x,y)
いちいち*を書かなくて良いのが便利そうですね。
疑問点
察しの良い人なら気付いていると思いますが、今回と前回で2つの疑問点が浮かんでいると思います。
- absとsaturate、結局カメラから裏見えないからどっちでも良い?
- SurfaceOutputStandardにもNormalなかった?
この2つです。
absとsaturate、結局カメラから裏見えないからどっちでも良い?
正直、どっちでも良いと思います。
しかし、今回のようなソースを書き、裏が完全に見えてしまうならsaturateの方が裏も正しい計算で通るのでそちらの方がよいかと。
SurfaceOutputStandardにもNormalなかった?
実はその他にももう1種類あります。
名称 | 用途 |
---|---|
SurfaceOutput Normal | 書き込まれる場合は、接地空間法線 |
input worldNormal | サーフェスシェーダーがSurfaceOutput Normalに書き込まない場合のワールドの法線ベクトルを含む |
input worldNormal; INTERNAL_DATA | サーフェスシェーダーがSurfaceOutput Normalに書き込む場合のワールドの法線ベクトルを含む。※ピクセル法線マップに基づいて法線ベクトルを取得するには、WorldNormalVector(IN, o.Normal)を使用する |
となっています。
今回のケースの場合、SurfaceOutput Normalに書き込まないのでどれを使用しても同じです。
詳しくはこちらのサイト様へ
docs.unity3d.com
RenderType
今まではQueueで描画順を指定していたと思います。
RenderTypeはどのように描画するかを決めるものです。
名称 | 用途 |
---|---|
Opaque | ほとんどのシェーダー |
Transparent | ほとんどが透過しているシェーダー(パーティクル等) |
TransparentCutout | マスキングされた透過シェーダー |
Background | Skybox |
Overlay | GUITexture、ハロー、フレアシェーダー |
TreeOpaque | Terrainの樹皮 |
TreeTransparentCutout | Terrainの木の葉 |
TreeBillboard | Terrainのビルボードされた木 |
Grass | Terrainの草 |
GrassBillboard | Terrainのビルボードされた草 |
となっています。
今回は特に特別な描画方法を使用しないので、Opaqueを使用します。
詳しい説明はこちらのサイト様に記述してあります。
不明な単語集
いくつかなんだそれ、となる言葉が出てきたと思うので解説していきたいと思います。
WorldNormalVector
法線情報をオブジェクトのローカル座標からワールド座標に変換するための関数です。
ハロー
ハロー(Halo)とは、光源周辺の明るいエリアを細かい粉塵で表現しているものです。
Halo - Unity マニュアル:より引用
フレアシェーダー
原文通り、flare shadersで検索してもヒットしなかったのでおそらくレンズフレアのことかなと思います。
Terrain
手軽に地形を作成できるUnityの機能の1つです。
ビルボード
2Dのテクスチャが3D空間で常にカメラの方向を向くようにすることです。
今回の成果
少しわかりにくいですが、ドラゴンの輪郭が光っています。
コメントを付与
Shader "Custom/rimlighting" { // あとで理解する SubShader { // 一般的なシェーダーを使用 Tags { "RenderType" = "Opaque"} // しきい値 LOD 200 // あとで理解する CGPROGRAM // あとで理解する #pragma surface surf Standard // あとで理解する #pragma target 3.0 // input構造体 struct Input { // 1ピクセル毎の法線 float3 worldNormal; // カメラからの視線 float3 viewDir; }; // surf関数 void surf(Input IN, inout SurfaceOutputStandard o) { // ベースカラーの変更 fixed4 baseColor = fixed4(0.05f,0.1f,0,1.0f); // リムライティングの色を決める fixed4 rimColor = fixed4(0.5f,0.7f,0.5f,1.0f); o.Albedo = baseColor; // リムライティングの度合いを法線と視線の2つのベクトルから取得 float rim = 1 - saturate(dot(IN.viewDir,IN.worldNormal)); // 発行度合いを調整する o.Emission = rimColor * pow(rim, 2); } // あとで理解する ENDCG } // あとで理解する FallBack "Diffuse" }
今回は以上となります。
次回もおもちゃラボ様を参考にシェーダーの勉強をしていきます!