UnityShader学习之旅 二

  1. 什么是Shader

    即着色器, 仅仅是渲染流水线中的一个环节
    1.GPU流水线上一些可高度编程的阶段,而由着色器编译的代码可以在GPU上运行
    2.有一些特定类型的着色器。eg:顶点、片元着色器
    3.依靠着色器我们可以控制流水线中的渲染细节

  2. 什么是渲染流水线

    定义: 是显示芯片内部处理图形信号相互独立的的并行处理单元
    工作任务: 计算机需要从一系列的顶点数据、纹理等信息出发,把这些信息转换成一张人脸可以看到的图像。由CPU、GPU共同完成。
    三个阶段: 应用阶段、几何阶段、光栅化阶段UnityShader学习之旅 二_第1张图片

阶段 实现 任务 输出
应用阶段 CPU负责实现 1.把数据加载到显存中1
2设置渲染状态2
3.调用DrawCall3
渲染所需的几何信息
渲染图元
几何阶段 GPU
处理所有与绘制的几何相关的事情
1.把顶点坐标变换到屏幕空间
2.交给光栅化器进行处理
进行逐顶点、逐多边形操作
屏幕空间的二维顶点坐标、每个顶点对应的深度值、着色等信息
光栅化阶段 GPU 决定每个渲染图元的哪些像素应该被绘制在屏幕上 渲染最终的图像

3.GPU流水线:GPU渲染的过程UnityShader学习之旅 二_第2张图片

流水线阶段 定义 输入 输出 特点 任务
顶点数据 由应用阶段加载到显存中,由Draw Call指定 传递给Vertex shader
顶点着色器 实现顶点的空间变换、顶点着色 CPU 后续阶段所需的数据 顶点之间相互独立 坐标变换、逐顶点光照
曲面细分着色器 4 用于细分图元 pach的顶点数量 曲面更加平滑细密 改变顶点与三角网格的数量–>插入新的顶点
几何着色器5 逐图元的着色、产生更多图元 一系列顶点组成的图元 顶点–数量发生变换 能够在GPU上创建数据 根据运行环境产生合适分辨率的图形
裁剪 图元 图元 将不在摄像机视野内的顶点裁剪,并剔除某些三角图元的面片
屏幕映射 三维坐标转换到二维坐标(x,y) 坐标:三维 坐标:二维 决定了顶点对应屏幕上哪个像素、距离 把每个图元的x,y坐标转换到屏幕坐标系下
三角形设置 计算三角网格表示数据的过程 三角网格每条边的两端点 边界像素的坐标信息 计算光栅化一个三角网格所需的信息
三角形遍历 找到哪些像素被三角网格覆盖的过程 上个阶段的计算结果 得到一个片元序列6 对覆盖区域的像素进行插值 检查每个像素是否被一个三角网格所覆盖
片元着色器 顶点信息插值的结果 一个或多个颜色值 仅影响单个片元 完成渲染技术7、效果
逐片元操作 片元 颜色缓冲区 对像素产生影响 经过测试8,决定每个片元的可见性问题
屏幕图像

4.什么是Shader Lab?

Unity Shader 是Unity为开发者提供的高层级的渲染抽象层。ShaderLab 是Unity提供的编写Unity Shader的一种说明性语言。用语义来描述文件的结构,包含了渲染所需的数据。UnityShader学习之旅 二_第3张图片

5.Unity Shader的结构
Properties语义块的作用仅仅是为了让这些属性可以出现在材质面板中。
Unity Shader文件可以包含多个SubShader,但至少要有一个。

Unity会自动选择第一个能够在目标平台上运行的subshader,如果不支持则会使用Fallback指定的UnityShader

