【UnityShader】3種類のノイズ #16
前回の成果
リングの位置を追従させた。
今回やること
今回は、ノイズを制作していきます。
前準備
PlaneをScene上に置き、今回制作するMaterialをアタッチしてください。
ランダムノイズの制作
ランダムノイズとは、テレビの砂嵐のようなものです。
ソースコード
Shader "Custom/randomNoise" { Properties { _MainTex("Albedo(RBG)", 2D) = "white" {} } SubShader { Tags { "RenderType" = "Opaque"} LOD 200 CGPROGRAM #pragma surface surf Standard fullforwardshadows #pragma target 3.0 struct Input { float2 uv_MainTex; }; float random(fixed2 uv) { return frac(sin(dot(uv, fixed2(12.9898f, 78.233f))) * 43758.5453); } void surf(Input IN, inout SurfaceOutputStandard o) { float randomNum = random(IN.uv_MainTex); o.Albedo = fixed4(randomNum, randomNum, randomNum, 1); } ENDCG } Fallback "Diffuse" }
float random(fixed2 uv) { return frac(sin(dot(uv, fixed2(12.9898f, 78.233f))) * 43758.5453); }
ここの部分でなぜこのような数値を出しているのかが謎です。
frac
これは小数値の小数部分を返す関数です。
float a = 1.0f; float b = 1.5f; // 0が返ってくる frac(a); // 0.5が返ってくる frac(b);
逆に、小数値の整数を返す関数もあります。
float a = 1.0f; float b = 3.5f; // 1が返ってくる floor(a); // 3が返ってくる floor(b);
frac(sin(dot(uv, fixed2(12.9898f, 78.233f))) * 43758.5453)
これはランダムな値を返すものです。
float rand(vec2 co){ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); }
GLSLでこのような擬似ランダム関数があるので、それをHLSLに変更させたものです。
詳しくはこちらのサイト様へ
結果
ランダムノイズの完成です。
ブロックノイズ
次はブロックノイズを制作していきます。
ソースコード
Shader "Custom/valueNoise" { Properties { _MainTex("Albedo(RBG)", 2D) = "white" {} // 変更点 _SideBlockNum("SideBlockNum", int) = 0 } SubShader { Tags { "RenderType" = "Opaque"} LOD 200 CGPROGRAM #pragma surface surf Standard fullforwardshadows #pragma target 3.0 struct Input { float2 uv_MainTex; }; int _SideBlockNum; float random(fixed2 uv) { return frac(sin(dot(uv, fixed2(12.9898f, 78.233f))) * 43758.5453); } float noise(fixed2 uv) { fixed2 uv_integer = floor(uv); return random(uv_integer); } void surf(Input IN, inout SurfaceOutputStandard o) { float randomNum = noise(IN.uv_MainTex * _SideBlockNum); // ここまで o.Albedo = fixed4(randomNum, randomNum, randomNum, 1); } ENDCG } Fallback "Diffuse" }
ランダムノイズから関数が1つ増えています。
解説
行なっていることは、先ほど制作したランダムノイズからブロックごとに代表的な1点を取り出しています。
その1点は、floorメソッドを使用して決めています。
例を出すと、
座標が(0.8,0.8)なら(0,0)に
(3.2,1.6)なら(3,1)になります。
今回は、テクスチャの座標をSideBlockNum倍しているので、SideBlockNum×_SideBlockNumのブロックノイズが生成されます。
結果
_SideBlockNumには5を指定しています。
バリューノイズ
ブロックノイズを濁したようなノイズです。
ソースコード
Shader "Custom/valueNoise" { Properties { _MainTex("Albedo(RBG)", 2D) = "white" {} _SideBlockNum("SideBlockNum", int) = 0 } SubShader { Tags { "RenderType" = "Opaque"} LOD 200 CGPROGRAM #pragma surface surf Standard fullforwardshadows #pragma target 3.0 struct Input { float2 uv_MainTex; }; int _SideBlockNum; float random(fixed2 uv) { return frac(sin(dot(uv, fixed2(12.9898f, 78.233f))) * 43758.5453); } float noise(fixed2 uv) { fixed2 uv_integer = floor(uv); return random(uv_integer); } // 変更点 float valueNoise(fixed2 uv) { fixed2 uv_integer = floor(uv); fixed2 uv_decimal = frac(uv); float v00 = random(uv_integer + fixed2(0, 0)); float v10 = random(uv_integer + fixed2(1, 0)); float v01 = random(uv_integer + fixed2(0, 1)); float v11 = random(uv_integer + fixed2(1, 1)); fixed2 lerpResult = (- 2.0f * pow(uv_decimal, 3)) + (3.0f * pow(uv_decimal, 2)); float v0010 = lerp(v00, v10, lerpResult.x); float v0111 = lerp(v01, v11, lerpResult.x); return lerp(v0010, v0111, lerpResult.y); } void surf(Input IN, inout SurfaceOutputStandard o) { float randomNum = valueNoise(IN.uv_MainTex * _SideBlockNum); // ここまで o.Albedo = fixed4(randomNum, randomNum, randomNum, 1); } ENDCG } Fallback "Diffuse" }
ブロックノイズから更に関数が1つ増えています。
解説
ほぼおもちゃラボ様の引用です。
色の出し方
バリューノイズは、ブロックノイズで描画された、正方形の四隅の色を取得します。
その色から正方形内の色を補間することによって表現されます。
補間の仕方
補間したい座標のオフセット値を求めることによって、表すことができます。
そこで、fracメソッドを使用することによってオフセット値を取得することができます。
補間数式
fixed2 lerpResult = (- 2.0f * pow(uv_decimal, 3)) + (3.0f * pow(uv_decimal, 2));
この部分は、
-2x3 + 3x2
という数式を使用して補間しています。
こちらが-2x3 + 3x2のグラフです。
補間手順
- 下の辺(v0010)の色を求める
- 上の辺(v0111)の色を求める
- 1,2で求めた2点を補間する
結果
今回はここまでとなります。
次回もシェーダーの勉強をしていこうと思います!