LOD 很简单,它是Level of Detail的缩写,在这里例子里我们指定了其为200(其实这是Unity的内建Diffuse着色器的设定值)。这个数值决定了我们能用什么样的 Shader。在Unity的Quality Settings中我们可以设定允许的最大LOD,当设定的LOD小于SubShader所指定的LOD时,这个SubShader将不可用。Unity 内建Shader定义了一组LOD的数值,我们在实现自己的Shader的时候可以将其作为参考来设定自己的LOD数值,这样在之后调整根据设备图形性能 来调整画质时可以进行比较精确的控制。
- VertexLit及其系列 = 100
- Decal, Reflective VertexLit = 150
- Diffuse = 200
- Diffuse Detail, Reflective Bumped Unlit, Reflective Bumped VertexLit = 250
- Bumped, Specular = 300
- Bumped Specular = 400
- Parallax = 500
- Parallax Specular = 600
-
Shader本体
前面杂项说完了,终于可以开始看看最主要的部分了,也就是将输入转变为输出的代码部分。为了方便看,请容许我把上面的SubShader的主题部分抄写一遍
123456789101112131415CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
接下来是是一个编译指令:#pragma surface surf Lambert,它声明了我们要写一个表面Shader,并指定了光照模型。它的写法是这样的
#pragma surface surfaceFunction lightModel [optionalparams]
- surface - 声明的是一个表面着色器
- surfaceFunction - 着色器代码的方法的名字
- lightModel - 使用的光照模型。
Pass的Tag
Shader "ShaderLab Tutorials/TestShader" {
SubShader {
Pass
{
Tags{ "LightMode"="ForwardBase" }
//...
}
}
}
和SubShader有自己专属的Tag类似,Pass也有Pass专属的Tag。
其中最重要Tag是 "LightMode"
,指定Pass和Unity的哪一种渲染路径(“Rendering Path”)搭配使用。这里需要描述的Tag取值可包括:
Always
,永远都渲染,但不处理光照ShadowCaster
,用于渲染产生阴影的物体ShadowCollector
,用于收集物体阴影到屏幕坐标Buff里。
其他渲染路径相关的Tag详见下面章节“Unity渲染路径种类”。
具体所有Tag取值,可参考ShaderLab syntax: Pass Tags。
!!!!!!!!!!!!!!!!!!还有哪些啊,说全啊!!!!!!!!!!!!!!!!!!
FallBack
Shader "ShaderLab Tutorials/TestShader"{
SubShader { Pass {} }
FallBack "Diffuse" // "Diffuse"即Unity预制的固有Shader
// FallBack Off //将关闭FallBack
}
当本Shader的所有SubShader都不支持当前显卡,就会使用FallBack语句指定的另一个Shader。FallBack最好指定Unity自己预制的Shader实现,因其一般能够在当前所有显卡运行。
Shader中的数据类型
有3种基本数值类型:float
、half
和fixed
。
这3种基本数值类型可以再组成vector和matrix,比如half3
是由3个half
组成、float4x4
是由16个float
组成。
float
:32位高精度浮点数。half
:16位中精度浮点数。范围是[-6万, +6万],能精确到十进制的小数点后3.3位。fixed
:11位低精度浮点数。范围是[-2, 2],精度是1/256。
数据类型影响性能
- 精度够用就好。
- 颜色和单位向量,使用
fixed
- 其他情况,尽量使用
half
(即范围在[-6万, +6万]内、精确到小数点后3.3位);否则才使用float
。
- 颜色和单位向量,使用
- 不要将低精度
fixed
类型转换为更高的精度,否则会产生性能问题。 - 低精度
fixed
不要使用“swizzle”(即形如myFixed4.xyzw
、myFixed2.xyxy
,中文不知咋译,“搅和
访问”?),否则会产生性能问题。作者donaldwu说:swizzle在编写Shader里是经常用到的,但到底怎样才算swizzle?
myFixed4.x
算不算?myFixed4.xyzw
算不算?myFixed4.xyxy
算不算?还是都算?
这个目前没有找到权威的定义,所以为了不要影响效率,建议fixed
尽量不要出现上面任意一种形式。
Shader形态
Shader形态之1:固定管线
固定管线是为了兼容老式显卡。都是顶点光照。之后固定管线可能是被Unity抛弃的功能,所以最好不学它、当它不存在。特征是里面出现了形如下面Material
块、没有CGPROGRAM
和ENDCG
块。
Shader "ShaderLab Tutorials/TestShader"
{
Properties {
_Color ("My Color", Color) = (.34, .85, .92, 1) // color
}
// Fixed Pipeline
SubShader
{
Pass
{
Material{
Diffuse [_Color]
Ambient [_Color]
}
Lighting On
}
}
}
Shader形态之2:可编程Shader
Shader "ShaderLab Tutorials/TestShader"
{
Properties {}
SubShader
{
Pass
{
// ... the usual pass state setup ...
CGPROGRAM
// compilation directives for this snippet, e.g.:
#pragma vertex vert
#pragma fragment frag
// the Cg/HLSL code itself
float4 vert(float4 v:POSITION) : SV_POSITION{
return mul(UNITY_MATRIX_MVP, v);
}
float4 frag() : COLOR{
return fixed4(1.0, 0.0, 0.0, 1.0);
}
ENDCG
// ... the rest of pass setup ...
}
}
}
- 功能最强大、最自由的形态。
- 特征是在Pass里出现
CGPROGRAM
和ENDCG
块 - 编译指令
#pragma
。详见官网Cg snippets。其中重要的包括:
编译指令 | 示例/含义 |
---|---|
#pragma vertex name #pragma fragment name | 替换name,来指定Vertex Shader函数、Fragment Shader函数。 |
#pragma target name | 替换name(为2.0 、3.0 等)。设置编译目标shader model的版本。 |
#pragma only_renderers name name ... #pragma exclude_renderers name name... | #pragma only_renderers gles gles3 ,#pragma exclude_renderers d3d9 d3d11 opengl ,只为指定渲染平台(render platform)编译 |
- 引用库。通过形如
#include "UnityCG.cginc"
引入指定的库。常用的就是UnityCG.cginc
了。其他库详见官网Built-in shader include files。 - ShaderLab内置值。Unity给Shader程序提供了便捷的、常用的值,比如下面例子中的
UNITY_MATRIX_MVP
就代表了这个时刻的MVP矩阵。详见官网ShaderLab built-in values。 - Shader输入输出参数语义(Semantics)。在管线流程中每个阶段之间(比如Vertex Shader阶段和FragmentShader阶段之间)的输入输出参数,通过语义字符串,来指定参数的含义。常用的语义包括:
COLOR
、SV_Position
、TEXCOORD[n]
。完整的参数语义可见HLSL Semantic(由于是HLSL的连接,所以可能不完全在Unity里可以使用)。 - 特别地,因为Vertex Shader的的输入往往是管线的最开始,Unity为此内置了常用的数据结构:
数据结构 | 含义 |
---|---|
appdata_base | vertex shader input with position, normal, one texture coordinate. |
appdata_tan | vertex shader input with position, normal, tangent, one texture coordinate. |
appdata_full | vertex shader input with position, normal, tangent, vertex color and two texture coordinates. |
appdata_img | vertex shader input with position and one texture coordinate. |