Shader "Name"    //UnityShader的名字 也是索引的路径 可在Name中添加(‘/’)控制面板中出现的位置
{
	Properties	//包含了一系列的属性 名字
	{
		//声明一个Color类型的属性
 	 	_Color("Color Tint", Color) = (1.0,1.0,1.0,1.0) //白色
 	 	/*属性名字:下划线开始. 某些有特殊要求。 eg:_Color
 	 	 显示的名称:在材质面板上可以看到名字--随便取:eg:Color Tint
 	 	 类型:属性指定的类型。eg:Color
 	 	 默认值:属性对应的默认值,第一次把shader赋给某个材质时,在材质面板上显示的默认值。eg:(1.0,1.0,1.0,1.0) 
 	 	*/
	}
	SubShader
	{
		Tags{} //标签 可选 -- 也可在pass中设定
		[RenderSetup] //状态可选
		//至少要有一个pass
		UsePass "ShaderLearn/Chapter12/GuassianShader/GAUSSIAN_BLUR_VERTICAL" //复用其他Pass
    		GrabPass {//抓取屏幕并将结果存储到一张纹理中,用于后续Pass处理
		"_RefractionTex"
		}
		Pass{ //渲染通道必须要有一个,一个Pass占一个CG,过多会造成渲染性能下降
		  [Name] //Pass名称 大写。通过名称其他的Shader可以调用该Pass
		  Tags{}
		  [RenderSetup]	
		}
	}
	Fallback "name" / Fallback Off //若以上SubShader在该显卡上不能运行执行name /关闭Fallback	
}
属性类型 默认值的定义语法 属性 例子 CG变量类型9
Int number 数字 _Int(“Int”, Int) = 2
Float10 number 数字 _Float(“Float”, Float) = 2 float,half,fixed
Range(min,max) number 数字 _Range(“Range”, Range(0,1)) = 0.5 float,half,fixed
Color (number,number,number,number) 四维向量 _Color(“Color Tint”, Color) = (1.0,1.0,1.0,1.0) float4,half4,fixed4
Vector (number,number,number,number) 四维向量 _Vector(“Vector”, Vector) = (1.0,1.0,1.0,1.0) float4,half4,fixed4
2D “defauttexture”{} 纹理类型11 _2D(“2D”, 2D) = “white”{} sampler2D
Cube “defauttexture”{} 纹理类型 _Cube(“Cube”, Cube) = “white”{} samplerCube
3D “defauttexture”{} 纹理类型 _3D(“3D”, 3D) = “black”{} sampler3D
bump 内置的法线纹理 对应了模型自带的法线信息

【Tags】SubShader标签
subshader的标签是一个键值对(Key - Value)

标签类型 说明 例子
Queue 控制渲染顺序,指定该物体属于哪一个渲染队列。
可以保证所有透明物体后渲染
Tags{“Queue” = “Transparent”}
RenderType 对着色器分类 Tags{“RenderType” = “Opaque”}
DisableBatching 是否对该SubShader使用批处理 Tags{“DisableBatching” = “True”}
ForceNoShadowCasting 控制使用该SubShader的物体是否会投射阴影 Tags{“ForceNoShadowCasting” = “True”}
IgnoreProjector 为True是,该SubShader不会受Projector的影响,用于半透明物体 Tags{“IgnoreProjector” = “True”}
CanUseSpriteAtlas 该SubShader用于Sprite时,设置为False Tags{“CanUseSpriteAtlas” = “False”}
PreviewType 材质面板预览材质,可设置为plane、skybox等 Tags{“PreviewType” = “Plane”}

—>以上标签只适用与SubShader

  • 渲染队列
渲染队列 队列索引号 描述 适用 例子
Background 1000 第一个被渲染的优先于其他队列 渲染那些需要绘制在背景上的物体
天空盒子
Tags{“Queue” = “Background”}
Geometry 2000 默认的渲染队列 不透明物体 Tags{“Queue” = “Geometry”}
AlphaTest 2450 所有不透明物体渲染之后再渲染它们会更加高效 需要透明度测试的物体 Tags{“Queue” = “AlphaTest”}
Transparent 3000 在Geometry与AlphaTest之后,再按从后往前的顺序进行渲染 使用了透明度混合的物体、关闭深度写入的Shader Tags{“Queue” = “Transparent”} Pass{ZWrite Off}
Overlay 4000 实现叠加效果 任何需要在最后渲染的物体 Tags{“Queue” = “Overlay”}

