文章目录
- 屏幕UV
- 代码
- 最后效果
- 屏幕UV扰动
- 代码
- 最后效果
屏幕UV
最主要的代码是屏幕UV的获取:
这里具体可以参考这位大佬的博客:
- 个人学习笔记——庄懂的技术美术入门课(美术向)17(VS空间畸变矫正的原理)
- 个人学习笔记——庄懂的技术美术入门课(美术向)02(屏幕UV的原理)
代码
Shader "shader forge/L17_ScreenUV"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {} //主纹理
_ScreenTex("Screen Tex", 2D) = "gray"{} //屏幕纹理
_Opacity ("Opacity",Range(0.0,1.0)) = 0.5 //透明度,是一张灰度图
}
SubShader
{
Tags {
"Queue" = "Transparent"
"RenderType"="Transparent"
"ForceNoShadowCasting" = "True"
"IgnoreProjector" = "True"
}
LOD 100
Pass
{
NAME "FORWARD"
Tags{
"LightMode" = "ForwardBase"
}
Blend One OneMinusSrcAlpha
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;
float2 screenUV : TEXCOORD1;
};
uniform sampler2D _MainTex;
uniform sampler2D _ScreenTex;
uniform float4 _ScreenTex_ST;
uniform half _Opacity;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
//下面是获取屏幕UV的写法
half3 posVS = UnityObjectToViewPos(v.vertex).xyz; //将顶点转换到视图空间下
half originDist = UnityObjectToViewPos(float3(0.0,0.0,0.0)).z; //将模型空间的原点转换到视图空间下,取得视图空间下模型空间的原点距离摄像机的z距离
o.screenUV = posVS.xy / posVS.z; //透视转正交
o.screenUV *= originDist; //大小锁定
//xy是Tiling,zw是offset,因为zw是两个分量,所以分别调整zw的值都会让屏幕贴图根据调整z(x)或w(y)的方向流动起来
o.screenUV = o.screenUV * _ScreenTex_ST.xy - frac(_Time.x * _ScreenTex_ST.zw);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
half4 var_MainTex = tex2D(_MainTex,i.uv);
half var_ScreenTex = tex2D(_ScreenTex,i.screenUV).r;
//最终颜色和不透明度
half3 finalColor = var_MainTex;
half opacity = _Opacity * var_ScreenTex * var_MainTex.a;
//return half4(finalColor,opacity);
return half4(finalColor * opacity,opacity);
}
ENDCG
}
}
}
最后效果
屏幕UV扰动
代码
Shader "shader forge/L17_ScreenWrap"
{
Properties
{
_MainTex ("Main Texture RGB:Color A:toutie", 2D) = "white" {}
_WrapMidVal ("Wrap Mid Value", Range(0.0,1.0)) = 0.2
_WrapInt("Wrap Intensity",Range(0.0,3.0)) = 0.5
_Opacity("Opacity",Range(0.0,1.0)) = 0.5
}
SubShader
{
Tags {
"Queue" = "Transparent"
"RenderType"="Transparent"
"ForceNoShadowCasting" = "True"
"IgnoreProjector" = "True"
}
LOD 100
GrabPass{
"_BgTex"
}
Pass
{
NAME "FORWARD"
Tags{
"LightMode" = "ForwardBase"
}
Blend One OneMinusSrcAlpha
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;
float4 grabPos : TEXCOORD1;
};
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
uniform sampler2D _BgTex;
uniform half _WrapMidVal;
uniform half _WrapInt;
uniform half _Opacity;
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
{
//采样MainTex,A通道是透贴
half4 var_MainTex = tex2D(_MainTex,i.uv);
//扰动背景纹理,采样uv。以主纹理的某个灰度通道作为扰动背景纹理UV的源,扰动背景纹理UV。
//减去一个值(中间值)是为了能在正负方向上都能偏移;再乘上一个透明度是因为越不透明折射越强,越透明越没有折射
i.grabPos.xy += (var_MainTex.r - _WrapMidVal) * _WrapInt * _Opacity;
half3 var_BgTex = tex2Dproj(_BgTex, i.grabPos).rgb;
//获取最终颜色和透明度
half3 finalColor = lerp(1.0, var_MainTex.rgb, _Opacity) * var_BgTex;
half opacity = var_MainTex.a * _Opacity;
return half4(finalColor * opacity, opacity);
//return half4(var_BgTex,1.0);
}
ENDCG
}
}
}
最后效果