読者です 読者をやめる 読者になる 読者になる

トイカメラ風のフィルター

トイカメラ風フィルターです。上下を暈すだけという、ちゃっちいテクニックです。

f:id:wkpn:20160821140621p:plain

Shaderの練習のために作ってみました。

ぼかし画像を作る部分は標準アセットのBlurのほぼコピペです。

ぼかし画像を一枚しか作っていないこともあり、イマイチですね。本当は複数のぼかしレベルの画像を送るべきですが、今回は練習なので手抜きです。

github.com

using UnityEngine;

public class ToyCameraImageEffect : MonoBehaviour
{
    private Material material;
    private Material blurMaterial;

    //ぼかし回数
    [Range(0,10)]
    public int iterations = 3;

    //ブラーのずらし量
    [Range(0.0f,1.0f)]
    public float blurSpread = 0.6f;

    protected virtual void Awake()
    {
        {
            string shaderName = "Hidden/ToyCameraImageEffectShader";
            Shader shader = Shader.Find( shaderName );
            Debug.Assert( shader != null );
            material = new Material( shader );
        }

        {
            string shaderName = "Hidden/BlurEffectConeTap";
            Shader shader = Shader.Find( shaderName );
            Debug.Assert( shader != null );
            blurMaterial = new Material( shader );
        }
    }

    void Update()
    {
    }

    void fourTapCone (RenderTexture src, RenderTexture dest, int iteration)
    {
        float off = 0.5f + iteration*blurSpread;
        Graphics.BlitMultiTap (src, dest, blurMaterial,
                new Vector2(-off, -off),
                new Vector2(-off,  off),
                new Vector2( off,  off),
                new Vector2( off, -off)
                );
    }

    void downSample4x (RenderTexture src, RenderTexture dest)
    {
        float off = 1.0f;
        Graphics.BlitMultiTap (src, dest, blurMaterial,
                new Vector2(-off, -off),
                new Vector2(-off,  off),
                new Vector2( off,  off),
                new Vector2( off, -off)
                );
    }

    void OnRenderImage( RenderTexture src, RenderTexture dest )
    {
        //ぼかしの画を作るために4分の一サイズの小さい一時バッファを作ります。
        int rtW = src.width/4;
        int rtH = src.height/4;
        RenderTexture buffer = RenderTexture.GetTemporary(rtW, rtH, 0);

        downSample4x (src, buffer);

        // Blur the small texture
        for(int i = 0; i < iterations; i++)
        {
            RenderTexture buffer2 = RenderTexture.GetTemporary(rtW, rtH, 0);
            fourTapCone (buffer, buffer2, i);
            RenderTexture.ReleaseTemporary(buffer);
            buffer = buffer2;
        }

        material.SetTexture( "_BlurTex", buffer );

        Graphics.Blit( src, dest, material );

        RenderTexture.ReleaseTemporary(buffer);
    }

}

Shader↓

Shader "Hidden/ToyCameraImageEffectShader"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
		_BlurTex ("Blur Texture", 2D) = "white" {}
		_FilterTex ("Filter Texture", 2D) = "white" {}
	}
	SubShader
	{
		// No culling or depth
		Cull Off ZWrite Off ZTest Always
        Fog { Mode Off }

		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 vertex : SV_POSITION;
			};

			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
				o.uv = v.uv;
				return o;
			}
			
			sampler2D _MainTex;
			sampler2D _BlurTex;
			sampler2D _FilterTex;

			fixed4 frag (v2f i) : SV_Target
			{
				fixed4 org = tex2D(_MainTex, i.uv);
				fixed4 blur = tex2D(_BlurTex, i.uv);
				fixed4 filter = tex2D(_FilterTex, i.uv);
                return lerp( org, blur, filter.r );
			}
			ENDCG
		}
	}
}