常用的Shader编程语言
HLSL、GLSL、Cg
- HLSL:全称(High Level Shading Language),由微软提供的基于Direct3D图形库
- GLSL:全称(OpenGL Shading Language),由OpenGL安委会提供,在OpenGL中进行着色器编程的语言。
- Cg:全称(C for graphics),由NVIDIA公司和Microsoft公司合作提供,有自己的一套关键字和函数库,独立于三维编程接口,在Direct3D和OpenGL上都可工作。
什么是ShaderLab
Unity中所有Shader文件都通过一种陈述性语言进行描述,称为“ShaderLab”, Shader文件中用一种嵌套式语法来描述着色器行为,如材质面板中显示的属性、使用的混合模式等等,实际的着色器代码(如HLSL/Cg)定义在CGPROGRAM与ENDCG之间。
简单说:Unity自己又封装了一层CG/HLSL/GLSL的接口,但为了实现跨平台,Unity重点支持Cg着色器语言。同时支持surface Shader、Vertex and Fragment Shader 和 Fixed function shader三种Shader
ShaderLab语法
Shader "Custom/Simple colored lighting" { //名称
Properties { //定义一个名为Main Color的颜色属性
_Color ("Main Color", Color) = (1, .5, .5, 1)
}
SubShader { //Shader的实现代码
Pass {
Material {
Diffuse [_Color]
}
Lighting On
}
}
}
代码解释
Shader "着色器名称(或者路径)" { //如上面示例Shader的名称为"Simple colored lighting"或者路径"Custom/Simple colored lighting" 在Unity纹理的Inspector面板上Shader可以查看,可查看下图在材质中选择Shader脚本
Properties { //属性定义
//定义属性:
//_Name:在Shader代码中的变量名,通过该名字获取该属性的内容
//Display Name:这个字符串将显示在Unity的材质编辑器中作为Shader的使用者可读的内容
//Type:属性的类型。具体类型查看Properties属性
//defaultValue:该属性的默认值,查看Properties默认值
//{options}:只对贴图纹理有效(2D/Rect/Cube),用于选择贴图,查看Properties属性
_Name ("Display Name", Type) = defaultValue[{options}]
}
SubShader {} //子着色器
SubShader {} //子着色器
...
Fallback "备用着色器名称" //如果所有子着色器都不运行,则使用备用着色器
}
在材质中选择Shader脚本
Shader默认创建在Custom中,也可以自己新写个路径,则会出现新的路径
Properties属性
定义:用来定义着色器中使用的贴图资源或者数值等,可以在Inspector面板显示,方便修改以及设置
代码
Properties
{
属性列表
}
Properties属性
语法 | 说明 | 默认值 | 示例 |
---|---|---|---|
名称(“显示名称”, Vector)=默认向量值 | 定义一个四维向量属性 | 四维数(x, y, z, w) | _Vector("Vector", Vector) = (2, 2, 2, 1) |
名称(“显示名称”,Color)=默认颜色值 | 定义一个颜色(取值为0~1的四维向量)属性 | rgba值(1, 1, 1, 1) | _Color("Color", Color) = (1, 1, 1, 1) |
名称(“显示名称”,Float)=默认浮点数值 | 定义一个浮点数属性 | 浮点数 | _Float("Float", Float) = 2.5 |
名称(“显示名称”,Range (min, max))=默认浮点数值 | 定义一个浮点数范围属性,取值从min到max | 浮点值 | _Range("Range", Range(0.02, 0.15)) = 0.07 |
名称(“显示名称”,2D)=默认贴图名称{选项} | 定义一个2D纹理属性 | 默认值可以为一个代表默认tint颜色的字符串,可以是空字符串或者”white”,”black”,”gray”,”bump”中的一个 | _Texture("Texture", 2D) = "" {} |
名称(“显示名称”,Rect)=默认贴图名称{选项} | 定义一个矩形纹理属性(非2的n次幂) | 默认值可以为一个代表默认tint颜色的字符串,可以是空字符串或者”white”,”black”,”gray”,”bump”中的一个 | _Rect("Rect", Rect) = "" {} |
名称(“显示名称”,Cube)=默认贴图名称{选项} | 定义一个立方体纹理属性 | 默认值可以为一个代表默认tint颜色的字符串,可以是空字符串或者”white”,”black”,”gray”,”bump”中的一个 | _Cube("Cube", Cube) = "" {} |
名称:指的是Shader代码中使用的属性名称
显示名称:指的是Inspector视图中用于显示的名称字符串
上面表格中贴图选项:是一些纹理的可选参数
- TexGen:纹理生成模式,可以是ObjectLinear、EyeLinear、SphereMap、CubeReflect、CubeNormal中的一种,这些模式与OpenGL的纹理生成模式相对于。如果使用自定义的顶点程序,那么该参数将被忽略
- LightmapMode:如果使用该选项,那么纹理将受渲染器的光照贴图参数影响。纹理将不会从材质中获取,而是取自渲染器的设置。
用法如下:
_Cube("Cube", Cube) = "" {TexGen ObjectLinear}
_Cube("Cube", Cube) = "" {LightmapMode}
如图所示
SubShader子着色器
一个着色器包含有一个或者多个子着色器。在渲染时会从上到下遍历子着色器列表,找到第一个能运行的子着色器用于渲染。子着色器由标签(可选)、通用状态(可选)、Pass列表组成
语法结构
Subshader {
[Tags]
[CommonState]
Passdef [Passdef ...]
}
当Unity使用着色器渲染时,会从上到下遍历子着色器,找到第一个能被用户设备支持的子着色器,并使用该子着色器进行渲染。如果没有子着色器能够运行,Unity则会使用备用着色器。因为硬件型号众多,新旧不一,如何让游戏在不同的硬件平台上运行良好,需要开发者深入研究。开发者当然希望在最新的硬件平台上展现最优秀的游戏画面,但是也不想将使用旧设备的用户拒之门外,因此在着色器中编写多个子着色器来适配不同能力的硬件平台是非常有必要的。
示例
SubShader {
Tags { "RenderType"="Opaque" }
Pass {
Lighting Off //关闭灯光
SetTexture [_MainTex] {} //使用MainTex纹理
}
}
Tags
表面着色器可以被若干的标签(tags)所修饰,而硬件将通过判定这些标签来决定什么时候调用该着色器。
如下例子
"RenderType"="Opaque"
告诉系统应该在渲染非透明物体时调用我们,该Tags将专门一篇讲解
Pass
在Unity使用子着色器进行渲染时,每个Pass都会渲染一次对象(有时根据光照交互情况会渲染多次)。由于每次渲染都会造成一定的开销,因此在硬件能力允许的情况下,尽量减少不必要的Pass数量。
语法结构
Pass { [Name and Tags名称和标签] [RenderSetup渲染设置] [TextureSetup纹理设置]}
名称和标签(Name and Tags)
可以定义Pass的名字以及任意数量的标签。为Pass命名后,可以在别的着色器中通过Pass名称来引用它。标签则可以用来向渲染管线说明Pass的意图,它是“键-值”对的形式。
渲染设置(RenderSetup)
设置图形硬件的各种状态,例如开启Alpha混合、开启雾效等。
渲染命令如下图
纹理设置(TextureSetup)
在设置渲染状态以后,可以指定一些要使用的纹理及其混合模式。用于固定功能管线,如果使用表面着色器或自定义的顶点及片段着色器,那么纹理设置将会被忽略
语法结构
SetTexture 纹理属性 {[命令选项]}
命令选项
- combine:将两个颜色源混合,混合的源可以是previous ( 上一次SetTexture的结果)、constant(常量颜色值) 、primary(顶点颜色)和texture(纹理颜色)中的—种
- constantColor:设置一个常量颜色值。
- matrix:设置矩阵对纹理坐标进行变换。
两种特殊的Pass
UsePass
可以通过UsePass来重用其他着色器中命名的Pass
示例
UsePass "Specular/BASE" //使用高光着色器Specular中名为BASE的Pass
UsePass可以减少代码的重复,通过代码重用提高开发效率,有点类似于脚本里定义的一些公共函数。
GrabPass
将屏幕抓取到一个纹理中,供后续的Pass使用,可以通过GrabTexture来访问
Fallback 备用着色器
如果当前硬件不支持任何子着色器运行,那么将使用备用着色器。
语法
- Fallback "备用着色器名称",如:Fallback "Diffuse"
- Fabllback Off:显示声明不使用备用着色器,当没有子着色器允许时也不会有任何警告
Category
分类用于提供让子着色器继承的命令,例如着色器中的多个子着色器都需要关闭雾效、设置混合模式,那么就可以通过使用Category语句来完成
例如
Shader "example" {
Category {
Fog {Mode Off}
Blend One One
SubShader {}
}
}