C for Graphic:语言(frag操作)
之前我们随便尝试了下vertex顶点函数能干些什么稀奇古怪的事情,本质上来说就是让我们开发者自己写代码操作顶点变换。这一篇就看看frag片段函数能干什么!如果看过前面的博客(当然我的意思是肯定要按顺序看前面的博客的),那么也就知道frag片段函数在图形流水线中,需要经过vertex顶点函数处理完顶点数据,再经过光栅化,才到frag片段函数处理最后的像素颜色。
这里就先通过一个小例子来看看效果,代码如下:
-
Shader "Unlit/FragEffectUnlitShader"
-
{
-
Properties
-
{
-
_MainTex ("Texture", 2D) = "white" {}
-
}
-
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 uv : TEXCOORD0;
-
float4 vertex : SV_POSITION;
-
};
-
-
sampler2D _MainTex;
-
float4 _MainTex_ST;
-
-
v2f vert (appdata v)
-
{
-
v2f o;
-
o.vertex = UnityObjectToClipPos(v.vertex);
-
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
-
return o;
-
}
-
-
fixed4 reverseColor(fixed4 col)
-
{
-
//将颜色反转
-
return fixed4(1.0-col.x,1.0-col.y,1.0-col.z,col.w);
-
}
-
-
fixed4 frag (v2f i) : SV_Target
-
{
-
fixed4 col = tex2D(_MainTex, i.uv);
-
//反转颜色值后,提交到图形流水线后续流程更新像素值
-
col = reverseColor(col);
-
return col;
-
}
-
ENDCG
-
}
-
}
-
}
效果如下:
用iphone的小伙伴们可能知道这个效果,就是辅助功能中的颜色反转。简单解释一下就是通过一个reverseColor函数将颜色值反转一下(这里颜色值分量是0-1.0f的浮点数),代码很简单,所以我直接写注释中解释。
当然还有其他效果了,如下:
-
Properties
-
{
-
_MainTex ("Texture", 2D) = "white" {}
-
_Appro("Approximate",Range(0.01,1.0)) = 0.1
-
}
-
-
float _Appro;
-
-
//判断一个浮点数是否在某个近似区间
-
bool approValue(float refer,float col)
-
{
-
if(col<refer+_Appro && col>refer-_Appro)
-
{
-
return true;
-
}
-
return false;
-
}
-
//判断一个颜色值rgb分量是否在某个近似区间
-
bool approColor(fixed4 refer,fixed4 col)
-
{
-
if(approValue(refer.x,col.x) && approValue(refer.y,col.y) && approValue(refer.z,col.z))
-
{
-
return true;
-
}
-
return false;
-
}
-
//判断frag颜色值是否近似白色并修改成红色
-
fixed4 whiteCol2Red(fixed4 col)
-
{
-
if(approColor(fixed4(1.0,1.0,1.0,1.0),col))
-
{
-
col = fixed4(1.0,0.0,0.0,1.0);
-
}
-
return col;
-
}
-
-
fixed4 frag (v2f i) : SV_Target
-
{
-
fixed4 col = tex2D(_MainTex, i.uv);
-
//将近似白色转红色
-
col = whiteCol2Red(col);
-
return col;
-
}
效果如下图:
这里我解释下,代码贴出关键部分,而且有注释很简单,就是判断片段tex2D采样函数中采样出来的col颜色值是否近似白色(当然我添加了一个近似阀值Approximate控制),通过手动拖拽修改近似阀值,就将纹理中白色值转换成红色值,可以看出最近接白色的uv坐标点颜色值最开始该变成红色,符合预期。
接下来来个动态效果看看,代码如下:
-
Properties
-
{
-
_MainTex ("Texture", 2D) = "white" {}
-
_Appro("Approximate",Range(0.01,1.0)) = 0.1
-
_Col("Col",Color) = (0,0,0,0)
-
_PingPong("PingPong",Range(0.01,5.0)) = 0.01
-
}
-
-
float4 _Col;
-
float _PingPong;
-
-
fixed4 frag (v2f i) : SV_Target
-
{
-
fixed4 col = tex2D(_MainTex, i.uv);
-
float _ppTime = 0.0;
-
//计算时间值于pingpong时间的关系,处于单数pingpong时间内就递增,双数就递减
-
if((((int)_Time.y/(int)_PingPong))%2 == 1)
-
{
-
_ppTime = _Time.y % _PingPong;
-
}
-
else
-
{
-
_ppTime = _PingPong-(_Time.y % _PingPong);
-
}
-
//给一个颜色值做叠加呼吸效果
-
col += _ppTime * _Col;
-
return col;
-
}
效果图如下:
代码也只贴出关键部分,其实也很简单,定义一个pingpong时间,一个叠加color值,通过_Time去处理pingpong呼吸灯颜色效果,顺便说一下,_Time这个结构变量,是有四个分量的,其中y分量就是unity提供的开始运行的增加时间量,贴下UnityShaderVariables.cginc代码,如下:
写到这里了,我想表达的意思就是fragment片段函数从图形流水线流程来看,就是提供给我们开发改变颜色值的接口函数,我们可以发挥自己想象力,写出炫丽的效果,上面三个简单的例子是为了形象的告诉大家fragment片段函数该怎么去处理,后面我们实现更高级的着色器效果的时候能看到更炫的代码。
so,接下来我们继续。