unity Shader 扭曲效果
程序员文章站
2024-02-12 23:37:58
...
原理
所谓扭曲就是扰动一个物体的uv坐标,表现出来就是一个扰动效果,如火焰扭曲空气,和水波对水底的影响。
1. 在shader 中我们需要一张当前渲染的纹理
2. 给一个物体渲染并使用当前纹理,用屏幕坐标作为uv坐标加上一个扰动值
unity
1.
unity提供了抓取的pass: GrabPass unity官网介绍
//每次遇到这个pass就去抓取一次提供了了一个默认名称_GrabTexture 不推荐使用
GrabPass
{
}
//第一次遇到去抓取一次每帧只会抓取一次,名称由你自己定义
GrabPass
{
"_BackgroundTexture"
}
2.
获取物体的屏幕坐标,unity也给出了内置函数
//官网代码
v2f vert(appdata_base v) {
v2f o;
// use UnityObjectToClipPos from UnityCG.cginc to calculate
// the clip-space of the vertex
o.pos = UnityObjectToClipPos(v.vertex);
// use ComputeGrabScreenPos function from UnityCG.cginc
// to get the correct texture coordinate
o.grabPos = ComputeGrabScreenPos(o.pos);
return o;
}
ComputeGrabScreenPos 函数就是得到屏幕坐标,下面是UnityCG.cginc里面的函数源码
inline float4 ComputeGrabScreenPos (float4 pos) {
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
float4 o = pos * 0.5f;
o.xy = float2(o.x, o.y*scale) + o.w;
#ifdef UNITY_SINGLE_PASS_STEREO
o.xy = TransformStereoScreenSpaceTex(o.xy, pos.w);
#endif
o.zw = pos.zw;
return o;
}
UNITY_UV_STARTS_AT_TOP 和设备的纹理坐标有关如图
pos传进来的坐标是齐次裁剪坐标x,y都在[-w,w]之间,不在这个范围的会在光栅化之前(之后执行片段着色器)裁剪掉。转换如图 A->B 就是o.xy = float2(o.x, o.y*scale) + o.w;
最后还要归一化得到最终纹理坐标是除o.w实现的这个在tex2Dproj 纹理采样中内置函数中实现的(纹理坐标在[0,1])
UV 扰动
UV扰动是对一张噪声纹理采用加上偏移值,同时让噪声纹理做uv移动,达到每次采用不同来实现一个动态的效果
关键代码
fixed4 frag (v2f i) : SV_Target
{
//让噪声纹理的uv移动
fixed4 col = tex2D(_Noise, i.uv+=_Time.xy*_distortFactorTime);
// 加上一个偏移值
i.grabPos.xy +=col.xy*_distortFactor;
half4 bgcolor = tex2Dproj(_BackgroundTexture, i.grabPos);
return bgcolor;
}
效果图
完整代码
Shader "Custom/Distort"
{
Properties
{
_Noise ("Noise", 2D) = "white" {}
_distortFactorTime("FactorTime",Range(0,5)) = 0.5
_distortFactor("factor",Range(0.04,1)) = 0
}
SubShader
{
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
LOD 100
Cull Off Lighting Off ZWrite Off
GrabPass
{
"_BackgroundTexture"
}
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;
float4 grabPos:TEXCOORD1;
};
sampler2D _Noise;
float4 _Noise_ST;
fixed _distortFactorTime;
fixed _distortFactor;
sampler2D _BackgroundTexture;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _Noise);
o.grabPos = ComputeGrabScreenPos(o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_Noise, i.uv+=_Time.xy*_distortFactorTime);
i.grabPos.xy +=col.xy*_distortFactor;
half4 bgcolor = tex2Dproj(_BackgroundTexture, i.grabPos);
return bgcolor;
}
ENDCG
}
}
}