パート1:溶解シェーダー
溶解シェーダーは美しい効果を返します。さらに、作成と理解が簡単です。 今日は
Unityシェーダーグラフで作成し、
HLSLで作成します。
作成するものの例を次に示します。
仕組み
ディゾルブシェーダーを作成するには、「Shader Graph」シェーダーの
AlphaClipThreshold値を操作するか、
clipというHLSL関数を使用する必要があり
ます 。
基本的に、渡された
テクスチャと
値に基づい
てピクセルをレンダリングしないようにシェーダーに指示
します 。 次のことを知る必要があり
ます 。
白い部分はより速く溶解します 。
次のテクスチャを使用します。
あなたはあなた自身を作成することができます-直線、三角形、しかし何でも!
白い部分がより速く溶解することを覚えておいてください。
「クラウド」フィルターを使用して、Photoshopでこのテクスチャを作成しました。
シェーダーグラフにのみ興味があり、HLSLについて何も知らない場合でも、Unityシェーダーグラフが内部でどのように機能するかを理解するのに役立つため、この部分を読むことをお勧めします。
Hlsl
HLSLでは、
clip(x)関数を使用し
ます 。
clip(x)関数は、
ゼロより小さい値を持つすべてのピクセルを破棄し
ます 。 したがって、
clip(-1)を呼び出すと、シェーダーがこのピクセルをレンダリングしないことが確実になります。
クリップの詳細については、
Microsoft Docsをご覧ください。
プロパティ
シェーダーには、2つのプロパティ
Dissolve Textureと
Amount (実行プロセス全体を示す)が必要です。 他のプロパティや変数と同様に、好きなものを呼び出すことができます。
Properties { //Your other properties //[...] //Dissolve shader properties _DissolveTexture("Dissolve Texture", 2D) = "white" {} _Amount("Amount", Range(0,1)) = 0 }
CGPROGRAM SubShaderの後に必ず以下を追加してください(つまり、変数を宣言します)。
sampler2D _DissolveTexture; half _Amount;
また、忘れないでください。 それらの名前は[プロパティ]セクションの名前と一致する必要があります。
機能
溶解の
テクスチャをサンプリングし
、赤の値を取得
することにより、
Surfaceまたは
Fragment関数を開始し
ます 。 PSテクスチャは
グレースケールで保存されます。つまり、
R 、
G 、
Bの値は等しく、
いずれかを選択でき
ます 。 たとえば、
白は
(1,1,1) 、
黒は
(0,0,0)です。
私の例では、サーフェスシェーダーを使用しています。
void surf (Input IN, inout SurfaceOutputStandard o) { half dissolve_value = tex2D(_DissolveTexture, IN.uv_MainTex).r;
それだけです! このプロセスを既存のシェーダーに適用して、
溶解シェーダーに変えることができます!
以下は、Unityエンジンの標準のSurface Shaderで、
両面 溶解シェーダーになりました。 Shader "Custom/DissolveSurface" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 //Dissolve properties _DissolveTexture("Dissolve Texutre", 2D) = "white" {} _Amount("Amount", Range(0,1)) = 0 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 Cull Off //Fast way to turn your material double-sided CGPROGRAM #pragma surface surf Standard fullforwardshadows #pragma target 3.0 sampler2D _MainTex; struct Input { float2 uv_MainTex; }; half _Glossiness; half _Metallic; fixed4 _Color; //Dissolve properties sampler2D _DissolveTexture; half _Amount; void surf (Input IN, inout SurfaceOutputStandard o) { //Dissolve function half dissolve_value = tex2D(_DissolveTexture, IN.uv_MainTex).r; clip(dissolve_value - _Amount); //Basic shader function fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = ca; } ENDCG } FallBack "Diffuse" }
シェーダーグラフ
Unity
Shader Graphを使用してこの効果を作成する必要がある場合は、
AlphaClipThreshold値(HLSLの
クリップ(x)とは異なる動作)を使用する必要があります。 この例では、PBRシェーダーを作成しました。
AlphaClipThreshold関数は、シェーダーに、
Alpha値より小さい値を持つすべてのピクセルを破棄するよう指示します。 たとえば、
0.3fでアルファ値が
0.2fの場合、シェーダー
はこのピクセルを
レンダリングしません 。
AlphaClipThreshold関数は、
Unityのドキュメント (
PBRマスターノードと
消灯マスターノード)にあります。
完成したシェーダーは次のとおりです。
ディゾルブテクスチャをサンプリングし
て赤の値を取得し
、それを
Amount値(全体の実行プロセスを示すために追加したプロパティです。値1は完全な
ディゾルブを意味します)に追加し、
AlphaClipThresholdに接続します。
できた!既存のシェーダーに適用する場合は
、 ノード接続を
AlphaClipThresholdに コピーするだけ
です (必要なプロパティをお見逃しなく!)。 また、それを
二国間とし、さらに美しい結果を得ることができます!
輪郭溶解シェーダー
そして、それに
輪郭を追加しようとすると? やりましょう!
既に分解されたピクセルを操作することはできません。なぜなら、
それらをドロップ
すると永久に消えてしまうからです 。 代わりに、「ほぼ分解された」値で作業できます!
HLSLでは、これは非常に簡単で、
クリップを計算した後にコードを数行追加するだけです。
void surf (Input IN, inout SurfaceOutputStandard o) {
できた!Shader Graphを使用する場合、ロジックはわずかに異なります。 完成したシェーダーは次のとおりです。
シンプルな
溶解シェーダーで非常に
クールなエフェクトを作成できます。
さまざまなテクスチャと
値を試して、他の何かを思いつくことができます!
パート2:世界探検シェーダー
世界探索シェーダー(または「
世界解散シェーダー 、または
グローバル解散 」)を使用すると、位置までの距離に基づいてシーン内のすべてのオブジェクトを非表示にすることができます。次に、
Unity Shader Graphでそのようなシェーダーを作成し、
HLSLで記述します。
作成するものの例を次に示します。
パラメータとしての距離
シーンから
オブジェクトが
プレーヤーから遠すぎる場合
、オブジェクトを
ディゾルブする必要があると
します 。 オブジェクトの消失/溶解を制御する
_Amountパラメーターを既に発表しているため、オブジェクトとプレーヤー間の距離に置き換える必要があります。
これを行うには、
Playerと
Objectの位置を取る必要があります。
プレイヤーの位置
このプロセスは、
Unity Shader Graphと
HLSLの両方で同様です。コード内のプレーヤーの位置を転送する必要があります。
private void Update() {
シェーダーグラフ
オブジェクトの位置とそれまでの距離
シェーダーグラフを使用して、位置ノードと距離ノードを使用できます。
PSこのシステムをスプライトレンダラーと連携させるには、_MainTexプロパティを追加し、サンプリングして、アルベドに接続する必要があります。 以前の
Sprites拡散シェーダーチュートリアル(シェーダーグラフを使用)を読むことができます。
HLSL(表面)
オブジェクトの位置
HLSLでは、
入力構造に
worldPos変数を追加して、オブジェクトの頂点の位置を取得できます。
struct Input { float2 uv_MainTex; float3 worldPos;
Unityのドキュメントページで 、入力構造に追加できるその他の組み込みパラメーターを確認できます。
距離を適用
分解の量として、オブジェクトとプレイヤーの間の距離を使用する必要があります。 これを行うには、組み込みの
距離関数を使用できます(
Microsoftのドキュメント )。
void surf (Input IN, inout SurfaceOutputStandard o) { half dissolve_value = tex2D(_DissolveTexture, IN.uv_MainTex).x; float dist = distance(_PlayerPos, IN.worldPos); clip(dissolve_value - dist/ 6f);
結果(3D)
結果(2D)
ご覧のとおり、各オブジェクトのUVを使用してサンプリングされたテクスチャから「溶解値」を取得するため、オブジェクトは「局所的に」溶解し、均一な効果は得られませんでした。 (2Dでは、これはあまり目立ちません)。
HLSLの3D LocalUV Dissolve Shader
Shader "Custom/GlobalDissolveSurface" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness("Smoothness", Range(0,1)) = 0.5 _Metallic("Metallic", Range(0,1)) = 0.0 _DissolveTexture("Dissolve texture", 2D) = "white" {} _Radius("Distance", Float) = 1 //distance where we start to reveal the objects } SubShader{ Tags { "RenderType" = "Opaque" } LOD 200 Cull off //material is two sided CGPROGRAM #pragma surface surf Standard fullforwardshadows #pragma target 3.0 sampler2D _MainTex; sampler2D _DissolveTexture; //texture where we get the dissolve value struct Input { float2 uv_MainTex; float3 worldPos; //Built-in world position }; half _Glossiness; half _Metallic; fixed4 _Color; float3 _PlayerPos; //"Global Shader Variable", contains the Player Position float _Radius; void surf (Input IN, inout SurfaceOutputStandard o) { half dissolve_value = tex2D(_DissolveTexture, IN.uv_MainTex).x; float dist = distance(_PlayerPos, IN.worldPos); clip(dissolve_value - dist/ _Radius); fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = ca; } ENDCG } FallBack "Diffuse" }
スプライト拡散-HLSLのLocalUV Dissolve Shader
Shader "Custom/GlobalDissolveSprites" { Properties { [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {} _Color("Tint", Color) = (1,1,1,1) [MaterialToggle] PixelSnap("Pixel snap", Float) = 0 [HideInInspector] _RendererColor("RendererColor", Color) = (1,1,1,1) [HideInInspector] _Flip("Flip", Vector) = (1,1,1,1) [PerRendererData] _AlphaTex("External Alpha", 2D) = "white" {} [PerRendererData] _EnableExternalAlpha("Enable External Alpha", Float) = 0 _DissolveTexture("Dissolve texture", 2D) = "white" {} _Radius("Distance", Float) = 1 //distance where we start to reveal the objects } SubShader { Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" "PreviewType" = "Plane" "CanUseSpriteAtlas" = "True" } Cull Off Lighting Off ZWrite Off Blend One OneMinusSrcAlpha CGPROGRAM #pragma surface surf Lambert vertex:vert nofog nolightmap nodynlightmap keepalpha noinstancing #pragma multi_compile _ PIXELSNAP_ON #pragma multi_compile _ ETC1_EXTERNAL_ALPHA #include "UnitySprites.cginc" struct Input { float2 uv_MainTex; fixed4 color; float3 worldPos; //Built-in world position }; sampler2D _DissolveTexture; //texture where we get the dissolve value float3 _PlayerPos; //"Global Shader Variable", contains the Player Position float _Radius; void vert(inout appdata_full v, out Input o) { v.vertex = UnityFlipSprite(v.vertex, _Flip); #if defined(PIXELSNAP_ON) v.vertex = UnityPixelSnap(v.vertex); #endif UNITY_INITIALIZE_OUTPUT(Input, o); o.color = v.color * _Color * _RendererColor; } void surf(Input IN, inout SurfaceOutput o) { half dissolve_value = tex2D(_DissolveTexture, IN.uv_MainTex).x; float dist = distance(_PlayerPos, IN.worldPos); clip(dissolve_value - dist / _Radius); fixed4 c = SampleSpriteTexture(IN.uv_MainTex) * IN.color; o.Albedo = c.rgb * ca; o.Alpha = ca; } ENDCG } Fallback "Transparent/VertexLit" }
PS最後のシェーダーを作成するために、標準のUnity Sprites-Diffuseシェーダーをコピーし、記事のこのパートで前述した「ディゾルブ」パートを追加しました。 すべての標準シェーダーは
ここにあります 。
効果を均一にする
効果を均一にするために、溶解テクスチャのUV座標としてグローバル座標(世界の位置)を使用できます。 また、テクスチャに気付かずに繰り返すことができるように、ディゾルブテクスチャパラメータで
Wrap = Repeatを設定することも重要です(テクスチャがシームレスで、よく繰り返すことを確認してください!)
HLSL(表面)
half dissolve_value = tex2D(_DissolveTexture, IN.worldPos / 4).x;
シェーダーグラフ
結果(2D)
これが結果です。溶解のテクスチャーが全世界で均一になっていることがわかります。
このシェーダーはすでに
2Dゲームに
最適ですが、
3Dオブジェクトの場合は
改善が必要です。
3Dオブジェクトの問題
ご覧のとおり、シェーダーは「垂直でない」面では機能せず、テクスチャを大きく歪ませます。 これが判明した理由です。 UV座標には値float2が必要です。worldPosを渡すと、XとYのみを受け取ります。
計算を適用してすべての面にテクスチャを表示することでこの問題を修正すると、新しい問題が発生します。暗くなると、オブジェクトは互いに交差し、均質に保たれなくなります。
初心者が解決策を理解することは困難です。テクスチャを取り除き、世界で3次元ノイズを生成し、そこから「溶解の価値」を取得する必要があります。 この投稿では、3Dノイズの生成については説明しませんが、すぐに使用できる関数の束を見つけることができます!
ノイズシェーダーの例を次に示します:
https :
//github.com/keijiro/NoiseShader 。 また、
https :
//thebookofshaders.com/11/およびここ:
https :
//catlikecoding.com/unity/tutorials/noise/からノイズを生成する方法を学ぶこともでき
ます。この方法で表面関数を設定します(既にノイズ部分を記述している場合):
void surf (Input IN, inout SurfaceOutputStandard o) { float dist = distance(_PlayerPos, IN.worldPos); //"abs" because you have to make sure that the noise is between the range [0,1] //you can remove "abs" if your noise function returns a value between [0,1] //also, replace "NOISE_FUNCTION_HERE" with your 3D noise function. half dissolve_value = abs(NOISE_FUNCTION_HERE(IN.worldPos)); if (dist > _Radius) { float clip_value = dissolve_value - ((dist - _Radius) / _Radius); clip(clip_value); if (clip_value < 0.05f) o.Emission = float3(1, 1, 1); } fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = ca; }
HLSLの簡単なリマインダー:関数を使用/呼び出す前に、それを記述/宣言する必要があります。
PSユニティシェーダーグラフを使用してシェーダーを作成する場合は、カスタムノードを使用する必要があります(また、HLSLコードを記述してノイズを生成します)。 カスタムノードについては、今後のチュートリアルで説明します。
結果(3D)
輪郭の追加
輪郭を追加するには、チュートリアルの前の部分のプロセスを繰り返す必要があります。
反転効果
そして、この効果を逆にしたい場合は? (プレイヤーが近くにいる場合、オブジェクトは消えなければなりません)
1行変更するだけで十分です。
float dist = _Radius - distance(_PlayerPos, IN.worldPos);
(同じプロセスがシェーダーグラフに適用されます)。