【Tags】Pass标签

标签类型 说明 例子
LightMode 定义该Pass渲染路径 Tags{"LightMode " = “ForwardBase”}
RequireOptions 满足某些条件才渲染该Pass。SoftVegetation Tags{“RequireOptions” = “SoftVegetation”}

SoftVegetation: Render this pass only if Soft Vegetation is on in the Quality window.

【LightMode 支持的渲染路径】

标签 描述 限制
Always 无论哪种渲染路径,该Pass总会被渲染,但不计算任何光照
ForwardBase 计算环境光、最重要的平行光、逐顶点/SH光源、Lightmaps 前向渲染
ForwardAdd 计算额外的逐像素光源,每个Pass对应一个光源 前向渲染
Deferred 渲染G缓冲 延迟渲染
ShadowCaster 把物体的深度信息渲染到阴影映射纹理或一张深度纹理中
PrepassBase 渲染法线和高光反射的指数部分 遗留的延迟渲染
PrepassFinal 合并纹理、光照和自发光来渲染得到最后的颜色 遗留的延迟渲染
Vertex、VertexLMRGBM、VertexLM 遗留的顶点照模渲染

【渲染状态】

状态名称 设置指令 解释
Cull Cull Back/Front/Off 设置剔除模式;剔除背面/正面/关闭
只渲染前面/后面/全都渲染
ZTest ZTest Less Greater/LEqual/GEqual/Equal/NotEqual/Always 设置深度测试时使用的函数
ZWrite ZWrite On/Off 开启/关闭深度写入
Blend Blend SrcFactor DstFactor 开启并设置混合模式
Offset Offset OffsetFactor, OffsetUnits 设置Z缓冲区深度偏移
ColorMask ColorMask RGB /A / 0/ any combination of R, G, B, A 设置颜色通道蒙版,0关闭颜色通道的渲染

6.Unity Shader的形式

Create 特点 劣势 例子
表面着色器 Surface Shader 包含标准光照 代码量少 渲染代价大 #pragma surface surf lambert
顶点/片元着色器 Unit Shader 无光照 灵活性高,可控制渲染的实现细节 复杂 #pragma vertex vert
#pragma fragment frag
标准着色器 Standard Shader 表面的升级版,PBR技术
后期屏幕渲染特效 Image Effect Shader 屏幕后处理效果 Graphics.Blit(scr,RT1,mat) ZWrite Off ZTest Always
计算着色器12 Compute Shader 大量数学计算 传输速率慢
CPU->GPU->CPU->GPU
#pragma kernel CSMain
固定函数 已被抛弃

7.坐标空间–顶点变换

定义 原点 坐标 顶点变换 维数
模型空间 与某个模型或者对象有关 模型的重心 顶点着色器访问到的顶点坐标 三维空间
世界空间 最大最外层的坐标系 游戏空间的中心 模型的位置若无父节点,则为世界坐标 模型变换
摄像机/观察空间 渲染游戏所使用的视角 摄像机位于原点 观察变换
齐次裁剪空间 能够方便地对渲染图元进行裁剪13 裁剪/投影矩阵14 四维空间
屏幕空间 显示的屏幕 屏幕左下角 归一化的设备坐标NDC 屏幕映射 二维空间
切线空间 二维空间

7.法线变换

8.Unity Shader的内置变量
1.变换矩阵

