【UnityShader】ノイズシェーダー拡張 【4】#48
前回の成果
ノイズシェーダーでテクスチャを歪ませました。
今回やること
ノイズで背景を歪めます。
事前準備
Scene上にPlaneを配置し、今回制作したMaterialをアタッチします。
ソースコード
Shader "Unlit/BackgroundNoise" { Properties { _NoiseTilingOffset ("NoiseTex Tiling(x,y)/Offset(z,w)", Vector) = (0.1, 0.1, 0,0) _NoiseSizeScroll ("NoiseTex Size(x,y)/Scroll(z,w)", Vector) = (16, 16, 0, 0) _DistortionPower ("Distortion Power", Float) = 0 } SubShader { Tags { "RenderType"="Transparent" "Queue"="Transparent"} LOD 100 Blend SrcAlpha OneMinusSrcAlpha GrabPass { "_BackgroundTexture" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "extensionNoiseUtil.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; float4 grabuv : TEXCOORD0; float2 noiseuv : TEXCOORD1; }; sampler2D _BackgroundTexture; fixed4 _NoiseTilingOffset; fixed4 _NoiseSizeScroll; float _DistortionPower; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.grabuv = ComputeGrabScreenPos(o.vertex); o.noiseuv = TRANSFORM_NOISE_TEX(v.uv, _NoiseTilingOffset, _NoiseSizeScroll); return o; } fixed4 frag (v2f i) : SV_Target { fixed3 dist = normalNoise(i.noiseuv, _NoiseSizeScroll.xy); dist = dist * 2 - 1; dist *= _DistortionPower; i.grabuv.xy += dist.xy; fixed4 col = tex2Dproj(_BackgroundTexture, UNITY_PROJ_COORD(i.grabuv)); return col; } ENDCG } } }
extensionNoiseUtil.cgincはこちらを参照してください。
レンダリング結果を取得
GrabPassで直前にレンダリングした結果を取得できるようになります。
GrabPassで取得した値は_GrabTextureで取得することができます。
// 直前のレンダリング結果を取得 GrabPass {} // GrabPassで取得した結果を格納 sampler2D _GrabTexture;
この処理は重いので1度しか呼ばない場合は良いですが何回も呼ぶ場合は名前を指定してあげます。
そうすると1フレームに1回のみテクスチャを取得し、そのテクスチャを使い回すようになるので負荷が減ります。
名前を指定する際には変数名も揃えてください。
// 直前のレンダリング結果を取得 GrabPass { "_hogeTexture" } // GrabPassで取得した結果を格納 sampler2D _hogeTexture;
座標系を揃える
o.grabuv = ComputeGrabScreenPos(o.vertex);
ComputeGrabScreenPos
でGrabPassで取得したテクスチャのUV座標を求めています。
GrabPassで取得したテクスチャはプラットフォームによって座標系が異なってしまうため、この関数を使用します。
テクスチャ座標の計算
fixed4 col = tex2Dproj(_BackgroundTexture, UNITY_PROJ_COORD(i.grabuv));
tex2Dprojはwで除算をしてからtex2Dをしている関数です。
wで除算する理由は下記サイト様が参考になります。
UNITY_PROJ_COORDは投影されたテクスチャ座標を適切なテクスチャ座標に変換するものです。
ほとんどのプラットフォームでは、引数に入れた値がそのまま帰ってきます。
結果
背景が歪んだら成功です。
property
描画結果
ソースコードにコメントを付与
Shader "Unlit/BackgroundNoise" { Properties { _NoiseTilingOffset ("NoiseTex Tiling(x,y)/Offset(z,w)", Vector) = (0.1, 0.1, 0,0) _NoiseSizeScroll ("NoiseTex Size(x,y)/Scroll(z,w)", Vector) = (16, 16, 0, 0) _DistortionPower ("Distortion Power", Float) = 0 } SubShader { Tags { "RenderType"="Transparent" "Queue"="Transparent"} LOD 100 Blend SrcAlpha OneMinusSrcAlpha // 直前のレンダリング結果を取得 GrabPass { "_BackgroundTexture" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "extensionNoiseUtil.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; float4 grabuv : TEXCOORD0; float2 noiseuv : TEXCOORD1; }; // GrabPassで取得した結果を格納 sampler2D _BackgroundTexture; fixed4 _NoiseTilingOffset; fixed4 _NoiseSizeScroll; float _DistortionPower; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.grabuv = ComputeGrabScreenPos(o.vertex); o.noiseuv = TRANSFORM_NOISE_TEX(v.uv, _NoiseTilingOffset, _NoiseSizeScroll); return o; } fixed4 frag (v2f i) : SV_Target { fixed3 dist = normalNoise(i.noiseuv, _NoiseSizeScroll.xy); dist = dist * 2 - 1; dist *= _DistortionPower; i.grabuv.xy += dist.xy; // tex2Dproj : i.grabuvを除算 // UNITY_PROJ_COORD : 投影されたテクスチャ座標を正しい座標に変換 fixed4 col = tex2Dproj(_BackgroundTexture, UNITY_PROJ_COORD(i.grabuv)); return col; } ENDCG } } }
今回は以上となります。
ここまでご視聴ありがとうございました。