当前位置:   article > 正文

UnityShader基础(六)——动画效果_unity shader序列帧动画

unity shader序列帧动画

一、纹理动画

        Unity提供了一些内置变量用于做动画效果,比如_Time变量等,其中_Time.y代表从游戏开始到现在的正常时间。

        1.1 序列帧动画

                对一张纹理进行偏移采样,首先计算出纹理动画是怎么分的,即这个时间段的对应行列,然后对原始的采样坐标先做一个比例缩放,然后加上偏移得到行列对应的采样坐标。

                原版写法:

  1. Shader "Custom/Test0"
  2. {
  3. Properties
  4. {
  5. //用于控制纹理的整体颜色表现
  6. _Color("Color",Color)=(1,1,1,1)
  7. _AnimationTex("动画纹理",2D)="white"{}
  8. _AnimationSpeed("动画速度",float)=1.0
  9. _HorAmount("水平数量",float)=8
  10. _VerAmount("垂直数量",float)=8
  11. }
  12. SubShader
  13. {
  14. Pass
  15. {
  16. CGPROGRAM
  17. #pragma vertex vert
  18. #pragma fragment frag
  19. #include "UnityCG.cginc"
  20. fixed4 _Color;
  21. sampler2D _AnimationTex;
  22. float4 _AnimationTex_ST;
  23. fixed _AnimationSpeed;
  24. fixed _HorAmount;
  25. fixed _VerAmount;
  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:TEXCOORD3;
  35. };
  36. v2f vert(a2v v)
  37. {
  38. v2f o;
  39. o.pos=UnityObjectToClipPos(v.vertex);
  40. o.uv=TRANSFORM_TEX(v.texcoord,_AnimationTex);
  41. return o;
  42. }
  43. fixed4 frag(v2f i):SV_Target
  44. {
  45. float time=_Time.y*_AnimationSpeed;
  46. float row=(floor(time/_HorAmount)+1)%_HorAmount;
  47. float col=floor(time%_HorAmount)+1;
  48. //x方向偏移
  49. i.uv.x/=_HorAmount;
  50. i.uv.x+=(col-1)/_HorAmount;
  51. //y方向偏移
  52. i.uv.y/=_VerAmount;
  53. i.uv.y+=(_VerAmount-row)/_VerAmount;
  54. //偏移后的结果采样
  55. fixed3 texResult=tex2D(_AnimationTex,i.uv);
  56. return fixed4(texResult,1);
  57. }
  58. ENDCG
  59. }
  60. }
  61. }

                结果:动态效果就不展示了,和用animation一下一下k帧等的效果一样,只是这种更方便高效。

                不足:如果在inspector界面调节纹理的offset值,会出现纹理闪烁的效果,参考书中的写法也没解决闪烁问题。

                出现原因:当物体的采样坐标偏移时,在纹理本身行列不变情况下,缩放后再加上行列的偏移,会使此时的uv坐标中的u坐标会超出1,即采样到了图片外,但使用了repeat模式,会将大于一的数值强制截取小数,一截取,u坐标直接回到了这一行的第一个图片,找到原因后解决就很简单了,要做的就是大于1的时候回到最后一张图片,v坐标同理。

                改良版:        

  1. Shader "Custom/Test0"
  2. {
  3. Properties
  4. {
  5. //用于控制纹理的整体颜色表现
  6. _Color("Color",Color)=(1,1,1,1)
  7. _AnimationTex("动画纹理",2D)="white"{}
  8. _AnimationSpeed("动画速度",float)=1.0
  9. _HorAmount("水平数量",float)=8
  10. _VerAmount("垂直数量",float)=8
  11. }
  12. SubShader
  13. {
  14. Pass
  15. {
  16. CGPROGRAM
  17. #pragma vertex vert
  18. #pragma fragment frag
  19. #include "UnityCG.cginc"
  20. fixed4 _Color;
  21. sampler2D _AnimationTex;
  22. float4 _AnimationTex_ST;
  23. fixed _AnimationSpeed;
  24. fixed _HorAmount;
  25. fixed _VerAmount;
  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:TEXCOORD3;
  35. };
  36. v2f vert(a2v v)
  37. {
  38. v2f o;
  39. o.pos=UnityObjectToClipPos(v.vertex);
  40. o.uv=TRANSFORM_TEX(v.texcoord,_AnimationTex);
  41. return o;
  42. }
  43. fixed4 frag(v2f i):SV_Target
  44. {
  45. float time=_Time.y*_AnimationSpeed;
  46. float row=(floor(time/_HorAmount)+1)%_HorAmount;
  47. float col=floor(time%_HorAmount)+1;
  48. //x方向偏移
  49. i.uv.x=(i.uv.x%1)/_HorAmount;
  50. i.uv.x+=(col-1)/_HorAmount;
  51. //y方向偏移
  52. i.uv.y=(i.uv.y%1)/_VerAmount;
  53. i.uv.y+=(_VerAmount-row)/_VerAmount;
  54. //偏移后的结果采样
  55. fixed3 texResult=tex2D(_AnimationTex,i.uv);
  56. return fixed4(texResult,1);
  57. }
  58. ENDCG
  59. }
  60. }
  61. }

                在计算采样时考虑偏移就行,对一取余。对于偏移正常处理即可。                                  

          1.2 背景滚动动画

                纹理采样加上x轴的变化即可。

  1. Shader "Custom/Test0"
  2. {
  3. Properties
  4. {
  5. //用于控制纹理的整体颜色表现
  6. _Color("Color",Color)=(1,1,1,1)
  7. _FarBackGround("较远背景纹理",2D)="white"{}
  8. _NearBackGround("较近背景纹理",2D)="white"{}
  9. _FarSpeed("较远背景纹理",float)=1.0
  10. _NearSpeed("较近背景纹理",float)=1.0
  11. }
  12. SubShader
  13. {
  14. Pass
  15. {
  16. CGPROGRAM
  17. #pragma vertex vert
  18. #pragma fragment frag
  19. #include "UnityCG.cginc"
  20. sampler2D _FarBackGround;
  21. sampler2D _NearBackGround;
  22. float4 _FarBackGround_ST;
  23. float4 _NearBackGround_ST;
  24. fixed _FarSpeed;
  25. fixed _NearSpeed;
  26. struct a2v
  27. {
  28. float4 vertex:POSITION;
  29. float4 texcoord:TEXCOORD0;
  30. };
  31. struct v2f
  32. {
  33. float4 pos:SV_POSITION;
  34. float4 uv:TEXCOORD0;
  35. };
  36. v2f vert(a2v v)
  37. {
  38. v2f o;
  39. o.pos=UnityObjectToClipPos(v.vertex);
  40. o.uv.xy=TRANSFORM_TEX(v.texcoord,_FarBackGround)+float2(_Time.y*_FarSpeed,0);
  41. o.uv.zw=TRANSFORM_TEX(v.texcoord,_NearBackGround)+float2(_Time.y*_NearSpeed,0);
  42. return o;
  43. }
  44. fixed4 frag(v2f i):SV_Target
  45. {
  46. fixed4 FarResult=tex2D(_FarBackGround,i.uv.xy);
  47. fixed4 NearResult=tex2D(_NearBackGround,i.uv.zw);
  48. fixed3 color=lerp(FarResult,NearResult,NearResult.a);
  49. return fixed4(color,1);
  50. }
  51. ENDCG
  52. }
  53. }
  54. }

