原文 https://zhuanlan.zhihu.com/p/49165180
大白话渲染管线
图形渲染管线之所以被叫做管线,就是因为它和一根管子的概念很像,我们可以理解为这根管子的末端连接的是我们最终的显示屏幕,管子的起始端连接的是我们的原始素材。
把我们想展示在屏幕上的素材从起始端放入,然后素材通过管子经过一系列操作最终展示在屏幕上。
而我们如果想加工一下素材最后的显示效果就可以在这根管子中做一些特殊的操作处理,以使素材经过我们所自定义的操作使其最终达到我们想要的效果。
这根管子从头到尾大致流程可以分为以下三个大阶段(概念上):
- 应用程序阶段(The Application Stage)
就是我们的原始素材准备阶段,包括我们的模型、贴图、相机和光源等,经过这个阶段会将所有素材转换成渲染图元并提交到下一阶段中(几何阶段)。
- 几何阶段(The Geometry Stage)
主要是对上一阶段中传过来的数据进行顶点上的加工处理,包括各种矩阵转换与顶点着色等,最终处理完后会输出屏幕空间的二维顶点坐标、顶点着色等信息,并再提交到下一阶段(光栅化阶段)。
- 光栅化阶段(The Rasterizer Stage)
经过几何阶段处理完后输送到光栅化阶段,从像素级别上对每个像素进行加工处理,最终显示于屏幕上。
- 这里仅仅只是以较通俗的说法来描述渲染管线,如果想了解更详细的内容可以查阅相关图形学书籍,推荐《OpenGL超级宝典》、《Render-Time Rendering,Third Edition》。
使用结构体如下
- 注意,上一节我们讲的变量,也就是这里的fixed4 _Color;这条语句一定要定义在它用到的函数之前,否会报错。
虽然相较之前的版本会显示的代码多了不少,但是这样做更加灵活方便。
struct具体语法:
- 结构体的声明以关键字 struct 开始,然后紧跟结构体的名字,结构体范围由{}定义,最后以分号结尾。
- 使用“.”引用结构体中的成员变量和成员函数。
现在我们在结构体中还没有使用到多个变量,现在让我们测试下,最后输出模型的UV做为颜色信息来显示:
拓展:什么是UV?
https://blog.kokojia.com/game/b-53.html
完整代码:
Shader "Custom/UVShader"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
}
SubShader
{
pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct appdata
{
float4 vertex:POSITION;
float2 uv:TEXCOORD;
};
struct v2f
{
float4 vertex:SV_POSITION;
float2 uv:TEXCOORD;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
float4 frag(v2f i):SV_TARGET
{
return fixed4(i.uv,0,1);
}
ENDCG
}
}
FallBack "Diffuse"
}
结果如下
- 这里属性中的_Color没有使用到,先不管它。
自定义函数
有的时候我们可能需要在顶点着色器或者片断着色器中写大量的代码,这样就会使得代码不够整洁,这个时候我们就可以使用自定义函数的方式,将部分代码整合进去,使其看起来直观易懂。
比如在上面的基础上,我们想实现一个利用模型自身UV来产生棋盘格的效果(不用贴图采用,而是程序生成的方式生成棋盘格),如下:
关键代码如下:
checker是我们自己定义的函数,内部就是利用模型自身UV来生成棋盘效果的方法,返回类型为fixed,然后在frag函数中,我们直接调用得到返回值,并最终输出即可。
- 注意,这里的checker函数同样也要在其用到之前进行声明,和上面的变量声明是一样的,这一点与脚本程序代码是有所不同的,ShaderLab中要先声明再调用。
相关知识:
https://zhuanlan.zhihu.com/p/158462351
辅助理解草稿:
完整代码
Shader "Custom/ChessboardShader"
{
Properties
{
}
SubShader
{
pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct appdata
{
float4 vertex:POSITION;
float2 uv:TEXCOORD;
};
struct v2f
{
float4 vertex:SV_POSITION;
float2 uv:TEXCOORD;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed checker(float2 uv)
{
float2 repeatUV = uv*10;
float2 c = floor(repeatUV) / 2;
float checker = frac(c.x + c.y) * 2;
return checker;
}
float4 frag(v2f i):SV_TARGET
{
fixed col = checker(i.uv);
return col;
}
ENDCG
}
}
FallBack "Diffuse"
}