Shader是可编程图形管线的算法片段,它主要分为两类,Vertex Shader和Fragment Shader。
圣典shader总目录(在最下方)
vs自动补全代码,语法高亮显示插件
入门指导博客
相关书籍:
相关网站:
渲染管线也称为渲染流水线,是显示芯片内部处理图形信号相互独立的并行处理单元。一个流水线式一序列可以并行和按照固定顺序进行的阶段。每个阶段都从它的前一阶段接收输入,然后把输出发给随后的阶段,就像一个在同一时间内,不同阶段不同的汽车一起制造的装配线,传统的图形硬件流水线以流水方式处理大量的顶点、几何图元和片段。
基于OpenGL的OpenGL Shading Language, 简称GLSL。语法体系自成一家。
OpenGL(全写Open Graphics Library)是指定义了一个跨编程语言、跨平台的编程接口规格的专业的图形程序接口。它用于三维图像(二维的亦可),是一个功能强大,调用方便的底层图形库。
OpenGL是行业领域中最为广泛接纳的 2D/3D 图形 API,其自诞生至今已催生了各种计算机平台及设备上的数千优秀应用程序。OpenGL是独立于视窗操作系统或其它操作系统的,亦是网络透明的。在包含CAD、内容创作、能源、娱乐、游戏开发、制造业、制药业及虚拟现实等行业领域中,OpenGL帮助程序员实现在 PC、工作站、超级计算机等硬件设备上的高性能、极具冲击力的高视觉表现力图形处理软件的开发。
基于DirectX的High Level Shading Language,简称HLSL。移植性较差。
DirectX,(Direct eXtension,简称DX)是由微软公司创建的多媒体编程接口。由C++编程语言实现,遵循COM。被广泛使用于Microsoft Windows、Microsoft XBOX、Microsoft XBOX 360和Microsoft XBOX ONE电子游戏开发,并且只能支持这些平台。最新版本为DirectX 12,创建在最新的Windows10。
还有NVIDIA公司的C for Graphic ,简称Cg语言。可以被OpenGL和Direct3D广泛支持的图形处理器编程语言。
区别:
- 没有嵌套CG语言,也就是代码段中没有CGPROGARAM和ENDCG关键字,就是固定功能着色器。
- 嵌套了CG语言,代码段中有surf函数的,就是表面着色器。
- 嵌套了CG语言,代码段中有#pragma vertex name和 #pragma fragment frag 声明的,就是顶点着色器&片段着色器
Shader---->路径(直接决定shader在material里出现的路径 )
Shader "Custom/LogoShader" {
}
Properties---->属性面板
2D:一张2的阶数大小的贴图,这张贴图将在采样后被转为对应基于模型UV的每个像素的颜色,最终显示出来。
Cube:即Cube map texture(立方体文理),简单说就是6张有联系的2D贴图的结合,主要用来做反射效果(比如天空盒和动态反射),也会被转换为对应的采样。
对于贴图来说,默认值可以是空字符或者"White"、"Black"、"Gray"、"Bump"中的一个,另外{},它只对2D、Rect、Cube贴图有关,当我们需要打开特定选项时可以把其写在这对花括号内。如果需要同时打开多个选项,可以使用空白分隔,
name ("display name", 2D) ="name" { options }
注:包含在纹理属性的大括号中的选项Options是可选的,可能选项如下:
- TexGen纹理生产类型:即纹理的自动生成纹理坐标时的模式,可以是ObjectLinear, EyeLinear,SphereMap, CubeReflect, CubeNormal的其中之一;这些模式和OpenGL纹理生成模式相对应。注意如果使用自定义顶点程序,那么纹理生成将被忽略。如下面的例子。
- LightmapMode光照贴图模式:如果我们给出这个选项,纹理将能被渲染器的光线贴图属性所影响。纹理不能被使用在材质中,而是取自渲染器的设定。
_MainTex ("Albedo (RGB)", 2D) = "white" {TexGen ObjectLinear}
关键字 | 类型 | 对应Cg类型 | 例 |
---|---|---|---|
Float | 浮点数 | float | _MyFloat ("My float", Float) = 0.5 |
Range | 浮点数 (在指定范围内) | float | _MyRange ("My Range", Range(0.01, 0.5)) = 0.1 |
Color | 浮点四元组 | float4 | _MyColor ("Some Color", Color) = (1,1,1,1) |
Vector | 浮点四元组 | float4 | _MyVector("Some Vector",Vector) = (1,1,1,1) |
2D | 2的阶数大小的贴图 | sampler2D | _MyTexture ("Texture", 2D) = "white" {options} |
Rect | 非2的阶数大小的贴图 | sampler2D | _MyRect("My Rect", Rect) = "white" {options} |
Cube | CubeMap | samplerCube | _MyCubemap ("Cubemap", Cube) = "" {options} |
Shader "Custom/LogoShader"
{
Properties {
_Range ("My Range", Range (0.02,0.15)) = 0.07 // sliders
_Color ("My Color", Color) = (.34, .85, .92, 1) // color
_2D ("My Texture 2D", 2D) = "" {} // textures
_Rect("My Rectangle", Rect) = "name" { }
_Cube ("My Cubemap", Cube) = "name" { }
_Float ("My Float", Float) = 1
_Vector ("My Vector", Vector) = (1,2,3,4)
}
}
SubShader---->unity中的每一个着色器都包含一个subshader的列表,当unity需要显示一个网格时,它能发现使用的着色器,并提取第一个能运行在当前用户的显示卡上的子着色器。呈现效果,可以多个,先从第一个开始,如果第一个方案不能达到,就执行第二个方案
Shader "MyShader" {
Properties {
_MyTexture ("My Texture", 2D) = "white" { }
// other properties like colors or vectors go here as well
}
SubShader {
// here goes the 'meat' of your
// - surface shader or
// - vertex and program shader or
// - fixed function shader
}
SubShader {
// here goes a simpler version of the SubShader
// above than can run on older graphics cards
}
}
Unity Shader里面的Tag分为两种,一种是自着色器(SubShader)Tags,一种是通道(Pass)Tags。SubShader中的标签设置是特定的,和Pass中使用的标签是不一样的。而对于状态设置来说,其使用的语法是相同的。但是,如果我们在SubShader进行了这些设置,那么将会用于所有的Pass。
- Tags---->SubShader标签(使用队里标签来确定对象的绘制顺序。shader决定起对象属于哪个渲染队列,这样所有透明的shader能保证在所有不透明的shader后渲染。)
- Background:最先被调用的渲染,通常用来渲染背景(天空盒)。渲染队列值 1000。
- Geometry(default):默认值,大多数物体使用此队列,用来渲染不透明的物体。渲染队列值 2000。
- AlphaTest: alpha tested的物体使用此队列。它是与几何一个独立的队列,因为在绘制所有实体后,渲染经过alpha tested的对象更有效率。渲染队列值 2450。
- Transparent:这个渲染队列是在Geometry和Alpha Test之后,以从后往前的顺序渲染的。任何alpha混合(alpha-blended)(即不写入深度缓冲区depth buffer的shader)应该在这里。例如玻璃,粒子特效。渲染队列值 3000。
- Overlay:此渲染队列用于叠加效果。任何最后呈现的东西都用在这里(例如:镜头光晕)。渲染队列值 4000。
注:Tags标记在Subshader节内,而不是Pass;渲染顺序是先从渲染队列值小的开始渲染。"RenderType"---->标签(Untiy可以运行时替换符合特定RenderType的所有Shader。Camera.RenderWithShader或Camera.SetReplacementShader配合使用。)Camera.RenderWithShader或Camera.SetReplacementShader不要求标签只能是RenderType,RenderType只是Unity内部用于Replace的一个标签而已,你也可以自定义全新的标签用于Replace。比如,你为自己的ShaderA.SubShaderA1(会被unity选取到的SubShader,常为Shader文件中的第一个SubShader)增加Tag为"Distort"="On",然后将"Distort"作为参数replacementTag传给函数。此时,作为replacementShader的实参的ShaderB.SubShaderB1中若有一模一样的"Distort"="On",且这A的材质参数包含B所需材质参数,则SubShaderB1将代替SubShaderA1用于本次渲染。具体可参考:Rendering with Replaced Shaders。
Queue | 队列类型,渲染顺序。 Background=1000 Geometry=2000(默认) AlphaTest=2450 Transparent=3000 Overlay=4000 自定义:"Queue"="3100" "Queue"="Transparent+100" |
RenderType | 渲染类型。内建值包括: Opaque:不透明(法线、自发光、反射、地形Shader) Transparent:半透明(透明、粒子、字体、地形添加通道Shader) TransparentCutout:遮罩透明(透明裁切、双通道植物Shader) Background:天空盒Shader Overlay:GUI纹理、光晕、闪光Shader TreeOpaque:地形引擎——树皮 TreeTransparentCutout:地形引擎——树叶 TreeBillboard:地形引擎——公告牌(始终面向摄像机)式树木 Grass:地形引擎——草 GrassBillboard:地形引擎——公告牌(始终面向摄像机)式草 |
DisableBatching | 禁用批处理,是否禁用Batch(打包、合并),可用值: True:禁用 False:不禁用(默认) LODFading:当LOD fade开启的时候禁用,一般用在树木上面 |
ForceNoShadowCasting | 是否强制不投射阴影,当这个值为True的时候,使用这个Shader的对象便不会投射阴影。 一般用于透明对象,或者不想继承其他shader阴影的时候 |
IgnoreProjector | 无视投影器,当这个值为True的时候,对象便不受投射器影响(不接受Projector组件的投影)。 一般用于半透明对象,因为让投射器影响它们不是什么好事情。 |
CanUseSpriteAtlas | 可使用精灵集,当这个值为False的时候,不能使用精灵集。 |
PreviewType | 材质的预览形式,默认显示为球体,可以使用Plane(2D平面)或Skybox(天空盒) |
Pass Tags
LightMode | 光照模式: 渲染对象的深度到阴影贴图或者深度纹理 MotionVectors: 用来计算逐对象式运动向量 PrepassBase: |
PassFlags | 标志渲染管线如何传递数据给通道 OnlyDirectional: 只有主平行光、环境光和光照探测器的数据会传递给通道 仅用于LightMode为ForwardBase |
RequireOptions | 标志通道至于在某些外部条件满足时才会被渲染 SoftVegetation: 当Quality Setting中的Soft Vegetation选项被开启时,才会渲染通道 |
Culling & Depth Testing
状态名称 | 设置指令 | 解释 |
Cull | Cull Back|Front|Off | 设置剔除模式,剔除背面(背向摄像机的面)|正面 (朝向摄像机的面)|关闭剔除 默认(CullBack) |
ZTest | ZTest Less|Greater|LEqual| Equal|NotEqual|Always|GEqual |
设置深度时使用的函数,少于|大于|小于或等于| 等于|不等|一直|大于或等于 默认(LEqual) |
ZWrite | ZWrite On|Off | 深度记录(默认)|关闭深度写入 |
Blend | Blend SrcFactor DstFactor | 开启并设置混合模式 |
Blend
语法
- Blend Off 关闭混合。
- Blend SrcFactor DstFactor 配合和启用混合,生成的颜色乘以SrcFactor,已在屏幕上的颜色乘以DstFactor,然后两者相加。
- Blend SrcFactor DstFactor,SrcFactorA DstFactorA 与上述操作相同,但是混合alpha通道要使用不同的因子。
- BlendOp Min|Max|Sub|RevSub 不将混合颜色相加,而是对它们进行不同的操作。
- Add---->FinalColor = SrcFactor*SrcColor + DstFactor*DstColor(加法)
- Sub---->FinalColor = SrcFactor*SrcColor - DstFactor*DstColor(减法,源-目标)
- RevSub---->FinalColor = DstFactor*DstColor - SrcFactor*SrcColor(减法,目标-源)
以下所有属性对SrcFactor(源因子)或DstFactor(目标因子)都可用。Source指的是被计算的颜色,Destination是已经在屏幕上的颜色。
注:设置好计算模式之后,就可以设置混合因子了,有两个公式,注意必须选择下面某个公式,Blend模式才算打开,不然默认关闭的。
经过Blending操作后,
混合颜色=缓存颜色*SrcFactor+目标颜色*DstFactor,风宇冲博客。
混合Alpha值=缓存Alpha值*SrcFactorA+目标Alpha值*DstFactorA。
看第一个公式,没有设置计算Alpha值的混合因子,其他只是把SrcFactorA=SrcFactor,DstFactorA=DstFactor了,相当于如果不写就默认用前面两个参数。
One | 值为1,使用此设置来让源或是目标颜色完全的通过。 |
Zero | 值为0,使用此设置来删除源或目标值。 |
SrcColor | 此阶段的值是乘以源颜色的值。 |
SrcAlpha | 此阶段的值是乘以源alpha的值。 |
DstColor | 此阶段的值是乘以帧缓冲区源颜色的值。 |
DstAlpha | 此阶段的值是乘以帧缓冲区源alpha的值。 |
OneMinusSrcColor | 此阶段的值是乘以(1-source color)。 |
OneMinusSrcAlpha | 此阶段的值是乘以(1-source alpha)。 |
OneMinusDstColor | 此阶段的值是乘以(1-destination color)。 |
OneMinusDstAlpha | 此阶段的值是乘以(1-destination alpha)。 |
以下是最常见的混合模式,例如:
- Blend SrcAlpha OneMinusSrcAlphea (透明混合)
- Blend One One(叠加)
- Blend OneMinusDstColoe One(软叠加)
- Blend DstColor Zero(相乘)
- Blend DstColor SrcColor(2x 相乘)
Shader "Custom/LogoShader" {
Properties
{
// Header creates a header text before the shader property.
[Header(Material Property Drawer Example)]
// Space creates vertical space before the shader property.
[Space]
_MainTex ("Main Tex", 2D) = "white" {}
_SecondTex ("Second Tex", 2D) = "white" {}
// Large amount of space
[Space(50)]
//混合状态的定义
//[HideInInspector] _Mode ("__mode", Float) = 0.0
//[HideInInspector] _SrcBlend ("__src", Float) = 1.0
//[HideInInspector] _DstBlend ("__dst", Float) = 0.0
//[HideInInspector] _ZWrite ("__zw", Float) = 1.0
// Toggle displays a **float** as a toggle.
// The property value will be 0 or 1, depending on the toggle state.
// When it is on, a shader keyword with the uppercase property name +"_ON" will be set,
// or an explicitly specified shader keyword.
[Toggle] _Invert ("Invert color?", Float) = 0
// Will set "ENABLE_FANCY" shader keyword when set
[Toggle(ENABLE_FANCY)] _Fancy ("Fancy?", Float) = 0
// Enum displays a popup menu for a **float** property.
// You can supply either an enum type name
// (preferably fully qualified with namespaces, in case there are multiple types),
// or explicit name/value pairs to display.
// Up to **7** name/value pairs can be specified
[Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend ("Src Blend Mode", Float) = 1
[Enum(UnityEngine.Rendering.BlendMode)] _DstBlend ("Dst Blend Mode", Float) = 1
[Enum(Off, 0, On, 1)] _ZWrite ("ZWrite", Float) = 0
[Enum(UnityEngine.Rendering.CompareFunction)] _ZTest ("ZTest", Float) = 0
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull Mode", Float) = 1
// KeywordEnum displays a popup menu for a **float** property, and enables corresponding shader keyword.
// This is used with "#pragma multi_compile" in shaders, to enable or disable parts of shader code.
// Each name will enable "property name" + underscore + "enum name", uppercased, shader keyword.
// Up to **9** names can be provided.
[KeywordEnum(None, Add, Multiply)] _Overlay ("Overlay mode", Float) = 0
// PowerSlider displays a slider with a non-linear response for a Range shader property.
// A slider with 3.0 response curve
[PowerSlider(3.0)] _Shininess ("Shininess", Range (0.01, 1)) = 0.08
}
SubShader
{
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
Blend [_SrcBlend] [_DstBlend]
ZWrite [_ZWrite]
ZTest [_ZTest]
Cull [_Cull]
Pass
{
//设置通道名称
Name "FORWARD"
CGPROGRAM
// Need to define _INVERT_ON shader keyword
#pragma shader_feature _INVERT_ON
// Need to define _INVERT_ON shader keyword
#pragma shader_feature ENABLE_FANCY
// No comma between features
#pragma multi_compile _OVERLAY_NONE _OVERLAY_ADD _OVERLAY_MULTIPLY
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _SecondTex;
float4 _SecondTex_ST;
float _Shininess;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
o.uv.zw = TRANSFORM_TEX(v.uv, _SecondTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv.xy);
// Use #if, #ifdef or #if defined
#if _INVERT_ON
col = 1 - col;
#endif
// Use #if, #ifdef or #if defined
#if ENABLE_FANCY
col.r = 0.5;
#endif
fixed4 secCol = tex2D(_SecondTex, i.uv.zw);
#if _OVERLAY_ADD
col += secCol;
#elif _OVERLAY_MULTIPLY
col *= secCol;
#endif
col *= _Shininess;
return col;
}
ENDCG
}
}
}
LOD
LOD是Level of Detail的简写,确切地说是Shader Level of Detail的简写,因为Unity中还有一个模型的LOD概念,这是两个不同的东西,这里介绍的是Shader中的LOD,模型的LOD。
设置:单个设置Shader.maximumLOD;全局设置Shader.globalMaximumLOD;
原理:小于指定值的shader和SubShader才能被使用。
Shader LOD 就是让我们设置一个数值,这个数值决定了我们能用什么样的Shader。可以通过Shader.maximumLOD或者Shader.globalMaximumLOD 设定允许的最大LOD,当设定的LOD小于SubShader所指定的LOD时,这个SubShader将不可用。通过LOD,我们就可以为某个材质写一组SubShader,指定不同的LOD,LOD越大则渲染效果越好,当然对硬件的要求也可能越高,然后根据不同的终端硬件配置来设置 globalMaximumLOD来达到兼顾性能的最佳显示效果。
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
public Shader targetShader;
private void Start ()
{
// 全局的值会被Shader本地址覆盖
Shader.globalMaximumLOD = 300;
if (targetShader != null)
{
targetShader.maximumLOD = 600;
}
}
Shader Programs
Shader中,编译指令分为两种,一种是常规的变异指令,也就是顶点片元着色器(Vetex & Fragment Shader)使用的编译指令,另一种就是表面着色器(Surface Shader)使用的编译指令。二者都使用#pragma语句来编写,并且都需要写在CGPROGRAM和ENDCG之间。区别在于,VF编译指令写在Pass里面,而表面着色器编译指令写在SubShader里面,表面着色器会自行编译到多通道里去,并且需要使用#pragma surface …指令来标识这是一个表面着色器。
- CGPROGARAM开始到ENDCG结束,如果SubShader有Pass通道,就要写到pass里面。
- 编译指令
#pragma vertex name | 编译name函数为顶点着色器 |
#pragma fragment name | 编译name函数为片元着色器 |
#pragma geometry name | 编译name函数为DX10的几何着色器 注:会自动开启#pragma target 4.0 |
#pragma hull name | 编译name函数为DX10的壳着色器 注:会自动开启#pragma target 5.0 |
#pragma domain name | 编译name函数为DX10的域着色器 注:会自动开启#pragma target 5.0 |
#pragma target name | 表明编译目标 参考着色器编译目标等级 |
#pragma only_renderers space_separated_names | 只为指定的渲染平台渲染着色器 包括下列值: d3d9:Direct3D 9 d3d11:Direct3D 11/12 glcore:OpenGL 3.x/4.x gles:OpenGL ES 2.0 gles:OpenGL ES 3.x metal:IOS&Mac Metal d3d11_9x:Direct3D 11 9.x特性等级一般用于WSA平台 xbox360:Xbox 360 xboxone:Xbox One ps4:PlayStation 4 psp2:PlayStation Vita n3ds:Nintendo 3DS wiiu:Nintendo Wii U |
#pragma exclude_renderers space_separated_names | 排除指定的渲染平台 参数同上 |
#pragma multi_compile... | 参考Shader山下(二十一)多重变体(Multiple Variants) 或者Unity官方文档:多重着色器变体 |
#pragma enable_d3d11_debug_symbols | 生成d3d11的调试信息 可以在VS2012(或以上)使用图形调试器调试shader |
#pragma hardware_tier_variants renderer_name | 针对所选渲染器的每个硬件层级 生成每个已编译的Shader的多重Shader硬件变体 参考Shader山下(二十一)多重变体(Multiple Variants) 或者Unity官方文档:多重着色器变体 |
表面编译指令
#pragma surface surfFunc lightingModel [optional params]
surfaceFunction(必选) | 表面着色器函数 |
lightModel(必选) | 光照模型函数,内置模型: Standard:基于物理的漫反射模型 StandardSpecular:基于物理的高光模型 Lambert:不基于物理的漫反射模型 BlinnPhong:不基于物理的高光模型 也可以自己写,命名规则:Lighting... ...为在编译指令里填写的名称 例如#pragma surface surf Custom 光照模型函数名就要写成: LightingCustom 具体参考表面着色器中的自定义光照模型 |
alpha或者alpha:auto | 透明度混合 对于简单的光照模型(例如Lambert和BlinnPhong)使用alpha:fade 对于基于物理的光照模型使用alpha:premul |
alpha:blend | 透明度混合 |
alpha:fade | 传统透明度混合(参考Shader山下(十八)混合(Blend)命令) |
alpha:premul | 预乘透明度混合 |
alphatest:variable_name | 透明度测试,并使用variable_name作为裁切阈值 |
keepalpha | 对于默认的不透明Shader,会无视光照模型返回的透明度值,直接把1.0写入Alpha通道。 使用keepalpha选项,允许在不透明Shader里保留光照模型返回的透明度值。 |
decal:add | 附加的贴花shader,这意味着对象在其他表面的上面并使用添加方法进行混合。 |
decal:blend | 半透明贴花shader,这意味着对象在其他表面的上面并使用透明度方法进行混合。 |
vertex:vertex_function | 自定义顶点函数 |
finalcolor:color_function | 自定义的最终颜色修改函数 |
finalgbuffer:gbuffer_function | 自定义的改变GBuffer内容的延迟路径 |
finalprepass:prepass_function | 自定义的预通道基础路径 |
addshadow | 生成一个阴影投射通道 一般用于自定义顶点函数,这样的话,就可以对阴影投射使用程序化的顶点动画 一般情况下,shader并不需要任何特殊的阴影处理,因为它们可以使用Fallback里的阴影投射通道 |
fullforwardshadows | 支持前向渲染路径里的所有光照阴影 默认情况下只支持一个平行光的阴影 如果需要点光源(point)或者聚光灯(spot)的阴影,那么就要使用这个选项 |
tessellate:tessellate_function | 使用DX11的GPU镶嵌,tessellate_function计算镶嵌参数 参考表面着色器镶嵌 |
exclude_path:path | 不生成指定渲染路径的通道 可选项: deferred forwad prepass |
noshadow | 禁用阴影 |
noambient | 禁用环境光或者光探头 |
novertexlights | 禁用前向渲染中的光探头或者每顶点光照 |
nolightmap | 禁用所有的光照贴图 |
nodynlightmap | 禁用动态光照贴图 |
nodirlightmap | 禁用平行光照贴图 |
nofog | 禁用内置雾效 |
nometa | 不生成元通道 光照贴图和动态全局光照使用元通道来提取表面信息 |
noforwardadd | 禁用前置渲染的附加通道 这样就让shader支持一个完全平行光,而其他的光使用每顶点或者SH(球谐函数)计算 同样让shader变得更轻 |
softvegetation | 在Quality Setting里的Soft Vegetation被开启的时候,才会被渲染 |
interpolateview | 在顶点着色器中计算视图方向并插入它(默认在像素着色器中计算) 这样使得Shader变得更快,不过需要多使用一个纹理插值。 |
halfasview | 传递半角向量给光照模型(默认是视图向量) 会在每个顶点计算并归一化半角向量 这样更快,但是并不完全正确。 |
approxview | 5.0中被interpolateview取代 |
dualforward | 在前向渲染路径中使用双光照贴图 |
编译指令的一些常见例子:
#pragma surface surfaceFunction lightModel [optionalparams]
// #pargma 关键词 函数名 光照模型 [其它选项]
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
#pragma surface surf Lambert
#pragma surface surf Lambert alpha
#pragma surface surf Lambert addshadow
// 使用model 3.0 可以得到一个更好的光照效果, 默认是2.0
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
//编译指令:不使用GLES渲染器编译
#pragma exclude_renderers gles
// ---------编译指令:着色器编译多样化--------
#pragma shader_feature _NORMALMAP
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature ___ _DETAIL_MULX2
#pragma shader_feature _PARALLAXMAP
// Need to define _INVERT_ON shader keyword
#pragma shader_feature _INVERT_ON
// Need to define _INVERT_ON shader keyword
#pragma shader_feature ENABLE_FANCY
//--------着色器编译多样化快捷指令------------
//编译指令:编译正向渲染基础通道(用于正向渲染中,应用环境光照、主方向光照和顶点/球面调和光照)所需的所有变体。
//这些变体用于处理不同的光照贴图类型、主要方向光源的阴影选项的开关与否
#pragma multi_compile_fwdbase
//编译指令:编译几个不同变种来处理不同类型的雾效(关闭/线性/指数/二阶指数/)
#pragma multi_compile_fog
#pragma multi_compile ___ UNITY_HDR_ON
#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
#pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE
#pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON
//编译指令:编译正向渲染基础通道所需的所有变体,但同时为上述通道的处理赋予了光照实时阴影的能力。
#pragma multi_compile_fwdadd_fullshadows
//快捷编译指令:进行阴影投射相关的多着色器变体的编译
#pragma multi_compile_shadowcaster
// No comma between features
#pragma multi_compile _OVERLAY_NONE _OVERLAY_ADD _OVERLAY_MULTIPLY
//跳过如下变体的编译,简化编译过程
#pragma skip_variants SHADOWS_SOFT DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE
#pragma skip_variants SHADOWS_SOFT
//编译指令:告知编译器顶点和片段着色函数的名称
#pragma vertex vert
#pragma fragment frag
//包含辅助CG头文件
#include "UnityCG.cginc"
#include "UnityStandardCore.cginc"
Include
数据类型
float | 32位浮点数据,一个符号位。浮点数据类型被所有的profile。 |
half | 16位浮点数据。 |
int | 32位整形数据,有些profile会将int类型作为float类型使用。 |
fixed | 12位定点数,被所有的fragment profiles所支持。 |
bool | 布尔数据,通常用于if和条件操作符,布尔数据类型被所有profiles支持。 |
simpler* | sampler,sampler1D,sampler2D,sampler3D,samplerCUBE,samplerRECT。DirectX profiles不支 持samplerRECT类型,除此之外这些类型被所有pixelprofiles和NV40 vertex program proflie所支持。 |
string | 字符类型,该类型不被当前存在的profile所支持,实际上也没有必要在Cg程序中用到字符类型,但是你可 以通过Cg runtime API声明该类型变量,并赋值;因此,该类型变量可以保存Cg文件的信息。(几乎不使用) |
//向量最长不能超过 4 元, 即在 Cg 程序中可以声明 float1 、 float2 、 float3 、float4
//类型的数组变量,但是不能声明超过 4 元的向量。
//在Cg中,向量、矩阵与数组是完全不同的,向量和矩阵是内置的数据类型,而数组则是一种数据结构。
float4 array = float4(1.0, 2.0, 3.0, 4.0);//四元向量
float2 a = float2(1.0, 1.0);
float4 b = float4(a, 0.0, 0.0);
float1x1 matrix1;//等价于 float matirx1; x 是字符,并不是乘号!
float2x3 matrix2;// 表示 2*3 阶矩阵,包含 6 个 float 类型数据
float4x2 matrix3;// 表示 4*2 阶矩阵,包含 8 个 float 类型数据
float4x4 matrix4;//表示 4*4 阶矩阵,这是最大的维数
float2x3 matrix5 = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
sampler2D _MainTex;
Pass
- 通道可以设置名称,例如:Name "FORWARD" ,Pass Tags在上面表格里面已介绍过了。
- Render Setup(渲染设置)
1.Material{Material Block(材质块)}
定义一个使用顶点光照管线的材质
Shader "Custom/LogoShader" {
Properties {
_Color ("Main Color", Color) = (1,1,1,0)
_SpecColor ("Spec Color", Color) = (1,1,1,1)
_Emission ("Emmisive Color", Color) = (0,0,0,0)
_Shininess ("Shininess", Range (0.01, 1)) = 0.7
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Pass {
Material {
//漫反射颜色构成,这是对象的基本颜色
Diffuse [_Color]
//环境色颜色构成,这是当对象被RenderSettings中设定的环境色所照射时对象所表现的颜色。
Ambient [_Color]
//加亮时的光泽度,在0和1之间。0的时候你会发现更大的高亮也看起来像漫反射光照,1的时候你会获得一个细微的亮斑。
Shininess [_Shininess]
//对象反射高光的颜色。
Specular [_SpecColor]
//自发光颜色,当不被任何光照所照到时,对象的颜色。
Emission [_Emission]
//或者
//Diffuse (1,1,1,1)
//Ambient (1,1,1,1)
}
Lighting On
SeparateSpecular On
SetTexture [_MainTex] {
Combine texture * primary DOUBLE, texture * primary
}
}
}
}
2.Lighting On|Off
开启或者关闭顶点光照
3.Cull Black|Front|Off
设置多边形剔除模式
4.ZTest Less|Greater|LEqual|GEqual|Equal|NotEqual|Always
设置深度测试模式
关于相机的深度贴图_CameraDepthTexture:
默认材质都自带RenderType的Tag;
自定义shader只有添加RenderType标签才会将深度写到_CameraDepthTexture。
5.ZWrite On|Off
设置深度写模式
6.Fog { Fog Block}
设置雾参数
7.AlphaTest Less|Greater|LEqual|GEqual|Equal|NotEqual|Always
开启alpha测试
固定管线:使用AlphaTest命令
动态管线:使用clip(alpha - cutoff)指令来实现
Alpha检测在ps完成计后,即将写入帧之前,通过和一个固定的数值比较,来决定当前ps的计算结果到底要不要写入帧中。
// inside SubShader
Tags { "Queue"="AlphaTest" "RenderType"="TransparentCutout" "IgnoreProjector"="True" }
// inside CGPROGRAM in the fragment Shader:
clip(textureColor.a - alphaCutoffValue);
AlphaTest抗锯齿:
// inside SubShader
Tags { "Queue"="AlphaTest" "RenderType"="TransparentCutout" "IgnoreProjector"="True" }
// inside Pass
AlphaToMask On
8.Blend SourceBlendMode DestBlendMode
设置alpha混合模式,shader渲染的最后一步,决定怎样将当前计算结果写入到帧缓存中。
9.Color
设置当顶点光照关闭时所使用的颜色
10.ColorMask RGB|A|0|any combination of R, G, B, A
设置颜色写遮罩,设置为0将关闭所有颜色通道的渲染
11.Offset OffsetFactor,OffsetUnits
设置深度偏移,对Z深度的偏移。
可以让像素看起来更靠前或更靠后,当两个面重叠时,可以手动指定谁相对靠前一些,而且不会战胜Z-Fitting。
Offset只会对ZTest的条件做修正,但是并不会改变最后的Z缓冲。
12.SeparateSpecular On|Off
开启或关闭顶点光照相关的平行高光颜色
13.ColorMaterial AmbientAndDiffus | Emission
当计算顶点光照时使用没顶点颜色
- Texture Setup(纹理设置)---圣典
SetTexture[TexturePropertyName{ Texture Block }],分配一个纹理,Texture Name必须定义为一个纹理属性。如何应用纹理被定义在TextrueBlock中。纹理块控制纹理如何被应用。如上面Pass通道里面的Material代码例子。
combine src1*src2 | 将源1和源2的元素相乘。结果会比单独输出任何一个都要暗 |
combine src1 + src2 | 将源1和源2的元素相加。结果回避单独输出任何一个都要亮 |
combine src1 - src2 | 源1减去源2 |
combine src1 +- src2 | 先相加,然后减去0.5(添加了一个符号) |
combine src1 lerp (src2)src3 | 使用源2的透明度通道值在源3和源1中进行差值,注意差值是反向的: 当透明度值是1时使用源1,透明度为0时使用源3 |
combine src1 * src2 + src3 | 源1和源2的透明度相乘,然后加上源3 |
combine src1 * src2 +- src3 | 源1和源2的透明度相乘,然后和源3座符号加 |
combine src1 * src2 - src3 | 源1和源2的透明度相乘,然后和源3相减 |
GrabPass (用于获取当前屏幕的纹理)
有两种方式将GrabPass放入到SubShader里面:
GrabPass{} 能捕获当前屏幕的内容到一个纹理中,纹理能在后续通道中通过_GrabTexture进行访问。注:这种形式的捕获通道将在每一个使用该通道的对象渲染中执行昂贵的屏幕捕获操作。
GrabPass{ "TextureName" } 能捕获屏幕内容到一个纹理中,但只会在每帧中处理第一个使用给定纹理名的纹理的对象的渲染过程中产生捕获操作。纹理在未来的通道中可以通过给定的纹理名访问。当你在一个场景中拥有多个使用GrabPass的对象时将提高性能。
Shader "Custom/GrabPass"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" "Queue"="Overlay" }//把渲染队列拉到最高overlay
LOD 100
//
GrabPass {} // 截图通道, 后面使用_GrabTexture访问截屏纹理
// end
Pass
{
name "ONE"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _GrabTexture;//使用前重新声明一下
float4 _GrabTexture_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _GrabTexture);//使用
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
//fixed4 col = tex2D(_GrabTexture, i.uv);//这个会使画面倒置了
float4 col = tex2D(_GrabTexture,float2(1-i.uv.x,1-i.uv.y));
return col;
}
ENDCG
}
}
}
UsePass (实际上不是Pass,而是调用其他的Pass的指令)
某些着色器重用其他着色器中已存在的通道,减少重复的代码。例如,在许多像素光照着色器中,阴影色或顶点光照通道在在相应的顶点光照着色器中是相同的。UsePass命令只是包含了另一个着色器的给定通道。例如当如下的命令可以使用内置的高光着色器中的名叫"Base"的通道:
(注:Unity内部会把所有Pass的名称转换成大写字母的表示,因此,在使用UsePass命令时必须使用大写形式的名字)
UsePass "Specular/BASE"
Shader "Unlit/myshader1"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
Name "MYPASS"
CGPROGRAM
}
}
}
Shader "Unlit/myshader2"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
//Unity内部会把所有Pass的名称转换成大写字母的表示,因此,
//在使用UsePass命令时必须使用大写形式的名字
UsePass "Unlit/myshader1/MYPASS"
}
}
Fog { Fog Commands}
Model Off | Gloal | Linear | Exp | Exp2
定义雾模式。全是全局的,依据雾在渲染设定中是否打开确定可从无变化到平方值。
Color ColorValue
设定雾的颜色。
Density FloatValue
以指数的方式,设定雾的密度
Range FloatValue,FloatValue
为Linear的雾设定远近距离
全局雾:
RenderSettings.fog = true;
RenderSettings.fogColor = Color.red;
RenderSettings.fogMode = FogMode.Linear;
RenderSettings.fogStartDistance = 0;
RenderSettings.fogEndDistance = 10;
Shader "Custom/LogoShader" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_From("From", Float) = 0
_To("To", Float) = 10
_Density("Density", Float) = 10
_Color ("Color", Color) = (1,1,1,0)
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
Fog { Mode Linear Color[_Color] Range [_From],[_To] Density [_Density]}
//Fog { Mode Exp Color[_Color] Range [_From],[_To] Density [_Density]}
//Fog { Mode Exp2 Color[_Color] Range [_From],[_To] Density [_Density]}
//Fog { Mode Linear Color (0.87,0.87,0.87,1) Density 0.1 Range 0,300 }
//Fog{ Mode Linear Color(1, 0, 0) Range 0, 10 }
CGPROGRAM
#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
}
FallBack "Diffuse"
}
BindChannels
BindChannels命令允许你指定顶点数据如何映射到显卡中。可编程顶点着色器使用时,BindChannels将没有效果。在这种情况下,绑定受顶点着色器输入控制。默认情况下,Unity3D会为你计算并绑定,但在某些清空下,你要使用自定义绑定。
BindChannels{ Bind "Source" , target }
Source可以是下面其中一个:
- Vertex:vertex position 顶点:顶点的位置
- Normal:vertex normal 法线:顶点的法线
- Tangent:vertex tangent 切线:顶点的切线
- Texcorrd:primary UV coordinate 主要的UV坐标
- Texcorrd1:secondary UV coordinate 次要的UV坐标
- Color:per-vertex color 颜色:每个顶点颜色
Target主要和Sourcel里面的这两个Texcorrd,Texcorrd1不一样
- Texcoord0, Texcoord1, ...: texture coordinates for corresponding texture stage 各个纹理处理阶段的纹理坐标
- Texcoord: texture coordinates for all texture stages 所有纹理处理阶段的纹理坐标
FallBack---->回滚(当本Shader的所有SubShader都不支持当前显卡,就会使用FallBack语句指定的另一个Shader。FallBack最好指定Unity自己预制的Shader实现,因其一般能够在当前所有显卡运行。当SubShader不能执行时,相当于执行默认值)
FallBack "Name" //回归到指定着色器
FallBack Off //不降级,也不会出现任何出错报警,没有子着色器也会继续运行
CustomEditor---->
Other---->
Unity内置着色器(圣典)