找回密码
 立即注册
查看: 368|回复: 1

手写Unity Shader 热扭曲效果

[复制链接]
发表于 2022-2-25 15:12 | 显示全部楼层 |阅读模式
大家好,我是老莫,今天分享一个热扭曲效果的实现。首先看一下效果。
场景资源地址  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
        }
    }
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2022-2-25 15:15 | 显示全部楼层
谢谢大佬,好东西,收藏起来[赞同]
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-16 23:31 , Processed in 0.094528 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表