Chicken shader: L8 UV disturbance animation - flame and simple water surface


These two shaders for taking notes are actually the homework of the course. The course mainly talks about the concept of UV disturbance, because the shaders of the course are on another computer, so I don’t take them with me when I take notes. I simply make shaders for flames and water surfaces.

cartoon flame

The part about the flame is actually made by the teacher with reference to a YouTuber. Here is a link to his personal blog and the video about the flame:

The main idea is to apply two self-made textures:
insert image description here

insert image description here

  • The picture on the left, that is, the one with a large blue area, has four RGBA channels.

    • The R channel is the red circle, which represents the outer flame of the flame.
    • The G channel is the green circle, which represents the inner flame of the flame.
    • The B channel is transparent, and it is not displayed behind.
    • The A channel is a mask, which is used to control the area where we disturb the UV. The black area does not need to be disturbed.
  • The picture on the right is composed of two different noise textures, and these two noises are used to disturb the UV of the fireworks map. The two layers of noise have different tilings, their own shapes are also different, the mixing ratio can also be adjusted, and the flow speed is also different,
    so the superposition of the two things will have great randomness.

    • The R channel stores noise 1.
    • G channel stores noise 2.

insert image description here

  • After the two noises are superimposed and multiplied by two different masks, the picture on the right can be obtained. It can be seen that only a part of the area is clearly visible, which is the area we want to disturb.

insert image description here

  • If we use the original UV to add the controllable area above, we can control the range of the disturbance UV, which will become our new UV.

insert image description here

  • Then use this calculated new UV to sample our flame map.

insert image description here

  • By adding the color part to the R channel and the G channel, the color of the inner flame and the outer flame can be controlled respectively.

What I want to say here is that the textures used in the shader are all drawn by the teacher himself. I have never learned SD before, and I don’t know how to adjust some operations, so I will use it for the time being. The learning of SD will be on the agenda later.
insert image description here

the code

Then put the code directly:

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
        }
    }
}

final effect

insert image description here
Because of the blending mode of AB, you can see the villain behind, and the colors are mixed:
insert image description here

water surface

  • The principle of the water surface is actually similar to that of the flame. The difference is that it has changed from simply controlling a V flow rate to controlling the UV flow rate.
  • It also uses two noises to perform UV perturbation on the original texture.
  • The original texture's own UV will also move.

the code

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
        }
    }
}

final effect

Uh, after all, it's an animation, it doesn't look like it changes when it's not moving, but the conditions are limited, so be it.
insert image description here
insert image description here

Guess you like

Origin blog.csdn.net/weixin_43789369/article/details/131636385