变量名 描述 矩阵 曾用名 用法
UnityObjectToClipPos 将顶点从模型空间->裁剪空间 模型 . 观察 . 投影矩阵 mul(UNITY_MATRIX_MVP,*) UnityObjectToClipPos(*)
UNITY_MAXTRIX_MV 将顶点从模型空间->观察空间 模型 . 观察 UNITY_MAXTRIX_MV
UNITY_MAXTRIX_V 将顶点从世界空间->观察空间 观察矩阵 UNITY_MAXTRIX_V
UNITY_MAXTRIX_P 将顶点从观察空间->裁剪空间 投影矩阵 UNITY_MAXTRIX_P
UNITY_MAXTRIX_VP 将顶点从观察空间->裁剪空间 观察 . 投影矩阵 UNITY_MAXTRIX_VP
UNITY_MAXTRIX_T_MV UNITY_MAXTRIX_MV的转置 UNITY_MAXTRIX_T_MV
UNITY_MAXTRIX_T_MV 法线从模型空间->观察空间 UNITY_MAXTRIX_MV的逆转置 UNITY_MAXTRIX_T_MV
unity_ObjectToWorld 顶点从模型空间->世界空间 模型矩阵 _Object2World
unityWorldToObject 顶点从世界空间->模型空间 _Object2World 的逆矩阵 _World2Object

2.Unity内置的摄像机和屏幕参数

变量名 类型 描述 曾用名 解析 用法
_WorldSpaceCameraPos float3 该摄像机在世界空间中的位置
_ProjectionParams float4 x=1.0/-1,y=Near,z=Far,w=1+1/Far Near:近裁剪平面
Far:远裁剪平面
_ScreenParams float4 x=width,y=height,z=1+1/width,w=1+1/height width:摄像机的渲染目标的像素宽度
Height:摄像机的渲染目标的像素高度
_ZBufferParams float4 x=1-Far/Near,y=Far/Near,z=x/Far,w=y/Far 用于线性化Z缓存中的深度值
unity_OrthoParams float4 x=width,y=heght,z无定义,w=1(正交)/0(透视) width:正交投影摄像机的宽度
height::正交投影摄像机的高度
unity_CameraProjection float4x4 摄像机的投影矩阵
unity_CameraInvProjection float4x4 摄像机的投影矩阵的逆矩阵
unity_CameraWorldClipPlanes[6] float4 摄像机的6个裁剪平面在世界空间下的等式顺序:左右下上近远裁剪平面

3.Unity 内置包含文件unity的安装路径下CGIncludes

文件名 描述
UnityCG.cginc 包含了最常使用的帮助函数、宏和结构体等
UnityShaderVariables.cginc 在编译UnityShader时自动包含。内置的全局变量ps:UNITY_MAXTIX_MVP(UnityObjectToClipPos) 访问事件、光照、雾化和环境光
Lighting.cginc 包含了各种内置的光照模型,surface shader 会自动包含
HLSLSupport.cginc 在编译UnityShader时自动包含。声明了很多跨平台编译的宏和定义
UnityStandardBRDF.cginc 实现基于物理的渲染
UnityStandardCore.cginc

4.UnityCG.cgin中一些常用的结构体

名称 描述 包含的变量 结构体
appdata_base 用于顶点着色器的输入 顶点位置、顶点法线、第一组纹理坐标 struct appdata_base {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID};
appdata_tan 用于顶点着色器的输入 顶点位置、顶点切线、顶点法线、第一组纹理坐标 struct appdata_tan {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID};
appdata_full 用于顶点着色器的输入 顶点位置、顶点切线、顶点法线、多组纹理坐标、顶点颜色 struct appdata_full {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
float4 texcoord1 : TEXCOORD1;
float4 texcoord2 : TEXCOORD2;
float4 texcoord3 : TEXCOORD3;
fixed4 color : COLOR;
UNITY_VERTEX_INPUT_INSTANCE_ID};
appdata_img 用于顶点着色器的输入 顶点位置、第一组纹理坐标 struct appdata_img{
float4 vertex : POSITION;
half2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID};
v2f_img 用于顶点着色器的输出 裁剪空间中的位置、纹理坐标 struct v2f_img{
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO};

5.UnityCG.cginc中一些常用的帮助函数

