The jonki

呼ばれて飛び出てじょじょじょじょーんき

【Unity】シェーダーで穴あきテクスチャを実現する

こんなものを作りました。穴を空ける(透過度0)シェーダーを作りました。まぁ昔かいた2Dリングとほぼ同じですね。日記書くほどでもないと思いますが一応。

コード

シェーダー

フラグメントシェーダのところで穴あきを実現しています。テクスチャの縦横比が16:9の場合を想定しているので、uv座標からxyが1対1になるように別途変数を作っています。またuv座標は0-1なので0.5引いて、-0.5-0.5の座標軸にしています。

Shader "Custom/PinHole" {
	Properties {
		_HoleSize("Hole Size", float) = 0.1
		_BlurThick("Blur Thick", float) = 0.1
		_HolePos("Hole vector", Vector) = (0.5, 0.5, 1.0, 1.0)
		_Color ("Color", Color) = (0.0,0.0,0.0,1.0)
	}
	
	SubShader {
		Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
		
		ZWrite Off
		Blend SrcAlpha OneMinusSrcAlpha 
	
		Pass {
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
				
			#include "UnityCG.cginc"
			
			float _HoleSize;
			float _BlurThick;
			fixed4 _HolePos;
			fixed4 _Color;
		
			struct v2f {
				float4 pos : POSITION;
				float2 uv : TEXCOORD0;
			};
			
			v2f vert (appdata_base v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				o.uv = float2(v.texcoord.x, v.texcoord.y);
				return o;
			}
			
			half4 frag (v2f i) : COLOR
			{
				half4 col = _Color;
				float2 pos = i.uv;

				// consider material resolution
				pos.y -= 0.5;
				pos.y *= (9.0 / 16.0);
				pos.y += 0.5;
				
				float dist = distance(pos, float2(_HolePos.x, _HolePos.y));
				if(dist < _HoleSize) {
					clip(-1.0);
				} else if(dist < _HoleSize + _BlurThick){
					col.a = (dist - _HoleSize) * 10.0;
					col.a = pow(col.a, 2.0);
				}
				
				return col;
			}	
			ENDCG
		}
	}
}
C#

とりあえずマウスのポジションを突っ込んでいます。

using UnityEngine;
using System.Collections;

public class PinHoleController : MonoBehaviour {
	// Use this for initialization
	void Start () {
	}
	
	// Update is called once per frame
	void Update () {
		var pinPos = new Vector4(Input.mousePosition.x / Screen.width, Input.mousePosition.y / Screen.height, 0f);
		renderer.material.SetVector("_HolePos", pinPos);
	}
}