Unity shader学习笔记(二)顶点函数和片元函数
发表于2018-04-28
继续给大家分享在学习shader时的一些学习笔记。Shader的方法都是写在CGPROGRAM和ENDCG里面的,其中最重要的方法就是顶点函数和片元函数,这里有两个概念,顶点是指模型表面有很多三角形切面,每个三角形的三个点就是顶点,三角形的面积就是片元。
#pragma vertex vert
顶点函数 这条语句只是声明了顶点函数的函数名 vert (简单说就是确定物体的显示位置)
模型表面有很多三角形切面,每个三角形切面的三个顶点都会执行该函数,顶点函数的基本作用是进行坐标变换 把每个三角形的切面的顶点的坐标从模型空间的坐标(三维视图中,顶点相对于建模时确定的中心点的坐标) 。转换到裁剪空间(通过摄像机视角得到的视锥体平面就是裁剪平面,近裁切平面和远裁切平面的距离为视角的深度范围,两个平面与其余四个平面组成的六边形内的空间就是裁切空间)的切面上的坐标。
#pragma fragment frag
片元函数 这里只是声明了片元函数的函数名 frag (简单说就是确定物体要现实的颜色)
片元函数的基本作用 把模型空间上物体每个像素点上的颜色进行变幻计算,然后得到一个颜色值并渲染到裁剪空间中对象对应的像素点上, 函数的返回值是一个颜色值
Shader中语义的作用是进行解释声明 告诉系统是何作用
语义的用法是 参数/方法 : 语义
如果语义跟在参数后面,那么就是对参数进行解释,比如上述的POSITION是对x进行解释,如果语义跟在方法后面,那么就是对返回值进行解释
语义的分类
从应用程序传递到顶点函数的语义有 POSITION 传递顶点坐标(模型空间) NORMAL 发现(模型空间) TANGENT 切线(模型空间) TEXCOORD0~N 纹理坐标 COLOR 顶点颜色 从顶点函数传递到片元函数的语义有 SV_POSITION 裁剪空间中的顶点坐标(一般系统使用) COLOR0 语义上是传递颜色,但实际上一般都是传递一组值 4个 COLOR1 同COLOR0 TEXCOORD0~7 语义上是传递纹理坐标,但不是一定,可以传别的 从片元函数传递给系统 SV_TARGET 颜色值,表示将要渲染的颜色值
每个语义都有各自的使用范围 比如在frag函数里面使用POSITION 会报错找不到语义
顶点函数的实现 需要让系统自动的把顶点坐标传入 实现中参数使用了POSITION 语义,对x作了解释声明,把顶点坐标传递给x
最后需要将返回值返回给系统 所以方法后面使用了SV_POSITION语义 对返回值进行了解释声明 意思是返回值是裁剪空间下的顶点坐标
float4 vert(float4 x : POSITION) : SV_POSITION { //UNITY_MATRIX_MVP是unity内置的一个模型矩阵 使用mul函数使模型矩阵与顶点坐标进行计算 ,得到顶点坐标在裁剪空间下的坐标 return mul(UNITY_MATRIX_MVP,x); }
SV_Target语义的作用是将返回的颜色值存储在一个渲染目标中
fixed4 frag() :SV_Target{ return fixed4(1,1,1,1); }
但是 语义推荐放在结构体里面进行定义, 然后再函数里面直接直接使用语义,会看起来比较清晰!
所以代码进行修改后为:
//结构体 application to vertex 应用到顶点的意思 struct a2v { float4 vertex : POSITION; //该语义会让系统把模型空间的顶点的值 自动传给vertex float3 normal : NORMAL; //该语义会让系统把模型空间的法线方向的值传给normal float4 texcoord : TEXCOORD0;//该语义会让系统把模型的第一套纹理坐标的值传给textcoord }; struct v2f { float4 position:SV_POSITION; float3 temp:COLOR0;//返回值必须有语义 不然程序会报错 这里的语义可以自己定义 一般都使用语义Color0 Color0用来存储颜色信息的语义 }; struct f2a { fixed4 target : SV_TARGET; }; v2f vert(a2v x) { //UNITY_MATRIX_MVP是unity内置的一个模型矩阵 使用mul函数使模型矩阵与顶点坐标进行计算 ,得到顶点坐标在裁剪空间下的坐标 v2f f; f.position = mul(UNITY_MATRIX_MVP, x.vertex); f.temp = x.normal; return f;//系统会自动根据结构体中变量的语义来进行取值 } //SV_Target语义的作用是将返回的颜色值存储在一个渲染目标中 f2a frag(v2f f) { f2a a; a.target = fixed4(f.temp, 1); return a; }
这样代码开起来就清晰多了。来自:https://blog.csdn.net/u013106366/article/details/53292850