二、顶点动画 

        做顶点动画时一定要注意加上DisableBatching标签,防止优化时对模型进行批处理,批处理会丢失模型本身的顶点信息,当然我们也可以将顶点相对于原点的偏离存储在顶点颜色中,就不用担心批处理的问题。

        2.1 二维河流动画:

                原理也是很简单,用正弦函数模拟坐标偏移即可。

                注意水流效果都由哪些偏移组成,首先是uv偏移,模拟水流移动,其次是顶点偏移,模拟水流起伏。

                这里也有一个小坑,那就是不要用Unity自带的Quad!!!,我一开始得到的效果巨怪,还以为自己写错了,谁知道是因为Quad只有4个顶点,根本做不出来sin的效果,说多了都是泪,参考书的Github网址有专门的多顶点Quad。        

                第一版写法:        

  1. Shader "Custom/Test0"
  2. {
  3. Properties
  4. {
  5. //用于控制纹理的整体颜色表现
  6. _Color("Color",Color)=(1,1,1,1)
  7. _MainTex("水流贴图",2D)="white"{}
  8. _HorizontalSpeed("水流速度",float)=1.0
  9. _VerticalSpeed("起伏速度",float)=1.0
  10. _Amount("起伏数量",float)=1.0
  11. _Offset("起伏偏移",float)=1.0
  12. //确保多个材质的初始的画面不同
  13. _InitialTime("初始时间",float)=1.0
  14. }
  15. SubShader
  16. {
  17. Tags{"DisableBatching"="True"}
  18. Pass
  19. {
  20. //开启透明度混合的原因是书中提供的素材图片周围有一圈白环
  21. //而白环的透明度是0,开启透明度混合可以过滤透明度为0的地方
  22. Blend SrcAlpha OneMinusSrcAlpha
  23. CGPROGRAM
  24. #pragma vertex vert
  25. #pragma fragment frag
  26. #include "UnityCG.cginc"
  27. fixed4 _Color;
  28. sampler2D _MainTex;
  29. float4 _MainTex_ST;
  30. fixed _HorizontalSpeed;
  31. fixed _VerticalSpeed;
  32. fixed _Offset;
  33. fixed _Amount;
  34. fixed _InitialTime;
  35. struct a2v
  36. {
  37. float4 vertex:POSITION;
  38. float4 texcoord:TEXCOORD0;
  39. };
  40. struct v2f
  41. {
  42. float4 pos:SV_POSITION;
  43. float2 uv:TEXCOORD0;
  44. };
  45. v2f vert(a2v v)
  46. {
  47. v2f o;
  48. float3 offset=float3(0,0,0);
  49. //模型使用的方向是z轴滚动,所以用z轴充当sin函数的变量值
  50. offset.x=sin((v.vertex.z+_VerticalSpeed*(_Time.y+_InitialTime))*_Amount)*_Offset/100;
  51. o.pos=UnityObjectToClipPos(v.vertex+offset);
  52. o.uv.xy=TRANSFORM_TEX(v.texcoord,_MainTex);
  53. o.uv+=float2(0,_Time.y*_HorizontalSpeed);
  54. return o;
  55. }
  56. fixed4 frag(v2f i):SV_Target
  57. {
  58. fixed3 color=tex2D(_MainTex,i.uv.xy)*_Color;
  59. return fixed4(color,0.5);
  60. }
  61. ENDCG
  62. }
  63. }
  64. }

       这种写法虽然实现了顶点偏移,但实际效果却很一般。

                 可以看到,上面的偏移和下面的偏移过于相似,导致实际效果看起来有些刻意。下面将展示效果更好的一种写法,有时候不得不佩服某些人的脑洞。 

                第二版写法:

  1. Shader "Custom/Test0"
  2. {
  3. Properties
  4. {
  5. //用于控制纹理的整体颜色表现
  6. _Color("Color",Color)=(1,1,1,1)
  7. _MainTex("水流贴图",2D)="white"{}
  8. _HorizontalSpeed("水流速度",float)=1.0
  9. _VerticalSpeed("起伏速度",float)=1.0
  10. _Amount("起伏数量",float)=1.0
  11. _Offset("起伏偏移",float)=1.0
  12. //确保多个材质的初始的画面不同
  13. _InitialTime("初始时间",float)=1.0
  14. }
  15. SubShader
  16. {
  17. Tags{"DisableBatching"="True"}
  18. Pass
  19. {
  20. //开启透明度混合的原因是书中提供的素材图片周围有一圈白环
  21. //而白环的透明度是0,开启透明度混合可以过滤透明度为0的地方
  22. Blend SrcAlpha OneMinusSrcAlpha
  23. CGPROGRAM
  24. #pragma vertex vert
  25. #pragma fragment frag
  26. #include "UnityCG.cginc"
  27. fixed4 _Color;
  28. sampler2D _MainTex;
  29. float4 _MainTex_ST;
  30. fixed _HorizontalSpeed;
  31. fixed _VerticalSpeed;
  32. fixed _Offset;
  33. fixed _Amount;
  34. fixed _InitialTime;
  35. struct a2v
  36. {
  37. float4 vertex:POSITION;
  38. float4 texcoord:TEXCOORD0;
  39. };
  40. struct v2f
  41. {
  42. float4 pos:SV_POSITION;
  43. float2 uv:TEXCOORD0;
  44. };
  45. v2f vert(a2v v)
  46. {
  47. v2f o;
  48. float3 offset=float3(0,0,0);
  49. //模型使用的方向是z轴滚动,所以用z轴充当sin函数的变量值
  50. offset.x=sin((v.vertex.z+v.vertex.x+_VerticalSpeed*(_Time.y+_InitialTime))*_Amount)*_Offset/100;
  51. o.pos=UnityObjectToClipPos(v.vertex+offset);
  52. o.uv.xy=TRANSFORM_TEX(v.texcoord,_MainTex);
  53. o.uv+=float2(0,_Time.y*_HorizontalSpeed);
  54. return o;
  55. }
  56. fixed4 frag(v2f i):SV_Target
  57. {
  58. fixed4 color=tex2D(_MainTex,i.uv.xy)*_Color;
  59. return fixed4(color);
  60. }
  61. ENDCG
  62. }
  63. }
  64. }

                sin变量的取值加上顶点的x值,实现某些地方看起来更大,某些地方看起来更窄。

                 这个效果就看起来自然了很多。                            

        2.2 广告牌技术:

                无论观察者处于什么位置观察任何图像,广告版都能提供一个朝向观众的面,这个面随着摄像机的改变而改变。

                BillBoard技术是计算机图形学领域中进行快速绘制的一种方法。在类似游戏这种对实时性要求较高的场景下采取BillBoard技术可以大大加快绘制的速度从而提高画面的流畅性。把3D的物体用2D来表示,然后让该物体始终朝向镜头。比如场景中的一棵树,对于整个场景来说不是主要物体,因此无需花费大量的时间去计算树的每一部分的细节。通常的做法是首先准备好一张树的照片,然后镜头运动的时候使得树始终正对着镜头,我们看到的始终是树的正面。我们在渲染树木,灌木丛,云,烟等效果时都会用到。

                广告牌技术的难点在于构建旋转矩阵,保证广告牌面的正方向永远面向玩家。

                广告牌的写法有两种,一个是面法线永远指向视角方向,另一个是向上的方向永远是(0,1,0),而法线永远是尽力指向视角方向,我们在shader中用一个数值来控制法线指向视角的程度。

                旋转矩阵的构建我们知道用坐标轴填充,同时基于模型空间的原点。当然,你可以不基于模型的原点,只需将旋转矩阵扩充到齐次坐标空间,最后一列填充偏移值。关于旋转矩阵的填充方式,这里有一个巨坑,我们的广告牌一般都是一张平面图,意味着有正面和反面,为了保证旋转后的面我们仍然可以看到,旋转矩阵内列向量的摆放至关重要。

                如果你看过参考书,你会发现书上的写法只针对quad,而plane则会看不到任何结果,可能会有些像素点,大概率由于浮点数精度造成,plane看不到结果是因为,plane只有在y方向才是面的正方向,而quad是在z轴,书中这个旋转矩阵的构建,会使plane模型下的z轴朝向我们,在z轴的方向我们肯定看不到任何结果。

                2.2.1 针对quad的竖直排列方式:        

  1. Shader "Custom/Test1"
  2. {
  3. Properties
  4. {
  5. //用于控制纹理的整体颜色表现
  6. _Color("Color",Color)=(1,1,1,1)
  7. _MainTex("纹理贴图",2D)="white"{}
  8. _Level("法线朝向控制",Range(0,1))=1
  9. }
  10. SubShader
  11. {
  12. Tags{"DisableBatching"="True"}
  13. Pass
  14. {
  15. Cull off
  16. CGPROGRAM
  17. #pragma vertex vert
  18. #pragma fragment frag
  19. #include "UnityCG.cginc"
  20. sampler2D _MainTex;
  21. float4 _MainTex_ST;
  22. fixed _Level;
  23. struct a2v
  24. {
  25. float4 vertex:POSITION;
  26. float4 texcoord:TEXCOORD0;
  27. };
  28. struct v2f
  29. {
  30. float4 pos:SV_POSITION;
  31. float4 uv:TEXCOORD0;
  32. };
  33. v2f vert(a2v v)
  34. {
  35. v2f o;
  36. o.uv.xy=TRANSFORM_TEX(v.texcoord,_MainTex);
  37. //假设向上的方向永远是(010),先根据法线计算出另一个坐标轴
  38. //先计算出模型空间下的视角方向,注意我们要的是面朝向我们,
  39. float3 viewDir=mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1));
  40. float3 normalDir=viewDir;
  41. normalDir.y=normalDir.y*_Level;
  42. normalDir=normalize(normalDir);
  43. float3 upDir=abs(normalDir.y)>0.999?float3(0,0,1):float3(0,1,0);
  44. float3 rightDir=normalize(cross(upDir,normalDir));
  45. upDir=normalize(cross(normalDir,rightDir));
  46. //旋转矩阵构建时,把视角放最后一行,确保旋转后面的z轴朝向我们
  47. float3 localPos=float3(0,0,0)+rightDir*v.vertex.x+upDir*v.vertex.y+normalDir*v.vertex.z;
  48. o.pos=UnityObjectToClipPos(float4(localPos,1));
  49. return o;
  50. }
  51. fixed4 frag(v2f i):SV_Target
  52. {
  53. fixed3 color=tex2D(_MainTex,i.uv.xy);
  54. return fixed4(color,1);
  55. }
  56. ENDCG
  57. }
  58. }
  59. }

                2.2.2 plane的水平排列方式:        

  1. Shader "Custom/Test0"
  2. {
  3. Properties
  4. {
  5. //用于控制纹理的整体颜色表现
  6. _Color("Color",Color)=(1,1,1,1)
  7. _MainTex("纹理贴图",2D)="white"{}
  8. _Level("法线朝向控制",Range(0,1))=1
  9. }
  10. SubShader
  11. {
  12. Tags{"DisableBatching"="True"}
  13. Pass
  14. {
  15. Cull off
  16. CGPROGRAM
  17. #pragma vertex vert
  18. #pragma fragment frag
  19. #include "UnityCG.cginc"
  20. sampler2D _MainTex;
  21. float4 _MainTex_ST;
  22. fixed _Level;
  23. struct a2v
  24. {
  25. float4 vertex:POSITION;
  26. float4 texcoord:TEXCOORD0;
  27. };
  28. struct v2f
  29. {
  30. float4 pos:SV_POSITION;
  31. float4 uv:TEXCOORD0;
  32. };
  33. v2f vert(a2v v)
  34. {
  35. v2f o;
  36. o.uv.xy=TRANSFORM_TEX(v.texcoord,_MainTex);
  37. //假设向上的方向永远是(010),先根据法线计算出另一个坐标轴
  38. //先计算出模型空间下的视角方向,注意我们要的是面朝向我们,
  39. float3 normalDir=mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1));
  40. //通过控制y值,实现up方向的控制
  41. normalDir.y=normalDir.y*_Level;
  42. normalDir=normalize(normalDir);
  43. //防止视角方向和向上方向重合从而得到错误错误结果
  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. //顶点*旋转矩阵,这里拆开写了,把视角放中间一行,确保旋转后面的y轴朝向我们
  48. float3 localPos=float3(0,0,0)+rightDir*v.vertex.x+normalDir*v.vertex.y+upDir*v.vertex.z;
  49. //旋转只针对顶点,并不针对模型坐标空间,所以还要作矩阵变换
  50. o.pos=UnityObjectToClipPos(float4(localPos,1));
  51. return o;
  52. }
  53. fixed4 frag(v2f i):SV_Target
  54. {
  55. fixed3 color=tex2D(_MainTex,i.uv.xy);
  56. return fixed4(color,1);
  57. }
  58. ENDCG
  59. }
  60. }
  61. }

                关于针对偏移的问题,只需要在开始normal计算上加上中心点偏移,同时,旋转矩阵的计算也加上偏移即可。

                2.2.3 针对quad的偏移写法:                

  1. Shader "Custom/Test1"
  2. {
  3. Properties
  4. {
  5. //用于控制纹理的整体颜色表现
  6. _Color("Color",Color)=(1,1,1,1)
  7. _MainTex("纹理贴图",2D)="white"{}
  8. _Level("法线朝向控制",Range(0,1))=1
  9. Center("中心点",Vector)=(0,0,0)
  10. }
  11. SubShader
  12. {
  13. Tags{"DisableBatching"="True"}
  14. Pass
  15. {
  16. Cull off
  17. CGPROGRAM
  18. #pragma vertex vert
  19. #pragma fragment frag
  20. #include "UnityCG.cginc"
  21. sampler2D _MainTex;
  22. float4 _MainTex_ST;
  23. fixed _Level;
  24. fixed3 Center;
  25. struct a2v
  26. {
  27. float4 vertex:POSITION;
  28. float4 texcoord:TEXCOORD0;
  29. };
  30. struct v2f
  31. {
  32. float4 pos:SV_POSITION;
  33. float4 uv:TEXCOORD0;
  34. };
  35. v2f vert(a2v v)
  36. {
  37. v2f o;
  38. o.uv.xy=TRANSFORM_TEX(v.texcoord,_MainTex);
  39. //假设向上的方向永远是(010),先根据法线计算出另一个坐标轴
  40. //先计算出模型空间下的视角方向,注意我们要的是面朝向我们
  41. //计算出在center下的视角方向
  42. float3 viewDir_Old=mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1));
  43. float3 tempDir=float3(0,0,0)-Center;
  44. float3 viewDir=tempDir+viewDir_Old;
  45. float3 normalDir=viewDir;
  46. normalDir.y=normalDir.y*_Level;
  47. normalDir=normalize(normalDir);
  48. float3 upDir=abs(normalDir.y)>0.999?float3(0,0,1):float3(0,1,0);
  49. float3 rightDir=normalize(cross(upDir,normalDir));
  50. upDir=normalize(cross(normalDir,rightDir));
  51. //旋转矩阵构建时,把视角放最后一行,确保旋转后面的z轴朝向我们
  52. float3 localPos=Center+rightDir*v.vertex.x+upDir*v.vertex.y+normalDir*v.vertex.z;
  53. o.pos=UnityObjectToClipPos(float4(localPos,1));
  54. return o;
  55. }
  56. fixed4 frag(v2f i):SV_Target
  57. {
  58. fixed3 color=tex2D(_MainTex,i.uv.xy);
  59. return fixed4(color,1);
  60. }
  61. ENDCG
  62. }
  63. }
  64. }

                问题:上面三种写法无法屏蔽模型本身旋转的影响,这里的旋转只是对顶点的变换,对于整个模型空间(即决定模型空间三个坐标轴)并未有任何变化。同时,问题二如果视角方向和向上,向下的差距不大时,图片会有一个明显的翻转。

                问题一的优化:说白了就是模型旋转导致顶点的旋转矩阵计算时,那个向上的向量也同步变换,我们在模型变换时,对向上的向量也做一次变换,使得向上的向量仍保持向上。

                2.2.4 针对问题一的quad优化:                

  1. Shader "Custom/Test1"
  2. {
  3. Properties
  4. {
  5. //用于控制纹理的整体颜色表现
  6. _Color("Color",Color)=(1,1,1,1)
  7. _MainTex("纹理贴图",2D)="white"{}
  8. _Level("法线朝向控制",Range(0,1))=1
  9. Center("中心点",Vector)=(0,0,0)
  10. }
  11. SubShader
  12. {
  13. Tags{"DisableBatching"="True"}
  14. Pass
  15. {
  16. Cull off
  17. CGPROGRAM
  18. #pragma vertex vert
  19. #pragma fragment frag
  20. #include "UnityCG.cginc"
  21. sampler2D _MainTex;
  22. float4 _MainTex_ST;
  23. fixed _Level;
  24. fixed3 Center;
  25. struct a2v
  26. {
  27. float4 vertex:POSITION;
  28. float4 texcoord:TEXCOORD0;
  29. };
  30. struct v2f
  31. {
  32. float4 pos:SV_POSITION;
  33. float4 uv:TEXCOORD0;
  34. };
  35. v2f vert(a2v v)
  36. {
  37. v2f o;
  38. o.uv.xy=TRANSFORM_TEX(v.texcoord,_MainTex);
  39. //假设向上的方向永远是(010),先根据法线计算出另一个坐标轴
  40. //先计算出模型空间下的视角方向,注意我们要的是面朝向我们
  41. //计算出在center下的视角方向
  42. float3 viewDir_Old=mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1));
  43. float3 tempDir=float3(0,0,0)-Center;
  44. float3 viewDir=tempDir+viewDir_Old;
  45. float3 normalDir=viewDir;
  46. normalDir.y=normalDir.y*_Level;
  47. normalDir=normalize(normalDir);
  48. float3 upDir=abs(normalDir.y)>0.999?mul(unity_WorldToObject,float3(0,0,1)):mul(unity_WorldToObject,float3(0,1,0));
  49. float3 rightDir=normalize(cross(upDir,normalDir));
  50. upDir=normalize(cross(normalDir,rightDir));
  51. //旋转矩阵构建时,把视角放最后一行,确保旋转后面的z轴朝向我们
  52. float3 localPos=Center+rightDir*v.vertex.x+upDir*v.vertex.y+normalDir*v.vertex.z;
  53. o.pos=UnityObjectToClipPos(float4(localPos,1));
  54. return o;
  55. }
  56. fixed4 frag(v2f i):SV_Target
  57. {
  58. fixed3 color=tex2D(_MainTex,i.uv.xy);
  59. return fixed4(color,1);
  60. }
  61. ENDCG
  62. }
  63. }
  64. }

                这样,无论模型本身怎么旋转都可以屏蔽掉这个影响。

                关于问题二的优化:能力有限,暂时无法解决。

                补充:你其实可以将我们上面提到的河流和广告牌结合起来,代码我就不展示了,可以看看自己对广告牌的理解是否透彻,毕竟顶点不仅要旋转,还要位移。

三、关于顶点动画的阴影问题

                顶点动画的阴影效果,我们必须要在Pass中实现自定义的效果,而不是仅仅使用Unity内置的阴影Shader,大致就是做阴影是考虑顶点变换,而不是在顶点变换之前就生成阴影纹理。

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

闽ICP备14008679号