当前位置:   article > 正文

UnityShader学习笔记 让画面动起来_uv.y -= row / _verticalamount;

uv.y -= row / _verticalamount;

UnityShader内置的时间变量(时间篇)

 

纹理动画

序列帧动画

  1. Shader "Custom/ImageSequency"
  2. {
  3. Properties
  4. {
  5. _Color ("Color Tint", Color) = (1, 1, 1, 1)
  6. _MainTex ("Image Sequency", 2D) = "white" {}
  7. _HorizontalAmount ("Horizontal Amount", Float) = 4
  8. _VerticalAmount ("Vertical Amount", Float) = 4
  9. _Speed ("Speed", Range(1, 100)) = 30
  10. }
  11. SubShader
  12. {
  13. Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
  14. Pass
  15. {
  16. Tags { "LightMode"="ForwardBase" }
  17. ZWrite Off
  18. Blend SrcAlpha OneMinusSrcAlpha
  19. CGPROGRAM
  20. #pragma vertex vert
  21. #pragma fragment frag
  22. #include "UnityCG.cginc"
  23. fixed4 _Color;
  24. sampler2D _MainTex;
  25. float4 _MainTex_ST;
  26. float _HorizontalAmount;
  27. float _VerticalAmount;
  28. float _Speed;
  29. struct a2v
  30. {
  31. float4 vertex : POSITION;
  32. float2 texcoord : TEXCOORD0;
  33. };
  34. struct v2f
  35. {
  36. float4 pos : SV_POSITION;
  37. float2 uv : TEXCOORD0;
  38. };
  39. v2f vert (a2v v)
  40. {
  41. v2f o;
  42. o.pos = UnityObjectToClipPos(v.vertex);
  43. o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
  44. return o;
  45. }
  46. fixed4 frag (v2f i) : SV_Target
  47. {
  48. float time = floor(_Time.y * _Speed);
  49. float row = floor(time / _HorizontalAmount);
  50. float column = time - row * _HorizontalAmount;
  51. // half2 uv = float2(i.uv.x /_HorizontalAmount, i.uv.y / _VerticalAmount);
  52. // uv.x += column / _HorizontalAmount;
  53. // uv.y -= row / _VerticalAmount;
  54. half2 uv = i.uv + half2(column, -row);
  55. uv.x /= _HorizontalAmount;
  56. uv.y /= _VerticalAmount;
  57. fixed4 c = tex2D(_MainTex, uv);
  58. c.rgb *= _Color;
  59. return c;
  60. }
  61. ENDCG
  62. }
  63. }
  64. FallBack "Transparent/VertexLit"
  65. }

 

滚动的背景

  1. Shader "Custom/LoopBg"
  2. {
  3. Properties
  4. {
  5. _MainTex ("Base Layer (RGB)", 2D) = "white" {}
  6. _DetailTex ("2nd Layer (RGB)", 2D) = "white" {}
  7. _ScrollX ("Base layer Scroll Speed", Float) = 1.0
  8. _Scroll2X ("2nd layer Scroll Speed", Float) = 1.0
  9. _Multiplier ("Layer Multiplier", Float) = 1
  10. }
  11. SubShader
  12. {
  13. Tags { "RenderType"="Opaque" "Queue"="Geometry"}
  14. Pass
  15. {
  16. Tags { "LightMode"="ForwardBase" }
  17. CGPROGRAM
  18. #pragma vertex vert
  19. #pragma fragment frag
  20. #include "UnityCG.cginc"
  21. sampler2D _MainTex;
  22. sampler2D _DetailTex;
  23. float4 _MainTex_ST;
  24. float4 _DetailTex_ST;
  25. float _ScrollX;
  26. float _Scroll2X;
  27. float _Multiplier;
  28. struct a2v
  29. {
  30. float4 vertex : POSITION;
  31. float4 texcoord : TEXCOORD0;
  32. };
  33. struct v2f
  34. {
  35. float4 pos : SV_POSITION;
  36. float4 uv : TEXCOORD0;
  37. };
  38. v2f vert (a2v v)
  39. {
  40. v2f o;
  41. o.pos = UnityObjectToClipPos(v.vertex);
  42. o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex) + frac(float2(_ScrollX, 0.0) * _Time.y);
  43. o.uv.zw = TRANSFORM_TEX(v.texcoord, _DetailTex) + frac(float2(_Scroll2X, 0.0) * _Time.y);
  44. return o;
  45. }
  46. fixed4 frag (v2f i) : SV_Target
  47. {
  48. fixed4 firstLayer = tex2D(_MainTex, i.uv.xy);
  49. fixed4 secondLayer = tex2D(_DetailTex, i.uv.zw);
  50. fixed4 c = lerp(firstLayer, secondLayer, secondLayer.a);
  51. c.rgb *= _Multiplier;
  52. return c;
  53. }
  54. ENDCG
  55. }
  56. }
  57. FallBack "VertexLit"
  58. }

