|
大家好,我是老莫,今天分享一个热扭曲效果的实现。首先看一下效果。
场景资源地址 Lighting Optimisation Tutorial | Tutorial Projects | Unity Asset Store
首先列一下可能需要的属性
_DistortTex ("Texture", 2D) = "white" {}
_DistortValue("DistortValue",Range(0,1)) = 1
_DistortSpeed("DistortSpeed",float) = 1
GrabPass
在unityshader中,我们可以使用GrabPass实现屏幕抓取。有两种写法。
GrabPass{}
**********
************
sampler2D _GrabTex;1、GrabPass{} 抓取当前屏幕存储到_GrabTexture中,然后我们就可以直接调用_GrabTexture,抓取当前屏幕。但是这样写有个弊端,就是每一个使用了此shader 的物体都睡抓取一次屏幕,消耗很大。可以在FrameDebug中看到。
2。我们一般用第二种方法,GrabPass{"GrabTex"} {}中的纹理名称可以自定义。使用了指定的纹理名称时,不管场景中有多少物体(同意shader),都只会抓取一次屏幕,大大减少运算量。
所以我们这里使用第二种方法
GrabPass{"_GrabTex"}定义GrabPass{"GrabTex"} 之后,需要写入sampler2D _GrabTex; 用于后面的调用
和模型采样贴图一样,有了纹理,我们还需要UV。unity中屏幕UV的获取方式为ComputeScreenPos(o.pos),注意这里的pos是进行了齐次剪裁后的值,原理是在齐次剪裁空间坐标下获取每个像素在屏幕中的UV坐标。ComputeScreenPos可以自动根据不同平台匹配屏幕坐标,因为DX和OpenGL的坐标轴起始点位置是不同的。这里更深入的知识点后面我会单独写一篇文章详述。
o. pos = UnityObjectToClipPos(v.vertex);
o.screenUV = ComputeScreenPos(o.pos);接下来采样我们抓取到的纹理看一下效果
fixed4 grabTex = tex2Dproj(_GrabTex,1-i.screenUV);
抓取成功,接下来我们让抓取到的纹理动起来,并且加上扭曲效果。
采样一张noise图,不用太讲究,网上随便下载一张
这里在片段着色器中做一个常规的uv移动,采样屏幕纹理时,在uv上加一个简单的lerp
fixed4 distortTex = tex2D(_DistortTex,i.uv.xy + _Time.xy * _DistortSpeed );
fixed4 grabTex = tex2Dproj(_GrabTex,lerp(i.screenUV,distortTex ,_DistortValue));
这时候我们所要的功能基本都已经实现了:屏幕抓取,UV扭曲+移动,但是边缘过于生硬,需要进一步优化一下。我们只需要中间火团的部分有热扭曲效果,那么我们需要得到一张这样的蒙版,可以自己在PS做一个,也可以在shader中生成,这里我随便拿公式写一个。
float fade = pow(1-length(i.maskUV-0.5),_Radius);
fixed4 grabTex = tex2Dproj(_GrabTex,lerp(i.screenUV,distortTex * fade,_DistortValue));
加上蒙版后再看一下效果,和没有加热扭曲效果的火把对比一下。
到这里今天的热扭曲效果就制作完成了,游戏中我们经常能在不经意中看到这种小细节,而往往是这种容易被忽略的细枝末节,最能表现出制作人的用心,也最能给玩家一种“此物从何来,对之惊且喜”之感。我是老莫,希望大家喜欢此次分享,不吝赐教!
以下是完整shader代码
Shader "Unlit/Distort04"
{
Properties
{
_DistortTex ("Texture", 2D) = "white" {}
_DistortValue("DistortValue",Range(0,1)) = 1
_DistortSpeed("DistortSpeed",float) = 1
_Radius ( "_Radius",float ) =1
}
SubShader
{
Tags { "Queue" = "Transparent"}
LOD 100
Cull Off
GrabPass{"_GrabTex"}//如果使用仅GrabPass{} 则每个使用了抓取shader的物体都会调用一次抓取,消耗大
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdate{
float2 uv : TEXCOORD0;
float4 vertex : POSITION;
};
struct v2f
{
float2 uv : TEXCOORD0;
float2 maskUV : TEXCOORD1;
fixed4 pos : SV_POSITION;
float4 screenUV : TEXCOORD2;
};
sampler2D _GrabTex;
sampler2D _DistortTex; float4 _DistortTex_ST;
fixed _DistortValue;
float _DistortSpeed;
float _Radius;
v2f vert (appdate v )
{
v2f o;
o.uv = TRANSFORM_TEX(v.uv,_DistortTex) ;
o.maskUV = v.uv;
o. pos = UnityObjectToClipPos(v.vertex);
o.screenUV = ComputeScreenPos(o.pos);//根据不同平台匹配屏幕坐标(DX或opengl)
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 distortTex = tex2D(_DistortTex,i.uv.xy + _Time.xy * _DistortSpeed );
float fade = pow(1-length(i.maskUV-0.5),_Radius);
fixed4 grabTex = tex2Dproj(_GrabTex,lerp(i.screenUV,distortTex * fade,_DistortValue));//和下面的结果一样
return grabTex;
}
ENDCG
}
}
} |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|