C for Graphic:语言(frag操作)

转载自: https://blog.****.net/yinhun2012/article/details/82784369


之前我们随便尝试了下vertex顶点函数能干些什么稀奇古怪的事情,本质上来说就是让我们开发者自己写代码操作顶点变换。这一篇就看看frag片段函数能干什么!如果看过前面的博客(当然我的意思是肯定要按顺序看前面的博客的),那么也就知道frag片段函数在图形流水线中,需要经过vertex顶点函数处理完顶点数据,再经过光栅化,才到frag片段函数处理最后的像素颜色。

      这里就先通过一个小例子来看看效果,代码如下:

  1. Shader "Unlit/FragEffectUnlitShader"
  2. {
  3. Properties
  4. {
  5. _MainTex ("Texture", 2D) = "white" {}
  6. }
  7. SubShader
  8. {
  9. Tags { "RenderType"="Opaque" }
  10. LOD 100
  11. Pass
  12. {
  13. CGPROGRAM
  14. #pragma vertex vert
  15. #pragma fragment frag
  16. #include "UnityCG.cginc"
  17. struct appdata
  18. {
  19. float4 vertex : POSITION;
  20. float2 uv : TEXCOORD0;
  21. };
  22. struct v2f
  23. {
  24. float2 uv : TEXCOORD0;
  25. float4 vertex : SV_POSITION;
  26. };
  27. sampler2D _MainTex;
  28. float4 _MainTex_ST;
  29. v2f vert (appdata v)
  30. {
  31. v2f o;
  32. o.vertex = UnityObjectToClipPos(v.vertex);
  33. o.uv = TRANSFORM_TEX(v.uv, _MainTex);
  34. return o;
  35. }
  36. fixed4 reverseColor(fixed4 col)
  37. {
  38. //将颜色反转
  39. return fixed4(1.0-col.x,1.0-col.y,1.0-col.z,col.w);
  40. }
  41. fixed4 frag (v2f i) : SV_Target
  42. {
  43. fixed4 col = tex2D(_MainTex, i.uv);
  44. //反转颜色值后,提交到图形流水线后续流程更新像素值
  45. col = reverseColor(col);
  46. return col;
  47. }
  48. ENDCG
  49. }
  50. }
  51. }

      效果如下:

      C for Graphic:语言(frag操作)

     用iphone的小伙伴们可能知道这个效果,就是辅助功能中的颜色反转。简单解释一下就是通过一个reverseColor函数将颜色值反转一下(这里颜色值分量是0-1.0f的浮点数),代码很简单,所以我直接写注释中解释。

     当然还有其他效果了,如下:

     

  1. Properties
  2. {
  3. _MainTex ("Texture", 2D) = "white" {}
  4. _Appro("Approximate",Range(0.01,1.0)) = 0.1
  5. }
  6. float _Appro;
  7. //判断一个浮点数是否在某个近似区间
  8. bool approValue(float refer,float col)
  9. {
  10. if(col<refer+_Appro && col>refer-_Appro)
  11. {
  12. return true;
  13. }
  14. return false;
  15. }
  16. //判断一个颜色值rgb分量是否在某个近似区间
  17. bool approColor(fixed4 refer,fixed4 col)
  18. {
  19. if(approValue(refer.x,col.x) && approValue(refer.y,col.y) && approValue(refer.z,col.z))
  20. {
  21. return true;
  22. }
  23. return false;
  24. }
  25. //判断frag颜色值是否近似白色并修改成红色
  26. fixed4 whiteCol2Red(fixed4 col)
  27. {
  28. if(approColor(fixed4(1.0,1.0,1.0,1.0),col))
  29. {
  30. col = fixed4(1.0,0.0,0.0,1.0);
  31. }
  32. return col;
  33. }
  34. fixed4 frag (v2f i) : SV_Target
  35. {
  36. fixed4 col = tex2D(_MainTex, i.uv);
  37. //将近似白色转红色
  38. col = whiteCol2Red(col);
  39. return col;
  40. }

       效果如下图:

       C for Graphic:语言(frag操作)

      这里我解释下,代码贴出关键部分,而且有注释很简单,就是判断片段tex2D采样函数中采样出来的col颜色值是否近似白色(当然我添加了一个近似阀值Approximate控制),通过手动拖拽修改近似阀值,就将纹理中白色值转换成红色值,可以看出最近接白色的uv坐标点颜色值最开始该变成红色,符合预期。

      接下来来个动态效果看看,代码如下:

      

  1. Properties
  2. {
  3. _MainTex ("Texture", 2D) = "white" {}
  4. _Appro("Approximate",Range(0.01,1.0)) = 0.1
  5. _Col("Col",Color) = (0,0,0,0)
  6. _PingPong("PingPong",Range(0.01,5.0)) = 0.01
  7. }
  8. float4 _Col;
  9. float _PingPong;
  10. fixed4 frag (v2f i) : SV_Target
  11. {
  12. fixed4 col = tex2D(_MainTex, i.uv);
  13. float _ppTime = 0.0;
  14. //计算时间值于pingpong时间的关系,处于单数pingpong时间内就递增,双数就递减
  15. if((((int)_Time.y/(int)_PingPong))%2 == 1)
  16. {
  17. _ppTime = _Time.y % _PingPong;
  18. }
  19. else
  20. {
  21. _ppTime = _PingPong-(_Time.y % _PingPong);
  22. }
  23. //给一个颜色值做叠加呼吸效果
  24. col += _ppTime * _Col;
  25. return col;
  26. }

      效果图如下:

      C for Graphic:语言(frag操作)

     代码也只贴出关键部分,其实也很简单,定义一个pingpong时间,一个叠加color值,通过_Time去处理pingpong呼吸灯颜色效果,顺便说一下,_Time这个结构变量,是有四个分量的,其中y分量就是unity提供的开始运行的增加时间量,贴下UnityShaderVariables.cginc代码,如下:

     C for Graphic:语言(frag操作)

     写到这里了,我想表达的意思就是fragment片段函数从图形流水线流程来看,就是提供给我们开发改变颜色值的接口函数,我们可以发挥自己想象力,写出炫丽的效果,上面三个简单的例子是为了形象的告诉大家fragment片段函数该怎么去处理,后面我们实现更高级的着色器效果的时候能看到更炫的代码。

     so,接下来我们继续。