[Unity5]破綻しない半透明描画を行う | notargs.com
ディザリングはUnity5標準の影の描画でも使われているため、デフォルトで「_DitherMaskLOD」という名前の3Dテクスチャが定義されています。
x/yにスクリーン座標、zにアルファ値を指定することで、そのピクセルが透明かどうか(透明なら0、違えば1)を取得できます。
これをそのままclip関数へ渡してやれば、ディザリングを用いた描画の実装は完了です。
シェーダで面を円形に切り抜きたかったため、ShadowCasterパスを定義し直しています。
UnityStandardShadow.cgincをinclude、標準のvertShadowCaster/fragShadowCasterの代わりに自前で定義したfrag/vert関数を使い、その中で切り抜きを行っています。
Shader "MyTransparent" { Properties { _Color("Color", Color) = (1,1,1,1) _Glossiness("Smoothness", Range(0.0, 1.0)) = 0.5 [Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0 [HideInInspector] _MainTex("Texture", 2D) = "white" {} } SubShader{ //============================ // レンダリング用のPass CGPROGRAM #pragma surface surf Standard half4 _Color; sampler3D _DitherMaskLOD; // 入力構造体 struct Input { float2 uv_MainTex; float3 worldPos; float4 screenPos; }; void surf(Input IN, inout SurfaceOutputStandard o) { // ディザリングで半透明を表現 half alphaRef = tex3D(_DitherMaskLOD, float3(IN.screenPos.xy / IN.screenPos.w * _ScreenParams.xy * 0.25, _Color.a*0.9375)).a; clip(alphaRef - 0.01); // 円形に切り抜く clip(0.5 - length(IN.uv_MainTex - 0.5)); // 色 o.Albedo = _Color.rgb; o.Alpha = _Color.a; } ENDCG //============================ // 影の判定を行うPass Pass{ Name "ShadowCaster" Tags{ "LightMode" = "ShadowCaster" } ZWrite On ZTest LEqual CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment frag #define UNITY_STANDARD_USE_SHADOW_OUTPUT_STRUCT #define UNITY_STANDARD_USE_DITHER_MASK #define UNITY_STANDARD_USE_SHADOW_UVS #include "UnityStandardShadow.cginc" // 頂点シェーダ出力構造体 struct VertexOutput { V2F_SHADOW_CASTER_NOPOS float2 tex : TEXCOORD1; }; // 頂点シェーダ void vert(VertexInput v, out VertexOutput o, out float4 opos : SV_POSITION) { TRANSFER_SHADOW_CASTER_NOPOS(o,opos) o.tex = v.uv0; } // フラグメントシェーダ half4 frag(VertexOutput i, UNITY_VPOS_TYPE vpos : VPOS) : SV_Target { // ディザリングで半透明を表現 half alphaRef = tex3D(_DitherMaskLOD, float3(vpos.xy*0.25, _Color.a*0.9375)).a; clip(alphaRef - 0.01); // 円形に切り抜く clip(0.5 -length(i.tex - 0.5)); SHADOW_CASTER_FRAGMENT(i) } ENDCG } } FallBack "Differd" }
Shader "Unlit/Screen Position" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 3.0 // この構造体に SV_POSITION がないことに注意 struct v2f { float2 uv : TEXCOORD0; }; v2f vert ( float4 vertex : POSITION, // 頂点位置の入力 float2 uv : TEXCOORD0, // テクスチャ座標の入力 out float4 outpos : SV_POSITION // クリップスペース位置の出力 ) { v2f o; o.uv = uv; outpos = UnityObjectToClipPos(vertex); return o; } sampler2D _MainTex; fixed4 frag (v2f i, UNITY_VPOS_TYPE screenPos : VPOS) : SV_Target { // screenPos.xy はピクセルの整数の座標を含みます // それを使用して、4×4 のピクセルの // レンダリングを行わない碁盤模様を実装します // 碁盤模様の 4x4 のピクセルの // checker 値は負の値です screenPos.xy = floor(screenPos.xy * 0.25) * 0.5; float checker = -frac(screenPos.r + screenPos.g); // 値が負の場合、HLSL の clip はレンダリングを行いません clip(checker); // 維持されたピクセルが、テクスチャを読み込み、それを出力します fixed4 c = tex2D (_MainTex, i.uv); return c; } ENDCG } } }