引子
Shader 简单介绍
主要讲一些概念的东西,和基本构造,是基础知识
动机
如果你是刚刚接触Shader编程的新手,你可能不知道从何开始踏出Shader编程的第一步。本教程将带你一步步完成一个表面着色器(Surface Shader)和片段着色器(Fragment Shader)。本教程也将介绍在Unity3D Shader编程中所使用的一些函数和变量,这些内容可能和你在网上看到的不一样哦!
如果你满足下面的条件,我觉得你应该看看这篇文章:
- 如果你是shader编程的新手。
- 你想在你的游戏中使用shader做一些很炫酷的效果,但是你在网上找不到可用的Shader(译者注:o(╯□╰)o自己动手丰衣足食)。
- 由于缺乏对基础知识的了解,造成不能随心所欲使用Strumpy着色器编辑器(译者注:Strumpy Shader Editor,一种图形化编写shader的方式,看着很诱人!)。
- 你想在你的Shader代码中手动处理纹理(Textures)
本文是该系列教程的第一篇文章,随后我们会制作一些更复杂的shader。相比起来,第一篇文章确实很简单。
Unity3D Shader有以下几种
1. 表面着色器(Surface Shader)
后台自动为你做的绝大部分的工作,减少了你工作量,并且适合绝大多数需要shader的情况。
2. 片段着色器(Fragment Shader)
可以让你做更多的效果,但是此shader更难写。你也可以用它做一些底层的工作,比如顶点光照(Vertex lighting,即在每个顶点存储该点的光照信息)。顶点光照对于移动设备很有用(译者注:估计省内存吧)。该shader对于一些需要多通道(multiple passes)的高级渲染效果也很有效。也可以称 CG Shader
3. Gpu 编程(Compute Shader)
是在GPU运行却又在普通渲染管线之外的程序。用于运行GPGPU program。
一个自动生成的 Surface Shader
这是使用Unity 新建SurfaceShader 自动生成的
1 | Shader "Custom/NewSurfaceShader" { |
- Properties 代表的是属性值定义
- SubShader Unity中的每一个着色器都包含一个subshader的列表 当Unity需要显示一个网格时,它能发现使用的着色器,并提取第一个能运行在当前用户的显示卡上的子着色器。
- FallBack 如果不可用则回调
Properties 介绍
1 | // properties for a water shader |
SubShader 介绍
一、SubShader Tags
Subshaders使用标签来告诉引擎如何以及何时将其渲染。
语法:
1 | Tags { "TagName1" = "Value1" "TagName2" = "Value2" } |
指定TagName1具有Value1的值,TagName2具有Value2的值。标签的数目不受限制。
1. Queue 标签。
定义渲染顺序
QueueTag | Value | 说明 |
---|---|---|
Background | 1000 | 比如用于天空盒。 |
Geometry | 2000 | 大部分物体在这个队列。不透明的物体也在这里。这个队列内部的物体的渲染顺序会有进一步的优化(应该是从近到远,early-z test可以剔除不需经过FS处理的片元)。其他队列的物体都是按空间位置的从远到近进行渲染。 |
AlphaTest | 2450 | 已进行AlphaTest的物体在这个队列。 |
Transparent | 3000 | 透明物体。 |
Overlay | 4000 | 比如镜头光晕。 |
自定义 | Geometry+10 |
2. RenderType 标签。
Unity可以运行时替换符合特定RenderType的所有Shader。Camera.RenderWithShader或者Camera.SetReplacementShader配合使用。
RenderTypeTag | 说明 |
---|---|
Opaque | 绝大部分不透明的物体都使用这个 |
Transparent | 绝大部分透明的物体、包括粒子特效都使用这个 |
TransparentCutout | 蒙皮透明着色器masked transparency shaders (Transparent Cutout,两个通道的植被着色器) |
Background | 天空盒都使用这个 |
Overlay | GUI、镜头光晕都使用这个 闪光着色器。 |
TreeOpaque | 地形引擎中的树皮。 |
TreeTransparentCutout | terrain engine tree leaves |
TreeBillboard | terrain engine billboarded trees. Grass: terrain |
GrassBillboard | terrain engine billboarded grass. |
自定义 | 参考Rendering with Replaced Shaders |
3. ForceNoShadowCasting
值为true时,表示不接受阴影。
4. IgnoreProjector
值为true时,表示不接受Projector组件的投影。
5. DisableBatching tag
禁用批处理
DisableBatchingTag | 说明 |
---|---|
True | 始终禁用此着色器的批处理 |
False | 不禁用批处理;这是默认值 |
LODFading | 当LOD衰减活动时禁用批处理;主要用于树 |
6. CanUseSpriteAtlas
可以使用Sprite图集
如果shader用于sprite,则将CanUseSpriteAtlas标记设置为“False”,并且当它们打包到地图集时不会工作(请参阅Sprite Packer)。
7. PreviewType
预览类型
PreviewType指示material inspector预览应如何显示材质。 默认情况下,材质显示为球体,但PreviewType也可以设置为“Plane”(显示为2D)或“Skybox”(将显示为天空盒)。
二、Pass的Tag
最重要Tag是 LightMode,指定 Pass 和 Unity 的哪一种渲染路径( Rendering Path )搭配使用。除最重要的ForwardBase、ForwardAdd外,这里需额外提醒的Tag取值可包括:
LightModeTag | 说明 |
---|---|
ForwardBase | XXX |
ForwardAdd | XXX |
Always | 永远都渲染,但不处理光照 |
ShadowCaster | 用于渲染产生阴影的物体 |
ShadowCollector | 用于收集物体阴影到屏幕坐标Buff里 |
三、Shader LOD
- 这个是另外一种控制细节级别的技术
- 在一个Shader当中,可以给不同的subshader指定不同的LOD属性,例如:
1 | SubShader { |
说明: Shader LOD 就是让我们设置一个数值,这个数值决定了我们能用什么样的Shader。可以通过Shader.maximumLOD或者Shader.globalMaximumLOD 设定允许的最大LOD,当设定的LOD小于SubShader所指定的LOD时,这个SubShader将不可用。通过LOD,我们就可以为某个材质写一组SubShader,指定不同的LOD,LOD越大则渲染效果越好,当然对硬件的要求也可能越高,然后根据不同的终端硬件配置来设置 globalMaximumLOD来达到兼顾性能的最佳显示效果。
四、CG程序
解释
1. CGPROGRAM和ENDCG之间存放的就是CG程序。
2. 预编译头:#pragma surface surf Standard fullforwardshadows
surface表示这是一个Surface Shader,surf表示表面函数的名字,Standard表示使用Standard的光照模型,fullforwardshadows是阴影类型
3. 预编译头:#pragma target 3.0
Shader model的版本,用来获取更好的光照效果
4. 剩余的就是如何操作surf函数
这里只是简单的进行赋值,因此会困惑人的地方就是CG语法了,CG可以参考The Cg Tutorial
关于光照模型的代码
可以在
Unity/Editor/Data/CGIncludes/UnityPBSLighting.cginc
Unity/Editor/Data/CGIncludes/Lighting.cginc
下找到很多光照模型的代码
函数前缀是Lighting的
例如下面这种
1 | inline half4 LightingStandard (SurfaceOutputStandard s, half3 viewDir, UnityGI gi) |
surf 函数的输出结果 是 SurfaceOutputStandard 类型
LightingStandard 函数输入参数为 SurfaceOutputStandard 类型
所以要注意你选择的 关照模型需要 那些参数,对哪些参数做出修改会比较好
更多学习点
- 理解下关照算法
- 阴影类型怎么运作的