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

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

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

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

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

3DCG

コンピュータの演算により、3次元空間の仮想物体を、2次元平面上で表現する手法である。

Q&A

1回答

1347閲覧

Dirctional LightのBias値はどのように内部で格納されますか

RY__

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

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

3DCG

コンピュータの演算により、3次元空間の仮想物体を、2次元平面上で表現する手法である。

0グッド

0クリップ

投稿2021/05/14 07:25

編集2021/05/14 07:26

知りたいこと

unityのシェーダーを勉強中のものです.
シャドウアクネを解消するために,ShadowCastのパスの際に3Dモデルをオフセットする処理があると思います.Directional LightのBiasやNormal Biasです.
Directional LightのInspectorにBiasやNormalBiasを入力する箇所がありますが,それらが何という変数に格納されるかを知りたいです.

###今わかっていること

unity_LightShadowBiasという変数に,BiasやNormalBiasに関係した値が入っていることまでは分かりましたが,その値はBias,NormalBiasそのものではありませんでした.
以下のコードはBias及びNormalBiasの処理のマクロを書き下したものです.

例えば,DirctionalLightのNormalBiasを1にしたときと,以下コードのunity_LightShadowBias.zを1で置換してレンダリングされたときでは,影のつき方が変わりました.なので,NormalBiasの値を何かしら処理された後の値がunity_LightShadowBias.zに格納されていると思います.

unity_LightShadowBiasにはどのような値が入っているかということも知りたいです.

Cg

