UNITYシェーダー研究 Vertexライティング?
コード
https://github.com/YukiMiyatake/UnityLesson/tree/Shader_7
はじめに
前回まではピクセルシェーダにてライティング計算をしていました
これはクオリティの高いライティングになりますが、少し処理が重くなるので
ディフューズカラー、スペキュラを頂点シェーダで計算しようという計画
シェーダー入出力の説明
今まで説明省略してたのを大雑把に
頂点シェーダ(vert)、フラグメントシェーダ(frag)には引数がある
頂点シェーダの引数は構造体で表現し、頂点ごとのパラメータが入ってくる
例えば ポジション、法線、UVなど
そして頂点シェーダの返り値も構造体で、頂点毎の情報を設定する
そして 頂点毎にフラグメントシェーダに
その時 ポジション(SV_POSITION)以外は線形補完されます
UVが保管され、テクスチャマッピングが正しく出来るのはわかると思うが
法線なども補完され、ライティングがスムースになります
シェーダ引数は、型のほかにセマンティクスがあり、目的別に指定します
細かい事は説明しません
たとえば前回は
struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; float2 uv : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; float4 vertexW: TEXCOORD0; float2 uv : TEXCOORD1; float3 normal : TEXCOORD2; };
頂点シェーダの引数は ポジション、法線、UV座標
フラグメントシェーダ引数は ポジション、ワールド座標でのポジション、UV、法線
フラグメントシェーダ引数はピクセルごとに補完される
方針
1個目のライト(ForwardBase)は現状通りのピクセルでのライティングを行う
2個目以降のライト(ForwardAdd)は、頂点シェーダでライト計算を行い ピクセルシェーダでは補完された値を使う
少し精度はわるくなるが、計算量は削減されるはずである
具体的には ディフューズの値を補完することができる
スペキュラに関しては補完することも可能であるが、大きくクオリティが落ちる可能性がある
今回は例として スペキュラも補完して軽くしよう
コード
具体的には ディフューズとスペキュラの計算を頂点シェーダに持っていく
ディフューズとスペキュラの値を フラグメントシェーダに渡す
構造体は下記になる
struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; float2 uv : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD1; float3 diffuse : TEXCOORD2; float3 specular : TEXCOORD3; };
頂点シェーダの入力に変更なし
フラグメントシェーダの入力は
仕様にて vertexは削れない
ワールド座標のポジションは不要
法線も不要
ディフューズ値とスペキュラ値を追加
v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); float4 vertexW = mul(unity_ObjectToWorld, v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); float3 normal = UnityObjectToWorldNormal(v.normal); float3 L = normalize(_WorldSpaceLightPos0.xyz); float3 V = normalize(_WorldSpaceCameraPos - vertexW.xyz); float3 N = normal; float3 H = normalize(L + V); float3 lightCol = _LightColor0.rgb * LIGHT_ATTENUATION(i); float3 NdotL = dot(N, L); o.diffuse = (NdotL*0.5 + 0.5) * lightCol; o.specular = pow(max(0.0, dot(H, N)), _Spec1Power) * _Spec1Color.xyz * lightCol; // Half vector return o; } float3 frag(v2f i) : SV_Target { // texture albedo float4 tex = tex2D(_MainTex, i.uv); return i.diffuse * tex + i.specular; }
フラグメントシェーダで計算していたディフューズとスペキュラを頂点シェーダで計算
フラグメントシェーダでは 補完されたディフューズとスペキュラをそのまま利用する
通常
軽量化
心配になるぐらい 変わらなかった(心配