函数名 描述 限制 实现
float3 UnityWorldSpaceViewDir(float3 worldPos) 输入一个模型空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向 return _WorldSpaceCameraPos.xyz - worldPos;
float3 ObjSpaceViewDir(float4 v) 输入一个模型空间中的顶点位置,返回模型空间中从该点到摄像机的观察方向 float3 objSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1)).xyz;
return objSpaceCameraPos - v.xyz;
float3 UnityWorldSpaceLightDir(float3 worldPos)
WorldSpaceLightDir(float4 vertex)
输入一个模型空间中的顶点位置,返回世界空间中从该点到光源的光照方向 前向渲染 return _WorldSpaceLightPos0.xyz - worldPos * _WorldSpaceLightPos0.w;
float3 ObjSpaceLightDir(float4 v) 输入一个模型空间中的顶点位置,返回模型空间中从该点到光源的光照方向 前向渲染 float3 objSpaceLightPos = mul(unity_WorldToObject, _WorldSpaceLightPos0).xyz;
return objSpaceLightPos.xyz - v.xyz * _WorldSpaceLightPos0.w;
float3 UnityObjectToWorldNormal(float3 normal) 把法线方向从模型空间转换到世界空间中 return normalize(mul(norm, (float3x3)unity_WorldToObject));
float3 UnityObjectToWorldDir(float3 dir) 把方向矢量从模型空间转换到世界空间中 return normalize(mul((float3x3)unity_ObjectToWorld, dir));
float3 UnityWorldToObjectDir(float3 dir) 把方向矢量从世界空间转换到模型空间中 return normalize(mul((float3x3)unity_WorldToObject, dir));
float3 Shade4PointLights(…) 计算4个点光源的光照。前向使用这个函数计算逐顶点光照 前向渲染

9.渲染路径

决定了光照是如何应用到UnityShader中。一般一个项目只使用一种渲染路径,如果使用多条渲染路径,需要在摄像机下设置以覆盖Project Setting中的设置。

渲染路径 原理 处理光照方式15 判断规则 Pass 缺陷
前向渲染路径 1.渲染该对象的渲染图元
2.计算两个缓冲区的信息:颜色缓冲区,深度缓冲区
逐顶点
逐像素
球谐函数SH
1.最亮的平行光–逐像素处理
2.渲染模式为Not Important–逐顶点/SH处理
3.渲染模式为Important–逐像素
4.以上小于设定的值更多光源按逐像素方式
1.Base Pass
2.Additional Pass
有大量实时光源时,渲染性能降低
延迟渲染路径 1.仅计算哪些片元是可见的–信息存储到G缓冲区
2.利用G缓冲中片元信息–计算真正的光照
逐像素 与光源的数目无关,与屏幕空间的大小有关 1.渲染G缓冲
2.计算真正的光照模型
1.不支持真正的抗锯齿
2.不能处理半透明
3.对显卡有要求
顶点照模渲染路径 已废弃

1.前向渲染的两种Pass

实现光照效果 渲染设置 光照计算 执行次数
Base Pass 光照纹理、自发光、环境光、阴影 Tags{“LightMode”=“ForwardBase”}
#pragma multi_compile_fwdbase}
一个逐像素的平行光以及所有逐顶点和SH光源 一次
Additional Pass 默认不支持阴影可用命令开启
#pragma multi_compile_fwdadd_fulls_shadows
Tags{“LightMode”=“ForwardAdd”}
Blend One One
#pragma multi_compile_fwdadd
其他影响该物体的逐像素每个光源执行一次Pass 多次

2.内置光照变量

