1、Shader
1.1 什么是shader
Shader,中文翻译为着色器,其实是一种用来渲染图形的技术,我们可以通过shader编程,来自定义显卡渲染画面的算法,来达到我们想要的结果。
个人理解呢,Shader通过算法,将三维世界的物体,以我们想要的效果,通过GPU运算,渲染到屏幕,其实是一种视觉欺骗,并未改变三维物体。
1.2 Shader编程语言
Shader并不是一个统一的标准,不同的图形接口的Shader并不相同。目前主流的有三种语言:
- 基于OpenGL的OpenGL Shading Language,简称GLSL。
- 基于DirectX的High Level Shading Language,简称HLSL。
- NVIDIA公司的C for Graphic,简称Cg语言。
GLSL与HLSL分别是基于OpenGL和Direct3D的接口,两者不能混用。 而Cg语言是用于图形的C语言,这其实说明了当时设计人员的一个初衷,就是让基于图形硬件的编程变得和C语言编程一样方便,自由。
Cg语言是Microsoft和NVIDIA相互协作在标准硬件光照语言的语法和语义上达成了一致,所以,HLSL和Cg其实是同一种语言。一般来说为了跨游戏平台方便,一般学CG语言。因为Cg/HLSL有更好的跨平台性,更倾向于使用Cg/HLSL来编写Shader程序,官方的建议也是用Cg/HLSL来编写。
1.3 Shader种类
OpenGL和Direct3D都提供了三类着色器:
顶点着色器:处理每个顶点,将顶点的空间位置投影在屏幕上,即计算顶点的二维坐标。同时,它也负责顶点的深度缓冲(Z-Buffer)的计算。顶点着色器可以掌控顶点的位置、颜色和纹理坐标等属性,但无法生成新的顶点。顶点着色器的输出传递到流水线的下一步。如果有之后定义了几何着色器,则几何着色器会处理顶点着色器的输出数据,否则,光栅化器继续流水线任务。
像素着色器(Direct3D),常常又称为片断着色器(OpenGL):处理来自光栅化器的数据。光栅化器已经将多边形填满并通过流水线传送至像素着色器,后者逐像素计算颜色。像素着色器常用来处理场景光照和与之相关的效果,如凸凹纹理映射和调色。名称片断着色器似乎更为准确,因为对于着色器的调用和屏幕上像素的显示并非一一对应。举个例子,对于一个像素,片断着色器可能会被调用若干次来决定它最终的颜色,那些被遮挡的物体也会被计算,直到最后的深度缓冲才将各物体前后排序。
几何着色器:可以从多边形网格中增删顶点。它能够执行对CPU来说过于繁重的生成几何结构和增加模型细节的工作。Direct3D版本10增加了支持几何着色器的API, 成为Shader Model 4.0的组成部分。OpenGL只可通过它的一个插件来使用几何着色器。
2、Unity Shader
2.1 什么是Unity Shader
Unity Shader严格来说并不是传统上的Shader,而是Unity自身封装后的一种便于书写的Shader,又称为ShaderLab。
我们只需关心如何去这实现我们想要的效果就好了,其余的事情全部交给Unity来自动处理。因为我们在Unity中编写的Shader最终会根据不同的平台来编绎成不同的着色器语言。
2.2 Unity Shader种类
Unity中有3种Shader:
- Surface Shaders 表面着色器
- Vertex/Fragment Shaders 顶点/片断着色器
- Fixed Function Shaders 固定管线着色器
其中Fixed Function Shaders已经被淘汰,完全没有学习的必要了。
Vertex/Fragment Shader(顶点片元着色器)和OpenGL,Direct3D中的顶点着色器和片段着色器没有什么区别。顶点片段着色器比表面着色器使用更自由也更强大,当然光照需要自行处理。Unity也允许在里面编写几何着色器,一般用得不多。
Surface Shader(表面着色器)是Unity提出的一个概念,其实就是Unity对Vertex/Fragment Shader的又一层包装,以使Shader的制作方式更符合人类的思维模式,同时可以以极少的代码来完成不同的光照模型与不同平台下需要考虑的事情。编写着色器与光照的交互是复杂的,光源有很多类型,不同的阴影选项,不同的渲染路径(正向和延时渲染),表面着色器将这一部分简化。Unity建议使用表面着色器来编写和光照有关的Shader。
但是Surface Shader也有它的局限性,就是Vertex/Fragment Shader能实现的效果,Surface Shader不一定能实现,反过来则成立,Surface Shader能实现的Vertex/Fragment Shader则一定可以实现。
2.3 Unity Shader程序结构
2.3.1 语法
Shader语法:
Shader "name" { [Properties] Subshaders [Fallback] [CustomEditor] }
Properties 语法:
Properties { Property [Property ...] }
Subshader 语法:
Subshader { [Tags] [CommonState] Passdef [Passdef ...] }
Pass 语法:
Pass { [Name and Tags] [RenderSetup] }
Fallback 语法:
Fallback "name"
2.3.2 结构简介
(1)Property Definition(属性定义):定义Shader的输入,这些输入可以在材质编辑的时候指定。
(2)SubShader(子着色器):一个Shader可以有多个子着色器,这些子着色器互不相干且只有一个会在最终的平台运行,编写多个的目的是解决兼容性问题,Unity会自己选择兼容终端平台的Shader运行。
(3)Fallback(回滚):如果子着色器在终端平台上都无法运行,那么使用Fallback指定的备用Shader,俗称备胎。
(4)Pass:一个Pass就是一次绘制。对于表面着色器,只能有一个Pass,所以不存在Pass节。顶点片段着色器可以有多个Pass。多次Pass可以实现很多特殊效果,例如当人物被环境遮挡时还可以看到人物轮廓就可以用多Pass来实现。
(5)Cg代码:每个Pass中都可以包含自定义的Cg代码,从CGPROGRAM开始到ENDCG结束。