앞에 쓰기
며칠 전 전직 동료가 갑자기 셰이더 제작을 도와달라고 부탁했고 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 회전과 스케일링을 따로 작성하는 것은 비교적 간단하지만 함께 사용하면 지저분해질 것입니다. 코드를 변경 한 후 며칠이 지나면 스케일링은 괜찮지 만 회전은 거의 빠른 특정 정점을 중심으로 회전합니다. 왠지 포기하고 생각했는데, 계속해서 일하는 한 이득이있을 것입니다!