質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

4262閲覧

Transparentなunlitシェーダに影を落としたい

gitalin

総合スコア24

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2018/05/21 05:47

編集2018/05/21 05:47

初心者なので、一部とんちんかんなことを言っているかもしれませんがご容赦くださいmm

解決したいこと

Unlit/Transparentなシェーダのマテリアルを適用したquadオブジェクトに影を落としたい。

進捗

Unlitなシェーダに影を落とすことはできたが、Transparentと共存できない。。。??
(影を落とすことはできたが、オブジェクトをColorのAlpha値などから半透明とかにすることができない)

以下に、現在のコードを記載します。

私自身、シェーダの知識が未熟でして、何がわからないのかも分からない状態です。
質問も意味不明なことを言ってしまっているかもしれませんが、なにとぞ、ご理解いただけますと幸いです。

HLSL

1 2Shader "Unlit/CastShadowTest1" { 3 Properties { 4 _Color ("Main Color", Color) = (1,1,1,1) 5 _MainTex ("Base (RGB)", 2D) = "white" {} 6 _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5 7 } 8 SubShader { 9 Tags {"Queue" = "AlphaTest" "RenderType" = "TransparentCutout"} 10 11 Pass { 12 Tags {"LightMode" = "ForwardBase"} 13 CGPROGRAM 14 #pragma vertex vert 15 #pragma fragment frag 16 #pragma multi_compile_fwdbase 17 #pragma fragmentoption ARB_fog_exp2 18 #pragma fragmentoption ARB_precision_hint_fastest 19 #pragma alphatest:_Cutoff 20 21 #include "UnityCG.cginc" 22 #include "AutoLight.cginc" 23 24 struct v2f 25 { 26 float4 pos : SV_POSITION; 27 float2 uv : TEXCOORD0; 28 LIGHTING_COORDS(1,2) 29 }; 30 31 v2f vert (appdata_tan v) 32 { 33 v2f o; 34 35 o.pos = UnityObjectToClipPos( v.vertex); 36 o.uv = v.texcoord.xy; 37 TRANSFER_VERTEX_TO_FRAGMENT(o); 38 return o; 39 } 40 41 sampler2D _MainTex; 42 float _Cutoff; 43 fixed4 _Color; 44 45 fixed4 frag(v2f i) : COLOR 46 { 47 fixed4 color = tex2D(_MainTex, i.uv); 48 clip(color.a - _Cutoff); 49 50 fixed atten = LIGHT_ATTENUATION(i); // Light attenuation + shadows. 51 //fixed atten = SHADOW_ATTENUATION(i); // Shadows ONLY. 52 return color * atten * _Color; 53 } 54 ENDCG 55 } 56 57 Pass { 58 Tags {"LightMode" = "ForwardAdd"} 59 Blend One One 60 CGPROGRAM 61 #pragma vertex vert 62 #pragma fragment frag 63 #pragma multi_compile_fwdadd_fullshadows 64 #pragma fragmentoption ARB_fog_exp2 65 #pragma fragmentoption ARB_precision_hint_fastest 66 67 #include "UnityCG.cginc" 68 #include "AutoLight.cginc" 69 70 struct v2f 71 { 72 float4 pos : SV_POSITION; 73 float2 uv : TEXCOORD0; 74 LIGHTING_COORDS(1,2) 75 }; 76 77 v2f vert (appdata_tan v) 78 { 79 v2f o; 80 81 o.pos = UnityObjectToClipPos( v.vertex); 82 o.uv = v.texcoord.xy; 83 TRANSFER_VERTEX_TO_FRAGMENT(o); 84 return o; 85 } 86 87 sampler2D _MainTex; 88 float _Cutoff; 89 fixed4 _Color; 90 91 fixed4 frag(v2f i) : COLOR 92 { 93 fixed4 color = tex2D(_MainTex, i.uv); 94 clip(color.a - _Cutoff); 95 96 fixed atten = LIGHT_ATTENUATION(i); // Light attenuation + shadows. 97 //fixed atten = SHADOW_ATTENUATION(i); // Shadows ONLY. 98 return tex2D(_MainTex, i.uv) * atten * _Color; 99 } 100 ENDCG 101 } 102 } 103 Fallback "Transparent/Cutout/VertexLit" 104} 105

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Bongo

2018/05/21 21:33

いくつか確認したいのですが、まず、そのシェーダーファイルを選択するとインスペクタに何かエラーは表示されるでしょうか(たとえば「Shader error in 'Unlit/CastShadowTest1': syntax error: unexpected token ';' at line 95」のような...)?2つ目は、実現したい描画結果は「他のオブジェクトの影を受けるが、陰付けはされない...つまりQuadが光源の方を向いていようが逆向きだろうが同じ明るさで表示される」と「他のオブジェクトの影を受け、さらに陰付けもされる」のどちらでしょうか?
gitalin

2018/05/22 02:41 編集

質問ありがとうございます! 1つ目ですが、とくにエラーは出ていないように思います。 シェーダーでエラーがあると、描画されたときになんか紫色っぽくなると思うのですが、描画自体は問題なくされているようです。 2つ目ですが、「他のオブジェクトの影を受けるが、陰付けはされない...つまりQuadが光源の方を向いていようが逆向きだろうが同じ明るさで表示される」が実現したい描画結果です。よろしくおねがいいたします。
guest

回答1

0

ベストアンサー

陰付けは不要とのことですので、それを前提に方法を調査してみました。
ですので、陰付けも一緒に行うLIGHTING_COORDSLIGHT_ATTENUATIONは使用せず、影用のマクロを用いることにしました。

現行バージョンでは、自身の上に落ちる影は下記3つのマクロが面倒を見てくれるようです。

  • UNITY_SHADOW_COORDS(idx1)...v2f定義内で使う。バーテックスシェーダーからフラグメントシェーダーへの情報伝達のための変数を追加する。引数に番号を指定することで、データ伝達に何番のテクスチャ座標用セマンティクスを使うか選べる。
  • UNITY_TRANSFER_SHADOW(a, coord)...バーテックスシェーダーで使う。av2f構造体で、それにフラグメントシェーダーに伝達するべき情報が書き込まれる。GI対応のため、coordにライトマップ用UV座標を渡してやる必要がある。
  • UNITY_SHADOW_ATTENUATION(a, worldPos)...フラグメントシェーダーで使う。aにはバーテックスシェーダーから送られてきたv2f構造体を、worldPosにはフラグメントのワールド座標を渡す。すると影係数が返ってくるので、これを出力色に掛けてやれば影の部分が暗くなる。

これらを使って下記のようにしてみましたが、あちらを立てればこちらが立たずといったジレンマが随所にあって、どこかしらに不満の残る結果になってしまいました。

  • 半透明を正しく描画するためにキューを「Transparent」にしたかったが、そうすると影描画ロジックが動かない
  • キューを「AlphaTest」にすれば影描画が行われるが、プレイモードではスカイボックス描画がAlphaTestよりも後に配置されているため、スカイボックスを透かして見る構図になると描画が破綻(背景がSolid Colorか不透明オブジェクトなら大丈夫そうです)するので対策が必要
  • 影描画はデプスシャドウ技法に基づくロジックになっているが、半透明をうまく扱うのは難しそう(シャドウマップ作成時にディザリングを行ってみたものの、ノイズが気になる...ノイズ除去フィルタを加えればマシになるかもしれませんが未実験です)

HLSL

1Shader "Unlit/CastShadowTest1" 2{ 3 Properties 4 { 5 _Color ("Main Color", Color) = (1, 1, 1, 1) 6 _MainTex ("Base (RGB)", 2D) = "white" { } 7 _ShadowIntensity ("Shadow Intensity", Range(0.0, 1.0)) = 0.5 // 大きくするほど影が暗くなる 8 // _Cutoff ("Alpha cutoff", Range(0, 1)) = 0.5 // 半透明物体の場合、アルファカットオフを可変にはせずに... 9 [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0 // カットオフをトグルで切り替え、オンならば固定値0.001でカットオフするケースが多いようです 10 } 11 CGINCLUDE 12 // 影係数の取得および緩和に使う 13 // 1 - (1 - 影係数) * _ShadowIntensity を最終的な影係数とすることで、影が暗くなりすぎるのを防ぐ 14 #define FADED_SHADOW_ATTENUATION(i) (1.0 - (1.0 - UNITY_SHADOW_ATTENUATION(i, i.worldPos)) * _ShadowIntensity) 15 ENDCG 16 SubShader 17 { 18 // Queueが「AlphaTest」になっていましたが、おそらく妥当な方法だと思います 19 // 本来は「AlphaTest」はアルファを基に完全透明・完全不透明を切り替えるタイプの不透明オブジェクトに 20 // 用いるもので、半透明オブジェクトは「Transparent」を使うべきかと思いますが、そうしてしまうと 21 // 影機能も使えなくなってしまうようです 22 // 半透明オブジェクトを正しくアルファ合成するには他の不透明オブジェクトよりも後に描画させたいところですが 23 // 「AlphaTest」なら一般的な不透明オブジェクトの「Geometry」よりは後になるそうなので、描画不具合も 24 // 起こりにくいのではないでしょうか 25 Tags { "Queue" = "AlphaTest" "RenderType" = "TransparentCutout" } 26 // シャドウキャスティングパス 27 // LightModeが「ShadowCaster」のパスがないと、影を落とす・受けるのいずれも行われなくなるようです 28 // コード末尾にFallbackを記述しておくことで他のシェーダーに処理を代替させることもできますが、 29 // 今回は半透明の特殊なケースですので、自前で用意することにしました 30 // なお、旧バージョンでは「ShadowCollector」パスが影を受ける処理を担当していたそうですが 31 // 現在は廃止されたようです 32 Pass 33 { 34 Name "ShadowCaster" 35 Tags { "LightMode" = "ShadowCaster" } 36 ZWrite On ZTest LEqual 37 CGPROGRAM 38 #define UNITY_STANDARD_USE_DITHER_MASK 39 #define UNITY_STANDARD_USE_SHADOW_UVS 40 #pragma target 3.0 41 #pragma vertex vert 42 #pragma fragment frag 43 #include "UnityStandardShadow.cginc" 44 struct VertexOutput 45 { 46 V2F_SHADOW_CASTER_NOPOS 47 float2 tex: TEXCOORD1; 48 }; 49 void vert(VertexInput v, out VertexOutput o, out float4 opos: SV_POSITION) 50 { 51 TRANSFER_SHADOW_CASTER_NOPOS(o, opos) 52 o.tex = v.uv0; 53 } 54 half4 frag(VertexOutput i, UNITY_VPOS_TYPE vpos: VPOS): SV_Target 55 { 56 // シャドウマップへの描画は原理的に完全透明か完全不透明でないとなりません 57 // そこで、Unity組み込みのディザリング用テクスチャをアルファに基づいて参照することで 58 // アルファが小さいほど高確率で透明、大きいほど不透明となるような動作をさせることができます 59 // できあがるシャドウマップにはディザリングによるノイズが乗っていますが、ソフトシャドウモードなら 60 // 後で近傍比率フィルタリングがかかるので、影に関してはさほど見た目は悪くないと思われます 61 // 半透明部分のエッジにノイズが目立つかもしれませんが、これはポストエフェクトなどでごまかす...? 62 half alpha = tex2D(_MainTex, i.tex.xy).a * _Color.a; 63 alpha = tex3D(_DitherMaskLOD, float3(vpos.xy * 0.25, alpha * 0.9375)).a; 64 // 場合によっては下記1行をコメントアウトして、Quad全面を完全描画させた方が良好な結果になるかと思います 65 clip(alpha - 0.01); // ディザリングの結果アルファ0.01未満になればフラグメントを破棄 66 SHADOW_CASTER_FRAGMENT(i) 67 } 68 69 ENDCG 70 } 71 // フォワードレンダリングベースパス 72 Pass 73 { 74 Name "ForwardBase" 75 Tags { "LightMode" = "ForwardBase" } 76 Blend SrcAlpha OneMinusSrcAlpha // 一般的なアルファ合成方式を使用 77 ZWrite On ZTest LEqual 78 CGPROGRAM 79 80 #pragma vertex vert 81 #pragma fragment frag 82 #pragma fragmentoption ARB_fog_exp2 83 #pragma fragmentoption ARB_precision_hint_fastest 84 #pragma multi_compile_fwdbase 85 #pragma multi_compile _ UNITY_UI_ALPHACLIP // アルファクリップがオン・オフの場合でマルチコンパイル 86 #include "UnityCG.cginc" 87 #include "AutoLight.cginc" 88 sampler2D _MainTex; 89 fixed4 _Color; 90 float _ShadowIntensity; 91 struct v2f 92 { 93 float4 pos: SV_POSITION; // UNITY_TRANSFER_SHADOW内ではクリッピング座標の名前が「pos」であることが前提になっているため、そのようにする(ご質問者さんのコードでは、すでにそうなっていました) 94 float2 uv: TEXCOORD0; 95 UNITY_SHADOW_COORDS(1) // TEXCOORD1を影情報伝達に使用する 96 float3 worldPos: TEXCOORD2; // TEXCOORD2をワールド座標伝達に使用する 97 }; 98 v2f vert(appdata_full v) // 頂点入力データの形式として、appdata_tanに代わってappdata_fullを使う 99 { 100 v2f o; 101 o.pos = UnityObjectToClipPos(v.vertex); 102 o.uv = v.texcoord.xy; 103 UNITY_TRANSFER_SHADOW(o, v.texcoord1); // texcoord1にライトマップ用UVが格納されているので、それを使って影情報の計算を行う 104 o.worldPos = mul(unity_ObjectToWorld, v.vertex); // worldPosに頂点のワールド座標をセットする 105 return o; 106 } 107 fixed4 frag(v2f i): SV_Target 108 { 109 fixed4 color = tex2D(_MainTex, i.uv) * _Color; 110 #ifdef UNITY_UI_ALPHACLIP 111 clip(color.a - 0.001); // アルファ0.001未満は完全透明と見なし、フラグメントを破棄してレンダリングしない 112 #endif 113 color.rgb *= FADED_SHADOW_ATTENUATION(i); // 影係数はアルファには作用させない 114 return color; 115 } 116 ENDCG 117 118 } 119 120 // フォワードレンダリング加算パス 121 Pass 122 { 123 Name "ForwardAdd" 124 Tags { "LightMode" = "ForwardAdd" } 125 Blend DstColor Zero // 普通は加算パスでは照明効果をどんどん加算していくかと思いますが、今回は影をどんどん乗算していくことにしました 126 ZWrite Off 127 CGPROGRAM 128 129 #pragma vertex vert 130 #pragma fragment frag 131 #pragma fragmentoption ARB_fog_exp2 132 #pragma fragmentoption ARB_precision_hint_fastest 133 #pragma multi_compile_fwdadd_fullshadows 134 #pragma multi_compile _ UNITY_UI_ALPHACLIP 135 #include "UnityCG.cginc" 136 #include "AutoLight.cginc" 137 sampler2D _MainTex; 138 fixed4 _Color; 139 float _ShadowIntensity; 140 // v2f、vertはベースパスと同じ(CGINCLUDEやcgincを使って共通コードをまとめることも可能かと思います) 141 struct v2f 142 { 143 float4 pos: SV_POSITION; 144 float2 uv: TEXCOORD0; 145 UNITY_SHADOW_COORDS(1) 146 float3 worldPos: TEXCOORD2; 147 }; 148 v2f vert(appdata_full v) 149 { 150 v2f o; 151 o.pos = UnityObjectToClipPos(v.vertex); 152 o.uv = v.texcoord.xy; 153 UNITY_TRANSFER_SHADOW(o, v.texcoord1); 154 o.worldPos = mul(unity_ObjectToWorld, v.vertex); 155 return o; 156 } 157 fixed4 frag(v2f i): SV_Target 158 { 159 float alpha = tex2D(_MainTex, i.uv).a * _Color.a; 160 #ifdef UNITY_UI_ALPHACLIP 161 clip(alpha - 0.001); // アルファ0.001未満は完全透明と見なし、フラグメントを破棄してレンダリングしない 162 #endif 163 float attenuation = FADED_SHADOW_ATTENUATION(i); 164 return fixed4(attenuation, attenuation, attenuation, 1.0); 165 } 166 ENDCG 167 168 } 169 } 170}

描画結果1

半透明部分にディザリングによるノイズが目立ちます。また、スカイボックス描画順問題の対策をしていないので、ゲームビューではスカイボックスの半透明部分を透かして見た部分が描画されていません。シーンビューではスカイボックスが最初にレンダリングされるらしく、ちゃんと透けています。
結果1

描画結果2

上記コードのシャドウキャスティングパスでclip(alpha - 0.01);をコメントアウトするとこうなります。デプスが単なる四角い板と同じになるので、落とす影が四角くなったり、前後関係を正しく表現できなかったりするかもしれませんが、ノイズは現れないのでこの方が好都合な場合もあるでしょう。
結果2

描画結果3

スカイボックス問題の対策として、

  • カメラを複製する。複製したカメラは元のカメラの子にして、カメラを動かせば追従して動くようにする。
  • 元のカメラの「Clear Flags」を「Don't Clear」とし、背景描画をさせなくする。
  • 複製したカメラの「Culling Mask」を「Nothing」にし、背景だけを描画させる。
  • 複製したカメラの「Depth」を元のカメラより小さくし(例えば-2)、複製したカメラの方を先に描画させるようにする。

とした場合です。とりあえずゲームビューでも背景の破綻は起こらなくなりました。
結果3

投稿2018/05/23 21:40

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gitalin

2018/05/28 06:23

とても詳細な解説をありがとうございます!! いただいた回答の描画結果2で無事解決に致しました! 仕事が忙しく返信が遅れてしまい大変申し訳ありませんでした! この度は本当にありがとうございました~mmm
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問