[ShaderLab] 쉐이더를 사용하여 중앙 마스크 확대 / 축소 효과 얻기

앞에 쓰기 

       며칠 전 전직 동료가 갑자기 셰이더 제작을 도와달라고 부탁했고 UI 컷신 효과를 만들고 싶다고했습니다. 아마도 만화 끝의 블랙 필드 효과와 같이 투명한 UI 이미지를 사용하여 검은 색 배경 가운데를 확대 및 축소해야합니다. 투명 UI가 가장 큰 경우 장면의 다른 UI가 표시되고, 투명 UI가 가장 작은 경우 장면 전체가 검은 색으로 표시되며 효과는 다음과 같습니다.

       사실 이것이 제 동료들이 원하는 효과인데, 실현의 원리는 매우 간단하고 별 노력없이 썼습니다. 나중에이 컷 신을 더 매력적으로 만들기 위해 디스플레이 효과를 최적화 할 수 있는지 확인하기 위해 그것에 대해 생각하고 모든 것을 썼습니다.

본문

      이 효과를 얻는 원리도 매우 간단합니다. 먼저 확대 / 축소해야하는 이미지 uv를 가져 와서 틸링 및 오프셋을 수정하는 데 사용합니다. uv는 0에서 1까지이기 때문에 직접 변경하면, uv는 확대 / 축소를위한 원점이므로 여기에서 그림의 오프셋을 (0.5, 0.5)로 오프셋 한 다음 확대 / 축소해야합니다. 그런 다음 필요한 그림의 알파 채널 정보를 가져옵니다. 확대 및 축소하고 기본 이미지와 비교합니다. 예, 두 이미지를 겹치게하고 알파가 1 인 확대 된 이미지 부분을 제거합니다. 이는 종종 마스크 효과라고합니다. 코드는 다음과 같습니다.

Shader "custom/masknormal"
{
	Properties
	{
		//底图
		_MainTex("_MainTex",2D) = "white"{}	
		//需要缩放的图
		_MaskTex("_MaskTex", 2D) = "white" {}
		//缩放比例
		_Progress("Progress", Range(-0.5,0.5)) = 0                                       
	}
		SubShader
	{
		Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" }
		Blend SrcAlpha OneMinusSrcAlpha
		Cull Off ZWrite Off ZTest Always

		Pass
	{
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#pragma target 3.0
		#include "UnityCG.cginc"

	struct appdata
	{
		float4 vertex : POSITION;
		float2 uv : TEXCOORD0;
	};

	struct v2f
	{
		float2 uv : TEXCOORD0;
		float2 uv2:TEXCOORD1;
		float4 vertex : SV_POSITION;
	};
	sampler2D _MainTex;
	sampler2D _MaskTex;
	float _Progress; 
	float4 _MaskTex_ST;

	v2f vert(appdata v)
	{
		v2f o;
		o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
		o.uv = v.uv;
		return o;
	}
	fixed4 frag(v2f i) : SV_Target
	{
		//_Progress = pow(_Progress,2);
		_Progress = log(0.5 - _Progress);

	_MaskTex_ST.xy = _Progress;                                        
	_MaskTex_ST.zw = (_Progress - 1)*-0.5;     
	//缩放图 同时做为掩膜图 
	fixed4 maskcol = tex2D(_MaskTex, i.uv*_MaskTex_ST.xy + _MaskTex_ST.zw);   
	//底图取样
	fixed4 outcol = tex2D(_MainTex,i.uv);
	//去除缩放图的alpha值 
	outcol.w = outcol.a*(1 - maskcol.a);
	return outcol;
	}
		ENDCG
	}
	}
}

위의 셰이더를 사용하고 c # 코드에서 _Progress에 대한 보간 제어를 수행하면이 그림과 동일한 효과를 얻을 수 있습니다.

그 효과는 전직 동료에게는 상당히 만족 스럽지만 효과는 여전히 매우 조잡합니다. 모든 것을 작성했다면 더 나은 효과를 얻으십시오!

배경색 바꾸기

검정색 배경은 색상 팔레트로 대체됩니다.이 구현은 비교적 간단합니다. 원래 출력 색상과 입력 색상을 곱하기 만하면됩니다. 또는 순수한 컬러 이미지이기 때문에 입력 색상의 rgb와 스케일링 된 마스크 이미지의 알파 채널을 색상 출력으로 직접 가져올 수 있습니다.