_MainTex和_DetailTex分别是第一层和第二层的背景纹理,_ScrollX和_Scroll2X对应了各自的水平滚动速度。_Multiplier参数则用于控制纹理的整体亮度。

在进行顶点变换时,把顶点从模型空间变换到裁剪空间中。然后我们计算了两层背景纹理的纹理坐标,然后利用_Time.y在水平方向上对纹理坐标进行偏移,以此达到滚动的效果。

在片元着色器中,首先分别利用i.uv.xy和i.uv.zw对两张背景纹理进行采样。然后,使用第二层纹理的透明通道来混合两张纹理。最后使用_Multiplier参数和输出颜色进行相乘,以调整背景亮度。

 

顶点动画

流动的河流

  1. Shader "Custom/Water"
  2. {
  3. Properties
  4. {
  5. _MainTex ("Main Tex", 2D) = "white" {}
  6. _Color ("Color Tint", Color) = (1, 1, 1, 1)
  7. _Magnitude ("Distortion Magnitude", Float) = 1
  8. _Frequency ("Distortion Frequency", Float) = 1
  9. _InvWaveLength ("Distortion Inverse Wave Length", Float) = 10
  10. _Speed ("Speed", Float) = 0.5
  11. }
  12. SubShader
  13. {
  14. Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"}
  15. Pass
  16. {
  17. Tags { "LightMode"="ForwardBase" }
  18. ZWrite Off
  19. Blend SrcAlpha OneMinusSrcAlpha
  20. Cull Off
  21. CGPROGRAM
  22. #pragma vertex vert
  23. #pragma fragment frag
  24. #include "UnityCG.cginc"
  25. sampler2D _MainTex;
  26. float4 _MainTex_ST;
  27. fixed4 _Color;
  28. float _Magnitude;
  29. float _Frequency;
  30. float _InvWaveLength;
  31. float _Speed;
  32. struct a2v
  33. {
  34. float4 vertex : POSITION;
  35. float4 texcoord : TEXCOORD0;
  36. };
  37. struct v2f
  38. {
  39. float4 pos : SV_POSITION;
  40. float2 uv : TEXCOORD0;
  41. };
  42. v2f vert(a2v v)
  43. {
  44. v2f o;
  45. float4 offset;
  46. offset.yzw = float3(0.0, 0.0, 0.0);
  47. offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;
  48. o.pos = UnityObjectToClipPos(v.vertex + offset);
  49. o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
  50. o.uv += float2(0.0, _Time.y * _Speed);
  51. return o;
  52. }
  53. fixed4 frag(v2f i) : SV_Target
  54. {
  55. fixed4 c = tex2D(_MainTex, i.uv);
  56. c.rgb *= _Color.rgb;
  57. return c;
  58. }
  59. ENDCG
  60. }
  61. }
  62. FallBack "Transparent/VertexLit"
  63. }

使用正弦函数模拟水流。

_MainTex是河流纹理,_Color用于控制整体颜色,_Magnitude用于控制水流波动的幅度,_Frequency用于控制波动频率,_InvWaveLength用于控制波长的倒数,_Speed用于控制河流纹理的移动速度。

