Unity はゼロからホログラフィック効果シェーダーを実装します

序文
今回は、最近実現されたホログラフィック モデルの効果を共有したいと思います。

私はBaidu出身なので、ホログラムの意味については詳しく説明しません〜

ホログラフィック効果を使用して、非常にサイバーで SF モデルの投影効果を実現できます。これは、一部の SF モンスターや NPC のゲーム パフォーマンスに使用できます。著者が共有するレンダリングは次のとおりです。

もし読者がサイバー空間が十分ではないと感じているなら、それは間違いなくモデルに問題があるに違いありません! (バツ


1. 準備段階
筆者が使用している Unity のバージョンは 2018.4.16f のままですが、一般的な状況からすると、バージョンが低すぎることはありません。

ターゲット モデルと関連するテクスチャを見つけます。作成者は例で使用されているモデルを公開しませんが、読者は試すモデルを見つけることができます。

(追伸: モデルのパッチ ノードは、間違った回転がないことを確認する必要があります。間違った回転とは、レンダリングされたパッチを含むモデルのノードが XYZ 軸の不可解な 90 度回転を持たないことです。モデルがシェーダー プロセスで修正される原因となる 方向の問題 作成者のモデルが手元にある場合、メッシュ オブジェクト ノードは不可解な回転を持ちます)


前と同じように、フォルダーの分類を適切に行い、対応するリソースを本来あるべきディレクトリに配置できるようにします。

新しい Shader HologramEffectを作成し、その中のすべての Properties と Subshader コンテンツを削除して、最初から作成する必要があります。

Shader "SaberShad/HologramEffect"
{
    Properties
    {
        
    }
    SubShader
    {
        
    }
}


シェーダー HologramMat を作成します。急いでシェーダーを置き換えないでください。以前の HologramEffect は間違いなくエラーを報告するためです...

詳細な効果実感なので長文ですが、気長に読んでいただければ幸いです。作者はまだ勉強中ですので、間違いや提案があれば指摘してください〜

2.透明効果から始める
まず、ホログラフィック効果は一種の光の投影であり、モデルの背後にあるオブジェクトをブロックするとは言えないため、ホログラフィック効果は透明でなければならないというのが私の個人的な理解です。

同時に、元のモデルの色を表示せず、単一の明るい色を使用します。元の色の効果を出すためにやったわけではないので…

実は実現できないわけではありませんが、まずは透明効果を実感してみましょう〜

HologramEffectを変更するには、いくつかの色フィールドを追加します. ここでは、色の透明度には他の機能があり、区別の透明度がモデル全体の透明度を決定するため、作成者はグローバルな透明度と色の透明度を区別します. 次に、標準の頂点およびフラグメント シェーダー処理関数を実装するだけです.以前にパスを削除したことを忘れないでください。したがって、このロジックを含めるには、サブシェーダーに新しいパスを作成する必要があります。最後に、レンダリング タイプは透過オブジェクトです。対応するレンダリング タイプ RenderType を追加し、深度書き込みを閉じる必要があります。

関連するロジックは次のとおりです。

Shader "SaberShad/HologramEffect"
{
    Properties
    {
        [HDR]_HologramColor("Hologram Color", Color) = (1, 1, 1, 0)
        _HologramAlpha("Hologram Alpha", Range(0.0, 1.0)) = 1.0
    }
    SubShader
    {
        Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
        CGINCLUDE
            struct a2v_hg
            {
                float4 vertex : POSITION;
            };
            struct v2f_hg
            {
                float4 pos : SV_POSITION;
            };

            float4 _HologramColor;
            fixed _HologramAlpha;
        ENDCG
        Pass
        {
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off
            CGPROGRAM
                #pragma target 3.0
                #pragma vertex HologramVertex
                #pragma fragment HologramFragment
            
                v2f_hg HologramVertex(a2v_hg v)
                {
                    v2f_hg o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    return o;
                }

                float4 HologramFragment(v2f_hg i) : SV_Target
                {
                    return float4(_HologramColor.rgb, _HologramAlpha);
                }
            ENDCG
        }
    }
}

HologramMat のシェーダーを HologramEffect に変更し、ターゲット モデルに割り当てます。
透明効果を確認するために、下の画像に示すように、モデルの後ろにボールを置きました。モデルが実際に透明であることがわかり、その後ろにボールが見えます。


ただし、透明効果はターゲット モデルのテクスチャを使用しないため、モデルの詳細は失われます。したがって、元のモデルの UV テクスチャを引き続き使用する必要がありますが、純粋な色の効果では UV テクスチャの色を完全に使用する必要はなく、チャネルの 1 つを使用して最終的な透明度を調整するだけです。

HologramEffect を変更して、UV サンプリングに関連するものを追加します。

Shader "SaberShad/HologramEffect"
{
    Properties
    {
        ...
        // 主纹理充当颜色蒙版
        _HologramMaskMap("Hologram Mask", 2D) = "white"{}
        _HologramMaskAffect("Hologram Mask Affect", Range(0.0, 1.0)) = 0.5
    }
    SubShader
    {
        ...
            struct a2v_hg
            {
                ...
                float2 uv : TEXCOORD0;
            };
            struct v2f_hg
            {
                ...
                float2 uv : TEXCOORD0;
            };
            ...
            // 全息蒙版
            sampler2D _HologramMaskMap;
            float4 _HologramMaskMap_ST;
            half _HologramMaskAffect;
        ENDCG
        Pass
        {
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off
            CGPROGRAM
                ...
                v2f_hg HologramVertex(a2v_hg v)
                {
                    ...
                    o.uv = v.uv;
                    return o;
                }

                float4 HologramFragment(v2f_hg i) : SV_Target
                {
                    float4 main_color = _HologramColor;
                    // 用主纹理的r通道做颜色蒙版
                    float2 mask_uv = i.uv.xy * _HologramMaskMap_ST.xy + _HologramMaskMap_ST.zw;
                    float4 mask = tex2D(_HologramMaskMap, mask_uv);
                    // 追加一个参数用来控制遮罩效果
                    float mask_alpha = lerp(1, mask.r, _HologramMaskAffect);
                    
                    float4 resultColor = float4(main_color.rgb, _HologramAlpha * mask_alpha);
                    return resultColor;
                }
            ENDCG
        }
    }
}


新しいロジックが追加された後、対応する詳細が UV 上のカバーされた位置に表示されることがわかりますが、元のモデルの背面にある頂点もレンダリングされていることがわかります。モデル全体を本体として使用すると同時に、背面を削除して深度を記述しなかったため、同じモデルの下での透過効果での自己浸透と自己表示の問題が発生しました。

この問題を解決するために、追加のパスを使用して事前に深さを書き込むことができますが、深さバッファに色をレンダリングすることはありません。その後、後続のパスは深さで書き込まれた頂点でレンダリングされます。HologramEffect を変更します。

    SubShader
    {
        Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
        CGINCLUDE
            ...
            // 因为顶点深入写入的Pass也是使用跟全息Pass一样的顶点函数,所以挪到这边来
            v2f_hg HologramVertex(a2v_hg v)
            {
                v2f_hg o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }
        ENDCG
        Pass
        {
            Name "Depth Mask"
            // 打开深度写入,并且设置颜色遮罩,0代表什么颜色都不输出
            ZWrite On 
            ColorMask 0

            CGPROGRAM
                #pragma target 3.0
                #pragma vertex HologramVertex
                #pragma fragment HologramMaskFragment

                float4 HologramMaskFragment(v2f_hg i) : SV_TARGET
                {
                    return 0;
                }
            ENDCG
        }
        Pass
        {
            Name "Hologram Effect"
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off
            CGPROGRAM
                #pragma target 3.0
                #pragma vertex HologramVertex
                #pragma fragment HologramFragment
            
                float4 HologramFragment(v2f_hg i) : SV_Target
                {
                    ...
                }
            ENDCG
        }
    }

どうですか、効果はずっと良いですか、それではいや、パフォーマンスが変わります...

もう 1 パスあるので、完全なレンダリングでモデルの頂点と三角形をもう一度計算する必要があります. 次の図は、シングル パスとダブル パスでの頂点と三角形の違いを示しています. 余分な部分は、まさに著者のものです. project のモデルの頂点と三角形の面の数。


したがって、モデル シェーダーを設計するとき、不透明効果と透明効果をできるだけ 1 つのパスに統合しようとします。At the same time, try to avoid multiple shaders on a model patch object and avoid render multiple vertices. これは、プロジェクト シーンの頂点と三角形の面の最適化戦略の 1 つでもあります。

最も基本的な透過​​性の問題を解決したら、次のステップはホログラフィック特殊効果の効果を実現することです。

3. 頂点の失敗効果
上の GIF からわかるように、モデルは左右にランダムにひきつります。これは、ホログラフィックブロードキャスト伝送をシミュレートするときに発生する不安定な信号によって引き起こされる影響変動の影響です (本当のようです...)。この効果を実現するには、モデルの頂点座標を変更してランダムなアニメーションを作成する必要があります。ここの作成者は、アニメーション関数を直接移動し、HologramEffect を変更します。

Properties
    {
        ...
        // 全息抖动参数设置,x代表速度,y代表抖动范围,z代表抖动偏移量,w代表频率(0~0.99)
        _HologramGliterData1("Hologram Gliter Data1", Vector) = (0, 1, 0, 0) 
        _HologramGliterData2("Hologram Gliter Data2", Vector) = (0, 1, 0, 0)
    }
    SubShader
    {
        Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
        CGINCLUDE
            ...

            half4 _HologramGliterData1, _HologramGliterData2;
            half3 VertexHologramOffset(float3 vertex, half4 offsetData)
            {
                half speed = offsetData.x;
                half range = offsetData.y;
                half offset = offsetData.z;
                half frequency = offsetData.w;

                half offset_time = sin(_Time.y * speed);
                // step(y, x) 如果 x >= y 则返回1,否则返回0,用来决定在正弦时间的某个地方才开始进行顶点抖动
                half timeToGliter = step(frequency, offset_time);
                half gliterPosY = sin(vertex.y + _Time.z);
                half gliterPosYRange = step(0, gliterPosY) * step(gliterPosY, range);
                // 获取偏移量
                half res = gliterPosYRange * offset * timeToGliter * gliterPosY;

                // 将这个偏移量定义为视角坐标的偏移量,再转到模型坐标
                float3 view_offset = float3(res, 0, 0);
                return mul((float3x3)UNITY_MATRIX_T_MV, view_offset);
            }

            v2f_hg HologramVertex(a2v_hg v)
            {
                v2f_hg o;
                // 产生模型顶点方向上的扭曲系数
                v.vertex.xyz += VertexHologramOffset(v.vertex.xyz, _HologramGliterData1);
                v.vertex.xyz += VertexHologramOffset(v.vertex.xyz, _HologramGliterData2);
                ...
                return o;
            }
        ENDCG
        ...
    }

(参考:https://zhuanlan.zhihu.com/p/141940278)

ここで私は大きな男の頂点フォルトのアニメーションのアイデアを参照します. 作者はここでいくつかの変更を加えました. 4 つのパラメータを Vector4 属性に統合しました. 最終出力のオフセット方向を、の方向のオフセットと見なします.視点空間からモデル空間へのモデルの頂点に適用すると、視点方向に応じてモデル空間で左右に振ることができます

実際、このアニメーションプロセスの読者は完全に自由です.とにかく、最も重要なステップは、オフセット頂点座標を出力することです.プロセスは可能な限りランダムにすることができます.ランダムであるほど、眩しいほど効果が高くなります.


(この時、ホログラフィックエフェクトと相容れない中東の電脳ロック少年は、新しいエフェクトの下でさらに揺れています)

 

4. 走査線効果
頂点のジッターだけでは十分ではなく、他の効果を積み重ねることができます。たとえば、ホログラフィーでより一般的な走査線効果です。

スキャン ライン効果は、実際にはシンプルな白黒の線テクスチャを使用して UV サンプリング アニメーションを実行し、UV サンプリングの結果を使用してホログラムの色に影響を与えることです。HologramEffect を再度変更して、今度はスキャン ラインのロジックを完成させます。

Properties
    {
           ...
        // 扫描线
        _HologramLine1("HologramLine1", 2D) = "white" {}
        _HologramLine1Speed("Hologram Line1 Speed", Range(-10.0, 10.0)) = 1.0
        _HologramLine1Frequency("Hologram Line1 Frequency", Range(0.0, 100.0)) = 20.0
        _HologramLine1Alpha("Hologram Line 1 Alpha", Range(0.0, 1.0)) = 0.15

        [Toggle(_USE_SCANLINE2)]_HologramLine2Tog("Hologram Line2 Toggle", float) = 0.0
        _HologramLine2("HologramLine2", 2D) = "white" {}
        _HologramLine2Speed("Hologram Line2 Speed", Range(-10.0, 10.0)) = 1.0
        _HologramLine2Frequency("Hologram Line2 Frequency", Range(0.0, 100.0)) = 20.0
        _HologramLine2Alpha("Hologram Line 2 Alpha", Range(0.0, 1.0)) = 0.15
    }
    SubShader
    {
        Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
        CGINCLUDE
            ...
            struct v2f_hg
            {
                ...
                float4 posWorld : TEXCOORD1;
            };
            ...
            // 全息扫描线
            sampler2D _HologramLine1;
            half _HologramLine1Speed, _HologramLine1Frequency, _HologramLine1Alpha;
            sampler2D _HologramLine2;
            half _HologramLine2Speed, _HologramLine2Frequency, _HologramLine2Alpha;
            
            v2f_hg HologramVertex(a2v_hg v)
            {
                v2f_hg o;
                // 产生模型顶点方向上的扭曲系数
                v.vertex.xyz += VertexHologramOffset(v.vertex.xyz, _HologramGliterData1);
                v.vertex.xyz += VertexHologramOffset(v.vertex.xyz, _HologramGliterData2);
                // o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                o.posWorld = mul(unity_ObjectToWorld, v.vertex);
                o.pos = mul(UNITY_MATRIX_VP, o.posWorld);

                return o;
            }
        ENDCG
        ...
        Pass
        {
            Name "Hologram Effect"
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off
            CGPROGRAM
                #pragma target 3.0
                #pragma shader_feature _USE_SCANLINE2
                ...
                
                float4 HologramFragment(v2f_hg i) : SV_Target
                {
                    ...
                    // 全息效果 扫描线
                    float2 line1_uv = (i.posWorld.y * _HologramLine1Frequency + _Time.y * _HologramLine1Speed).xx;
                    float line1 = clamp(tex2D(_HologramLine1, line1_uv).r, 0.0, 1.0);
                    float4 line1_color = float4((main_color * line1).rgb, line1) * _HologramLine1Alpha;
                    float line1_alpha = clamp(((main_color).a + (line1_color).w), 0.0 , 1.0);

                    #if defined (_USE_SCANLINE2)
                        float2 line2_uv = (i.posWorld.y * _HologramLine2Frequency + _Time.y * _HologramLine2Speed).xx;
                        float line2 = clamp(tex2D(_HologramLine2, line2_uv).r, 0.0, 1.0);
                        float4 line2_color = float4((main_color * line2).rgb, line2) * _HologramLine2Alpha;
                        float line2_alpha = clamp(((main_color).a + (line2_color).w), 0.0 , 1.0);
                    #else
                        float4 line2_color = 0.0;
                        float line2_alpha = 1.0;
                    #endif

                    float4 resultColor = float4(
                        // rgb
                        main_color.rgb + line1_color.rgb * line1_alpha + line2_color.rgb * line2_alpha, 
                        // alpha
                        _HologramAlpha * mask_alpha
                    );
                    return resultColor;
                }
            ENDCG
        }
    }


コードから、2 種類のスキャン ラインを構成したことがわかります。2 番目のタイプのスキャン ラインには、それを使用するかどうかを制御するバリアントが追加されています。

2 つの異なるスキャン ラインがあるため、異なるスキャン ライン テクスチャとテクスチャ速度を構成して、よりランダムなスキャン効果を作成できます。うーん...実際、ランダムにはなりませんでしたが、重ね合わせ効果が良く見えますね~

 

5. フェスネル反射効果
現在、ホログラフィックの頂点の不具合と走査線の効果がありますが、モデル全体のパフォーマンスはフラットすぎて、光の感覚がなく、十分に眩しくありません! !

したがって、岩の少年を光に変えるには、フレネル反射にエッジ ハイライトを追加する必要があります。

HologramEffect を調整して、細かい反射の部分を増やします。

Properties
    {
        ...
        // 全息菲涅尔
        _FresnelScale("Fresnel Scale", Float) = 1
        _FresnelPower("Fresnel Power", Float) = 2
    }
    SubShader
    {
        Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
        CGINCLUDE
            struct a2v_hg
            {
                ..
                float3 normal:NORMAL;
            };
            struct v2f_hg
            {
                ...
                float3 normalDir : TEXCOORD2;
            };

            ...
            // 全息菲涅尔
            half _FresnelScale, _FresnelPower;
            ...

            v2f_hg HologramVertex(a2v_hg v)
            {
                ...
                o.normalDir = mul((float3x3)unity_ObjectToWorld, v.normal);

                return o;
            }
        ENDCG
        ...
        Pass
        {
            Name "Hologram Effect"
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off
            CGPROGRAM
                ...
                float4 HologramFragment(v2f_hg i) : SV_Target
                {
                    ...
                    // 菲涅尔反射
                    float3 w_viewDir = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
                    float3 w_normal = normalize(i.normalDir);
                    float nDotV = dot(w_normal, w_viewDir);
                    float rim_nDotV = 1.0 - nDotV;
                    float4 fresnel = _FresnelScale * pow(rim_nDotV, _FresnelPower);
                    fresnel.a = clamp(fresnel.a, 0.0, 1.0);
                    float4 fresnel_color = (float4(fresnel.rgb, 1.0) * float4(main_color.rgb, 1.0)) * fresnel.a;

                    float4 resultColor = float4(
                        // rgb
                        main_color.rgb + line1_color.rgb * line1_alpha + line2_color.rgb * line2_alpha + fresnel_color.rgb, 
                        // alpha
                        _HologramAlpha * mask_alpha
                    );
                    return resultColor;
                }
            ENDCG
        }
    }

フレネルのアルゴリズムに関して言えば、ここで話していることはバイドゥほど詳細ではありません…

つまり、視野角方向とモデルの法線方向の点積を使用して、頂点が視野角方向に見えるエッジ上にあるかどうかを判断し、上記のコードのアルゴリズムが色を強調します。エッジのこの部分を最終的な色に重ねます透明度が 0 ~ 1 の範囲を超えてはならないことに注意してください。もちろん、より特殊な効果を得るために、上限を設定せずに透明度を 0 より低くしないようにすることもできます。

フィニアリフレクション効果のあるロックボーイを追加し、似たような見た目に。. . もうちょっといいですよ~

 

第 6 に、パーティクル エフェクト
全体のエフェクトはすでに確認できますが、全体のエフェクトをさらに洗練することができます。以前の変更は比較的全体的なものでしたが、今回はクローズアップのディテール強化 (カラー パーティクル エフェクト) を追加しました。

カラーパーティクル効果は、モデルの表面の色を再び乱すことですが、乱れ効果といえば、ノイズ効果を使用してそれを実現できます。ノイズは、ノイズ アルゴリズムを使用するか、ノイズ テクスチャをサンプリングすることによって生成できます。筆者のエフェクトはモバイル側での使用を想定して設計されていたため、ノイズ テクスチャ サンプリング法を使用して実現しました。

ノイズ テクスチャのサンプリングは、上記のメイン UV モデルの詳細と同じです。つまり、チャネルの 1 つだけをサンプリングする必要があります。ノイズ テクスチャをサンプリングした結果は、最終的なメイン カラーに直接適用できます。HologramEffect を調整します。変更内容は次のとおりです。

Properties
    {
        ...
        _HologramNoiseMap("Hologram Noise Map", 2D) = "white"{}
        ...
        // 颗粒效果
        // xy:噪声采样tilling(需要噪声图),zw:噪声颜色区间(0~1)
        _HologramGrainData("Hologram Grain Data", Vector) = (20, 20, 0, 1)
        _HologramGrainSpeed("Hologram Grain Speed", Float) = 1.0
        _HologramGrainAffect("Hologram Grain Affect", Range(0 , 1)) = 1
    }
    SubShader
    {
        Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
        CGINCLUDE
            ...
            sampler2D _HologramNoiseMap;
            ...
            // 全息颜色颗粒
            half4 _HologramGrainData;
            half _HologramGrainSpeed, _HologramGrainAffect;

            ...
            // 采样噪声图
            float SampleNoiseMap(float2 uv)
            {
                return tex2D(_HologramNoiseMap, uv).r;
            }

            ...
        ENDCG
        ...
        Pass
        {
            Name "Hologram Effect"
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off
            CGPROGRAM
                ...
            
                float4 HologramFragment(v2f_hg i) : SV_Target
                {
                    ...
                    // 颗粒效果
                    float grain_noise = SampleNoiseMap((i.posWorld.xy * _HologramGrainData.xy + _Time.y * _HologramGrainSpeed));
                    float grain_amount = lerp(_HologramGrainData.z, _HologramGrainData.w, grain_noise) * _HologramGrainAffect;

                    float4 resultColor = float4(
                        // rgb
                        main_color.rgb + line1_color.rgb * line1_alpha + line2_color.rgb * line2_alpha + fresnel_color.rgb + grain_amount, 
                        // alpha
                        _HologramAlpha * mask_alpha
                    );
                    return resultColor;
                }
            ENDCG
        }
    }

今この特殊効果を見て、すぐに出てくると思いますか〜そうです、良いシェーダー効果は効果を積み重ねることです...

7. カラー グリッチ エフェクト
先ほど、頂点グリッチ エフェクトを作成して、信号不足による画像の歪みをシミュレートしましたが、画像が歪んでいるのに、なぜ色がまだオンのままなのですか?

これは理不尽です!私は満足していません!

したがって、色の伝達が不安定な場合のモデルのちらつき効果をシミュレートするために、別の効果を追加する必要があります。

上記のカラー パーティクル エフェクトを作成したときにノイズ テクスチャを使用しましたが、ここでも引き続き使用できます。サンプリング結果は、最終的な出力カラーに直接影響します。HologramEffect を変更します。

Properties
    {
        ...
        // 全息颜色故障效果
        [Toggle] _HologramColorGlitchTog("Enable Hologram Color Glitch", Float) = 0
        // 噪声速度(使用XY分量)
        _HologramColorGlitch("Hologram Color Glitch", Range(0.0, 1.0)) = 0.5
        _HologramColorGlitchData("Hologram Color Glitch Data", Vector) = (1, 1, 0, 0)
        _HologramColorGlitchMin("Hologram Color Glitch Min", Range(0.0, 1.0)) = 0.5
    }
    SubShader
    {
        Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
        CGINCLUDE
            ...
            // 颜色故障效果
            half _HologramColorGlitchTog, _HologramColorGlitch, _HologramColorGlitchMin;
            half4 _HologramColorGlitchData;

            ...
        ENDCG
        ...
        Pass
        {
            Name "Hologram Effect"
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off
            CGPROGRAM
                ...
            
                float4 HologramFragment(v2f_hg i) : SV_Target
                {
                    ...
                    // 颜色故障效果
                    float color_glicth_noise = SampleNoiseMap(float2(_Time.x * _HologramColorGlitchData.x, _Time.x * _HologramColorGlitchData.y));
                    color_glicth_noise = color_glicth_noise * (1.0 - _HologramColorGlitchMin) + _HologramColorGlitchMin;
                    color_glicth_noise = clamp(color_glicth_noise, 0.0, 1.0);
                    float color_glitch = lerp(1.0, color_glicth_noise, _HologramColorGlitch * _HologramColorGlitchTog);
                    ...
                    // 应用全局颜色故障效果
                    resultColor *= color_glitch;

                    return resultColor;
                }
            ENDCG
        }
    }

 _HologramColorGlitchTog は、上記の 2 番目のスキャン ラインと同じ効果を持つスイッチです。違いは、この効果がオンになっていない場合は値が 0 であり、コードを使用できるため、ここでのスイッチはシェーダー バリアントである必要がないことです。このカラー グリッチ効果を巧みに回避します。

_HologramColorGlitchMin の役割は、点滅する色の最小値を決定することで、最も暗いときにこれよりも暗くならないようにすることです。

この色のグリッチを追加した後、私たちは最高の最終的な効果を持っています~

うちのロックボーイも全身になりました~

CustomEditor
シェーダー パラメータはまだ比較的大きく、パネルに配置するのは面倒です。同様に、アートの子供の靴が私たちのシェーダー パネルを見たら、おそらく彼らは 40 メートルの長さのナイフを持って、プログラムでドラゴン ソードを撃つでしょう。

したがって、アート子供靴用のシェーダー エディターを作成する必要がかなりあります。

したがって!ShaderEditor のカスタマイズに戻ります。ただし、特定の論理的な説明はコードに入れているため、繰り返しません〜読者は、対応する位置の著者のコメントに従って読むことができます。

Editor ディレクトリを作成し、HologramEditor という名前の C# ファイルを作成します。完全なコードは次のとおりです。

using UnityEngine;
using UnityEditor;

public class HologramEditor : ShaderGUI
{
    Material target;
    MaterialEditor editor;
    MaterialProperty[] properties;
    static GUIContent staticLabel = new GUIContent();
    // 折叠参数
    bool expand_mask;
    bool expand_ver_gliter1;
    bool expand_ver_gliter2;
    bool expand_line1;
    bool expand_line2;
    bool expand_fresnel;
    bool expand_grain;
    bool expand_color_glitch;

    public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
    {
        // base.OnGUI(materialEditor, properties);
        this.target = materialEditor.target as Material;
        this.editor = materialEditor;
        this.properties = properties;
        DoBase();
        DoHgMask();
        DoVertexGliter();
        DoScanLine();
        DoFresnel();
        DoGrain();
        DoColorGlitch();
    }

    // 基础参数
    void DoBase()
    {
        // 全息颜色
        MaterialProperty hg_color = FindProperty("_HologramColor");
        editor.ShaderProperty(hg_color, MakeLabel("全息整体颜色"));
        MaterialProperty hg_alpha = FindProperty("_HologramAlpha");
        editor.ShaderProperty(hg_alpha, MakeLabel("全息整体透明度"));
        MaterialProperty glitch_map = FindProperty("_HologramNoiseMap");
        editor.TextureProperty(glitch_map, "噪声纹理", false);
        GUILayout.Space(10);
    }

    // 蒙版
    void DoHgMask()
    {
        // 这个是Editor的折叠UI,当这个值为true时便会渲染下面的属性词条UI出来
        expand_mask = EditorGUILayout.Foldout(expand_mask, "整体蒙版");
        if(expand_mask) 
        {
            EditorGUI.indentLevel += 1;
            // 获取材质属性
            MaterialProperty mask = FindProperty("_HologramMaskMap");
            MaterialProperty mask_affect = FindProperty("_HologramMaskAffect");
            // 绘制EditorGUI属性词条
            editor.TextureProperty(mask, "蒙版");
            editor.ShaderProperty(mask_affect, "蒙版强度");
            EditorGUI.indentLevel -= 1;
        }
    }

    // 顶点故障效果
    void DoVertexGliter()
    {
        expand_ver_gliter1 = EditorGUILayout.Foldout(expand_ver_gliter1, "顶点故障1");
        if(expand_ver_gliter1)
        {
            EditorGUI.indentLevel += 1;
            MaterialProperty gliter1 = FindProperty("_HologramGliterData1");
            GUILayout.Label("x:速度,y:抖动范围,z:抖动偏移量(正负区分左右抖动),w代表频率(0~0.99)", EditorStyles.centeredGreyMiniLabel);
            editor.VectorProperty(gliter1, "故障参数1");
            EditorGUI.indentLevel -= 1;
        }
        expand_ver_gliter2 = EditorGUILayout.Foldout(expand_ver_gliter2, "顶点故障2");
        if(expand_ver_gliter2)
        {
            EditorGUI.indentLevel += 1;
            MaterialProperty gliter2 = FindProperty("_HologramGliterData2");
            GUILayout.Label("x:速度,y:抖动范围,z:抖动偏移量(正负区分左右抖动),w代表频率(0~0.99)", EditorStyles.centeredGreyMiniLabel);
            editor.VectorProperty(gliter2, "故障参数2");
            EditorGUI.indentLevel -= 1;
        }
    }

    // 扫描线属性
    void DoScanLine()
    {
        expand_line1 = EditorGUILayout.Foldout(expand_line1, "扫描线效果1");
        if(expand_line1)
        {
            EditorGUI.indentLevel += 1;
            MaterialProperty line1_map = FindProperty("_HologramLine1");
            MaterialProperty line1_speed = FindProperty("_HologramLine1Speed");
            MaterialProperty line1_tilling = FindProperty("_HologramLine1Frequency");
            MaterialProperty line1_alpha = FindProperty("_HologramLine1Alpha");
            editor.TextureProperty(line1_map, "扫描线1纹理", false);
            editor.ShaderProperty(line1_speed, "扫描线1速度");
            editor.ShaderProperty(line1_tilling, "扫描线1tilling");
            editor.ShaderProperty(line1_alpha, "扫描线1透明度");
            EditorGUI.indentLevel -= 1;
        }

        expand_line2 = EditorGUILayout.Foldout(expand_line2, "扫描线效果2");
        if(expand_line2)
        {
            EditorGUI.indentLevel += 1;
            EditorGUI.BeginChangeCheck();
            MaterialProperty line2_tog = FindProperty("_HologramLine2Tog");
            editor.ShaderProperty(line2_tog, "使用扫描线2");
            // 当扫描线2的选项勾选之后才会绘制下方的属性GUI
            bool line2_enabled = GetToggleEnabled(line2_tog);
            if(line2_enabled)
            {
                MaterialProperty line2_map = FindProperty("_HologramLine2");
                MaterialProperty line2_speed = FindProperty("_HologramLine2Speed");
                MaterialProperty line2_tilling = FindProperty("_HologramLine2Frequency");
                MaterialProperty line2_alpha = FindProperty("_HologramLine2Alpha");
                editor.TextureProperty(line2_map, "扫描线2纹理", false);
                editor.ShaderProperty(line2_speed, "扫描线2速度");
                editor.ShaderProperty(line2_tilling, "扫描线2tilling");
                editor.ShaderProperty(line2_alpha, "扫描线2透明度");
            }
            EditorGUI.indentLevel -= 1;
            if(EditorGUI.EndChangeCheck())
            {
                SetKeyword("_USE_SCANLINE2", line2_enabled);
            }
        }
    }

    // 颜色故障效果
    void DoColorGlitch()
    {
        expand_color_glitch = EditorGUILayout.Foldout(expand_color_glitch, "全息颜色故障效果");
        if(expand_color_glitch)
        {
            EditorGUI.indentLevel += 1;
            MaterialProperty c_g_tog = FindProperty("_HologramColorGlitchTog");
            editor.ShaderProperty(c_g_tog, "使用颜色故障");
            if(GetToggleEnabled(c_g_tog))
            {
                MaterialProperty glitch_val = FindProperty("_HologramColorGlitch");
                MaterialProperty glitch_data = FindProperty("_HologramColorGlitchData");
                MaterialProperty glitch_min = FindProperty("_HologramColorGlitchMin");
                editor.ShaderProperty(glitch_val, "颜色故障强度");
                editor.VectorProperty(glitch_data, "噪声速度(使用XY分量)");
                editor.ShaderProperty(glitch_min, "颜色故障最小值");
            }
            EditorGUI.indentLevel -= 1;
        }
    }

    // 菲涅尔反射
    void DoFresnel()
    {
        expand_fresnel = EditorGUILayout.Foldout(expand_fresnel, "全息Fresnel效果");
        if(expand_fresnel)
        {
            EditorGUI.indentLevel += 1;
            MaterialProperty fresnel_scale = FindProperty("_FresnelScale");
            MaterialProperty fresnel_power = FindProperty("_FresnelPower");
            editor.ShaderProperty(fresnel_scale, "Fresnel大小");
            editor.ShaderProperty(fresnel_power, "Fresnel指数");
            EditorGUI.indentLevel -= 1;
        }
    }

    // 颗粒效果
    void DoGrain()
    {
        expand_grain = EditorGUILayout.Foldout(expand_grain, "颗粒效果");
        if(expand_grain)
        {
            EditorGUI.indentLevel += 1;
            MaterialProperty grain_data = FindProperty("_HologramGrainData");
            MaterialProperty grain_speed = FindProperty("_HologramGrainSpeed");
            MaterialProperty grain_affect = FindProperty("_HologramGrainAffect");
            GUILayout.Label("xy:噪声采样tilling(需要噪声图),zw:噪声颜色区间(0~1)", EditorStyles.centeredGreyMiniLabel);
            editor.VectorProperty(grain_data, "颗粒参数");
            editor.ShaderProperty(grain_speed, "颗粒效果速度");
            editor.ShaderProperty(grain_affect, "颗粒效果强度");
            EditorGUI.indentLevel -= 1;
        }
    }


    // 利用方法优化GUI代码结构,使得代码更容易看
    MaterialProperty FindProperty(string name)
    {
        return FindProperty(name, properties);
    }

    static GUIContent MakeLabel(string text, string tooltip = null)
    {
        staticLabel.text = text;
        staticLabel.tooltip = tooltip;
        return staticLabel;
    }

    static GUIContent MakeLabel(MaterialProperty property, string tooltip = null)
    {
        staticLabel.text = property.displayName;
        staticLabel.tooltip = tooltip;
        return staticLabel;
    }
    // 设置shader关键字
    void SetKeyword(string keyword, bool state)
    {
        if(state)
        {
            foreach(Material m in editor.targets)
            {
                m.EnableKeyword(keyword);
            }
        }
        else{
            foreach(Material m in editor.targets)
            {
                m.DisableKeyword(keyword);
            }
        }
    }

    bool GetToggleEnabled(MaterialProperty property)
    {
        return (int)property.floatValue == 1;
    }
}

コンパイルが渡されると、HologramEffect はエディターで次のようになります。

矢印をクリックしてプロパティ GUI を展開します。


最も重要なことは何ですか、最も重要なことは、すべて中国語で作成できることです。このように、アートの子供靴は言語理解の壁がないという快楽を浴びることができ、もしかしたら番組をひっぱたいてくれるかもしれません(??

 

最後に書かれています
この共有があなたに役立つなら、それは著者の最大の名誉です. 最初にこの効果を作成したとき、著者は多くの情報を見つけることができず、最終的にこれらの効果をゆっくりと要約するのに多くの時間がかかりました.

アルゴリズム的には、実はあまり目立ったところはありませんが、その中で技術的なアイデアが盛り込まれていると思います. 他にもっと眩しい効果があれば、コメント欄で共有していただけると助かります. . アップ〜


———————————————

オリジナルリンク: https://blog.csdn.net/SaberZG/article/details/114955414

おすすめ

転載: blog.csdn.net/weixin_42565127/article/details/130324196