흐림 효과

투명 줌 이미지와 기본 이미지 사이의 전환 효과가 약간 어색하고 흐림 효과가 추가되었습니다. 구현 원리도 매우 간단합니다. 왼쪽 상단, 왼쪽 하단, 오른쪽 상단, 오른쪽 하단, 5 개 현재 정점의 포인트와 평균을 내고 출력, 얻은 평균 색상을 조각의 출력으로 사용할 수 있습니다.

렌더링 첨부

아래와 같이 코드 쇼

Shader "custom/mask"
{
	Properties
	{
		//底图
		_MainTex("_MainTex",2D) = "white"{}
	//需要缩放的图
	_MaskTex("_MaskTex", 2D) = "white" {}
	//缩放比例
	_Progress("Progress", Range(-0.5,0.5)) = 0    
         //底图颜色                                                             
		_Color("Color",color) = (0,0,0,0)
		//模糊系数
		_blurOffset("Blur",Range(0,0.01)) = 0.0075
	}
		SubShader
	{
		Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" }
		Blend SrcAlpha OneMinusSrcAlpha
		Cull Off ZWrite Off ZTest Always

		Pass
	{
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#pragma target 3.0
		#include "UnityCG.cginc"

		struct appdata
		{
			float4 vertex : POSITION;
			float2 uv : TEXCOORD0;
		};

		struct v2f
		{
			float2 uv : TEXCOORD0;
			float2 uv2:TEXCOORD1;
			float4 vertex : SV_POSITION;
		};

		sampler2D _MaskTex;
		sampler2D _MainTex;
		float _Progress;
		float4 _MaskTex_ST;
		fixed4 _Color;
		fixed _blurOffset;

	v2f vert(appdata v)
	{
		v2f o;
		o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
		o.uv = v.uv;
		o.uv2 = cos(o.uv*_Time.x);
		return o;
	}
	fixed4 frag(v2f i) : SV_Target
	{
			//_Progress = pow(_Progress,2);
			_Progress = log2(0.5 - _Progress);
			_MaskTex_ST.xy = _Progress;                      
			_MaskTex_ST.zw = (_Progress - 1)*-0.5;                               
			fixed4 maskcol = tex2D(_MaskTex, i.uv*_MaskTex_ST.xy + _MaskTex_ST.zw);   
			//高斯模糊
			//leftup
			fixed4 maskcol1 = tex2D(_MaskTex, i.uv*_MaskTex_ST.xy + _MaskTex_ST.zw + fixed2(-_blurOffset, _blurOffset));
			//leftdown
			fixed4 maskcol2 = tex2D(_MaskTex, i.uv*_MaskTex_ST.xy + _MaskTex_ST.zw + fixed2(-_blurOffset, -_blurOffset));
			//rightup
			fixed4 maskcol3 = tex2D(_MaskTex, i.uv*_MaskTex_ST.xy + _MaskTex_ST.zw + fixed2(_blurOffset, _blurOffset));
			//rightdown
			fixed4 maskcol4 = tex2D(_MaskTex, i.uv*_MaskTex_ST.xy + _MaskTex_ST.zw + fixed2(_blurOffset, -_blurOffset));
			fixed4 mix = (maskcol + maskcol1 + maskcol2 + maskcol3 + maskcol4)*0.2;
			mix = lerp(maskcol, mix, 0.5);
			fixed4 outcol = tex2D(_MainTex,i.uv);
			outcol.w = outcol.a*(1 - mix.a);
			outcol = fixed4(_Color.x,_Color.y,_Color.z, outcol.w);
			return outcol;
	}
		ENDCG
	}
	}
}

이런 식으로 눈에 더 즐거워 보입니다. .

그러나 그것이 뇌를 펌핑하는지 또는 무언가인지는 모르겠지만 여전히 줌 이미지 회전 효과를 추가하고 싶습니다. 샘플을 가져 와서 며칠 동안 온라인에서 공부 한 후 알아 냈기 때문입니다. 전에 수학 수업을 잘 듣지 못했다고 탓만했기 때문에 먼저 자외선 회전 공식을 게시했습니다.

이 공식이 왜 그런지에 대해서는 내 노트를 읽을 수 있습니다 .

렌더링 첨부

마지막으로 코드를 첨부하십시오.

