【UnityShader】動く円を作る #14
前回の成果
テクスチャのブレンドができるようになった。
今回やること
円を描画し、それを動かしていこうと思います。
前準備
SceneにPlaneを置きます。
その時に、Positionが0,0,0になるように配置してください。
他のパラメーターは適当でも大丈夫です。
まずは円を描画していきます。
ソースコード
Shader "Custom/moveRing" { SubShader { Tags { "RenderType" = "Opaque" } LOD 200 CGPROGRAM #pragma surface surf Standard #pragma target 3.0 struct Input { float3 worldPos; }; void surf (Input IN, inout SurfaceOutputStandard o) { float dist = distance(fixed3(0, 0, 0), IN.worldPos); float radius = 2; if (radius < dist) { fixed4 purple = fixed4(110 / 255.0f, 87 / 255.0f, 139 / 255.0f, 1); o.Albedo = purple; } else { o.Albedo = fixed4(1,1,1,1); } } ENDCG } FallBack "Diffuse" }
distとradiusを比較して、ベースカラーを変更しているように見えます。
worldPos
ワールド座標のことです。
名称 | 説明 |
---|---|
ワールド座標(グローバル座標) | 原点から見た座標 |
ローカル座標 | 1つ上の親から見た相対的な座標 |
distance
これは指定した2点の間の距離を求める関数です。
// a ... 距離を求めたい1つ目の点 // b ... 距離を求めたい2つ目の点 distance (a, b);
今回の場合、
distance(fixed3(0, 0, 0), IN.worldPos);
なので原点とワールド座標との距離を取っています。
円の完成
このように出れば完成です。
円をリングにする
Shader "Custom/moveRing" { SubShader { Tags { "RenderType" = "Opaque" } LOD 200 CGPROGRAM #pragma surface surf Standard #pragma target 3.0 struct Input { float3 worldPos; }; void surf (Input IN, inout SurfaceOutputStandard o) { float dist = distance(fixed3(0, 0, 0), IN.worldPos); // 変更点 float circleRadius = 2; float ringWidth = 0.2f; if (circleRadius < dist && dist < circleRadius + ringWidth) { o.Albedo = fixed4(1,1,1,1); } else { fixed4 purple = fixed4(110 / 255.0f, 87 / 255.0f, 139 / 255.0f, 1); o.Albedo = purple; } // ここまで } ENDCG } FallBack "Diffuse" }
リングの幅を作ってあげるようにします。
リングの完成
これでリングを描画することができました。
次はたくさんリングを描画してみます。
リングをたくさん描画
Shader "Custom/moveRing" { SubShader { Tags { "RenderType" = "Opaque" } LOD 200 CGPROGRAM #pragma surface surf Standard #pragma target 3.0 struct Input { float3 worldPos; }; void surf (Input IN, inout SurfaceOutputStandard o) { float dist = distance(fixed3(0, 0, 0), IN.worldPos); // 変更点 float interval = 3.0f; float val = abs(sin(dist * interval)); float ringWidth = 0.98f; if (val > ringWidth) { o.Albedo = fixed4(1,1,1,1); } else { fixed4 purple = fixed4(110 / 255.0f, 87 / 255.0f, 139 / 255.0f, 1); o.Albedo = purple; } // ここまで } ENDCG } FallBack "Diffuse" }
だんだん複雑になってきました。
sin
#13で行なったsinTimeと同じで、こちらはtimeを使用していないだけです。
前回も説明しましたが、正弦波の絶対値を取得することによって、0~1の間を往復する波ができます。
次に、リングの幅を示すために正弦波の山の部分のみを白にします。
これでリングを複数個描画できるようになりました。
リングをたくさん描画の完成
あとは動かすだけです!
動かす
Shader "Custom/moveRing" { Properties { // 変更点 _Color ("Color" , Color) = (1 ,1 ,1 ,1) // ここまで } SubShader { Tags { "RenderType" = "Opaque" } LOD 200 CGPROGRAM #pragma surface surf Standard #pragma target 3.0 struct Input { float3 worldPos; }; // 変更点 fixed4 _Color; // ここまで void surf (Input IN, inout SurfaceOutputStandard o) { float dist = distance(fixed3(0, 0, 0), IN.worldPos); float interval = 3.0f; // 変更点 float speed = 10.0f; float val = abs(sin(dist * interval + _Time.y * speed)); float ringWidth = 0.98f; if (val > ringWidth) { o.Albedo = fixed4(1,1,1,1); } else { o.Albedo = _Color; } // ここまで } ENDCG } FallBack "Diffuse" }
主な変更点は
float val = abs(sin(dist * interval + _Time.y * speed));
ここで、正弦波の波をTimeで移動させてあげているだけです。
ちなみに
interval + _Time.y
ここを-に変更すると、波の動きが逆になります。
リングを動かしてみた
このようにリングが動けば完成です。
リングの動きは同じなので、別のオブジェクトにマテリアルをアタッチしてあげるとこのようなこともできます。
ソースコードにコメントを付与
Shader "Custom/moveRing" { // プロパティ Properties { // 波紋の色 _Color ("Color" , Color) = (1 ,1 ,1 ,1) } // Shaderの中身の記述 SubShader { // 一般的なShaderを使用 Tags { "RenderType" = "Opaque" } // しきい値 LOD 200 // cg言語記述 CGPROGRAM // 指定しないとフォワードレンダリング #pragma surface surf Standard // Shader Model #pragma target 3.0 // input構造体 struct Input { // ワールド座標 float3 worldPos; }; // 波紋の色 fixed4 _Color; // surf関数 void surf (Input IN, inout SurfaceOutputStandard o) { // 原点からの距離 float dist = distance(fixed3(0, 0, 0), IN.worldPos); // 波紋の感覚 float interval = 3.0f; // 波紋のスピード float speed = 10.0f; // sin波 float val = abs(sin(dist * interval + _Time.y * speed)); // リングの幅(0 ~ 1) float ringWidth = 0.98f; // ベースカラーを変化させる if (val > ringWidth) { o.Albedo = fixed4(1,1,1,1); } else { o.Albedo = _Color; } } // Shaderの記述終了 ENDCG } // SubShaderが失敗した時に呼ばれる FallBack "Diffuse" }
今回は以上となります。
次回は、オブジェクトの座標をワールド座標からローカル座標に変換してみようと思います!