注意需要设置SubShader标签DisableBatching,不能使用批处理,这是因为批处理会合并所有相关的模型,而这些模型各自的模型空间就会丢失。而在本例中我们需要在物体的模型空间下对顶点位置进行偏移。

在顶点着色器中,对顶点的x方向进行位移,利用_Frequency属性和内置的_Time.y变量来控制正弦函数的频率,并加上模型空间下的位置位置分量,并乘以_InvWaveLength来控制波长,最后,对结果乘以_Magnitude属性来控制波动幅度,得到最终位移,加到顶点位置上进行正常得分顶点变换即可。

 

广告牌

  1. Shader "Custom/Board"
  2. {
  3. Properties
  4. {
  5. _MainTex ("Main Tex", 2D) = "white" {}
  6. _Color ("Color Tint", Color) = (1, 1, 1, 1)
  7. _VerticalBillboarding ("Vertical Restraints", Range(0, 1)) = 1
  8. }
  9. SubShader
  10. {
  11. Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"}
  12. Pass
  13. {
  14. Tags { "LightMode"="ForwardBase" }
  15. ZWrite Off
  16. Blend SrcAlpha OneMinusSrcAlpha
  17. Cull Off
  18. CGPROGRAM
  19. #pragma vertex vert
  20. #pragma fragment frag
  21. #include "Lighting.cginc"
  22. sampler2D _MainTex;
  23. float4 _MainTex_ST;
  24. fixed4 _Color;
  25. fixed _VerticalBillboarding;
  26. struct a2v
  27. {
  28. float4 vertex : POSITION;
  29. float4 texcoord : TEXCOORD0;
  30. };
  31. struct v2f
  32. {
  33. float4 pos : SV_POSITION;
  34. float2 uv : TEXCOORD0;
  35. };
  36. v2f vert (a2v v)
  37. {
  38. v2f o;
  39. float3 center = float3(0, 0, 0);
  40. float3 viewer = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos, 1));
  41. float3 normalDir = viewer - center;
  42. normalDir.y =normalDir.y * _VerticalBillboarding;
  43. normalDir = normalize(normalDir);
  44. float3 upDir = abs(normalDir.y) > 0.999 ? float3(0, 0, 1) : float3(0, 1, 0);
  45. float3 rightDir = normalize(cross(upDir, normalDir));
  46. upDir = normalize(cross(normalDir, rightDir));
  47. float3 centerOffs = v.vertex.xyz - center;
  48. float3 localPos = center + rightDir * centerOffs.x + upDir * centerOffs.y + normalDir * centerOffs.z;
  49. o.pos = UnityObjectToClipPos(float4(localPos, 1));
  50. o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
  51. return o;
  52. }
  53. fixed4 frag (v2f i) : SV_Target
  54. {
  55. fixed4 c = tex2D (_MainTex, i.uv);
  56. c.rgb *= _Color.rgb;
  57. return c;
  58. }
  59. ENDCG
  60. }
  61. }
  62. FallBack "Transparent/VertexLit"
  63. }

在顶点着色器中,首先选择模型空间中的原点作为广告牌的锚点,利用内置变量获取模型空间下的视角位置。

开始计算3个正交矢量,根据观察位置和锚点计算目标法线方向,并根据_VerticalBillboarding属性来控制垂直方向上的约束度。

接着得到粗略的向上方向,如果法向方向的单位矢量的y接近与1了向上,那么取(0,0,1),否则为(0,1,0)。

然后根据法线方向和粗略的向上方向得到向右的方向,归一化,最后,再根据法线方向和右方向得到向上方向。

这样,三个方向上的正交基向量就可以得到了,再根据原始位置相对于锚点的偏移量以及3个正交基向量,以得到新的顶点位置。

最后完成顶点位置变换。

 

需要注意的是,在模型空间中增加顶点动画,往往画会通过SubShader的DiableBatching标签来强制取消批处理,增加Dc,因此尽量避免显示使用迷哦行空间下的一些绝对位置和方向来进行计算。

