前に「Overlay Filters 2D」というアセットを紹介した時に、スプライトの形にエフェクトをかける方法が気になったので調べてみました。
※ 今回紹介する方法はURP、HDRPでは使えません
やり方
「GrabPass」を用いることでシェーダー内で現在のスクリーンの状態をテクスチャで取得できます。
使い方は描画Passの前に
GrabPass {}
と書いて、あとはPass内で「_GrabTexture」という名前の変数を宣言します。
sampler2D _GrabTexture
こうすることで、現在のスクリーンの状態をテクスチャで取得できます。
また、GrabPass内でテクスチャの名前を指定することができます。
GrabPass { "_GrabTexture1" }
こうすると1フレームの間に最初に取得したテクスチャを、そのフレームの間使いまわします。
テクスチャ名を指定した時としなかったときの違いは重ねた時に現れます。
以下の画像は、単純に描画前の色に黄色を加算するだけのシェーダーをスプライトに適用して、それを2枚重ねたものです
右がGrabPassに何も書かなかった場合、左がテクスチャ名を指定した場合です。
左側は奥のスプライトが描画された後、その描画後のテクスチャを手前のスプライトのシェーダーが取得するため、色の加算効果が重なります。
一方で右側は、手前のスプライトも奥のスプライトが描画される前のテクスチャを参照するので、結果的に重なっていないように見えます。
テクスチャ名を指定しない場合、描画するオブジェクトの数が増えれば増えるほど負荷が増加するので、重ねることがない場合はテクスチャ名を指定することをお勧めします。
例
黄色を加算するだけのシェーダーです。
Shader "Norakyo/GrabPass"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Transparent" }
Blend One OneMinusSrcAlpha
GrabPass {}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 grabPos : TEXCOORD1;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
sampler2D _GrabTexture;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.grabPos = ComputeGrabScreenPos(o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
float4 screenColor = tex2Dproj(_GrabTexture, i.grabPos);
float3 outColor = screenColor + float3(0.6,0.5,0.25);
outColor *= col.a;
return half4(outColor.r, outColor.g, outColor.b, col.a);
}
ENDCG
}
}
}
アセットはこれを使いました
Forest Sprite Pack | 2D Environments | Unity Asset Store
Elevate your workflow with the Forest Sprite Pack asset from Tito Lívio. Find this & more Environments on the Unity Asset Store.
コメント