名称 类型 描述 渲染路径使用 Pass限制
_LightColor0 float4 该Pass处理的逐像素光源的颜色 前向
_WorldSpaceLightPos0 float4 xyz分量是处理的逐像素光源的位置
平行光 w==0,其他光源w == 1
前向、延迟
_LightMatrix0 float4x4 从世界空间到光源空间的变换矩阵,可用于采样cookie和光强衰减纹理 前向
unity_4LightPosX0、unity_4LightPosY0、unity_4LightPosZ0 float4 前4个非重要的点光源在世界空间中的位置 前向 Base Pass
unity_4LightAtten0 float4 前4个非重要的点光源的衰减因子 前向 Base Pass
unity_LightColor half4[4] 前4个非重要的点光源的颜色 前向 Base Pass
_LightColor float4 光源颜色 延迟

3.渲染纹理
UnityShader 入门精要 作者github
彩图

4.Unity内置的时间变量

名称 类型 描述 分量
_Time float4 t是自该场景加载开始所经过的时间 (t/20,t,2t,3t)
_SinTime float4 t是时间的正弦值 (t/8,t/4,t/2,t)
_CosTime float4 t是时间的余弦值 (t/8,t/4,t/2,t)
unity_DeltaTime float4 dt是时间增量 (dt,1/dt,smoothDt,1/smoothDt)

  1. 1.所有渲染需要的数据都要从硬盘中加载到系统内存中。
    2.网格和纹理等数据又被加载到显卡的存储空间–显存中 <== 显卡对于显存的访问速度更快。
    3.某些不需要的数据可以从RAM中移除 <==硬盘加载到RAM的过程耗时。 ↩︎

  2. 定义了场景中的网格是怎么被渲染的。eg:使用哪个顶点着色器/片元着色器、光源属性、材质等
    如果没有更改渲染状态,所有的网格都将使用同一种渲染状态。
    UnityShader学习之旅 二_第4张图片 ↩︎

  3. DrawCall 就是一个命令。它的发起方:CPU,接收方:GPU。这个命令仅仅会指向一个需要被渲染的图元列表,而不会包含任何材质信息。 ↩︎

  4. 细分着色器介绍 ↩︎

  5. 几何着色器介绍 ↩︎

  6. 片元并不是真正意义上的像素,而是包含了许多状态的集合。状态包括:它的屏幕坐标、深度信息,以及其他从几何阶段输出的顶点信息,法线、纹理坐标等。 ↩︎

  7. 纹理采样:
    1.在顶点着色器阶段输出每个顶点对应的纹理坐标
    2.经过光栅化阶段对三角网格的3个顶点对应的纹理坐标进行插值
    3.得到其覆盖的片元纹理坐标。 ↩︎

  8. 主要任务:1.决定每个片元的可见性
    2.若一个片元通过了所有的测试,就需要把这个片元的颜色值与已经在缓冲区的颜色进行合并。
    UnityShader学习之旅 二_第5张图片
    模板测试:UnityShader学习之旅 二_第6张图片
    UnityShader学习之旅 二_第7张图片 ↩︎

  9. CG代码块中访问属性 。uniform关键字:CG中修饰变量和参数的一种修饰,仅仅用于提供关于该变量的初始值是如何指定和存储相关信息。 ↩︎

  10. ↩︎
  11. 内置的纹理名称:white、black、gray、bump等。花括号 原本是用于指定一些纹理属性。后来被移除了。 ↩︎

  12. Compute Shader ↩︎

  13. 视锥体决定了哪些部分剔除,裁剪。
    视锥体是空间中的一块区域六面体组成的裁剪平面,决定了摄像机能看到的空间。两种类型:
    正交投影 :所有网格大小都一样,保持了物体的距离和角度 |视锥体为长方体型
    透视投影:模拟人眼看世界的方式 |视锥体为金字塔型 ↩︎

  14. 投影矩阵的目的:1.为投影做准备。2.对x、y、z分量进行缩放 ↩︎

  15. 决定一个光源使用哪种处理模式取决于它的类型和渲染模型。
    光源类型:该光源是平行光还是其他类型的光源
    光源的渲染模式:该光源是否是重要的(Important or Not Important) ↩︎

你可能感兴趣的:(UnityShader,shader)