菜鸡shader:L8 UV扰动动画——火焰和简单水面


这此做笔记的两个shader其实是课程的作业,课程主要也是讲UV扰动的概念,因为课程的shader在另一台电脑上,做笔记就暂时不带他们了,简单做下火焰和水面的shader。

卡通火焰

火焰这部分其实也是老师参考油管的一个管主做的,放下他的个人博客和这次火焰的视频链接:

主要思路就是应用两张自己做的贴图:
在这里插入图片描述

在这里插入图片描述

  • 左边那张图,也就是一大片蓝色的那张是有RGBA四个通道。

    • R通道是红色那圈,表示火焰的外焰。
    • G通道是绿色那圈,表示火焰的内焰。
    • B通道是透贴,后面是不显示的。
    • A通道是蒙版,用来控制我们扰动UV的区域,黑色的区域是不需要扰动的。
  • 右边那张图,是由两张不同的噪声纹理合成的,这两张噪声后后面用来扰动焰火贴图的UV的。两层noise有不同的tiling,本身形态也不同,混合的占比也可以调节,流动速度也不一样
    这样两个东西叠加就会有很大随机性。

    • R通道存放噪声1。
    • G通道存放噪声2。

在这里插入图片描述

  • 两个噪声叠加后再乘两个不同的蒙版,就能得到右图那张图,可以看到只有一部分区域是清晰可见的,这是我们要扰动的区域。

在这里插入图片描述

  • 如果用原始的UV去加上上面的那块可控区域,我们就能控制扰动UV的区域范围,这个会成为我们新的UV。

在这里插入图片描述

  • 然后用这个算出来的新UV去采样我们的火焰贴图。

在这里插入图片描述

  • 通过给R通道和G通道添加上颜色部分,就能分别控制内焰和外焰的颜色。

这里要说的是,shader里用到的贴图都是老师自己画的,我之前没有学过SD,一些操作不知道怎么调整,所以暂且用着,后面SD的学习得提上日程了。
在这里插入图片描述

代码

然后直接放上代码吧:

Shader "shader forge/L16_Fire"
{
    Properties
    {
        _Mask ("R:OuterFire  G:InsideFire  B:Ohter", 2D) = "white" {}
        _Noise ("R: Noise1  G: Noise2",2D) = "gray" {}
        _NoiseParam1 ("Noise1  X: Scale  Y: FlowSpeed  Z: Intensity",vector) = (1.0,0.2,0.2,1.0)
        _NoiseParam2 ("Noise2  X: Scale  Y: FlowSpeed  Z: Intensity",vector) = (1.0,0.2,0.2,1.0)
        _OuterColor ("Outer Color",Color) = (1.0,1.0,1.0,1.0)
        _InsideColor("Inside Color",Color) = (1.0,1.0,1.0,1.0)
        _BColor("Inside Color",Color) = (0.0,0.0,0.0,0.0)
    }
    SubShader
    {
        Tags {
            "RenderType"="Transparent" 
            "Queue" = "Transparent"
            "ForceNoShadowCasting" = "True"
            "IgnoreProjector" = "True"
        }

        Blend One OneMinusSrcAlpha		//混合方式用AB

        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv0 : TEXCOORD0; //Mask
                float2 uv1 : TEXCOORD1; //Noise1
                float2 uv2 : TEXCOORD2; //Noise2
                float4 vertex : SV_POSITION;
            };

            uniform sampler2D _Mask;
            uniform sampler2D _Noise;
            uniform half3 _NoiseParam1;
            uniform half3 _NoiseParam2;
            uniform half4 _OuterColor;
            uniform half4 _InsideColor;
            uniform half4 _BColor;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv0 = v.uv;
                //用_NoiseParam1的x参数,去控制UV的大小,然后加上_NoiseParam1的y参数去控制UV的流动方向和速度
                o.uv1 = v.uv * _NoiseParam1.x - float2(0.0,frac(_Time.x * _NoiseParam1.y));
                o.uv2 = v.uv * _NoiseParam2.x - float2(0.0,frac(_Time.x * _NoiseParam2.y));
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                //单独取出渐变层
                half mask_b = tex2D(_Mask,i.uv0).b;
                // 采样出两个噪声贴图
                half noise1 = tex2D(_Noise, i.uv1).r;
                half noise2 = tex2D(_Noise, i.uv2).g; 
                //这个混合噪声是为了后续扰动UV而准备的
                half blendNoise = noise1 * _NoiseParam1.z + noise2 * _NoiseParam2.z;        
                //这是扭曲后的uv
                half2 wrapUV = i.uv0 - float2(0.0,blendNoise) * mask_b;      
				//通过扭曲的uv去采样遮罩
                half3 wrapMask = tex2D(_Mask, wrapUV);  
                //rg分别乘上不同的颜色,来控制颜色的变化
                wrapMask = wrapMask.r * _OuterColor.rgb + wrapMask.g * _InsideColor.rgb;
                //这里透明度只需要rg通道相加,因为我们只想看到火焰部分,不需要g通道,而rg通道只有火焰部分有值,其他都为黑色也就是0,所以除了火焰部分其他的值都为0.
                half opacity = wrapMask.r + wrapMask.g;
                //half3 noMask = tex2D(_Mask,i.uv0);
                return float4(wrapMask,opacity);
            }
            ENDCG
        }
    }
}