在广告牌的例子中,我们可以利用顶点颜色来存储每个顶点到锚点的距离值。

如果想要为添加了顶点动画的物体添加阴影,无法使用内置的Diffuse等包含的阴影Pass来渲染,无法向其他物体正确地投射阴影,这是因为Unity的阴影绘制需要调用一个ShaderCasterPass,而如果直接使用这些内置的Pass并没有进行相关的顶点动画。

 

添加阴影的水流动画

  1. Shader "Custom/VertexAnimationWithShadow"
  2. {
  3. Properties
  4. {
  5. _MainTex ("Main Tex", 2D) = "white" {}
  6. _Color ("Color Tint", Color) = (1, 1, 1, 1)
  7. _Magnitude ("Distortion Magnitude", Float) = 1
  8. _Frequency ("Distortion Frequency", Float) = 1
  9. _InvWaveLength ("Distortion Inverse Wave Length", Float) = 10
  10. _Speed ("Speed", Float) = 0.5
  11. }
  12. SubShader
  13. {
  14. // Need to disable batching because of the vertex animation
  15. Tags {"DisableBatching"="True"}
  16. Pass
  17. {
  18. Tags { "LightMode"="ForwardBase" }
  19. Cull Off
  20. CGPROGRAM
  21. #pragma vertex vert
  22. #pragma fragment frag
  23. #include "UnityCG.cginc"
  24. sampler2D _MainTex;
  25. float4 _MainTex_ST;
  26. fixed4 _Color;
  27. float _Magnitude;
  28. float _Frequency;
  29. float _InvWaveLength;
  30. float _Speed;
  31. struct a2v
  32. {
  33. float4 vertex : POSITION;
  34. float4 texcoord : TEXCOORD0;
  35. };
  36. struct v2f
  37. {
  38. float4 pos : SV_POSITION;
  39. float2 uv : TEXCOORD0;
  40. };
  41. v2f vert(a2v v)
  42. {
  43. v2f o;
  44. float4 offset;
  45. offset.yzw = float3(0.0, 0.0, 0.0);
  46. offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;
  47. o.pos = UnityObjectToClipPos(v.vertex + offset);
  48. o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
  49. o.uv += float2(0.0, _Time.y * _Speed);
  50. return o;
  51. }
  52. fixed4 frag(v2f i) : SV_Target
  53. {
  54. fixed4 c = tex2D(_MainTex, i.uv);
  55. c.rgb *= _Color.rgb;
  56. return c;
  57. }
  58. ENDCG
  59. }
  60. // Pass to render object as a shadow caster
  61. Pass
  62. {
  63. Tags { "LightMode" = "ShadowCaster" }
  64. CGPROGRAM
  65. #pragma vertex vert
  66. #pragma fragment frag
  67. #pragma multi_compile_shadowcaster
  68. #include "UnityCG.cginc"
  69. float _Magnitude;
  70. float _Frequency;
  71. float _InvWaveLength;
  72. float _Speed;
  73. struct v2f
  74. {
  75. V2F_SHADOW_CASTER;
  76. };
  77. v2f vert(appdata_base v)
  78. {
  79. v2f o;
  80. float4 offset;
  81. offset.yzw = float3(0.0, 0.0, 0.0);
  82. offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;
  83. v.vertex = v.vertex + offset;
  84. TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
  85. return o;
  86. }
  87. fixed4 frag(v2f i) : SV_Target
  88. {
  89. SHADOW_CASTER_FRAGMENT(i)
  90. }
  91. ENDCG
  92. }
  93. }
  94. FallBack "VertexLit"
  95. }

在自定义投射阴影的Pass中,我们通常会使用Unity提供的内置宏V2F_SHADOW_CASTER,TRANSFER_SHADOW_CASTER_NORMALOFFSET和SHADOW_CASTER_FRAGMENT来计算阴影投射的各种变量。

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/138342
推荐阅读
相关标签
  

闽ICP备14008679号