Shader编程学习笔记(九)—— Cg语言入门1 - 输入输出和语义
Cg入门一:输入输出和语义
本小节对Cg语言进行一个入门了解。
在以前的课程中,我们了解了渲染管线、顶点和片段程序和颜色计算等,在本小结中来了解一个简单的shader的顶点和片段程序的输入输出以及常用语义。
编写一个简单的顶点和片段着色器,代码如下:
Shader "Lesson/vertex&fragment"{ SubShader{ pass{ CGPROGRAM #pragma vertex vert #pragma fragment frag void vert(in float2 objPos:POSITION, out float4 pos:POSITION){ pos = float4(objPos,0,1); } void frag(out float4 col:COLOR){ col = float4(1,0,0,1); } ENDCG } } }
Surface Shader没有pass通道,Vertex & Frament Shader至少有一个pass通道。其中,Cg是一个镶嵌的代码段,在ShaderLab语法中需要使用关键词“CGPROGRAM”和“ENDCG”将Cg代码段包含起来才能编译使用,需要注意的是这两个关键词都是大写的。
顶点程序会对顶点做一系列的处理,如几何变换,在处理后把需要的数据传递给片段程序,片段程序拿到顶点程序当中处理后的数据继续进行最终的计算。“void vert(in float2 objPos:POSITION, out float4 pos:POSITION)” 中有两个参数,其中第一个参数中的“in”表示引擎提供的输入,“float2”表示数据的类型为二阶的向量,参数名“objPos”冒号后需要带上语义,语义指的是顶点程序和片段程序能够被识别的变量的实际意义,这里使用“POSITION”。第二个参数中“out”表示输出,数据类型为“float4”,语义也是“POSITION”。如果顶点程序要输出一个“POSITION”语义的变量,这个变量必须要以“float4”四阶向量的形式。另外,在片段程序中需要有语义为“COLOR”的变量作为输入,这里使用“out float4 col:COLOR”作为颜色变量的输出,语义“COLOR”就是指“COLOR0”。
接下来创建一个使用该shader的Material,并在场景创建一个Cube使用该Material。效果如下:
拖动场景窗口,可以发现物体的大小随着窗口的变化而变化。目前需要了解的就是传递给顶点程序的就是模型的顶点数据,由模型的(x,y)凑成一个四阶向量,“POSITION”语义变量并没有在片段程序中输出,但是物体确实有大小上的变化,实际上“POSITION”语义是比较特殊的,可以不用在片段程序中直接使用“POSITION”输出,它被图形硬件直接做最后的处理和显示。在这里目前需要关心的是颜色的显示,我们可以在顶点程序中为颜色计算做一个输出,代码和效果如下:
Shader "Lesson/vertex&fragment"{ SubShader{ pass{ CGPROGRAM #pragma vertex vert #pragma fragment frag void vert(in float2 objPos:POSITION, out float4 col:COLOR, out float4 pos:POSITION){ pos = float4(objPos,0,1); col = float4(0,0,1,1); } void frag(inout float4 col:COLOR){ // col = float4(0,1,0,1); } ENDCG } } }
片段程序的颜色设置已经注释掉了,否则会覆盖顶点程序的颜色值。需要注意的是作为输出的“COLOR”变量要放在作为输出的“POSITION”语义之前,如“vert(in float2 objPos:POSITION, out float4 col:COLOR, out float4 pos:POSITION)”,否则颜色输出始终是无法改变的。
计算机图形硬件想要对3D场景中的物体做一个正确的显示时,它需要经过一系列的坐标系变换,如果输入一个物体的坐标系,这个物体的坐标系是没有参考价值的,它只存在物体自身的空间当中,物体在世界坐标中,与其他物体之间有一个相对位置,被摄像机照射时,物体在不同的位置,摄像机最终获取的结果是不一样的。通过这一些列的变换,会得到一个称为“CVV(Canonical View Volume)”的裁剪立方体,“CVV”实际上就是在进行摄像机透视投影在齐次空间当中的一个裁剪立方体,称为“正规化可视空间”,它的x值和y值总是在-1到1之间。
对于Unity中默认创建的一个Cube,它的网格数据的顶点信息中存储的x值和y值最大为0.5,最小为-0.5,模型的坐标中心为正中间(0,0)。当模型空间当中的x和y作为一个“POSITION”语义的输入时,可以知道它最大值为(0.5,0.5,0,1),最小为(-0.5,-0.5,0,1),在“CVV”的裁剪立方体当中x值和y值始终是-0.5到0.5,场景窗口最左边位置x为-1,正中间x为0,最右边位置x为1,y值同理。因此拖动窗口时,物体总是会随着窗口的变化而变化。
注释掉片段程序中的颜色输出,在顶点程序中将位置信息“pos”作为颜色信息,在Cg当中只要数据类型相同,两者之间是可以互相赋值的,尽管语义不同,语义只是在顶点和片段程序中输入输出的一个规范。代码和效果如下:
Shader "Lesson/vertex&fragment"{ SubShader{ pass{ CGPROGRAM #pragma vertex vert #pragma fragment frag void vert(in float2 objPos:POSITION, out float4 col:COLOR, out float4 pos:POSITION){ pos = float4(objPos,0,1); col = pos; } void frag(inout float4 col:COLOR){ // col = float4(0,1,0,1); } ENDCG } } }
物体的颜色会随着位置的变化而变化,颜色值的范围是(-0.5,-0.5,0,1)到(0.5,0.5,0,1)。