最后效果

在这里插入图片描述
因为用的AB的混合模式,所以可以看见背后的小人,颜色进行了混合:
在这里插入图片描述

水面

  • 水面道理其实和火焰差不多,不一样的是从只单纯控制一个V流速,变成了控制UV的流速。
  • 也是使用两个噪声对原始贴图进行UV扰动。
  • 原始贴图自己的UV也会动。

代码

Shader "shader forge/L16_Water"
{
    Properties
    {
    	//原始贴图
        _MainTex ("Texture", 2D) = "white" {}
        [Space]
        //用来控制原始贴图的uv流动
        _MainSpeed("Main Tex Speed  X:u_speed  Y:v_speed",vector) = (1.0,0.2,0.2,1.0)
        //扰动UV的贴图,该帖图有RG两个通道,存两张不同的噪声图。分别要缩放,XY的流速,扰动强度
        _WrapTex("Wrap Tex",2D) = "gray"{}
        _WrapParam1 ("Wrap1  X:Scale  Y:u_speed  Z:v_speed  W:Intensity",vector) = (1.0,0.2,0.2,1.0)
        _WrapParam2 ("Wrap2  X:Scale  Y:u_speed  Z:v_speed  W:Intensity",vector) = (1.0,0.2,0.2,1.0)
    }
    SubShader
    {
        Tags {            
            "RenderType"="Opaque" 
        }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag           

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv0 : TEXCOORD0;
                float2 uv1 : TEXCOORD1;
                float2 uv2 : TEXCOORD2;
                float4 vertex : SV_POSITION;
            };

            uniform sampler2D _MainTex;
            uniform half2  _MainSpeed;
            uniform float4 _MainTex_ST;
            uniform sampler2D _WrapTex;
            uniform half4 _WrapParam1;
            uniform half4 _WrapParam2;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv0 = v.uv - frac(_Time.x * _MainSpeed);
                //_WrapParam1的x通道存UV大小,yz通道分别存UV也就是XY的流动速度
                o.uv1 = v.uv * _WrapParam1.x - frac(_Time.x * _WrapParam1.yz);	
                o.uv2 = v.uv * _WrapParam2.x - frac(_Time.x * _WrapParam2.yz);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // 采样贴图,用之前定义好的两个不同的UV来采样,得到同一张贴图的不同UV表现形式。
                //这个采样出来的rg贴图结果,其实是两个被扰动后的UV,而b通道好像原来要做什么用,没用上。                
                half3 var_Wrap1 = tex2D(_WrapTex, i.uv1).rgb;
                half3 var_Wrap2 = tex2D(_WrapTex, i.uv2).rgb;
				//使用两个不同的强度混合两个不同的uv,得到扰动混合
                half2 wrap = (var_Wrap1.xy - 0.5) * _WrapParam1.w + (var_Wrap2.xy - 0.5) * _WrapParam2.w;
                //加上原来的UV,也就是扰动原来的UV
                half2 wrapUV = i.uv0 + wrap;
				//用扰动后的UV去采样原来的纹理贴图
                half3 var_MainTex = tex2D(_MainTex, wrapUV).rgb;
                
                return half4(var_MainTex,1.0);
            }
            ENDCG
        }
    }
}

最后效果

呃呃,毕竟是动画,不动起来看起来没什么变化,但条件限制,就这样吧。
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值