1 2struct v2f_forShadowCast{ //ShadowCastパスの頂点シェーダー出力型 3 float4 pos : SV_POSITION; 4}; 5 6 7v2f_forShadowCast vs_forShadowCast(appdata v) //ShadowCast用頂点シェーダー 8{ 9 v2f_shadow o; 10 11 float4 worldPos = mul(unity_ObjectToWorld, v.pos); 12 half3 worldNormal = UnityObjectToWorldNormal(v.normal); 13 14 half3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos.xyz)); 15 half NdotL = dot(worldNormal, lightDir); 16 half Sine = sqrt(1 - NdotL * NdotL); 17 18 o.pos.xyz = worldPos.xyz - worldNormal * _NormalBias * unity_LightShadowBias.z * Sine; 19 20 o.pos.w = worldPos.w; 21 o.pos = UnityWorldToClipPos(o.pos); 22 23 #if defined(UNITY_REVERSED_Z) 24 o.pos.z += max(-1, min(unity_LightShadowBias.x / o.pos.w, 0)); 25 float clamped = min(o.pos.z, o.pos.w * UNITY_NEAR_CLIP_VALUE); 26 #else 27 o.pos.z += saturate(unity_LightShadowBias.x / o.pos.w); 28 float clamped = max(o.pos.z, o.pos.w * UNITY_NEAR_CLIP_VALUE); 29 #endif 30 o.pos.z = lerp(o.pos.z, clamped, unity_LightShadowBias.y); 31 32 return o; 33}

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

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

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

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

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

guest

回答1

0

おっしゃるとおりunity_LightShadowBiasが一体何なのか検索してみても、明確な情報はひっかかりませんね...
かろうじてヒントになりそうなのはUnityCG.cgincに記述されている...

ShaderLab

1float4 UnityClipSpaceShadowCasterPos(float4 vertex, float3 normal) 2{ 3 float4 wPos = mul(unity_ObjectToWorld, vertex); 4 5 if (unity_LightShadowBias.z != 0.0) 6 { 7 float3 wNormal = UnityObjectToWorldNormal(normal); 8 float3 wLight = normalize(UnityWorldSpaceLightDir(wPos.xyz)); 9 10 // apply normal offset bias (inset position along the normal) 11 // bias needs to be scaled by sine between normal and light direction 12 // (http://the-witness.net/news/2013/09/shadow-mapping-summary-part-1/) 13 // 14 // unity_LightShadowBias.z contains user-specified normal offset amount 15 // scaled by world space texel size. 16 17 float shadowCos = dot(wNormal, wLight); 18 float shadowSine = sqrt(1-shadowCos*shadowCos); 19 float normalBias = unity_LightShadowBias.z * shadowSine; 20 21 wPos.xyz -= wNormal * normalBias; 22 } 23 24 return mul(UNITY_MATRIX_VP, wPos); 25}

のコメントぐらいでしょうか。ですがそれもzについてだけであり、xyについては言及されていないようです。

多少なりともご参考になれば...と思いまして、「マテリアルのインスペクター上でBiasとNormal Biasを独自に設定して影を描く」というのを目標にフレームデバッガーで変数の値を観察しつつ試行錯誤して、下記のような計算式をひねり出してみました。

ShaderLab

1Shader "Unlit/CustomShadowBias" 2{ 3 Properties 4 { 5 _MainTex ("Texture", 2D) = "white" {} 6 _ShadowIntensity ("Shadow Intensity", Range(0.0, 1.0)) = 0.5 7 [Toggle(CUSTOM_BIAS_ENABLED)] _UseCustomBias ("Use Custom Bias", Float) = 0 8 _ShadowMapResolution ("Shadow Map Resolution", Int) = 1024 9 _Bias ("Bias", Range(0.0, 2.0)) = 0.05 10 _NormalBias ("Normal Bias", Range(0.0, 3.0)) = 0.4 11 } 12 SubShader 13 { 14 Tags { "RenderType"="Opaque" "LightMode"="ForwardBase" } 15 16 Pass 17 { 18 CGPROGRAM 19 #pragma vertex vert 20 #pragma fragment frag 21 #pragma multi_compile_fwdbase 22 23 #include "UnityCG.cginc" 24 #include "AutoLight.cginc" 25 26 struct appdata 27 { 28 float4 vertex : POSITION; 29 float2 uv : TEXCOORD0; 30 }; 31 32 struct v2f 33 { 34 float2 uv : TEXCOORD0; 35 float4 pos : SV_POSITION; 36 SHADOW_COORDS(1) 37 }; 38 39 sampler2D _MainTex; 40 float4 _MainTex_ST; 41 float _ShadowIntensity; 42 43 v2f vert(appdata v) 44 { 45 v2f o; 46 o.pos = UnityObjectToClipPos(v.vertex); 47 o.uv = TRANSFORM_TEX(v.uv, _MainTex); 48 TRANSFER_SHADOW(o) 49 return o; 50 } 51 52 fixed4 frag(v2f i) : SV_Target 53 { 54 fixed4 color = tex2D(_MainTex, i.uv); 55 color.rgb *= lerp(1.0, SHADOW_ATTENUATION(i), _ShadowIntensity); 56 return color; 57 } 58 ENDCG 59 } 60 61 Pass 62 { 63 Tags { "LightMode"="ShadowCaster" } 64 65 CGPROGRAM 66 #pragma vertex vert 67 #pragma fragment frag 68 #pragma multi_compile_shadowcaster 69 #pragma multi_compile _ CUSTOM_BIAS_ENABLED 70 #include "UnityCG.cginc" 71 72 struct v2f { 73 V2F_SHADOW_CASTER; 74 }; 75 76 int _ShadowMapResolution; 77 float _Bias; 78 float _NormalBias; 79 80 float3 shadowBias() 81 { 82 float3 bias = unity_LightShadowBias.xyz; 83 84 #ifdef CUSTOM_BIAS_ENABLED 85 // yはDirectionalなら1、それ以外なら0になる? 86 float isDirectional = bias.y; 87 88 // xはBiasに比例して変化しているように見える 89 // Directionalの場合はBiasにクリップ空間の奥行きスケールを乗じたもの? 90 // Directional以外だと、xの絶対値はBiasがそのまま入ってくるように見える 91 // 符号はPointだと1、それ以外だと-1? 92 #ifdef SHADOWS_CUBE 93 float biasXSign = 1.0; 94 #else 95 float biasXSign = -1.0; 96 #endif 97 bias.x = lerp(1.0, UNITY_MATRIX_P._33, isDirectional) * biasXSign * _Bias; 98 99 // zはNormal Biasに比例して変化しているように見える 100 // Directionalの場合はNormal Biasを2倍し、クリップ空間の水平スケール×ビューポートサイズで割ったもの? 101 // Directional以外だと常に0? 102 // ビューポートサイズがやっかいで、おそらく https://docs.unity3d.com/Manual/shadow-mapping.html で 103 // 説明されているShadow map resolutionと同一だと思うが、それをシェーダー上で取得する方法がわからない... 104 // さしあたり_ShadowMapResolutionとしてインスペクター上で与えるようにしたが、これだとシャドウマップの 105 // 実際の解像度に応じて自動的に設定することができず、いまいち便利でない 106 // スクリプト上で計算してシェーダーに与えてやることになるのだろうか? 107 bias.z = lerp(0.0, 2.0 / (UNITY_MATRIX_P._11 * _ShadowMapResolution), isDirectional) * _NormalBias; 108 109 // ShadowCasterパスはカメラ視点でのデプスレンダリング(UpdateDepthTexture)と 110 // ライト視点でのシャドウマップレンダリング(Shadows.RenderShadowMap)の両方で使われるが 111 // どうやらUpdateDepthTextureではunity_LightShadowBiasは(0, 0, 0, 0)となり 112 // バイアスがかからないようになっているらしい? 113 // UpdateDepthTextureでバイアスをかけてしまうと、カメラ視点でのデプスが狂い 114 // スクリーンスペースでの影レンダリング(Shadows.CollectShadows)時に異常な影を 115 // 生じてしまいそうだった 116 // UpdateDepthTextureとShadows.RenderShadowMapのどちらであるかをシェーダー上で 117 // 区別する方法がわからず、しかたないのでunity_LightShadowBiasがゼロベクトルなら 118 // biasも全成分ゼロにすることにした 119 bias = lerp(0.0, bias, sign(dot(unity_LightShadowBias, unity_LightShadowBias))); 120 #endif 121 122 return bias; 123 } 124 125 // Normal Biasの適用 126 float4 clipSpaceShadowCasterPos(float4 vertex, float3 normal, float3 bias) 127 { 128 float4 wPos = mul(unity_ObjectToWorld, vertex); 129 130 if (bias.z != 0.0) 131 { 132 float3 wNormal = UnityObjectToWorldNormal(normal); 133 float3 wLight = normalize(UnityWorldSpaceLightDir(wPos.xyz)); 134 float shadowCos = dot(wNormal, wLight); 135 float shadowSine = sqrt(1 - shadowCos * shadowCos); 136 float normalBias = bias.z * shadowSine; 137 138 wPos.xyz -= wNormal * normalBias; 139 } 140 141 return mul(UNITY_MATRIX_VP, wPos); 142 } 143 144 // Biasの適用 145 float4 applyLinearShadowBias(float4 clipPos, float3 bias) 146 { 147 #if !(defined(SHADOWS_CUBE) && defined(SHADOWS_CUBE_IN_DEPTH_TEX)) 148 #if defined(UNITY_REVERSED_Z) 149 clipPos.z += max(-1, min(bias.x / clipPos.w, 0)); 150 #else 151 clipPos.z += saturate(bias.x / clipPos.w); 152 #endif 153 #endif 154 155 #if defined(UNITY_REVERSED_Z) 156 float clamped = min(clipPos.z, clipPos.w * UNITY_NEAR_CLIP_VALUE); 157 #else 158 float clamped = max(clipPos.z, clipPos.w * UNITY_NEAR_CLIP_VALUE); 159 #endif 160 161 clipPos.z = lerp(clipPos.z, clamped, bias.y); 162 163 return clipPos; 164 } 165 166 v2f vert(appdata_base v) 167 { 168 v2f o; 169 float3 bias = shadowBias(); 170 171 #if defined(SHADOWS_CUBE) && !defined(SHADOWS_CUBE_IN_DEPTH_TEX) 172 o.vec = mul(unity_ObjectToWorld, v.vertex).xyz - _LightPositionRange.xyz; 173 o.pos = UnityObjectToClipPos(v.vertex); 174 #else 175 o.pos = clipSpaceShadowCasterPos(v.vertex, v.normal, bias); 176 o.pos = applyLinearShadowBias(o.pos, bias); 177 #endif 178 179 return o; 180 } 181 182 float4 frag(v2f i) : SV_Target 183 { 184 float3 bias = shadowBias(); 185 186 #if defined(SHADOWS_CUBE) && !defined(SHADOWS_CUBE_IN_DEPTH_TEX) 187 return UnityEncodeCubeShadowDepth((length(i.vec) + bias.x) * _LightPositionRange.w); 188 #else 189 return 0; 190 #endif 191 } 192 ENDCG 193 } 194 } 195}

ですが、シャドウマップの解像度をインスペクターで指定してやらなければならず不便で、計算式もあれでいいのか自信がありません。信頼できる情報筋...できればUnity Technologiesの方からの意見をいただきたいところではあります。
What's in unity_LightShadowBias? - Unity Answers」で類似した質問が出ているようですが(もしかしてご質問者さんご本人でしょうかね?)、あちらならUnityの開発者さんの目にとまりやすいかもしれません。時折チェックして新情報が投稿されていないかご確認いただくといいかと思います。

投稿2021/05/16 00:27

Bongo

総合スコア10807

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

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

RY__

2021/05/16 07:46

何とご丁寧に,ありがとうございます! 実験的に値を確かめていただいたようで,非常に感謝します. プロジェクション行列などでスケーリングされているような感じなんですね. まだじっくり意味を見て読むところまでできていないので,また質問をさせていただくかもしれません. 少し話がそれますが,フレームデバッガーを使ってシェーダーが持つ変数の値を見れるのですね. フレームデバッガ―はシャドウマップのレンダリング確認くらいでしか使用したことがなく,そのような使い方ができることを初めて知り感動しました. シェーダーのデバッグ(特に変数の値のデバッグ)が今までできなくて,かなり苦労したので非常にありがたい知見になりました. 最後におっしゃっていただいた,Unityの掲示板での質問はご推測通り私が投稿したものです.(笑) まだご回答が得られず,こちらで質問させていただいた次第です. 改めましてじっくり調査していただいて誠に感謝いたします. また質問をさせていただくかもしれませんが,非常に助かりました.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問