本文章用于帮助自己学习,因此只记录一些个人认为比较重要或者还不够熟悉的内容。
原作者:http://blog.csdn.net/candycat1992/article/
第三章 Unity Shader基础
3.1Unity Shader概述
最常见的流程:
由一个三维场景生成一张二维图像。
(1) 创建一个材质;
(2) 创建一个Unity Shader,并把它赋给上一步中创建的材质:
(3) 把材质赋给要渲染的对象;
(4) 在材质面板中调整Unity Shader的属性,以得到满意的效果。
3.2ShaderLab
Unity Shader是Unity为开发者提供的高层级的渲染抽象层。
在Unity中,所有的Unity Shader都是用ShaderLab来编写的。ShaderLab是Unity提供的编写Unity Shader的一种说明性语言。
3.3Unity Shader的结构
3.3.1给Shader起名
Shader "Custom/MyShader"
通过在字符串中添加斜杠(“/”),可以控制Unity Shader在材质面板中出现的位置。
3.3.2Properties
Properties语义块中包含了一系列属性(property), 这些属性将会出现在材质面板中。
Properties
{
Name ("display name", PropertyType) = DefaultValue
}
Name是属性的名字,一般由一个下划线开始。
display name是显示在材质面板上的名字。
PropertyType是属性的类型。
等号后面的DefaultValue就是需要给属性指定的默认值。
属性类型 | 默认值的定义语法 | 例子 |
---|---|---|
Int | number | ("Int”, Int) = 2 |
Float | number | Float ("Float”, Float) = 1.5 |
Range(min,max) | number | _Range(“Range”, Range(0.0, 5.0)) = 3.0 |
Color | (number,number,number,number) | Color ("Color”, Color) = (1,13,1) |
Vector | (number,number,number,number) | _Vector (“Vector”, Vector) = (2, 3, 6, 1) |
2D | “defaulttexture” {} | _2D ("2D”, 2D) = ”” {} |
3D | “defaulttexture” {} | 3D(”3D”,3D) = "black” () |
Cube | “defaulttexture” {} | _Cube (“Cube”, Cube) = “white” (} |
3.3.3SubShader
SubShader语义块中包含的定义通常如下:
SubShader {
//可选的
[Tags]
//可选的
[RenderSetup]
Pass (
}
// Other Passes
SubShader中定义了一系列Pass以及可选的状态([RenderSetup])和标签([Tags])设置。每个Pass定义了一次完整的渲染流程。状态和标签同样可以在Pass声明,但是,如果在Shader进行了这些设置,那么将会用于所有的Pass。
- 状态设置可以设置显卡的各种状态。
表3.2 |
常见的渲染状态设置选项 |
|
状态名称 |
设置指令 |
解 释 |
Cull |
Cull Back | Front | Off |
设置剔除模式:剔除背面/正面/关闭 剔除 |
ZTest |
ZTest Less Greater | LEqual | GEqual | Equal | NotEqual | Always |
设置深度测试时使用的函数 |
ZWrite |
ZWrite On | Off |
开启/关闭深度写入 |
Blend |
Blend SrcFactor DstFactor |
开启并设置混合模式 |
当在SubShader块中设置了上述渲染状态时,将会应用到所有的Pass。
-
SubShader 的标签
SubShader的标签(Tags)是一个键值对(Key/Value Pair),它的键和值都是字符串类型。它们用来告诉Unity的渲染引擎:SubShader我希望怎样以及何时渲染这个对象。
Tags { "TagName1" = "Valuel" "TagName2" ="Value2" }
表3.3 |
SubShader的标签类型 |
|
标签类型 |
说 明 |
例 子 |
Queue |
控制渲染顺序,指定该物体属于哪一个渲染队列,通 过这种方式可以保证所有的透明物体可以在所有不透 明物体后面被渲染(详见第8章),我们也可以自定义 使用的渲染队列来控制物体的渲染顺序 |
Tags ("Queue'1 = "Transparent" } |
RenderType |
对着色器进行分类,例如这是一个不透明的着色器, 或是一个透明的着色器等。这可以被用于着色器替换 (Shader Replacement)功能 |
Tags {"RenderType" = "Opaque" } |
DisableBatching |
一些S泌S/wd”在使用Unity的批处理功能时会出现问 题,例如使用了模型空间下的坐标进行顶点动画(详 见11.3节)。这时可以通过该标签来直接指明是否对该 SubShader使用批处理 |
Tags ("DisableBatching" = "True" } |
ForceNoShadowCasting |
控制使用该SubShader的物体是否会投射阴影(详见 8.4 节) |
Tags { "ForceNoShadowCasting"= "True” } |
IgnoreProjector |
如果该标签值为“True”,那么使用该SubShader的物 体将不会受Projector的影响。通常用于半透明物体 |
Tags ('IgnoreProjector" = "True" } |
CanUseSpriteAtlas |
当该SubShade矿是用于精灵(sprites)时,将该标签设 为 “False” |
Tags {"CanUseSpriteAtlas" = "False"} |
PreviewType |
指明材质面板将如何预览该材质。默认情况下,材质 将显示为一个球形,我们可以通过把该标签的值设为 “Plane” “SkyBox”来改变预览类型 |
Tags ( "PreviewType” = "Plane" } |
上述标签仅可以在SubShader中声明,而不可以在Pass块中声明。
- Pass语义块
Pass语义块包含的语义如下:
Pass (
[Name]
[Tags]
[RenderSetup]
// Other code
}
首先定义名称,例如:
Name "MyPassName"
可以使用ShaderLab的UsePass命令来直接使用其他Unity Shader中的 Pass。例如:
UsePass "MyShader/MYPASSNAME"
在使用UsePass命令时必须使用大写形式的名字。
其次,可以对Pass设置渲染状态。SubShader的状态设置同样适用于Pass。
Pass同样可以设置标签,但它的标签不同于SubShader的标签。
表3.4 |
Pass的标签类型 |
|
标签类型 |
说 明 |
例 子 |
LightMode |
定义该Pass在Unity的渲染流水线中的角色 |
Tags { "LightMode** = "ForwardBase" } |
RequireOptions |
用于指定当满足某些条件时才渲染该Pass,它的值是一个 由空格分隔的字符串。目前,Unity支持的选项有: Soft Vegetation o在后面的版本中,可能会增加更多的选项 |
Tags ( "RequireOptions" = "SoftVegetation"} |
3.3.4Fallback
紧跟在各个SubShader语义块后面的,可以是一个Fallback指令。它用于告诉Unity:“如果上面所有的SubShader在这块显卡上都不能运行,那么就使用这个最低级的Shader。 ”
它的语义如下:
Fallback "name"
//或者
Fallback Off//关闭Fallback
例:
Fallback "VertexLit"
3.4Unity Shader的形式
UnityShader最重要的任务是指定各种着色器所需的代码。这些着色器代码可以写在SubShader语义块中(表面着色器的做法),也可以写在Pass语义块中(顶点/片元着色器和固定函数着色器的做法)。
Shader "MyShader"(
Properties {
//所需的各种属性
}
SubShader (
//真正意义上的Shader代码会出现在这里
//表面着色器(Surface Shader )或者
//顶点/片元着色器(Vertex/Fragment Shader )或者
// 固定函数着色器(Fixed Function Shader )
}
SubShader {
//和上一个SubShader类似
}
}
3.4.1表面着色器
表面着色器在本质上和顶点/片元着色器是一样的。当给Unity提供一个表面着色器的时候,它在背后仍旧把它转换成对应的顶点/片元着色器。
示例代码:
Shader "Custom/Simple Surface Shader" {
SubShader {
Tags ( "RenderType** = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input (
float4 color : COLOR;
);
void surf (Input IN, inout Surfaceoutput o) (
o.Albedo = 1;
}
ENDCG
}
Fallback “Diffuse”
)
表面着色器被定义在SubShader语义块(而非Pass语义块)中的 CGPROGRAM和ENDCG之间。
CGPROGRAM和ENDCG之间的代码是使用CG/HLSL编写的。
3.4.1顶点/片元着色器
示例代码:
Shader "Custom/Simple VertexFragment Shader" (
SubShader (
Pass (
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 vert(float4 v : POSITION) : SV_POSITION (
return mul (UNITY_MATRIX_MVP, v);
}
fixed4 frag() : SV_Target (
return fixed4(1.0,0.0,0.0,1.0);
}
ENDCG
}
}
}
顶点/片元着色器的代码也需要定义在CGPROGRAM和ENDCG之间, 但不同的是,顶点/片元着色器是写在Pass语义块内,而非SubShader内的。