Shader 基础笔记

该部分笔记对应入门精要中 1、2、3 章内容

Shader 渲染流程

在 OpenGl 中,矩阵的变换过程如下

为了将坐标从一个坐标系变换到另一个坐标系,我们需要用到几个变换矩阵,最重要的几个分别是模型(Model)、观察(View)、投影(Projection)三个矩阵。我们的顶点坐标起始于局部空间(Local Space),在这里它称为局部坐标(Local Coordinate),它在之后会变为世界坐标(World Coordinate),观察坐标(View Coordinate),裁剪坐标(Clip Coordinate),并最后以屏幕坐标(Screen Coordinate)的形式结束。下面的这张图展示了整个流程以及各个变换过程做了什么:
y9O1C.png

  • 《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
2
3
4
5
Properties {
Name ("display name",PropertyType) = DefaultValue
Name ("display name",PropertyType) = DefaultValue
//更多属性
}
  • 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
2
3
4
5
6
7
8
9
10
11
12
13
SubShader {
//可选的
[Tags]

//可选的
[RenderSetup]

Pass{

}

// Other Passes
}

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
2
3
4
5
6
7
Pass{
[Name]
[Tags]
[RenderSetup]

// Other Code
}

可以通过 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
2
3
4
Fallback "name"

//关闭 Fallback 功能
Fallback Off

Fallback 还会影响阴影的投射。在渲染阴影纹理时,Unity 会在每个 Unity Shader 中寻找一个阴影投射的
Pass。一般我们不需要自己专门实现 Pass,Fallback 会使用内置 Shader 一个通用的 Pass。

SV_POSITION 的含义

1
2
3
float4 vert(float4 v : POSITION) : SV_POSITION{
return mul (UNITY_MATRIX_MVP);
}

POSITION 表示将模型的顶点坐标填充到输入参数 v 中,SV_POSITION 表示 顶点着色器的输出是裁剪空间中的顶点坐标。

SV_Target 的含义

1
2
3
fixed4 frag() :SV_Target{
return fixed(1,1,1,1);
}

SV_Target 表示把用户的输出颜色存储到一个渲染目标,这里将输出到默认的帧缓存中。

结构体的语义

1
2
3
4
5
6
7
8
9
10
//输入数据
struce a2v
{
// POSITION 语义告诉 Unity,用模型空间的顶点坐标填充 vertex 变量
float4 vertex : POSITION;
// NORMAL 语义告诉 Unity,用模型空间的法线法向填充 normal 变量
float3 normal : NORMAL;
// TEXCOORD0 语义告诉 Unity,用模型的第一套纹理坐标填充 texcoord 变量
float4 texcoord : TEXCOORD0;
}