[Unity]オブジェクトをレントゲンのように透過させて表示するシェーダ

こんにちは。

いきなりですが、このように人物などを透過させてレントゲンのように影だけ表示させたいってことありますよね。


![](http://blog-imgs-50.fc2.com/l/o/g/logchouchou/201412070656247ec.png)
メタルギアソリッド4から引用させていただきました。


実はAssetStoreにもあるんですが, （"X-Ray"や"See Through"などで検索すると出てきます。）
**どれもこれもUnity5.0対応してねえ..**

ひとつ対応してると書いてあったやつを買ったんですが, 普通に動きませんでした...
最近このパターン多すぎて萎えまくりです。


Unity5.0とそれ以前とではマテリアルに関してはガラッと変わっちゃいましたし
Unity5.0ならやっぱりPBL使いたいですよね!


まあしかもシェーダーを買っちゃうとその部分はブラックボックス化するので
パフォーマンス的にもよろしくない。

じゃあもう自分で作っちゃおうということで、今回はこれを実装していきたいと思います。


# 1.まずはオブジェクトを透けさせる

オブジェクトを透けさせるということは, 常に最前面に描画すればいいわけです。
オブジェクトの前後関係は深度バッファで管理されていますので、
まずは簡単に深度バッファについておさらいしておきましょう。

## 深度バッファ
深度バッファというのは, 各ピクセルごとにカメラとの距離を保持しているメモリ領域のことです。
解像度分だけ深度バッファが用意されていて、これのおかげで正しい順番でオブジェクトがレンダリングされるんですね〜。

各画面ピクセルを描画する際に, カメラとの距離を深度バッファに書き込むのですが
このとき, いま書き込もうとしている数値(=カメラとの距離)よりも すでに深度バッファに書き込まれている数値が小さい場合は
そのピクセルのレンダリングをスキップします。
つまり、前回の描画よりカメラとの距離が遠かったら書き込まないようにするということですね。
深度バッファとの数値を比較して, レンダリングするかどうかを決めることを**深度テスト(ZTest)**と言います。

この深度テストを常に合格するようにしてやれば、実際のオブジェクトのZ位置にかかわらず最前面に描画されるはずです。
『深度テストを常に合格させる』というのはShaderで以下の1行を加えるだけです。

`ZTest always`

そのまんまですね。

## ZTest alwaysで最前面に描画!

さてやってみましょう。
元画像はこちら
<img width="581" alt="スクリーンショット 2015-08-28 17.20.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/91414/d1bbe77b-2c45-a1c9-4912-896e0f2a9afc.png">

これに`ZTest always`を加えて...

<img width="581" alt="スクリーンショット 2015-08-28 17.21.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/91414/db362e6b-c925-8329-d7bf-6b9f467fc879.png">


おおお、最前面に描画されましたね!
(シェーダーのコードはunity5のStandardシェーダを元にしています。
いちいちコードをのせると長いので、最後に完成品だけ載せます。)

**めちゃくちゃ簡単ですね!!!**

# 2.いや、透けたけどさ・・・

というか、これは透けたと言えるのでしょうか?
単に最前面に描画されただけでは...

さらによくみると、他の問題もあることがわかります。

<img width="580" alt="スクリーンショット 2015-08-28 17.28.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/91414/d93975b2-ec05-cc7f-7466-c040038a4777.png">


ZTestをalwaysにしたせいで、自分自身のメッシュもところどころ奥が描画されてしまっています。
この問題は意外に深く、しばらくハマってしまいました..


#2. PASS＆ステンシルで解決!

この難問を解決すべくいろいろ探し回った結果,
passとステンシルを使えば解決できるんじゃないか？
という結論に達しました。

考え方はこうです。

**1. まずはいつも通り描画する。
2. そのあと建物の陰にかくれている部分だけ外観を変えて描画する。**

つまり2回にわけて描画するわけですね！
すべて1回で描画しきろうと思うと、
前章のように自身のオブジェクトとの深度テストがうまくいかず, 描画が変になってしまうのです。

##passとは

passを使うことで, ひとつのオブジェクトで二回描画することができます。

passというのはunityのシェーダーでは最も基本的な機能の一つです。
unityのshaderは大きく以下のような構造になっていますね。


```csharp
Shader "name" {
    Properties {
    }
    SubShader {
        Pass { ... }
        Pass { ... }
    }
    SubShader {
        Pass { ... }
        Pass { ... }
    }
}
```

`properties`にはマテリアルの引数となる変数を定義したりする部分です。
`SubShader`でくるまれた部分が実際のシェーダーのコードとなります。
SubShaderが複数記述されることがあるのは、
なんらかの理由(プラットフォームが対応していないなど)で1つめのSubShaderが使えない場合に、かわりに2つ目のSubShaderを使用する... という具合に
シェーダーが実行すべきコードを順番に自動選択してくれるからです。

今回重要なのはSubShader内のPassブロックです。
このPassブロックを複数書くことで, ひとつのシェーダーで何度も描画することができます。

たとえば、トゥーンシェーダーなど郭線を描画するシェーダーでは、
1つ目のパスですこし大きめの真っ黒なオブジェクトをレンダリングし、
2つ目のパスで上から通常のレンダリングをするという手法が使われることがあります。

![](http://loumo.jp/img/2014/01/140125base-outline-toon-cubemap.jpg)




今回の例では1つ目のパスで通常のレンダリングを行い、2つめのパスで上から陰だけを最前面に描画して(=ZTest always)、
透けた感じを演出してみましょう。



##ステンシルバッファとは

ステンシルバッファとは、平たく言えば**3D空間でマスキングを行う**ために用意されているメモリ領域です。
このバッファも解像度分だけ用意されています。

ステンシルバッファを用いて3D空間でマスキングを行う場合、以下のような流れになります。

**1. まずオブジェクトAを描画する際に, ある条件を満たすピクセルだけステンシルバッファに数値を書き込む。
2. 次にオブジェクトBを描画するとき, 対象ピクセルのステンシルバッファから数値を読み取り, 描画するか否かを決定する。**

ざっと説明するとこんな感じです。
詳しい説明はUnityの公式リファレンスにあります。
http://docs.unity3d.com/ja/current/Manual/SL-Stencil.html

公式リファレンスの難解な例でも、見事マスキングに成功していることがわかります。

![](http://docs.unity3d.com/ja/current/uploads/Main/StencilExample.png)
三つの球体が重なり方に応じて見えたりみえなかったりしています。

このステンシルバッファを今回はこう使いましょう。
**『深度テストに失敗したピクセル (=陰として表示されるべきピクセル) をステンシルバッファに書き込んでき、あとからその部分だけを陰として描画する。』**


ステンシルバッファに書き込む部分をコードに直すとこんな感じです。

```csharp
Stencil {
       Ref 2
       Comp always
       Pass keep
       Fail keep
       ZFail replace
}
```

これで、深度テストに失敗した場合はステンシルバッファに2が代入されることになります。
あとはステンシルバッファが2のところだけを次のパスで描画すれば、陰だけが描画されることになりますね。
　


　



**...なんですが、**
大変ややこしくて申し訳ないのですが
実はこのまま進むと、後でまたもや変な外観になってしまいます。
※対象オブジェクトの奥側が自分自身とのZTestに失敗する部分までステンシルバッファに書き込んでしまうのです。

以下のようにするとうまくいきます。



*『深度テストに失敗したピクセルをステンシルバッファに書き込んでき、あとからその部分だけを陰として描画する。』*
ではなく、
**『深度テストに合格したピクセルをステンシルバッファに書き込んでき、あとからそれ以外の部分だけを陰として描画する。』**
です。


ではそれも踏まえて1パス目のコードを書き換えると..
こうなりますね。

```csharp
Stencil {
       Ref 2
       Comp always
       Pass replace
       Fail replace
       ZFail keep
}          
```

そして陰を描画する2パス目はこうです。

```csharp
Stencil {
       Ref 2
       Comp notequal
}
```

さて、長かったですが、コードとしてはとても単純ですね。
まとめましょう。


# 3.できた！

2パス目の陰を描画する部分は, 単色塗りつぶしにしてみました。
おまけで遠くほど色が薄くなるコードも入れてみました。

※コードは長いのでこのページの最後に載せています!

Standardシェーダのコードを探してみたのですが見つからなかったので
ShaderForgeの自動生成Standardシェーダを採用しています。

<img width="577" alt="スクリーンショット 2015-08-28 18.34.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/91414/a6ee4309-8ba5-c262-ddb6-04aea268d8e4.png">

おっ透けてる

<img width="581" alt="スクリーンショット 2015-08-28 18.34.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/91414/96563c3f-0664-abab-031c-7299f28dd8b8.png">

(わかりにくいけど遠くに行けば行くほど薄くなっているんだ)


# 4.おまけ

このまんまじゃ少々味気ないので
陰部分の描画にフレネルとかを駆使して、すこしゴーストっぽくしてみました。

<img width="700" alt="スクリーンショット 2015-08-28 18.41.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/91414/32ac6edb-1003-7d97-b77d-1e3553749189.png">

<img width="700" alt="スクリーンショット 2015-08-28 18.41.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/91414/0bbf5c82-f31d-5420-e90e-a177e6a97fa0.png">


うん、なかなかいい感じ!



それと、もうひとつ地味に問題になってくるのが
メインキャラ等、透けてほしくないものまで透けてしまうということ

たとえばプレイヤーキャラクターが手前にいる場合

<img width="700" alt="スクリーンショット 2015-08-28 18.45.56.png" src="https://qiita-image-store.s3.amazonaws.com/0/91414/4975f9e1-7c51-2f3e-63f3-3995a9d07ad9.png">


**ああ^~　ゴースト邪魔じゃ^~**

 

これは致命的な問題ですよね。
ですが、解決策はシンプルです。
手前のプレイヤーのマテリアルにはレントゲンをキャンセルするシェーダーを入れとけばいいんです。

```
Stencil {
        Ref 2
        Comp always
        Pass replace
        Fail replace
}
```

これでそのオブジェクトが描画される領域のステンシルを無効化することができますね。
（あるいは逆に特定のオブジェクトのみ透けさせるということも, 同様のやり方で可能です。）

結果はこうなります。
<img width="700" alt="スクリーンショット 2015-08-28 18.50.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/91414/e72b4911-e89e-25aa-5eec-d94705ef9b8f.png">



**いいですね〜**


まあ、描画コストはもちろん上がっちゃうのですが
それなりに効果的でもあるので、アリなんじゃないでしょうか？



今日はここまでにしときます。
それではみなさん、さよなら〜



# 5.ソースコード

```csharp

Shader "Shader Forge/X-Ray_test" {
    Properties {
        _BumpMap ("Normal Map", 2D) = "bump" {}
        _Color ("Color", Color) = (0.5019608,0.5019608,0.5019608,1)
        _MainTex ("Base Color", 2D) = "white" {}
        _Metallic ("Metallic", Range(0, 1)) = 0
        _Gloss ("Gloss", Range(0, 1)) = 0.8
        _VisibleRange ("VisibleRange", Range(1, 300)) = 100
        _ShadeColor ("ShadeColor", Color) = (0.5019608,0.5019608,0.5019608,1)
    }
    SubShader {
        Tags {
            "RenderType"="Opaque"
        }
        
        Pass {
            Name "FRONTCULL"
            Tags {
            }
            Cull Front
        }
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }
            
            Stencil {
                Ref 2
                Comp always
                Pass replace
                Fail replace
                ZFail keep
            }
            
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #define UNITY_PASS_FORWARDBASE
            #define SHOULD_SAMPLE_SH ( defined (LIGHTMAP_OFF) && defined(DYNAMICLIGHTMAP_OFF) )
            #define _GLOSSYENV 1
            #include "UnityCG.cginc"
            #include "AutoLight.cginc"
            #include "Lighting.cginc"
            #include "UnityPBSLighting.cginc"
            #include "UnityStandardBRDF.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
            #pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE
            #pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON
            #pragma multi_compile_fog
            #pragma exclude_renderers gles3 metal d3d11_9x xbox360 xboxone ps3 ps4 psp2 
            #pragma target 3.0
            uniform float4 _Color;
            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
            uniform sampler2D _BumpMap; uniform float4 _BumpMap_ST;
            uniform float _Metallic;
            uniform float _Gloss;
            struct VertexInput {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 tangent : TANGENT;
                float2 texcoord0 : TEXCOORD0;
                float2 texcoord1 : TEXCOORD1;
                float2 texcoord2 : TEXCOORD2;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
                float2 uv0 : TEXCOORD0;
                float2 uv1 : TEXCOORD1;
                float2 uv2 : TEXCOORD2;
                float4 posWorld : TEXCOORD3;
                float3 normalDir : TEXCOORD4;
                float3 tangentDir : TEXCOORD5;
                float3 bitangentDir : TEXCOORD6;
                LIGHTING_COORDS(7,8)
                UNITY_FOG_COORDS(9)
                #if defined(LIGHTMAP_ON) || defined(UNITY_SHOULD_SAMPLE_SH)
                    float4 ambientOrLightmapUV : TEXCOORD10;
                #endif
            };
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.uv0 = v.texcoord0;
                o.uv1 = v.texcoord1;
                o.uv2 = v.texcoord2;
                #ifdef LIGHTMAP_ON
                    o.ambientOrLightmapUV.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
                    o.ambientOrLightmapUV.zw = 0;
                #elif UNITY_SHOULD_SAMPLE_SH
            #endif
            #ifdef DYNAMICLIGHTMAP_ON
                o.ambientOrLightmapUV.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
            #endif
            o.normalDir = UnityObjectToWorldNormal(v.normal);
            o.tangentDir = normalize( mul( _Object2World, float4( v.tangent.xyz, 0.0 ) ).xyz );
            o.bitangentDir = normalize(cross(o.normalDir, o.tangentDir) * v.tangent.w);
            o.posWorld = mul(_Object2World, v.vertex);
            float3 lightColor = _LightColor0.rgb;
            o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
            UNITY_TRANSFER_FOG(o,o.pos);
            TRANSFER_VERTEX_TO_FRAGMENT(o)
            return o;
        }
        float4 frag(VertexOutput i) : COLOR {
            i.normalDir = normalize(i.normalDir);
            float3x3 tangentTransform = float3x3( i.tangentDir, i.bitangentDir, i.normalDir);
/// Vectors:
            float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
            float3 _BumpMap_var = UnpackNormal(tex2D(_BumpMap,TRANSFORM_TEX(i.uv0, _BumpMap)));
            float3 normalLocal = _BumpMap_var.rgb;
            float3 normalDirection = normalize(mul( normalLocal, tangentTransform )); // Perturbed normals
            float3 viewReflectDirection = reflect( -viewDirection, normalDirection );
            float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);
            float3 lightColor = _LightColor0.rgb;
            float3 halfDirection = normalize(viewDirection+lightDirection);
// Lighting:
            float attenuation = LIGHT_ATTENUATION(i);
            float3 attenColor = attenuation * _LightColor0.xyz;
            float Pi = 3.141592654;
            float InvPi = 0.31830988618;
///// Gloss:
            float gloss = _Gloss;
            float specPow = exp2( gloss * 10.0+1.0);
/// GI Data:
            UnityLight light;
            #ifdef LIGHTMAP_OFF
                light.color = lightColor;
                light.dir = lightDirection;
                light.ndotl = LambertTerm (normalDirection, light.dir);
            #else
                light.color = half3(0.f, 0.f, 0.f);
                light.ndotl = 0.0f;
                light.dir = half3(0.f, 0.f, 0.f);
            #endif
            UnityGIInput d;
            d.light = light;
            d.worldPos = i.posWorld.xyz;
            d.worldViewDir = viewDirection;
            d.atten = attenuation;
            #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
                d.ambient = 0;
                d.lightmapUV = i.ambientOrLightmapUV;
            #else
                d.ambient = i.ambientOrLightmapUV;
            #endif
            d.boxMax[0] = unity_SpecCube0_BoxMax;
            d.boxMin[0] = unity_SpecCube0_BoxMin;
            d.probePosition[0] = unity_SpecCube0_ProbePosition;
            d.probeHDR[0] = unity_SpecCube0_HDR;
            d.boxMax[1] = unity_SpecCube1_BoxMax;
            d.boxMin[1] = unity_SpecCube1_BoxMin;
            d.probePosition[1] = unity_SpecCube1_ProbePosition;
            d.probeHDR[1] = unity_SpecCube1_HDR;
            UnityGI gi = UnityGlobalIllumination (d, 1, gloss, normalDirection);
            lightDirection = gi.light.dir;
            lightColor = gi.light.color;
// Specular:
            float NdotL = max(0, dot( normalDirection, lightDirection ));
            float LdotH = max(0.0,dot(lightDirection, halfDirection));
            float4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(i.uv0, _MainTex));
            float3 diffuseColor = (_MainTex_var.rgb*_Color.rgb); // Need this for specular when using metallic
            float specularMonochrome;
            float3 specularColor;
            diffuseColor = DiffuseAndSpecularFromMetallic( diffuseColor, _Metallic, specularColor, specularMonochrome );
            specularMonochrome = 1-specularMonochrome;
            float NdotV = max(0.0,dot( normalDirection, viewDirection ));
            float NdotH = max(0.0,dot( normalDirection, halfDirection ));
            float VdotH = max(0.0,dot( viewDirection, halfDirection ));
            float visTerm = SmithBeckmannVisibilityTerm( NdotL, NdotV, 1.0-gloss );
            float normTerm = max(0.0, NDFBlinnPhongNormalizedTerm(NdotH, RoughnessToSpecPower(1.0-gloss)));
            float specularPBL = max(0, (NdotL*visTerm*normTerm) * unity_LightGammaCorrectionConsts_PIDiv4 );
            float3 directSpecular = 1 * pow(max(0,dot(halfDirection,normalDirection)),specPow)*specularPBL*lightColor*FresnelTerm(specularColor, LdotH);
            half grazingTerm = saturate( gloss + specularMonochrome );
            float3 indirectSpecular = (gi.indirect.specular);
            indirectSpecular *= FresnelLerp (specularColor, grazingTerm, NdotV);
            float3 specular = (directSpecular + indirectSpecular);
/// Diffuse:
            NdotL = max(0.0,dot( normalDirection, lightDirection ));
            half fd90 = 0.5 + 2 * LdotH * LdotH * (1-gloss);
            float3 directDiffuse = ((1 +(fd90 - 1)*pow((1.00001-NdotL), 5)) * (1 + (fd90 - 1)*pow((1.00001-NdotV), 5)) * NdotL) * attenColor;
            float3 indirectDiffuse = float3(0,0,0);
            indirectDiffuse += gi.indirect.diffuse;
            float3 diffuse = (directDiffuse + indirectDiffuse) * diffuseColor;
// Final Color:
            float3 finalColor = diffuse + specular;
            fixed4 finalRGBA = fixed4(finalColor,1);
            UNITY_APPLY_FOG(i.fogCoord, finalRGBA);
            return finalRGBA;
        }
        ENDCG
    }
    Pass {
        Name "FORWARD_DELTA"
        Tags {
            "LightMode"="ForwardAdd"
        }
        Blend One One
        
        
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #define UNITY_PASS_FORWARDADD
        #define SHOULD_SAMPLE_SH ( defined (LIGHTMAP_OFF) && defined(DYNAMICLIGHTMAP_OFF) )
        #define _GLOSSYENV 1
        #include "UnityCG.cginc"
        #include "AutoLight.cginc"
        #include "Lighting.cginc"
        #include "UnityPBSLighting.cginc"
        #include "UnityStandardBRDF.cginc"
        #pragma multi_compile_fwdadd_fullshadows
        #pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
        #pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE
        #pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON
        #pragma multi_compile_fog
        #pragma exclude_renderers gles3 metal d3d11_9x xbox360 xboxone ps3 ps4 psp2 
        #pragma target 3.0
        uniform float4 _Color;
        uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
        uniform sampler2D _BumpMap; uniform float4 _BumpMap_ST;
        uniform float _Metallic;
        uniform float _Gloss;
        struct VertexInput {
            float4 vertex : POSITION;
            float3 normal : NORMAL;
            float4 tangent : TANGENT;
            float2 texcoord0 : TEXCOORD0;
            float2 texcoord1 : TEXCOORD1;
            float2 texcoord2 : TEXCOORD2;
        };
        struct VertexOutput {
            float4 pos : SV_POSITION;
            float2 uv0 : TEXCOORD0;
            float2 uv1 : TEXCOORD1;
            float2 uv2 : TEXCOORD2;
            float4 posWorld : TEXCOORD3;
            float3 normalDir : TEXCOORD4;
            float3 tangentDir : TEXCOORD5;
            float3 bitangentDir : TEXCOORD6;
            LIGHTING_COORDS(7,8)
        };
        VertexOutput vert (VertexInput v) {
            VertexOutput o = (VertexOutput)0;
            o.uv0 = v.texcoord0;
            o.uv1 = v.texcoord1;
            o.uv2 = v.texcoord2;
            o.normalDir = UnityObjectToWorldNormal(v.normal);
            o.tangentDir = normalize( mul( _Object2World, float4( v.tangent.xyz, 0.0 ) ).xyz );
            o.bitangentDir = normalize(cross(o.normalDir, o.tangentDir) * v.tangent.w);
            o.posWorld = mul(_Object2World, v.vertex);
            float3 lightColor = _LightColor0.rgb;
            o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
            TRANSFER_VERTEX_TO_FRAGMENT(o)
            return o;
        }
        float4 frag(VertexOutput i) : COLOR {
            i.normalDir = normalize(i.normalDir);
            float3x3 tangentTransform = float3x3( i.tangentDir, i.bitangentDir, i.normalDir);
/// Vectors:
            float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
            float3 _BumpMap_var = UnpackNormal(tex2D(_BumpMap,TRANSFORM_TEX(i.uv0, _BumpMap)));
            float3 normalLocal = _BumpMap_var.rgb;
            float3 normalDirection = normalize(mul( normalLocal, tangentTransform )); // Perturbed normals
            float3 lightDirection = normalize(lerp(_WorldSpaceLightPos0.xyz, _WorldSpaceLightPos0.xyz - i.posWorld.xyz,_WorldSpaceLightPos0.w));
            float3 lightColor = _LightColor0.rgb;
            float3 halfDirection = normalize(viewDirection+lightDirection);
// Lighting:
            float attenuation = LIGHT_ATTENUATION(i);
            float3 attenColor = attenuation * _LightColor0.xyz;
            float Pi = 3.141592654;
            float InvPi = 0.31830988618;
///// Gloss:
            float gloss = _Gloss;
            float specPow = exp2( gloss * 10.0+1.0);
// Specular:
            float NdotL = max(0, dot( normalDirection, lightDirection ));
            float LdotH = max(0.0,dot(lightDirection, halfDirection));
            float4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(i.uv0, _MainTex));
            float3 diffuseColor = (_MainTex_var.rgb*_Color.rgb); // Need this for specular when using metallic
            float specularMonochrome;
            float3 specularColor;
            diffuseColor = DiffuseAndSpecularFromMetallic( diffuseColor, _Metallic, specularColor, specularMonochrome );
            specularMonochrome = 1-specularMonochrome;
            float NdotV = max(0.0,dot( normalDirection, viewDirection ));
            float NdotH = max(0.0,dot( normalDirection, halfDirection ));
            float VdotH = max(0.0,dot( viewDirection, halfDirection ));
            float visTerm = SmithBeckmannVisibilityTerm( NdotL, NdotV, 1.0-gloss );
            float normTerm = max(0.0, NDFBlinnPhongNormalizedTerm(NdotH, RoughnessToSpecPower(1.0-gloss)));
            float specularPBL = max(0, (NdotL*visTerm*normTerm) * unity_LightGammaCorrectionConsts_PIDiv4 );
            float3 directSpecular = attenColor * pow(max(0,dot(halfDirection,normalDirection)),specPow)*specularPBL*lightColor*FresnelTerm(specularColor, LdotH);
            float3 specular = directSpecular;
/// Diffuse:
            NdotL = max(0.0,dot( normalDirection, lightDirection ));
            half fd90 = 0.5 + 2 * LdotH * LdotH * (1-gloss);
            float3 directDiffuse = ((1 +(fd90 - 1)*pow((1.00001-NdotL), 5)) * (1 + (fd90 - 1)*pow((1.00001-NdotV), 5)) * NdotL) * attenColor;
            float3 diffuse = directDiffuse * diffuseColor;
// Final Color:
            float3 finalColor = diffuse + specular;
            return fixed4(finalColor * 1,0);
        }
        ENDCG
    }
    Pass {
        Name "Meta"
        Tags {
            "LightMode"="Meta"
        }
        Cull Off
        
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #define UNITY_PASS_META 1
        #define SHOULD_SAMPLE_SH ( defined (LIGHTMAP_OFF) && defined(DYNAMICLIGHTMAP_OFF) )
        #define _GLOSSYENV 1
        #include "UnityCG.cginc"
        #include "Lighting.cginc"
        #include "UnityPBSLighting.cginc"
        #include "UnityStandardBRDF.cginc"
        #include "UnityMetaPass.cginc"
        #pragma fragmentoption ARB_precision_hint_fastest
        #pragma multi_compile_shadowcaster
        #pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
        #pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE
        #pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON
        #pragma multi_compile_fog
        #pragma exclude_renderers gles3 metal d3d11_9x xbox360 xboxone ps3 ps4 psp2 
        #pragma target 3.0
        uniform float4 _Color;
        uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
        uniform float _Metallic;
        uniform float _Gloss;
        struct VertexInput {
            float4 vertex : POSITION;
            float2 texcoord0 : TEXCOORD0;
            float2 texcoord1 : TEXCOORD1;
            float2 texcoord2 : TEXCOORD2;
        };
        struct VertexOutput {
            float4 pos : SV_POSITION;
            float2 uv0 : TEXCOORD0;
            float2 uv1 : TEXCOORD1;
            float2 uv2 : TEXCOORD2;
            float4 posWorld : TEXCOORD3;
        };
        VertexOutput vert (VertexInput v) {
            VertexOutput o = (VertexOutput)0;
            o.uv0 = v.texcoord0;
            o.uv1 = v.texcoord1;
            o.uv2 = v.texcoord2;
            o.posWorld = mul(_Object2World, v.vertex);
            o.pos = UnityMetaVertexPosition(v.vertex, v.texcoord1.xy, v.texcoord2.xy, unity_LightmapST, unity_DynamicLightmapST );
            return o;
        }
        float4 frag(VertexOutput i) : SV_Target {
            float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
            UnityMetaInput o;
            UNITY_INITIALIZE_OUTPUT( UnityMetaInput, o );
            
            o.Emission = 0;
            
            float4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(i.uv0, _MainTex));
            float3 diffColor = (_MainTex_var.rgb*_Color.rgb);
            float specularMonochrome;
            float3 specColor;
            diffColor = DiffuseAndSpecularFromMetallic( diffColor, _Metallic, specColor, specularMonochrome );
            float roughness = 1.0 - _Gloss;
            o.Albedo = diffColor + specColor * roughness * roughness * 0.5;
            
            return UnityMetaFragment( o );
        }
        ENDCG
    }
    
    Pass {
    	Name "X-Ray"
            Tags {
                "LightMode"="ForwardBase"
            }
            Blend OneMinusDstColor One
            ZTest Always
            
            Stencil {
                Ref 2
                Comp notequal
            }
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #define UNITY_PASS_FORWARDBASE
            #include "UnityCG.cginc"
            #include "AutoLight.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma multi_compile_fog
            #pragma exclude_renderers gles3 metal d3d11_9x xbox360 xboxone ps3 ps4 psp2 
            #pragma target 3.0
            uniform float4 _LightColor0;
            uniform sampler2D _MainColor; uniform float4 _MainColor_ST;
            uniform float _VisibleRange;
            uniform float4 _ShadeColor;
            struct VertexInput {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float2 texcoord0 : TEXCOORD0;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
                float2 uv0 : TEXCOORD0;
                float4 projPos : TEXCOORD3;
                LIGHTING_COORDS(3,4)
                UNITY_FOG_COORDS(5)
            };
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.uv0 = v.texcoord0;
                float3 lightColor = _LightColor0.rgb;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
            	o.projPos = ComputeScreenPos (o.pos);
                UNITY_TRANSFER_FOG(o,o.pos);
                TRANSFER_VERTEX_TO_FRAGMENT(o)
                return o;
                
            }
            float4 frag(VertexOutput i) : COLOR {
            	float partZ = 1.0 - (max(0,i.projPos.z - _ProjectionParams.g) / _VisibleRange);
                float3 diffuseColor = lerp(float4(0,0,0,0),_ShadeColor.rgb,partZ);
                fixed4 finalRGBA = fixed4( diffuseColor,1);
                return finalRGBA;
            }
            ENDCG
        }
}
FallBack "Diffuse"
CustomEditor "ShaderForgeMaterialInspector"
}
```