第三章 Unity Shader基础
1.Unity Shader概述1.1 一对好兄弟:材质和Unity Shader
unity中需要配合使用材质(Material)和Unity Shader才能达到需要的效果。一个常见的流程是:
(1)创建一个材质;
(2)创建一个Unity Shader,并把它赋给上一步创建的材质;
(3)把材质赋给要渲染的对象;
(4)在材质面板中调整Unity Shader的属性,以得到满意的效果。
Unity Shader定义了渲染所需的各种代码(如顶点着色器和片元着色器)、属性(如使用哪些纹理)和指令(渲染和标签设置等),而材质则允许我们调节这些属性,并将其最终赋值给相应的模型。
1.2 Unity中的材质
要在 Unity 中绘制某物,必须提供描述其形状的信息以及描述其表面外观的信息。使用网格(Mesh)可描述形状,使用材质(Material)可描述表面的外观。材质包含着Shader对象。
1.3 Unity中的Shader
着色器程序,通常称为着色器,是在 GPU 上运行的程序。本质上是一个文本文件。必须和材质配合使用。
2. Unity Shader的基础:ShaderLab
什么是ShaderLab?
Unity Shader是Unity为开发者提供的高层级的渲染抽象层。在Unity中,所有的Unity Shader都是用ShaderLab来编写的。ShaderLab是Unity提供的编写Unity Shader的一种说明性语言。
一个Unity Shader的基本结构如下:
Shader "ShaderName"
{
Properties {//属性 }
SubShader {//显卡A使用的子着色器 }
SubShader {//显卡B使用的子着色器}
Fallback"VertexLit"
} 3. Unity Shader的结构
3.1 给我们的Shader起个名字
每个Unity Shader第一行都需要通过Shader语义指定该Unity Shader的名字。例如:
Shader "Custom/MyShader" {}通过在字符串中添加(“/”),可以控制Unity Shader在材质面板中出现的位置。
3.2 材质和Unity Shader的桥梁:Properties
Properties语义块中包含了一系列属性(Property),这些属性将会出现在材质面板中。其中Name是Shader中调用需要的属性,Display name是出现在材质面板山的名字,PropertyType则是属性的类型。
Properties {
Name ("Display name", PropertyType) = DefaultValue
Name ("Display name", PropertyType) = DefaultValue
//更多属性
}
Shader "Custom/ShaderLabProperties"{
Properties{
// numbers and sliders
_Int("Int",Int) = 2
_Float("Float",Float) = 1.5
_Range("Range",Range(0.0,5.0)) = 3.0
// Colors and Vectors
_Color("Color",Color) = (1,1,1,1)
_Vector("Vector",Vector) = (2,3,6,1)
// Textures
_2D("2D",2D) = ""{}
_Cube("Cube",Cube) = "White"{}
_3D("3D",3D) = "black"{}
}
FallBack "Diffuse"
}3.3 重量级成员:SubShader
一个Unity Shader文件可以包含多个SubShader语义块,但最少要有一个。当Unity需要加载这个Unity Shader时,Unity会扫描所有的SubShader语义块,然后选择第一个能够在目标平台上运行的SubShader。如果都不支持的话,Unity就会使用Fallback语义指定的Unity Shader。这种做法是为了支持Unity在不同的显卡上执行不同的渲染操作。
SubShader中定义了一系列Pass以及可选的状态和标签设置。一个Pass通道代表一个完整的渲染流程。所以Pass通道数目越少越好。
3.3.1 状态设置
状态设置的目的是为了设置渲染状态。渲染状态将会应用于目标SubShader下的所有的Pass通道,比如说各类测试的开关,合并模式的开关等。如果需要Pass通道差异化,则需要在Pass通道模块中进行单独的设置。
3.3.2 SubShader的标签
标签的结构如下:
Tags{"TagName1"="Value1" "TagName2"="Value2"}
状态设置是为了定义渲染状态,而标签设置是为了定义何时以及怎样渲染。
3.3.3 Pass语义块
我们可以定义名称,然后通过UsePass命令使用其它Shader中的Pass。
Usepass "MyShader/MYPASSNAME"由于Unity内部会把所有Pass的名称转换为大写,因此,使用UsePass命令时必须使用大写。
Pass通道同样可以设置标签和渲染状态:
除此之外,Unity Shader还支持一些特殊Pass:
Use Pass:可以用这个命令来赋值其他的Unity Shader中的Pass、
GrabPass:负责抓取屏幕并将结果存储在一张纹理中,以用于后续Pass的处理。
3.3.4 Fallback
紧跟在各个SubShader语义块后面,如果所有SubShader都不能运行,则使用这个默认Shader。
3.3.5 ShaderLab的其他语义
可以用CustomEditor语义来扩展编辑界面。
可以用Category来对UnityShader中的命令进行分组。
3.4 Unity的形式
3.4.1 表面着色器
表面着色器是Unity自己创造的一种着色器代码类型,但它的本质仍然是顶点着色器或者片元着色器,可以理解为Unity将表面着色器最终转化为了顶点/片元着色器。而表面着色器的意义在于为我们处理了很多光照细节。
表面着色器的代码定义是写在SubShader内的。
3.4.2 最聪明的孩子:顶点/片元着色器
顶点/片元着色器的代码定义是写在Pass通道内的,而非SubShader,原因是为了更高的灵活性,我们需要在每个Pass通道中自定义代码。
CG/HLSL语言。
3.4.3 被抛弃的角落:固定函数着色器
上面两种Unity Shader形式都使用了可编程管线。一些较旧的设备不支持可编程管线着色器。已逐渐被抛弃使用。
3.4.4 Unity Shader的选择
如果要和各种光源打交道,那么使用表面着色器最方便,但是要注意性能优化问题,尤其是在移动平台。
如果需要的光照数目很少,那么请使用顶点/片元着色器。
如果有很多自定义的渲染效果,那么请选择顶点/片元着色器。
3.5 答疑解惑
3.5.1 Unity Shader和CG/HLSL之间的关系
Unity Shader是用Shader Lab语言编写的,但对于表面着色器和顶点/片元着色器,我们可以在ShaderLab内部嵌套CG/HLSL语言来编写着色器代码。
通常CG代码块是位于Pass语义块内部的,如下所示:
3.5.2 GLSL
Unity Shader同样支持用GLSL进行编写,但是编写的产品则只能上架支持OpenGL的平台。
页:
[1]