Shader "custom/mask1"
{
	Properties
	{
		_MainTex("_MainTex",2D) = "white"{}	
		_MaskTex("_MaskTex", 2D) = "white" {}  
		_Progress("Progress", Range(0,1)) = 0 
		_Color("Color",color) = (0,0,0,0)		
		_blurOffset("Blur",Range(0,0.03)) = 0.0075
		_RotateSpeed("RotateSpeed",Range(0,10))=5
	}
		SubShader
	{
		Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" }
		Blend SrcAlpha OneMinusSrcAlpha
		Cull Off ZWrite Off ZTest Always

		Pass
	{
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#pragma target 3.0
		#include "UnityCG.cginc"

		struct appdata
		{
			float4 vertex : POSITION;
			float2 uv : TEXCOORD0;
		};

		struct v2f
		{
			float2 uv : TEXCOORD0;
			float4 vertex : SV_POSITION;
		};

		sampler2D _MaskTex;
		sampler2D _MainTex;
		float _Progress;  //声明缩放量
		float4 _MaskTex_ST;
		fixed4 _Color;
		fixed _blurOffset;
		fixed _RotateSpeed;

		v2f vert(appdata v)
		{
			v2f o;
			o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
			o.uv = v.uv;
			return o;
		}
		fixed4 frag(v2f i) : SV_Target
		{
			fixed4 uv;
			//手动控制缩放
			//_Progress =abs(log(_Progress)));
			_Progress =abs(log(sin(_Time.y)));
			//offset偏移
			 uv.xy = i.uv.xy- fixed2(0.5, 0.5);
			uv.zw *=(1-_Progress) ; 
			//旋转公式 乘上缩放
			uv.xy = fixed2(uv.x * cos(_RotateSpeed * _Time.y) - uv.y * sin(_RotateSpeed * _Time.y),
			uv.x * sin(_RotateSpeed * _Time.y) + uv.y * cos(_RotateSpeed * _Time.y))*_Progress;
			//复原offset
			uv.xy += fixed2(0.5, 0.5);
			fixed4 maskcol = tex2D(_MaskTex, uv); 

			//高斯模糊
			//leftup
			fixed4 maskcol1 = tex2D(_MaskTex, uv+fixed2(-_blurOffset, _blurOffset));
			//leftdown
			fixed4 maskcol2 = tex2D(_MaskTex, uv + fixed2(-_blurOffset, -_blurOffset));
			//rightup
			fixed4 maskcol3 = tex2D(_MaskTex, uv + fixed2(_blurOffset, _blurOffset));
			//rightdown
			fixed4 maskcol4 = tex2D(_MaskTex, uv + fixed2(-_blurOffset, -_blurOffset));
			fixed4 mix = (maskcol + maskcol1 + maskcol2 + maskcol3 + maskcol4)*0.2;
			mix = lerp(maskcol, mix, 0.5);
			fixed4 outcol = tex2D(_MainTex,uv);
			outcol.w = outcol.a*(1 - mix.a);
			outcol = fixed4(_Color.x,_Color.y,_Color.z, outcol.w);
			return outcol;
		}
		ENDCG
	}
	}
}

요약하자면

      셰이더를 제어하는 ​​C # 코드를 작성하기에는 너무 게으 르기 때문에 직접 sin 함수를 사용하여 확대 / 축소를 제어하므로주기가 약간 길어지고 확대 / 축소 비율 제어가 여전히 약간 불만족 스러울 것 같습니다. 로그 방법을 사용하여 제어하는 ​​것을 생각했기 때문에 줌이 갑자기 사라질 것입니다. 그리고 최적화 방법에 대해 생각하고 여기에 쓰십시오. 다른 사람의 공식을 온라인으로 직접 복사하는 데 사용되는 uv의 회전. 이번에는 혼자서 한 번 도출했는데 다행히도 잊지 않았습니다. uv 회전과 스케일링을 따로 작성하는 것은 비교적 간단하지만 함께 사용하면 지저분해질 것입니다. 코드를 변경 한 후 며칠이 지나면 스케일링은 괜찮지 만 회전은 거의 빠른 특정 정점을 중심으로 회전합니다. 왠지 포기하고 생각했는데, 계속해서 일하는 한 이득이있을 것입니다!

추천

출처blog.csdn.net/ssssssilver/article/details/91822748