Shader 基础笔记01
Shader 基础笔记
该部分笔记对应入门精要中 1、2、3 章内容
Shader 渲染流程
在 OpenGl 中,矩阵的变换过程如下。
为了将坐标从一个坐标系变换到另一个坐标系,我们需要用到几个变换矩阵,最重要的几个分别是模型(Model)、观察(View)、投影(Projection)三个矩阵。我们的顶点坐标起始于局部空间(Local Space),在这里它称为局部坐标(Local Coordinate),它在之后会变为世界坐标(World Coordinate),观察坐标(View Coordinate),裁剪坐标(Clip Coordinate),并最后以屏幕坐标(Screen Coordinate)的形式结束。下面的这张图展示了整个流程以及各个变换过程做了什么:
- 《Render-Time Rendering,Third Edition》一书中将一个渲染流程分成三个阶段:应用阶段(Application Stage)、几何阶段(Germetry Stage),光栅化阶(Rasterizer Stage)段。
应用阶段
- 准备场景数据,如摄像机的位置、视锥体、场景中包含了哪些模型、使用了那些光源等。
- 设置模型的渲染状态包括材质、纹理、Shader等。
几何阶段
- 逐顶点,逐多边形操作。将顶点坐标变换到屏幕空间中,交给光栅器处理。
- 这一阶段将会输出屏幕空间的二维顶点坐标、每个顶点对应的深度值、着色等相关信息,并传递给下一阶段。
光栅化阶段
- 决定每个渲染图元中的哪些像素应该被绘制在屏幕上。
- 需要对上一个阶段得到的逐顶点数据进行插值,然后进行逐像素处理。
Unity 中的几种 Shader 模板
Standard Surface Shader
- 包含了一个标准光照模型的表面着色器模板
Unlit Shader
- 一个不包含光照(但包含雾效)的基本的顶点/片元着色器。
Image Effect Shader
- 实现各种屏幕后处理效果的基本模板
Compute Shader
- 特殊 Shader 类型,利用 GPU 的并行性来进行一些与常规渲染流水线无关的计算。
Unity Shader 和 材质的桥梁
- Properties 语义块 包含了一系列属性,将会出现在材质面板中,定义通常如下
1 | Properties { |
- Properties 语义块支持的属性类型
属性类型 | 默认值的定义语法 | 例子 |
---|---|---|
Int | number | _Int(“Int”,Int) = 2 |
Float | number | _Float(“Float”,Float) = 1.5 |
Range(min,max) | number | _Range(“Range”,Range(0.0,5.0)) = 3.0 |
Color | (number,number,number,number) | _Color(“Color”,Color) = (1,1,1,1) |
Vector | (number,number,number,number) | _Vector(“Vector”,Vector) = (2,3,6,1) |
2D | “defaulttexture”{} | _2D(“2D”,2D) = “”{} |
Cube | “defaulttexture”{} | _Cube(“Cube”,Cube) = “White”{} |
3D | “defaulttexture”{} | _3D(“3D”,3D) = “black”{} |
- 可以在 CG 片段中定义和属性类型相匹配的变量,即使不在 Properties 语义块中声明这些属性。
因此在语义块中定义属性的意义在于让这些属性出现在材质面板中。
SubShader 的 构成
- SubShader 的语义块结构如下
1 | SubShader { |
RenderSetup 状态设置
- 常见的渲染状态设置选项
状态名称 | 设置指令 | 解释 |
---|---|---|
Cull | Cull Back / Front / Off | 设置剔除模式:剔除背面/正面/关闭剔除 |
ZTest | ZTest Less Greater / LEqual / GEqual / Equal / NotEqual / Always | 设置深度测试时使用的函数 |
ZWrite | ZWrite On / Off | 开启 / 关闭 深度写入 |
Blend | Blend SrcFactor DstFactor | 开启并设置混合模式 |
Tags 标签
SubShader 中的标签设置是特定的,和 Pass 中使用的标签是不一样的。 (标签设置[Tags])
状态设置 [RenderSetup] SubShader 和 Pass 是一样的, SubShader 的设置会应用于所有的 Pass。[Tags] 是一个键值对,结构如下
1 | Tags { "TagName1" = "Value1" "TagName2" = "Value2" } |
SubShader 的标签类型
标签类型 | 说明 | 例子 |
---|---|---|
Queue | 控制渲染顺序,指定该物体属于哪一个渲染队列 | Tags {“Queue” = “Transparent” } |
RenderTYpe | 对着色器进行分类 | Tags {“RenderType” = “Opaque”} |
DisableBatching | 是否使用批处理 | Tags {“DisableBatching” = “True”} |
ForceNoShadowCasting | 是否会投射阴影 | Tags {“ForceNoShadowCasting” = “True”} |
IgnoreProjector | 是否受 Projector 的影响 | Tags {“OgnoreProjector” = “True”} |
CanUseSpriteAltas | 是否用于 Sprite | Tags {“CanUseSpriteAltas” = “False”} |
PreviewType | 指明材质面板如何预览该材质 | Tags {“PreviewType” = “Plane”} |
Pass 相关
Pass 语义块 结构如下
1 | Pass{ |
可以通过 ShaderLab 的 UsePass 命令来直接使用其他 Unity Shader 中的 Pass。
1 | UsePass "MyShader/MYPASSNAME" |
Pass 的标签类型
标签类型 | 说明 | 例子 |
---|---|---|
LightMode | 定义该 Pass 在 Unity 的渲染流水线中的角色 | Tags {“LightMode” = “ForwardBase”} |
RequireOptions | 用于指定当满足某些条件时才渲染该 Pass 的 | Tags {“RequireOptions” = “SoftVegtation”} |
Unity 内部会把所有 Pass 的名称转换成大写字母,因此在使用 UsePass 命令时必须使用大写形式的名字。
特殊 Pass:
UsePass:可以使用该命令来复用其他 Unity Shader 中的 Pass。
GrabPass: 该 Pass 负责抓取屏幕并将结果存储在一张纹理中,以用于后续的 Pass 处理。
Fallback:如果上面所有的 SubShader 都不能运行,那么就执行此语句。
1 | Fallback "name" |
Fallback 还会影响阴影的投射。在渲染阴影纹理时,Unity 会在每个 Unity Shader 中寻找一个阴影投射的
Pass。一般我们不需要自己专门实现 Pass,Fallback 会使用内置 Shader 一个通用的 Pass。
SV_POSITION 的含义
1 | float4 vert(float4 v : POSITION) : SV_POSITION{ |
POSITION 表示将模型的顶点坐标填充到输入参数 v 中,SV_POSITION 表示 顶点着色器的输出是裁剪空间中的顶点坐标。
SV_Target 的含义
1 | fixed4 frag() :SV_Target{ |
SV_Target 表示把用户的输出颜色存储到一个渲染目标,这里将输出到默认的帧缓存中。
结构体的语义
1 | //输入数据 |